@the-inclusionist/engine 8.0.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (756) hide show
  1. package/README.md +89 -78
  2. package/app/css/style.css +584 -374
  3. package/app/public/vendor/fonts/bitter-var-ext.woff2 +0 -0
  4. package/app/public/vendor/fonts/bitter-var.woff2 +0 -0
  5. package/app/public/vendor/fonts/bodonimoda-var-ext.woff2 +0 -0
  6. package/app/public/vendor/fonts/bodonimoda-var.woff2 +0 -0
  7. package/app/public/vendor/fonts/cat-abril_fatface-400-ext.woff2 +0 -0
  8. package/app/public/vendor/fonts/cat-abril_fatface-400.woff2 +0 -0
  9. package/app/public/vendor/fonts/cat-adlam_display-400-ext.woff2 +0 -0
  10. package/app/public/vendor/fonts/cat-adlam_display-400.woff2 +0 -0
  11. package/app/public/vendor/fonts/cat-agu_display-400-ext.woff2 +0 -0
  12. package/app/public/vendor/fonts/cat-agu_display-400.woff2 +0 -0
  13. package/app/public/vendor/fonts/cat-alfa_slab_one-400-ext.woff2 +0 -0
  14. package/app/public/vendor/fonts/cat-alfa_slab_one-400.woff2 +0 -0
  15. package/app/public/vendor/fonts/cat-are_you_serious-400-ext.woff2 +0 -0
  16. package/app/public/vendor/fonts/cat-are_you_serious-400.woff2 +0 -0
  17. package/app/public/vendor/fonts/cat-asimovian-400-ext.woff2 +0 -0
  18. package/app/public/vendor/fonts/cat-asimovian-400.woff2 +0 -0
  19. package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400-ext.woff2 +0 -0
  20. package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400.woff2 +0 -0
  21. package/app/public/vendor/fonts/cat-bakbak_one-400-ext.woff2 +0 -0
  22. package/app/public/vendor/fonts/cat-bakbak_one-400.woff2 +0 -0
  23. package/app/public/vendor/fonts/cat-bangers-400-ext.woff2 +0 -0
  24. package/app/public/vendor/fonts/cat-bangers-400.woff2 +0 -0
  25. package/app/public/vendor/fonts/cat-barriecito-400-ext.woff2 +0 -0
  26. package/app/public/vendor/fonts/cat-barriecito-400.woff2 +0 -0
  27. package/app/public/vendor/fonts/cat-berkshire_swash-400-ext.woff2 +0 -0
  28. package/app/public/vendor/fonts/cat-berkshire_swash-400.woff2 +0 -0
  29. package/app/public/vendor/fonts/cat-bevan-400-ext.woff2 +0 -0
  30. package/app/public/vendor/fonts/cat-bevan-400.woff2 +0 -0
  31. package/app/public/vendor/fonts/cat-bitcount-400-ext.woff2 +0 -0
  32. package/app/public/vendor/fonts/cat-bitcount-400.woff2 +0 -0
  33. package/app/public/vendor/fonts/cat-bowlby_one_sc-400-ext.woff2 +0 -0
  34. package/app/public/vendor/fonts/cat-bowlby_one_sc-400.woff2 +0 -0
  35. package/app/public/vendor/fonts/cat-bungee_shade-400-ext.woff2 +0 -0
  36. package/app/public/vendor/fonts/cat-bungee_shade-400.woff2 +0 -0
  37. package/app/public/vendor/fonts/cat-charm-400-ext.woff2 +0 -0
  38. package/app/public/vendor/fonts/cat-charm-400.woff2 +0 -0
  39. package/app/public/vendor/fonts/cat-charm-700-ext.woff2 +0 -0
  40. package/app/public/vendor/fonts/cat-charm-700.woff2 +0 -0
  41. package/app/public/vendor/fonts/cat-cherry_bomb_one-400-ext.woff2 +0 -0
  42. package/app/public/vendor/fonts/cat-cherry_bomb_one-400.woff2 +0 -0
  43. package/app/public/vendor/fonts/cat-chokokutai-400-ext.woff2 +0 -0
  44. package/app/public/vendor/fonts/cat-chokokutai-400.woff2 +0 -0
  45. package/app/public/vendor/fonts/cat-chonburi-400-ext.woff2 +0 -0
  46. package/app/public/vendor/fonts/cat-chonburi-400.woff2 +0 -0
  47. package/app/public/vendor/fonts/cat-climate_crisis-400-ext.woff2 +0 -0
  48. package/app/public/vendor/fonts/cat-climate_crisis-400.woff2 +0 -0
  49. package/app/public/vendor/fonts/cat-cookie-400.woff2 +0 -0
  50. package/app/public/vendor/fonts/cat-dela_gothic_one-400-ext.woff2 +0 -0
  51. package/app/public/vendor/fonts/cat-dela_gothic_one-400.woff2 +0 -0
  52. package/app/public/vendor/fonts/cat-fascinate_inline-400-ext.woff2 +0 -0
  53. package/app/public/vendor/fonts/cat-fascinate_inline-400.woff2 +0 -0
  54. package/app/public/vendor/fonts/cat-ga_maamli-400-ext.woff2 +0 -0
  55. package/app/public/vendor/fonts/cat-ga_maamli-400.woff2 +0 -0
  56. package/app/public/vendor/fonts/cat-itim-400-ext.woff2 +0 -0
  57. package/app/public/vendor/fonts/cat-itim-400.woff2 +0 -0
  58. package/app/public/vendor/fonts/cat-jacquard_24-400-ext.woff2 +0 -0
  59. package/app/public/vendor/fonts/cat-jacquard_24-400.woff2 +0 -0
  60. package/app/public/vendor/fonts/cat-kablammo-400-ext.woff2 +0 -0
  61. package/app/public/vendor/fonts/cat-kablammo-400.woff2 +0 -0
  62. package/app/public/vendor/fonts/cat-kalam-400-ext.woff2 +0 -0
  63. package/app/public/vendor/fonts/cat-kalam-400.woff2 +0 -0
  64. package/app/public/vendor/fonts/cat-kalam-700-ext.woff2 +0 -0
  65. package/app/public/vendor/fonts/cat-kalam-700.woff2 +0 -0
  66. package/app/public/vendor/fonts/cat-katibeh-400-ext.woff2 +0 -0
  67. package/app/public/vendor/fonts/cat-katibeh-400.woff2 +0 -0
  68. package/app/public/vendor/fonts/cat-lemonada-400-ext.woff2 +0 -0
  69. package/app/public/vendor/fonts/cat-lemonada-400.woff2 +0 -0
  70. package/app/public/vendor/fonts/cat-lilita_one-400-ext.woff2 +0 -0
  71. package/app/public/vendor/fonts/cat-lilita_one-400.woff2 +0 -0
  72. package/app/public/vendor/fonts/cat-lobster-400-ext.woff2 +0 -0
  73. package/app/public/vendor/fonts/cat-lobster-400.woff2 +0 -0
  74. package/app/public/vendor/fonts/cat-luckiest_guy-400-ext.woff2 +0 -0
  75. package/app/public/vendor/fonts/cat-luckiest_guy-400.woff2 +0 -0
  76. package/app/public/vendor/fonts/cat-marhey-400-ext.woff2 +0 -0
  77. package/app/public/vendor/fonts/cat-marhey-400.woff2 +0 -0
  78. package/app/public/vendor/fonts/cat-modak-400-ext.woff2 +0 -0
  79. package/app/public/vendor/fonts/cat-modak-400.woff2 +0 -0
  80. package/app/public/vendor/fonts/cat-momo_signature-400-ext.woff2 +0 -0
  81. package/app/public/vendor/fonts/cat-momo_signature-400.woff2 +0 -0
  82. package/app/public/vendor/fonts/cat-monofett-400-ext.woff2 +0 -0
  83. package/app/public/vendor/fonts/cat-monofett-400.woff2 +0 -0
  84. package/app/public/vendor/fonts/cat-monomakh-400-ext.woff2 +0 -0
  85. package/app/public/vendor/fonts/cat-monomakh-400.woff2 +0 -0
  86. package/app/public/vendor/fonts/cat-monoton-400-ext.woff2 +0 -0
  87. package/app/public/vendor/fonts/cat-monoton-400.woff2 +0 -0
  88. package/app/public/vendor/fonts/cat-nerko_one-400-ext.woff2 +0 -0
  89. package/app/public/vendor/fonts/cat-nerko_one-400.woff2 +0 -0
  90. package/app/public/vendor/fonts/cat-noto_sans_adlam-400-ext.woff2 +0 -0
  91. package/app/public/vendor/fonts/cat-noto_sans_adlam-400.woff2 +0 -0
  92. package/app/public/vendor/fonts/cat-noto_sans_arabic-400-ext.woff2 +0 -0
  93. package/app/public/vendor/fonts/cat-noto_sans_arabic-400.woff2 +0 -0
  94. package/app/public/vendor/fonts/cat-noto_sans_devanagari-400-ext.woff2 +0 -0
  95. package/app/public/vendor/fonts/cat-noto_sans_devanagari-400.woff2 +0 -0
  96. package/app/public/vendor/fonts/cat-noto_sans_hebrew-400-ext.woff2 +0 -0
  97. package/app/public/vendor/fonts/cat-noto_sans_hebrew-400.woff2 +0 -0
  98. package/app/public/vendor/fonts/cat-noto_sans_jp-400-ext.woff2 +0 -0
  99. package/app/public/vendor/fonts/cat-noto_sans_jp-400.woff2 +0 -0
  100. package/app/public/vendor/fonts/cat-noto_sans_khmer-400-ext.woff2 +0 -0
  101. package/app/public/vendor/fonts/cat-noto_sans_khmer-400.woff2 +0 -0
  102. package/app/public/vendor/fonts/cat-noto_sans_kr-400-ext.woff2 +0 -0
  103. package/app/public/vendor/fonts/cat-noto_sans_kr-400.woff2 +0 -0
  104. package/app/public/vendor/fonts/cat-noto_sans_sc-400-ext.woff2 +0 -0
  105. package/app/public/vendor/fonts/cat-noto_sans_sc-400.woff2 +0 -0
  106. package/app/public/vendor/fonts/cat-noto_sans_thai-400-ext.woff2 +0 -0
  107. package/app/public/vendor/fonts/cat-noto_sans_thai-400.woff2 +0 -0
  108. package/app/public/vendor/fonts/cat-ole-400-ext.woff2 +0 -0
  109. package/app/public/vendor/fonts/cat-ole-400.woff2 +0 -0
  110. package/app/public/vendor/fonts/cat-pacifico-400-ext.woff2 +0 -0
  111. package/app/public/vendor/fonts/cat-pacifico-400.woff2 +0 -0
  112. package/app/public/vendor/fonts/cat-patrick_hand-400-ext.woff2 +0 -0
  113. package/app/public/vendor/fonts/cat-patrick_hand-400.woff2 +0 -0
  114. package/app/public/vendor/fonts/cat-petit_formal_script-400-ext.woff2 +0 -0
  115. package/app/public/vendor/fonts/cat-petit_formal_script-400.woff2 +0 -0
  116. package/app/public/vendor/fonts/cat-pixelify_sans-400-ext.woff2 +0 -0
  117. package/app/public/vendor/fonts/cat-pixelify_sans-400.woff2 +0 -0
  118. package/app/public/vendor/fonts/cat-plaster-400-ext.woff2 +0 -0
  119. package/app/public/vendor/fonts/cat-plaster-400.woff2 +0 -0
  120. package/app/public/vendor/fonts/cat-playwrite_ar_guides-400-0.woff2 +0 -0
  121. package/app/public/vendor/fonts/cat-playwrite_at-400-0.woff2 +0 -0
  122. package/app/public/vendor/fonts/cat-playwrite_at_guides-400-0.woff2 +0 -0
  123. package/app/public/vendor/fonts/cat-playwrite_au_nsw-400-0.woff2 +0 -0
  124. package/app/public/vendor/fonts/cat-playwrite_au_nsw_guides-400-0.woff2 +0 -0
  125. package/app/public/vendor/fonts/cat-playwrite_au_qld-400-0.woff2 +0 -0
  126. package/app/public/vendor/fonts/cat-playwrite_au_qld_guides-400-0.woff2 +0 -0
  127. package/app/public/vendor/fonts/cat-playwrite_au_sa-400-0.woff2 +0 -0
  128. package/app/public/vendor/fonts/cat-playwrite_au_sa_guides-400-0.woff2 +0 -0
  129. package/app/public/vendor/fonts/cat-playwrite_au_tas-400-0.woff2 +0 -0
  130. package/app/public/vendor/fonts/cat-playwrite_au_tas_guides-400-0.woff2 +0 -0
  131. package/app/public/vendor/fonts/cat-playwrite_au_vic-400-0.woff2 +0 -0
  132. package/app/public/vendor/fonts/cat-playwrite_au_vic_guides-400-0.woff2 +0 -0
  133. package/app/public/vendor/fonts/cat-playwrite_be_vlg-400-0.woff2 +0 -0
  134. package/app/public/vendor/fonts/cat-playwrite_be_vlg_guides-400-0.woff2 +0 -0
  135. package/app/public/vendor/fonts/cat-playwrite_be_wal-400-0.woff2 +0 -0
  136. package/app/public/vendor/fonts/cat-playwrite_be_wal_guides-400-0.woff2 +0 -0
  137. package/app/public/vendor/fonts/cat-playwrite_br_guides-400-0.woff2 +0 -0
  138. package/app/public/vendor/fonts/cat-playwrite_ca_guides-400-0.woff2 +0 -0
  139. package/app/public/vendor/fonts/cat-playwrite_cl_guides-400-0.woff2 +0 -0
  140. package/app/public/vendor/fonts/cat-playwrite_co_guides-400-0.woff2 +0 -0
  141. package/app/public/vendor/fonts/cat-playwrite_cu_guides-400-0.woff2 +0 -0
  142. package/app/public/vendor/fonts/cat-playwrite_cz-400-0.woff2 +0 -0
  143. package/app/public/vendor/fonts/cat-playwrite_cz_guides-400-0.woff2 +0 -0
  144. package/app/public/vendor/fonts/cat-playwrite_de_grund-400-0.woff2 +0 -0
  145. package/app/public/vendor/fonts/cat-playwrite_de_grund_guides-400-0.woff2 +0 -0
  146. package/app/public/vendor/fonts/cat-playwrite_de_la-400-0.woff2 +0 -0
  147. package/app/public/vendor/fonts/cat-playwrite_de_la_guides-400-0.woff2 +0 -0
  148. package/app/public/vendor/fonts/cat-playwrite_de_sas-400-0.woff2 +0 -0
  149. package/app/public/vendor/fonts/cat-playwrite_de_sas_guides-400-0.woff2 +0 -0
  150. package/app/public/vendor/fonts/cat-playwrite_de_va-400-0.woff2 +0 -0
  151. package/app/public/vendor/fonts/cat-playwrite_de_va_guides-400-0.woff2 +0 -0
  152. package/app/public/vendor/fonts/cat-playwrite_dk_loopet-400-0.woff2 +0 -0
  153. package/app/public/vendor/fonts/cat-playwrite_dk_loopet_guides-400-0.woff2 +0 -0
  154. package/app/public/vendor/fonts/cat-playwrite_dk_uloopet-400-0.woff2 +0 -0
  155. package/app/public/vendor/fonts/cat-playwrite_dk_uloopet_guides-400-0.woff2 +0 -0
  156. package/app/public/vendor/fonts/cat-playwrite_es_deco_guides-400-0.woff2 +0 -0
  157. package/app/public/vendor/fonts/cat-playwrite_es_guides-400-0.woff2 +0 -0
  158. package/app/public/vendor/fonts/cat-playwrite_fr_moderne-400-0.woff2 +0 -0
  159. package/app/public/vendor/fonts/cat-playwrite_fr_moderne_guides-400-0.woff2 +0 -0
  160. package/app/public/vendor/fonts/cat-playwrite_fr_trad-400-0.woff2 +0 -0
  161. package/app/public/vendor/fonts/cat-playwrite_fr_trad_guides-400-0.woff2 +0 -0
  162. package/app/public/vendor/fonts/cat-playwrite_gb_j_guides-400-0.woff2 +0 -0
  163. package/app/public/vendor/fonts/cat-playwrite_gb_s_guides-400-0.woff2 +0 -0
  164. package/app/public/vendor/fonts/cat-playwrite_hr-400-0.woff2 +0 -0
  165. package/app/public/vendor/fonts/cat-playwrite_hr_guides-400-0.woff2 +0 -0
  166. package/app/public/vendor/fonts/cat-playwrite_hr_lijeva-400-0.woff2 +0 -0
  167. package/app/public/vendor/fonts/cat-playwrite_hr_lijeva_guides-400-0.woff2 +0 -0
  168. package/app/public/vendor/fonts/cat-playwrite_hu-400-0.woff2 +0 -0
  169. package/app/public/vendor/fonts/cat-playwrite_hu_guides-400-0.woff2 +0 -0
  170. package/app/public/vendor/fonts/cat-playwrite_id-400-0.woff2 +0 -0
  171. package/app/public/vendor/fonts/cat-playwrite_id_guides-400-0.woff2 +0 -0
  172. package/app/public/vendor/fonts/cat-playwrite_ie-400-0.woff2 +0 -0
  173. package/app/public/vendor/fonts/cat-playwrite_ie_guides-400-0.woff2 +0 -0
  174. package/app/public/vendor/fonts/cat-playwrite_in-400-0.woff2 +0 -0
  175. package/app/public/vendor/fonts/cat-playwrite_in_guides-400-0.woff2 +0 -0
  176. package/app/public/vendor/fonts/cat-playwrite_is-400-0.woff2 +0 -0
  177. package/app/public/vendor/fonts/cat-playwrite_is_guides-400-0.woff2 +0 -0
  178. package/app/public/vendor/fonts/cat-playwrite_it_moderna-400-0.woff2 +0 -0
  179. package/app/public/vendor/fonts/cat-playwrite_it_moderna_guides-400-0.woff2 +0 -0
  180. package/app/public/vendor/fonts/cat-playwrite_it_trad-400-0.woff2 +0 -0
  181. package/app/public/vendor/fonts/cat-playwrite_it_trad_guides-400-0.woff2 +0 -0
  182. package/app/public/vendor/fonts/cat-playwrite_mx_guides-400-0.woff2 +0 -0
  183. package/app/public/vendor/fonts/cat-playwrite_ng_modern-400-0.woff2 +0 -0
  184. package/app/public/vendor/fonts/cat-playwrite_ng_modern_guides-400-0.woff2 +0 -0
  185. package/app/public/vendor/fonts/cat-playwrite_nl-400-0.woff2 +0 -0
  186. package/app/public/vendor/fonts/cat-playwrite_nl_guides-400-0.woff2 +0 -0
  187. package/app/public/vendor/fonts/cat-playwrite_no-400-0.woff2 +0 -0
  188. package/app/public/vendor/fonts/cat-playwrite_no_guides-400-0.woff2 +0 -0
  189. package/app/public/vendor/fonts/cat-playwrite_nz-400-0.woff2 +0 -0
  190. package/app/public/vendor/fonts/cat-playwrite_nz_basic-400-0.woff2 +0 -0
  191. package/app/public/vendor/fonts/cat-playwrite_nz_basic_guides-400-0.woff2 +0 -0
  192. package/app/public/vendor/fonts/cat-playwrite_nz_guides-400-0.woff2 +0 -0
  193. package/app/public/vendor/fonts/cat-playwrite_pe_guides-400-0.woff2 +0 -0
  194. package/app/public/vendor/fonts/cat-playwrite_pl-400-0.woff2 +0 -0
  195. package/app/public/vendor/fonts/cat-playwrite_pl_guides-400-0.woff2 +0 -0
  196. package/app/public/vendor/fonts/cat-playwrite_pt_guides-400-0.woff2 +0 -0
  197. package/app/public/vendor/fonts/cat-playwrite_ro-400-0.woff2 +0 -0
  198. package/app/public/vendor/fonts/cat-playwrite_ro_guides-400-0.woff2 +0 -0
  199. package/app/public/vendor/fonts/cat-playwrite_sk-400-0.woff2 +0 -0
  200. package/app/public/vendor/fonts/cat-playwrite_sk_guides-400-0.woff2 +0 -0
  201. package/app/public/vendor/fonts/cat-playwrite_tz-400-0.woff2 +0 -0
  202. package/app/public/vendor/fonts/cat-playwrite_tz_guides-400-0.woff2 +0 -0
  203. package/app/public/vendor/fonts/cat-playwrite_us_modern_guides-400-0.woff2 +0 -0
  204. package/app/public/vendor/fonts/cat-playwrite_us_trad_guides-400-0.woff2 +0 -0
  205. package/app/public/vendor/fonts/cat-playwrite_vn-400-0.woff2 +0 -0
  206. package/app/public/vendor/fonts/cat-playwrite_vn_guides-400-0.woff2 +0 -0
  207. package/app/public/vendor/fonts/cat-playwrite_za-400-0.woff2 +0 -0
  208. package/app/public/vendor/fonts/cat-playwrite_za_guides-400-0.woff2 +0 -0
  209. package/app/public/vendor/fonts/cat-potta_one-400-ext.woff2 +0 -0
  210. package/app/public/vendor/fonts/cat-potta_one-400.woff2 +0 -0
  211. package/app/public/vendor/fonts/cat-ranchers-400-ext.woff2 +0 -0
  212. package/app/public/vendor/fonts/cat-ranchers-400.woff2 +0 -0
  213. package/app/public/vendor/fonts/cat-ranga-400-ext.woff2 +0 -0
  214. package/app/public/vendor/fonts/cat-ranga-400.woff2 +0 -0
  215. package/app/public/vendor/fonts/cat-ranga-700-ext.woff2 +0 -0
  216. package/app/public/vendor/fonts/cat-ranga-700.woff2 +0 -0
  217. package/app/public/vendor/fonts/cat-risque-400-ext.woff2 +0 -0
  218. package/app/public/vendor/fonts/cat-risque-400.woff2 +0 -0
  219. package/app/public/vendor/fonts/cat-rowdies-400-ext.woff2 +0 -0
  220. package/app/public/vendor/fonts/cat-rowdies-400.woff2 +0 -0
  221. package/app/public/vendor/fonts/cat-rowdies-700-ext.woff2 +0 -0
  222. package/app/public/vendor/fonts/cat-rowdies-700.woff2 +0 -0
  223. package/app/public/vendor/fonts/cat-ruge_boogie-400-ext.woff2 +0 -0
  224. package/app/public/vendor/fonts/cat-ruge_boogie-400.woff2 +0 -0
  225. package/app/public/vendor/fonts/cat-ruslan_display-400-ext.woff2 +0 -0
  226. package/app/public/vendor/fonts/cat-ruslan_display-400.woff2 +0 -0
  227. package/app/public/vendor/fonts/cat-sacramento-400-ext.woff2 +0 -0
  228. package/app/public/vendor/fonts/cat-sacramento-400.woff2 +0 -0
  229. package/app/public/vendor/fonts/cat-sancreek-400-ext.woff2 +0 -0
  230. package/app/public/vendor/fonts/cat-sancreek-400.woff2 +0 -0
  231. package/app/public/vendor/fonts/cat-sankofa_display-400-ext.woff2 +0 -0
  232. package/app/public/vendor/fonts/cat-sankofa_display-400.woff2 +0 -0
  233. package/app/public/vendor/fonts/cat-sedgwick_ave_display-400-ext.woff2 +0 -0
  234. package/app/public/vendor/fonts/cat-sedgwick_ave_display-400.woff2 +0 -0
  235. package/app/public/vendor/fonts/cat-shantell_sans-400-ext.woff2 +0 -0
  236. package/app/public/vendor/fonts/cat-shantell_sans-400.woff2 +0 -0
  237. package/app/public/vendor/fonts/cat-smokum-400-ext.woff2 +0 -0
  238. package/app/public/vendor/fonts/cat-smokum-400.woff2 +0 -0
  239. package/app/public/vendor/fonts/cat-solitreo-400-ext.woff2 +0 -0
  240. package/app/public/vendor/fonts/cat-solitreo-400.woff2 +0 -0
  241. package/app/public/vendor/fonts/cat-spicy_rice-400-ext.woff2 +0 -0
  242. package/app/public/vendor/fonts/cat-spicy_rice-400.woff2 +0 -0
  243. package/app/public/vendor/fonts/cat-sriracha-400-ext.woff2 +0 -0
  244. package/app/public/vendor/fonts/cat-sriracha-400.woff2 +0 -0
  245. package/app/public/vendor/fonts/cat-srisakdi-400-ext.woff2 +0 -0
  246. package/app/public/vendor/fonts/cat-srisakdi-400.woff2 +0 -0
  247. package/app/public/vendor/fonts/cat-srisakdi-700-ext.woff2 +0 -0
  248. package/app/public/vendor/fonts/cat-srisakdi-700.woff2 +0 -0
  249. package/app/public/vendor/fonts/cat-stix_two_math-400-0.woff2 +0 -0
  250. package/app/public/vendor/fonts/cat-tillana-400-ext.woff2 +0 -0
  251. package/app/public/vendor/fonts/cat-tillana-400.woff2 +0 -0
  252. package/app/public/vendor/fonts/cat-tillana-700-ext.woff2 +0 -0
  253. package/app/public/vendor/fonts/cat-tillana-700.woff2 +0 -0
  254. package/app/public/vendor/fonts/cat-titan_one-400-ext.woff2 +0 -0
  255. package/app/public/vendor/fonts/cat-titan_one-400.woff2 +0 -0
  256. package/app/public/vendor/fonts/cat-yatra_one-400-ext.woff2 +0 -0
  257. package/app/public/vendor/fonts/cat-yatra_one-400.woff2 +0 -0
  258. package/app/public/vendor/fonts/cat-yomogi-400-ext.woff2 +0 -0
  259. package/app/public/vendor/fonts/cat-yomogi-400.woff2 +0 -0
  260. package/app/public/vendor/fonts/dmserifdisplay-400-ext.woff2 +0 -0
  261. package/app/public/vendor/fonts/dmserifdisplay-400.woff2 +0 -0
  262. package/app/public/vendor/fonts/domine-var-ext.woff2 +0 -0
  263. package/app/public/vendor/fonts/domine-var.woff2 +0 -0
  264. package/app/public/vendor/fonts/fraunces-var-ext.woff2 +0 -0
  265. package/app/public/vendor/fonts/fraunces-var.woff2 +0 -0
  266. package/app/public/vendor/fonts/fredoka-var-ext.woff2 +0 -0
  267. package/app/public/vendor/fonts/fredoka-var.woff2 +0 -0
  268. package/app/public/vendor/fonts/jakarta-var-ext.woff2 +0 -0
  269. package/app/public/vendor/fonts/jakarta-var.woff2 +0 -0
  270. package/app/public/vendor/fonts/lora-var-ext.woff2 +0 -0
  271. package/app/public/vendor/fonts/lora-var.woff2 +0 -0
  272. package/app/public/vendor/fonts/merriweather-var-ext.woff2 +0 -0
  273. package/app/public/vendor/fonts/merriweather-var.woff2 +0 -0
  274. package/app/public/vendor/fonts/notosans-var-ext.woff2 +0 -0
  275. package/app/public/vendor/fonts/notosans-var.woff2 +0 -0
  276. package/app/public/vendor/fonts/nunito-var-ext.woff2 +0 -0
  277. package/app/public/vendor/fonts/nunito-var.woff2 +0 -0
  278. package/app/public/vendor/fonts/playfair-var-ext.woff2 +0 -0
  279. package/app/public/vendor/fonts/playfair-var.woff2 +0 -0
  280. package/app/public/vendor/fonts/playwrite-cu.woff2 +0 -0
  281. package/app/public/vendor/fonts/playwrite-es-deco.woff2 +0 -0
  282. package/app/public/vendor/fonts/playwrite-es.woff2 +0 -0
  283. package/app/public/vendor/fonts/playwrite-gb-j.woff2 +0 -0
  284. package/app/public/vendor/fonts/playwrite-gb-s.woff2 +0 -0
  285. package/app/public/vendor/fonts/playwrite-pe.woff2 +0 -0
  286. package/app/public/vendor/fonts/playwrite-pt.woff2 +0 -0
  287. package/app/public/vendor/fonts/quicksand-var-ext.woff2 +0 -0
  288. package/app/public/vendor/fonts/quicksand-var.woff2 +0 -0
  289. package/app/public/vendor/fonts/robotoflex-var-ext.woff2 +0 -0
  290. package/app/public/vendor/fonts/robotoflex-var.woff2 +0 -0
  291. package/app/public/vendor/fonts/sora-var-ext.woff2 +0 -0
  292. package/app/public/vendor/fonts/sora-var.woff2 +0 -0
  293. package/app/public/vendor/fonts/spacegrotesk-var-ext.woff2 +0 -0
  294. package/app/public/vendor/fonts/spacegrotesk-var.woff2 +0 -0
  295. package/app/public/vendor/fonts/spectral-400-ext.woff2 +0 -0
  296. package/app/public/vendor/fonts/spectral-400.woff2 +0 -0
  297. package/app/public/vendor/fonts/spectral-700-ext.woff2 +0 -0
  298. package/app/public/vendor/fonts/spectral-700.woff2 +0 -0
  299. package/app/public/vendor/fonts/teachers-var-ext.woff2 +0 -0
  300. package/app/public/vendor/fonts/teachers-var.woff2 +0 -0
  301. package/app/public/vendor/fonts/ubuntu-400-ext.woff2 +0 -0
  302. package/app/public/vendor/fonts/ubuntu-400.woff2 +0 -0
  303. package/app/public/vendor/fonts/ubuntu-700-ext.woff2 +0 -0
  304. package/app/public/vendor/fonts/ubuntu-700.woff2 +0 -0
  305. package/app/public/vendor/fonts.css +1167 -51
  306. package/dist-pkg/boot/create-game.d.ts +467 -162
  307. package/dist-pkg/boot/create-game.js +3563 -426
  308. package/dist-pkg/core/a11y-sr.d.ts +25 -3
  309. package/dist-pkg/core/a11y-sr.js +40 -19
  310. package/dist-pkg/core/accessible-label.d.ts +17 -0
  311. package/dist-pkg/core/accessible-label.js +37 -0
  312. package/dist-pkg/core/accommodation-subjects.d.ts +26 -0
  313. package/dist-pkg/core/accommodation-subjects.js +32 -0
  314. package/dist-pkg/core/accommodations.d.ts +107 -0
  315. package/dist-pkg/core/accommodations.js +178 -0
  316. package/dist-pkg/core/actions.d.ts +75 -51
  317. package/dist-pkg/core/actions.js +98 -69
  318. package/dist-pkg/core/calm-mode.d.ts +31 -0
  319. package/dist-pkg/core/calm-mode.js +47 -0
  320. package/dist-pkg/core/camera-cycle.d.ts +15 -0
  321. package/dist-pkg/core/camera-cycle.js +7 -0
  322. package/dist-pkg/core/caption-duration.d.ts +15 -0
  323. package/dist-pkg/core/caption-duration.js +19 -0
  324. package/dist-pkg/core/cartridge-problems.d.ts +34 -0
  325. package/dist-pkg/core/cartridge-problems.js +53 -0
  326. package/dist-pkg/core/constants.d.ts +0 -54
  327. package/dist-pkg/core/constants.js +9 -76
  328. package/dist-pkg/core/contract.d.ts +143 -163
  329. package/dist-pkg/core/contract.js +223 -207
  330. package/dist-pkg/core/dom-query.d.ts +4 -4
  331. package/dist-pkg/core/dom-query.js +12 -20
  332. package/dist-pkg/core/entity.d.ts +62 -77
  333. package/dist-pkg/core/entity.js +18 -32
  334. package/dist-pkg/core/escape-html.d.ts +9 -10
  335. package/dist-pkg/core/escape-html.js +16 -20
  336. package/dist-pkg/core/flash-threshold.d.ts +17 -0
  337. package/dist-pkg/core/flash-threshold.js +113 -0
  338. package/dist-pkg/core/game-speed.d.ts +11 -0
  339. package/dist-pkg/core/game-speed.js +16 -0
  340. package/dist-pkg/core/genres.d.ts +20 -0
  341. package/dist-pkg/core/genres.js +44 -0
  342. package/dist-pkg/core/i18n.d.ts +87 -41
  343. package/dist-pkg/core/i18n.js +206 -153
  344. package/dist-pkg/core/loop.d.ts +17 -6
  345. package/dist-pkg/core/loop.js +26 -26
  346. package/dist-pkg/core/pause-icon-catalogue.d.ts +15 -0
  347. package/dist-pkg/core/pause-icon-catalogue.js +54 -0
  348. package/dist-pkg/core/ring.d.ts +17 -0
  349. package/dist-pkg/core/ring.js +29 -0
  350. package/dist-pkg/core/rng.d.ts +7 -12
  351. package/dist-pkg/core/rng.js +23 -53
  352. package/dist-pkg/core/route.d.ts +26 -26
  353. package/dist-pkg/core/route.js +126 -121
  354. package/dist-pkg/core/scenes.d.ts +37 -40
  355. package/dist-pkg/core/scenes.js +41 -43
  356. package/dist-pkg/core/screens.d.ts +4 -4
  357. package/dist-pkg/core/screens.js +11 -16
  358. package/dist-pkg/core/setting-defaults.d.ts +61 -0
  359. package/dist-pkg/core/setting-defaults.js +66 -0
  360. package/dist-pkg/core/speech-rate.d.ts +29 -0
  361. package/dist-pkg/core/speech-rate.js +47 -0
  362. package/dist-pkg/core/state.d.ts +118 -118
  363. package/dist-pkg/core/state.js +322 -297
  364. package/dist-pkg/core/visual-cycles.d.ts +30 -0
  365. package/dist-pkg/core/visual-cycles.js +52 -0
  366. package/dist-pkg/core/visual-state.d.ts +13 -0
  367. package/dist-pkg/core/visual-state.js +6 -0
  368. package/dist-pkg/educational/activities-registry.d.ts +1 -1
  369. package/dist-pkg/educational/activities-registry.js +9 -8
  370. package/dist-pkg/educational/adaptive-engine.d.ts +11 -11
  371. package/dist-pkg/educational/adaptive-engine.js +17 -17
  372. package/dist-pkg/educational/segment-bar.d.ts +12 -12
  373. package/dist-pkg/educational/segment-bar.js +9 -9
  374. package/dist-pkg/i18n/en.js +321 -215
  375. package/dist-pkg/i18n/es.js +320 -215
  376. package/dist-pkg/i18n/pt.js +342 -215
  377. package/dist-pkg/input/default-bindings.d.ts +37 -38
  378. package/dist-pkg/input/default-bindings.js +127 -144
  379. package/dist-pkg/input/devices.d.ts +7 -7
  380. package/dist-pkg/input/devices.js +17 -16
  381. package/dist-pkg/input/edges.d.ts +23 -32
  382. package/dist-pkg/input/edges.js +23 -28
  383. package/dist-pkg/input/empathy-filter.d.ts +22 -0
  384. package/dist-pkg/input/empathy-filter.js +34 -0
  385. package/dist-pkg/input/face-map.d.ts +96 -0
  386. package/dist-pkg/input/face-map.js +255 -0
  387. package/dist-pkg/input/face-signals.d.ts +40 -0
  388. package/dist-pkg/input/face-signals.js +48 -0
  389. package/dist-pkg/input/gamepad.d.ts +164 -145
  390. package/dist-pkg/input/gamepad.js +351 -559
  391. package/dist-pkg/input/gaze-cycle.d.ts +64 -0
  392. package/dist-pkg/input/gaze-cycle.js +133 -0
  393. package/dist-pkg/input/gaze-relative.d.ts +68 -0
  394. package/dist-pkg/input/gaze-relative.js +142 -0
  395. package/dist-pkg/input/hand-map.d.ts +28 -0
  396. package/dist-pkg/input/hand-map.js +142 -0
  397. package/dist-pkg/input/input-cooldown.d.ts +17 -0
  398. package/dist-pkg/input/input-cooldown.js +39 -0
  399. package/dist-pkg/input/keyboard-runtime.d.ts +18 -20
  400. package/dist-pkg/input/keyboard-runtime.js +23 -27
  401. package/dist-pkg/input/keyboard.d.ts +68 -62
  402. package/dist-pkg/input/keyboard.js +83 -105
  403. package/dist-pkg/input/keydown.d.ts +124 -132
  404. package/dist-pkg/input/keydown.js +283 -288
  405. package/dist-pkg/input/latch-edge.d.ts +25 -21
  406. package/dist-pkg/input/latch-edge.js +33 -35
  407. package/dist-pkg/input/latch-scope.d.ts +43 -47
  408. package/dist-pkg/input/latch-scope.js +66 -75
  409. package/dist-pkg/input/latch-store.d.ts +28 -29
  410. package/dist-pkg/input/latch-store.js +44 -47
  411. package/dist-pkg/input/latch-sync.d.ts +28 -29
  412. package/dist-pkg/input/latch-sync.js +25 -25
  413. package/dist-pkg/input/latch.d.ts +14 -17
  414. package/dist-pkg/input/latch.js +29 -37
  415. package/dist-pkg/input/pad-defaults.d.ts +13 -16
  416. package/dist-pkg/input/pad-defaults.js +21 -28
  417. package/dist-pkg/input/pad-reading.d.ts +76 -0
  418. package/dist-pkg/input/pad-reading.js +164 -0
  419. package/dist-pkg/input/pad-wizard.d.ts +96 -0
  420. package/dist-pkg/input/pad-wizard.js +205 -0
  421. package/dist-pkg/input/pointer-space.d.ts +19 -20
  422. package/dist-pkg/input/pointer-space.js +27 -32
  423. package/dist-pkg/input/pointer.d.ts +39 -40
  424. package/dist-pkg/input/pointer.js +42 -45
  425. package/dist-pkg/input/state.d.ts +101 -89
  426. package/dist-pkg/input/state.js +54 -134
  427. package/dist-pkg/input/switch-scan.d.ts +42 -0
  428. package/dist-pkg/input/switch-scan.js +54 -0
  429. package/dist-pkg/input/synthetic-source.d.ts +42 -0
  430. package/dist-pkg/input/synthetic-source.js +57 -0
  431. package/dist-pkg/input/touch-bindings.d.ts +127 -113
  432. package/dist-pkg/input/touch-bindings.js +158 -173
  433. package/dist-pkg/input/touch.d.ts +130 -70
  434. package/dist-pkg/input/touch.js +321 -123
  435. package/dist-pkg/input/transport-in-use.d.ts +107 -0
  436. package/dist-pkg/input/transport-in-use.js +130 -0
  437. package/dist-pkg/input/transports.d.ts +96 -114
  438. package/dist-pkg/input/transports.js +104 -106
  439. package/dist-pkg/input/virtual-controller.d.ts +46 -0
  440. package/dist-pkg/input/virtual-controller.js +41 -0
  441. package/dist-pkg/input/vocabulary-migration.d.ts +50 -49
  442. package/dist-pkg/input/vocabulary-migration.js +80 -79
  443. package/dist-pkg/input/voice-map.d.ts +43 -0
  444. package/dist-pkg/input/voice-map.js +125 -0
  445. package/dist-pkg/platform/audio-ambient.d.ts +13 -1
  446. package/dist-pkg/platform/audio-ambient.js +11 -13
  447. package/dist-pkg/platform/audio-earcons.d.ts +20 -19
  448. package/dist-pkg/platform/audio-earcons.js +51 -42
  449. package/dist-pkg/platform/audio-jingles.js +9 -10
  450. package/dist-pkg/platform/audio-mixer.d.ts +14 -2
  451. package/dist-pkg/platform/audio-mixer.js +36 -39
  452. package/dist-pkg/platform/audio-sonar.d.ts +96 -113
  453. package/dist-pkg/platform/audio-sonar.js +245 -238
  454. package/dist-pkg/platform/audio.d.ts +53 -19
  455. package/dist-pkg/platform/audio.js +161 -169
  456. package/dist-pkg/platform/flash-sampler.d.ts +19 -0
  457. package/dist-pkg/platform/flash-sampler.js +79 -0
  458. package/dist-pkg/platform/guide-intensity.d.ts +26 -27
  459. package/dist-pkg/platform/guide-intensity.js +50 -52
  460. package/dist-pkg/platform/heavy-catalogue.d.ts +31 -0
  461. package/dist-pkg/platform/heavy-catalogue.js +223 -0
  462. package/dist-pkg/platform/heavy-mirror.d.ts +26 -0
  463. package/dist-pkg/platform/heavy-mirror.js +76 -0
  464. package/dist-pkg/platform/heavy.d.ts +104 -0
  465. package/dist-pkg/platform/heavy.js +169 -0
  466. package/dist-pkg/platform/interruptible-speech.d.ts +16 -16
  467. package/dist-pkg/platform/interruptible-speech.js +50 -51
  468. package/dist-pkg/platform/kokoro-port.d.ts +27 -0
  469. package/dist-pkg/platform/kokoro-port.js +50 -0
  470. package/dist-pkg/platform/kokoro-runtime.d.ts +20 -0
  471. package/dist-pkg/platform/kokoro-runtime.js +52 -0
  472. package/dist-pkg/platform/kokoro.d.ts +70 -0
  473. package/dist-pkg/platform/kokoro.js +133 -0
  474. package/dist-pkg/platform/listener-scope.d.ts +12 -0
  475. package/dist-pkg/platform/listener-scope.js +81 -0
  476. package/dist-pkg/platform/locale-host.d.ts +10 -0
  477. package/dist-pkg/platform/locale-host.js +34 -0
  478. package/dist-pkg/platform/microphone.d.ts +51 -0
  479. package/dist-pkg/platform/microphone.js +118 -0
  480. package/dist-pkg/platform/onnx-runtime.d.ts +34 -0
  481. package/dist-pkg/platform/onnx-runtime.js +42 -0
  482. package/dist-pkg/platform/reading-in-worker.d.ts +40 -0
  483. package/dist-pkg/platform/reading-in-worker.js +87 -0
  484. package/dist-pkg/platform/reading-model.d.ts +73 -0
  485. package/dist-pkg/platform/reading-model.js +247 -0
  486. package/dist-pkg/platform/reading-runtime.d.ts +24 -0
  487. package/dist-pkg/platform/reading-runtime.js +159 -0
  488. package/dist-pkg/platform/reading-worker.d.ts +41 -0
  489. package/dist-pkg/platform/reading-worker.js +58 -0
  490. package/dist-pkg/platform/reading.d.ts +69 -0
  491. package/dist-pkg/platform/reading.js +128 -0
  492. package/dist-pkg/platform/speech-recognition.d.ts +51 -0
  493. package/dist-pkg/platform/speech-recognition.js +84 -0
  494. package/dist-pkg/platform/speech.d.ts +14 -1
  495. package/dist-pkg/platform/speech.js +13 -13
  496. package/dist-pkg/platform/storage-keys.d.ts +96 -0
  497. package/dist-pkg/platform/storage-keys.js +106 -0
  498. package/dist-pkg/platform/storage.d.ts +46 -111
  499. package/dist-pkg/platform/storage.js +104 -169
  500. package/dist-pkg/platform/tts.d.ts +51 -38
  501. package/dist-pkg/platform/tts.js +217 -119
  502. package/dist-pkg/platform/vision-loop.d.ts +23 -0
  503. package/dist-pkg/platform/vision-loop.js +56 -0
  504. package/dist-pkg/platform/vision.d.ts +132 -0
  505. package/dist-pkg/platform/vision.js +117 -0
  506. package/dist-pkg/platform/voice-listener.d.ts +36 -0
  507. package/dist-pkg/platform/voice-listener.js +88 -0
  508. package/dist-pkg/platform/voice-plan.d.ts +6 -102
  509. package/dist-pkg/platform/voice-plan.js +9 -151
  510. package/dist-pkg/platform/vosk-runtime.d.ts +71 -0
  511. package/dist-pkg/platform/vosk-runtime.js +93 -0
  512. package/dist-pkg/render/canvas.d.ts +13 -7
  513. package/dist-pkg/render/canvas.js +13 -13
  514. package/dist-pkg/render/crt.d.ts +46 -12
  515. package/dist-pkg/render/crt.js +82 -80
  516. package/dist-pkg/render/cvd-matrices.d.ts +18 -18
  517. package/dist-pkg/render/cvd-matrices.js +33 -38
  518. package/dist-pkg/render/hc-role-data.d.ts +7 -7
  519. package/dist-pkg/render/hc-role-data.js +14 -14
  520. package/dist-pkg/render/high-contrast.d.ts +66 -54
  521. package/dist-pkg/render/high-contrast.js +221 -216
  522. package/dist-pkg/render/low-vision-drawing.d.ts +5 -0
  523. package/dist-pkg/render/low-vision-drawing.js +46 -0
  524. package/dist-pkg/render/lq-filter.d.ts +32 -20
  525. package/dist-pkg/render/lq-filter.js +59 -65
  526. package/dist-pkg/render/port.d.ts +86 -88
  527. package/dist-pkg/render/port.js +17 -23
  528. package/dist-pkg/render/screen-pipeline.d.ts +42 -42
  529. package/dist-pkg/render/screen-pipeline.js +80 -87
  530. package/dist-pkg/render/sprite-fx.d.ts +2 -1
  531. package/dist-pkg/render/sprite-fx.js +16 -14
  532. package/dist-pkg/render/viewports.d.ts +20 -15
  533. package/dist-pkg/render/viewports.js +83 -114
  534. package/dist-pkg/render/viz-axes-labels.d.ts +47 -0
  535. package/dist-pkg/render/viz-axes-labels.js +88 -0
  536. package/dist-pkg/render/viz-axes.d.ts +80 -86
  537. package/dist-pkg/render/viz-axes.js +115 -116
  538. package/dist-pkg/render/viz-modes.d.ts +28 -29
  539. package/dist-pkg/render/viz-modes.js +40 -45
  540. package/dist-pkg/render/viz-refusal.d.ts +32 -0
  541. package/dist-pkg/render/viz-refusal.js +57 -0
  542. package/dist-pkg/render/viz-setters.d.ts +104 -66
  543. package/dist-pkg/render/viz-setters.js +182 -191
  544. package/dist-pkg/ui/aac-sets.d.ts +40 -0
  545. package/dist-pkg/ui/aac-sets.js +49 -0
  546. package/dist-pkg/ui/audio-choices.d.ts +63 -0
  547. package/dist-pkg/ui/audio-choices.js +94 -0
  548. package/dist-pkg/ui/audio-rows-that-apply.d.ts +12 -0
  549. package/dist-pkg/ui/audio-rows-that-apply.js +43 -0
  550. package/dist-pkg/ui/camera-control.d.ts +6 -0
  551. package/dist-pkg/ui/camera-control.js +14 -0
  552. package/dist-pkg/ui/changed-mark.d.ts +9 -8
  553. package/dist-pkg/ui/changed-mark.js +22 -53
  554. package/dist-pkg/ui/control-choices.d.ts +37 -0
  555. package/dist-pkg/ui/control-choices.js +84 -0
  556. package/dist-pkg/ui/debug-panel.d.ts +59 -43
  557. package/dist-pkg/ui/debug-panel.js +68 -69
  558. package/dist-pkg/ui/dom.d.ts +10 -14
  559. package/dist-pkg/ui/dom.js +10 -47
  560. package/dist-pkg/ui/drawing-problems.d.ts +25 -0
  561. package/dist-pkg/ui/drawing-problems.js +93 -0
  562. package/dist-pkg/ui/eye-control.d.ts +36 -0
  563. package/dist-pkg/ui/eye-control.js +178 -0
  564. package/dist-pkg/ui/face-control.d.ts +25 -0
  565. package/dist-pkg/ui/face-control.js +183 -0
  566. package/dist-pkg/ui/focus-trap.d.ts +39 -49
  567. package/dist-pkg/ui/focus-trap.js +56 -65
  568. package/dist-pkg/ui/fonts.d.ts +118 -63
  569. package/dist-pkg/ui/fonts.js +267 -111
  570. package/dist-pkg/ui/game-options.d.ts +42 -0
  571. package/dist-pkg/ui/game-options.js +138 -0
  572. package/dist-pkg/ui/gaze-overlay.d.ts +64 -0
  573. package/dist-pkg/ui/gaze-overlay.js +165 -0
  574. package/dist-pkg/ui/hand-control.d.ts +25 -0
  575. package/dist-pkg/ui/hand-control.js +143 -0
  576. package/dist-pkg/ui/help-panel.d.ts +76 -0
  577. package/dist-pkg/ui/help-panel.js +232 -0
  578. package/dist-pkg/ui/hud-bands.d.ts +45 -0
  579. package/dist-pkg/ui/hud-bands.js +108 -0
  580. package/dist-pkg/ui/hud.d.ts +73 -70
  581. package/dist-pkg/ui/hud.js +94 -98
  582. package/dist-pkg/ui/item-announcement.d.ts +13 -12
  583. package/dist-pkg/ui/item-announcement.js +25 -26
  584. package/dist-pkg/ui/latch-refusal.d.ts +22 -21
  585. package/dist-pkg/ui/latch-refusal.js +37 -37
  586. package/dist-pkg/ui/layout.d.ts +103 -28
  587. package/dist-pkg/ui/layout.js +114 -99
  588. package/dist-pkg/ui/locale-flags.d.ts +16 -0
  589. package/dist-pkg/ui/locale-flags.js +30 -0
  590. package/dist-pkg/ui/loop-crash.d.ts +17 -17
  591. package/dist-pkg/ui/loop-crash.js +33 -62
  592. package/dist-pkg/ui/menu-intent.d.ts +32 -0
  593. package/dist-pkg/ui/menu-intent.js +54 -0
  594. package/dist-pkg/ui/menu-items.d.ts +10 -0
  595. package/dist-pkg/ui/menu-items.js +22 -0
  596. package/dist-pkg/ui/menu-nav.d.ts +60 -90
  597. package/dist-pkg/ui/menu-nav.js +301 -274
  598. package/dist-pkg/ui/mobility-choices.d.ts +26 -0
  599. package/dist-pkg/ui/mobility-choices.js +41 -0
  600. package/dist-pkg/ui/motion-choices.d.ts +31 -0
  601. package/dist-pkg/ui/motion-choices.js +68 -0
  602. package/dist-pkg/ui/motion-scene.d.ts +24 -19
  603. package/dist-pkg/ui/motion-scene.js +29 -61
  604. package/dist-pkg/ui/mount-panel.d.ts +81 -0
  605. package/dist-pkg/ui/mount-panel.js +61 -0
  606. package/dist-pkg/ui/panel-shell.d.ts +65 -31
  607. package/dist-pkg/ui/panel-shell.js +92 -66
  608. package/dist-pkg/ui/panel-widgets.d.ts +116 -0
  609. package/dist-pkg/ui/panel-widgets.js +208 -0
  610. package/dist-pkg/ui/pause-buttons.d.ts +35 -0
  611. package/dist-pkg/ui/pause-buttons.js +66 -0
  612. package/dist-pkg/ui/pause-icons.d.ts +250 -343
  613. package/dist-pkg/ui/pause-icons.js +614 -605
  614. package/dist-pkg/ui/pause-markup.d.ts +86 -0
  615. package/dist-pkg/ui/pause-markup.js +125 -0
  616. package/dist-pkg/ui/reach-notice.d.ts +22 -23
  617. package/dist-pkg/ui/reach-notice.js +55 -58
  618. package/dist-pkg/ui/scan-overlay.d.ts +23 -0
  619. package/dist-pkg/ui/scan-overlay.js +42 -0
  620. package/dist-pkg/ui/settings-aac.d.ts +68 -0
  621. package/dist-pkg/ui/settings-aac.js +189 -0
  622. package/dist-pkg/ui/settings-audio.d.ts +91 -113
  623. package/dist-pkg/ui/settings-audio.js +407 -405
  624. package/dist-pkg/ui/settings-controls.d.ts +53 -92
  625. package/dist-pkg/ui/settings-controls.js +143 -215
  626. package/dist-pkg/ui/settings-empathy.d.ts +39 -30
  627. package/dist-pkg/ui/settings-empathy.js +53 -60
  628. package/dist-pkg/ui/settings-mobility.d.ts +195 -0
  629. package/dist-pkg/ui/settings-mobility.js +374 -0
  630. package/dist-pkg/ui/settings-motion.d.ts +91 -70
  631. package/dist-pkg/ui/settings-motion.js +287 -198
  632. package/dist-pkg/ui/settings-panel.d.ts +48 -45
  633. package/dist-pkg/ui/settings-panel.js +164 -93
  634. package/dist-pkg/ui/settings-typo.d.ts +28 -76
  635. package/dist-pkg/ui/settings-typo.js +145 -125
  636. package/dist-pkg/ui/settings-visual.d.ts +29 -87
  637. package/dist-pkg/ui/settings-visual.js +240 -193
  638. package/dist-pkg/ui/shell.d.ts +113 -134
  639. package/dist-pkg/ui/shell.js +143 -216
  640. package/dist-pkg/ui/simulation-list.d.ts +27 -0
  641. package/dist-pkg/ui/simulation-list.js +76 -0
  642. package/dist-pkg/ui/simulation-over-the-world.d.ts +23 -0
  643. package/dist-pkg/ui/simulation-over-the-world.js +131 -0
  644. package/dist-pkg/ui/simulation-refusal.d.ts +5 -31
  645. package/dist-pkg/ui/simulation-refusal.js +8 -56
  646. package/dist-pkg/ui/switchable-control.d.ts +11 -0
  647. package/dist-pkg/ui/switchable-control.js +19 -0
  648. package/dist-pkg/ui/title.d.ts +4 -4
  649. package/dist-pkg/ui/title.js +11 -13
  650. package/dist-pkg/ui/top-band.d.ts +24 -0
  651. package/dist-pkg/ui/top-band.js +100 -0
  652. package/dist-pkg/ui/typo-choices.d.ts +71 -0
  653. package/dist-pkg/ui/typo-choices.js +84 -0
  654. package/dist-pkg/ui/visual-axes-panel.d.ts +11 -47
  655. package/dist-pkg/ui/visual-axes-panel.js +12 -94
  656. package/dist-pkg/ui/visual-choices.d.ts +77 -0
  657. package/dist-pkg/ui/visual-choices.js +107 -0
  658. package/dist-pkg/ui/vlibras.d.ts +33 -10
  659. package/dist-pkg/ui/vlibras.js +58 -81
  660. package/dist-pkg/ui/voice-control.d.ts +46 -0
  661. package/dist-pkg/ui/voice-control.js +143 -0
  662. package/dist-pkg/ui/voice-settings.d.ts +96 -0
  663. package/dist-pkg/ui/voice-settings.js +302 -0
  664. package/dist-pkg/ui/where-the-child-is.d.ts +31 -0
  665. package/dist-pkg/ui/where-the-child-is.js +70 -0
  666. package/docs/CREDITS.md +198 -54
  667. package/docs/LICENSES.md +160 -145
  668. package/package.json +24 -25
  669. package/scripts/heavy-into-the-delivery.mjs +144 -0
  670. package/scripts/licences/Apache-2.0.txt +176 -0
  671. package/scripts/licences/GPL-3.0.txt +674 -0
  672. package/scripts/licences/MIT.txt +17 -0
  673. package/scripts/licences/third-party.mjs +287 -0
  674. package/scripts/licences/vosk-browser.NOTICE.txt +268 -0
  675. package/app/public/vendor/fonts/comicneue-400.woff2 +0 -0
  676. package/app/public/vendor/fonts/comicneue-700.woff2 +0 -0
  677. package/dist-pkg/core/anel.d.ts +0 -17
  678. package/dist-pkg/core/anel.js +0 -31
  679. package/dist-pkg/core/collision.d.ts +0 -21
  680. package/dist-pkg/core/collision.js +0 -62
  681. package/dist-pkg/core/layers.d.ts +0 -63
  682. package/dist-pkg/core/layers.js +0 -95
  683. package/dist-pkg/core/letter-grid.d.ts +0 -55
  684. package/dist-pkg/core/letter-grid.js +0 -116
  685. package/dist-pkg/core/password.d.ts +0 -34
  686. package/dist-pkg/core/password.js +0 -205
  687. package/dist-pkg/core/rotulo-acessivel.d.ts +0 -17
  688. package/dist-pkg/core/rotulo-acessivel.js +0 -41
  689. package/dist-pkg/core/run-state.d.ts +0 -115
  690. package/dist-pkg/core/run-state.js +0 -40
  691. package/dist-pkg/core/tiles.d.ts +0 -12
  692. package/dist-pkg/core/tiles.js +0 -61
  693. package/dist-pkg/core/world.d.ts +0 -4
  694. package/dist-pkg/core/world.js +0 -58
  695. package/dist-pkg/input/origem-sintetica.d.ts +0 -44
  696. package/dist-pkg/input/origem-sintetica.js +0 -60
  697. package/dist-pkg/input/transporte-em-uso.d.ts +0 -101
  698. package/dist-pkg/input/transporte-em-uso.js +0 -130
  699. package/dist-pkg/platform/audio-nav.d.ts +0 -51
  700. package/dist-pkg/platform/audio-nav.js +0 -99
  701. package/dist-pkg/platform/pesados-catalogo.d.ts +0 -14
  702. package/dist-pkg/platform/pesados-catalogo.js +0 -177
  703. package/dist-pkg/platform/pesados.d.ts +0 -31
  704. package/dist-pkg/platform/pesados.js +0 -75
  705. package/dist-pkg/platform/vozes-prontas.d.ts +0 -28
  706. package/dist-pkg/platform/vozes-prontas.js +0 -61
  707. package/dist-pkg/render/camera.d.ts +0 -58
  708. package/dist-pkg/render/camera.js +0 -105
  709. package/dist-pkg/render/cenario-data.d.ts +0 -127
  710. package/dist-pkg/render/cenario-data.js +0 -145
  711. package/dist-pkg/render/city-tex.d.ts +0 -63
  712. package/dist-pkg/render/city-tex.js +0 -228
  713. package/dist-pkg/render/city-tiles.d.ts +0 -11
  714. package/dist-pkg/render/city-tiles.js +0 -140
  715. package/dist-pkg/render/draw.d.ts +0 -149
  716. package/dist-pkg/render/draw.js +0 -231
  717. package/dist-pkg/render/fx.d.ts +0 -63
  718. package/dist-pkg/render/fx.js +0 -123
  719. package/dist-pkg/render/minimap.d.ts +0 -11
  720. package/dist-pkg/render/minimap.js +0 -94
  721. package/dist-pkg/render/parallax.d.ts +0 -85
  722. package/dist-pkg/render/parallax.js +0 -158
  723. package/dist-pkg/render/player-anim.d.ts +0 -71
  724. package/dist-pkg/render/player-anim.js +0 -152
  725. package/dist-pkg/render/recycling-tex.d.ts +0 -48
  726. package/dist-pkg/render/recycling-tex.js +0 -164
  727. package/dist-pkg/render/scene-city.d.ts +0 -77
  728. package/dist-pkg/render/scene-city.js +0 -181
  729. package/dist-pkg/render/scene-parallax.d.ts +0 -72
  730. package/dist-pkg/render/scene-parallax.js +0 -426
  731. package/dist-pkg/render/scene-sky.d.ts +0 -126
  732. package/dist-pkg/render/scene-sky.js +0 -295
  733. package/dist-pkg/render/set-cenario.d.ts +0 -54
  734. package/dist-pkg/render/set-cenario.js +0 -103
  735. package/dist-pkg/render/textures.d.ts +0 -75
  736. package/dist-pkg/render/textures.js +0 -240
  737. package/dist-pkg/render/title-scene.d.ts +0 -46
  738. package/dist-pkg/render/title-scene.js +0 -75
  739. package/dist-pkg/render/weather.d.ts +0 -96
  740. package/dist-pkg/render/weather.js +0 -171
  741. package/dist-pkg/render/wheelchair-sprites.d.ts +0 -32
  742. package/dist-pkg/render/wheelchair-sprites.js +0 -69
  743. package/dist-pkg/render/world-tex.d.ts +0 -18
  744. package/dist-pkg/render/world-tex.js +0 -87
  745. package/dist-pkg/ui/activities-menu.d.ts +0 -258
  746. package/dist-pkg/ui/activities-menu.js +0 -648
  747. package/dist-pkg/ui/caa-sets.d.ts +0 -39
  748. package/dist-pkg/ui/caa-sets.js +0 -65
  749. package/dist-pkg/ui/map-hub.d.ts +0 -56
  750. package/dist-pkg/ui/map-hub.js +0 -138
  751. package/dist-pkg/ui/settings-caa.d.ts +0 -45
  752. package/dist-pkg/ui/settings-caa.js +0 -137
  753. package/dist-pkg/ui/settings-motor.d.ts +0 -175
  754. package/dist-pkg/ui/settings-motor.js +0 -342
  755. package/dist-pkg/ui/webcam.d.ts +0 -7
  756. package/dist-pkg/ui/webcam.js +0 -93
package/app/css/style.css CHANGED
@@ -1,47 +1,60 @@
1
1
  /* SPDX-License-Identifier: AGPL-3.0-or-later */
2
2
  :root{
3
+ /* The engine stylesheet's sentinel: `createGame` reads it to say in `problems` when a page did not link this file. */
4
+ --incl-engine-stylesheet:1;
3
5
  --bg:#0b1020; --panel:#1b2440; --ink:#f5f8ff; --ink-soft:#cdd6f2;
4
6
  --accent:#ffd23f; --accent-ink:#1a1400; --focus:#ffd23f; --good:#34e29b;
5
- --changed:#fff; /* ADR-0029: moldura de quem saiu do padrão */
6
- /* Alto contraste no DOM (issue #83): o véu do painel sem transparência, e o fundo de botão. Ficam aqui,
7
- junto dos outros tokens, para o teste de contraste poder lê-los do CSS em vez de os copiar. */
7
+ --changed:#fff; /* ADR-0029: the frame of a setting that left its default */
8
+ /* High contrast in the DOM (issue #83): the panel veil without transparency, and the button background. They live here,
9
+ beside the other tokens, so the contrast test can read them from the CSS instead of copying them. */
8
10
  --bg-solid:#04070f; --panel-btn:#1a2740;
9
11
  --maxw:1000px; --tap:44px;
10
- --ui-fs:16px; /* fonte-base da UI (<p>): 16px = MÍNIMO a 640×360; o JS (layout) aumenta conforme o canvas cresce */
11
- /* ===== Tipografia oficial EdSP ===== */
12
- /* 'Noto Color Emoji' no fim do stack → emoji consistentes (nativo no Chromebook/Android; woff2 abaixo p/ Windows) */
12
+ --ui-fs:16px; /* the UI's base font size (<p>): 16px = the MINIMUM at 640×360; `ui/layout` raises it as the canvas grows */
13
+ /* ===== The engine's typography ===== */
14
+ /* 'Noto Color Emoji' at the end of the stack → consistent emoji (native on Chromebook/Android; the system face elsewhere) */
13
15
  --font-fallback:system-ui,"Segoe UI",Roboto,Arial,sans-serif,'Noto Color Emoji';
14
- --font:'Atkinson Hyperlegible',var(--font-fallback); /* PADRÃO */
15
- --font-math:'Atkinson Hyperlegible Mono',ui-monospace,"Cascadia Mono",Consolas,monospace; /* matemática */
16
- /* Espaçamento padrão do projeto (≥ recomendações WCAG 2.2 §1.4.12) */
17
- --ls:0.12em; /* letter-spacing */
18
- --ws:0.16em; /* word-spacing */
16
+ --font:'Atkinson Hyperlegible',var(--font-fallback); /* DEFAULT */
17
+ --font-math:'Atkinson Hyperlegible Mono',ui-monospace,"Cascadia Mono",Consolas,monospace; /* mathematics */
18
+ /* ===== SPACING: THE DEFAULT ROSE FROM THE WCAG FLOOR TO THE BDA'S (ADR-0149 §2) =====
19
+ It was 0.12em/0.16em — the floor of WCAG 2.2 §1.4.12 —, and it is now 0.18em/0.63em, the British Dyslexia
20
+ Association's recommendation: word ≥ 3.5× letter. The Dev's decision on 2026-09-12: «somente fontes
21
+ cursivas não precisam seguir; ao usar todas as outras fontes, é obrigatório seguir».
22
+
23
+ ⚠️ THIS USED TO BE THE EXCEPTION OF ONE FACE. The BDA numbers lived only in `[data-fonte="dislexia"]` (Lexend),
24
+ and the DEFAULT face — Atkinson, which every game draws — sat on the WCAG floor. It was not «no spacing at all»,
25
+ as a first version of the record said; it was the lower of the two floors, applied because of a LABEL instead of
26
+ because of a rule about faces.
27
+
28
+ 🔴 AND THE REACH OF THIS IS EVERY GAME: changing the default face's spacing changes the metrics of every screen at
29
+ once. It is the right rule, and it is a layout change in every game that uses the engine. */
30
+ --ls:0.18em; /* letter-spacing — BDA */
31
+ --ws:0.63em; /* word-spacing — BDA (≥ 3.5× the letter) */
19
32
  --lh:1.5; /* line-height */
20
33
 
21
- /* ===== ORDEM-Z CANÔNICA — a faixa de OVERLAY do `core/layers.ts` (ADR-0020) =====
22
- Estes valores são a MESMA fonte que o mundo usa em PIXI, trazida para o CSS. Eles existem antes do
23
- primeiro consumidor DE PROPÓSITO, e o motivo é o mesmo que a Fase C deu ao barramento tipado: o contrato
24
- precisa nascer certo em vez de ser retipado depois. `tests/z-order-css.node.test.js` compara este bloco,
25
- valor a valor, com o `Z` do TypeScript — divergir fica vermelho.
26
-
27
- ⚠️ NENHUM SELETOR AINDA OS USA, e isso NÃO é esquecimento. Adotá-los inverte três ordens que hoje valem,
28
- e inverter ordem é decisão de produto:
29
-
30
- · `.caption` (8) está ABAIXO de `#touch-controls` (14). Canonicamente CAPTIONS(26000) fica ACIMA de
31
- TOUCH_CONTROLS(25000). A inversão CONSERTA um defeito — legenda é recurso de surdez, e controle de
32
- toque cobrindo legenda é a coisa errada —, mas muda a tela.
33
- · `.quiz` (12) está ABAIXO de `#touch-controls` (14); canonicamente DIALOGUE(27000) fica acima.
34
- · `.skip-link` (100) está ACIMA dos modais (60). O comentário do `Z` põe o skip-link em CAPTIONS
35
- (26000), o que o deixaria ABAIXO de MENU(30000) — e um "pular para o conteúdo" embaixo de um modal
36
- não é alcançável. Aqui o comentário do `Z` é que está errado, não o CSS.
37
-
38
- E DUAS COISAS NÃO TÊM SLOT: os dois pseudo-elementos do CRT (`crt-vig-1::before` em 5 e
39
- `crt-scan-1::after` em 500). Pelo ADR-0020 o CRT é PÓS-PROCESSO, não camada — inventar um número para
40
- ele repetiria o erro de categoria que a emenda de 2026-08-26 já registrou no `app.stage`.
41
-
42
- ⚠️ E `z-index` de CSS NÃO É PLANO. `#game-hud` tem `z-index:4` e CRIA CONTEXTO DE EMPILHAMENTO, então o
43
- `.screen-pause` (6) compete só lá dentro — o menu de pausa vive efetivamente em "4" na raiz. Uma lista
44
- plana de valores globais não expressa isso. Adotar exige decidir, por elemento, em que contexto ele vive. */
34
+ /* ===== THE Z-ORDER SLOTS — the engine's canonical stacking order (ADR-0020, ADR-0102) =====
35
+ These `--z-*` variables are where the z-order lives now. They were born as the OVERLAY band of the `Z` table in
36
+ `core/layers.ts`; that table was the platformer's world order and left with the tile world (ADR-0228), so the
37
+ slots below are the only copy. `tests/the-skip-link-outranks-the-transition.node.test.js` holds what the engine
38
+ needs of them: the skip link sits on its slot, above the transition and every other slot except the loop-crash
39
+ notice and the debug panel, and no literal `z-index` in this file reaches it.
40
+
41
+ ⚠️ MOST SELECTORS STILL CARRY LITERALS, and that is not forgetfulness. Only `.skip-link`, `#incl-parou` and the
42
+ touch pad over an open panel read a slot. Adopting the slots everywhere inverts three orders that hold today, and
43
+ inverting an order is a product decision:
44
+
45
+ · `.caption` (8) is BELOW the touch pad (14). In the slots, captions (26000) are ABOVE touch controls (25000).
46
+ The inversion FIXES a defect — the caption serves deaf players, and a touch control covering it is the wrong
47
+ way round —, but it changes the screen.
48
+ · `.quiz` (12) is BELOW the touch pad (14); in the slots, dialogue (27000) is above.
49
+ · the skip link was already corrected: it sits on `--z-skip-link`, above the modals and the transition.
50
+
51
+ AND TWO THINGS HAVE NO SLOT: the two CRT pseudo-elements (`crt-vig-1::before` at 5 and `crt-scan-1::after` at
52
+ 500). Under ADR-0020 the CRT is POST-PROCESSING, not a layer — inventing a number for it would repeat the category
53
+ error the record already names.
54
+
55
+ ⚠️ AND CSS `z-index` IS NOT FLAT. `#game-hud` has `z-index:4` and CREATES A STACKING CONTEXT, so `.screen-pause`
56
+ (6) competes only inside it — the pause menu effectively lives at "4" at the root. A flat list of global values
57
+ cannot express that. Adopting the slots means deciding, per element, which context it lives in. */
45
58
  --z-hud:24000;
46
59
  --z-touch-controls:25000;
47
60
  --z-captions:26000;
@@ -55,326 +68,342 @@
55
68
  --z-loop-crash:45000;
56
69
  --z-debug:90000;
57
70
  }
58
- /* Emoji: usa o Noto Color Emoji do sistema (Chromebook/Android/Linux) e, se ausente, o woff2 embutido
59
- (offline). Se o arquivo não estiver presente, o navegador cai no emoji do SO — sem quebrar. */
60
- @font-face{ font-family:'Noto Color Emoji'; src:local('Noto Color Emoji'); /* só a fonte do sistema; sem download (o .woff2 nunca existiu) */ font-display:swap; }
61
- /* Modo ALFABETIZAÇÃO → Andika */
71
+ /* Emoji: the system's Noto Color Emoji (Chromebook/Android/Linux). No file is shipped for it, so where the system
72
+ lacks it the browser falls back to the OS emoji — without breaking. */
73
+ @font-face{ font-family:'Noto Color Emoji'; src:local('Noto Color Emoji'); /* the system face only; no download (the .woff2 never existed) */ font-display:swap; }
74
+ /* LITERACY mode → Andika */
62
75
  :root[data-fonte="alfabetizacao"]{ --font:'Andika',var(--font-fallback); }
63
- /* Modo DISLEXIA/TDAH → Lexend + espaçamento da British Dyslexia Association
64
- (palavra ≥ 3,5× letra: letter 0.18em / word 0.63em) */
65
- :root[data-fonte="dislexia"]{ --font:'Lexend',var(--font-fallback); --ls:0.18em; --ws:0.63em; }
66
- /* Tipografia: qualquer fonte do catálogo (menu próprio na pausa); --font-custom traz a pilha com fallback */
76
+ /* DYSLEXIA/ADHD mode → Lexend. 📌 The BDA spacing is not here: it is the document's default (see `:root`, ADR-0149 §2),
77
+ not this face's exception. The rule keeps only the FAMILY, which is all it ever had of its own. */
78
+ :root[data-fonte="dislexia"]{ --font:'Lexend',var(--font-fallback); }
79
+ /* ===== THE CURSIVE EXCEPTION (ADR-0149 §3) =====
80
+ 🔴 Letter spacing on a JOINED face breaks it exactly at the joins that make it cursive: what is meant to help the
81
+ reading would destroy the thing being read. The Dev's words: «para manter os conectores».
82
+ It is not a concession — it is the same rule applied to a face where it inverts.
83
+ ⚠️ `normal` and not `0`: `word-spacing:0` is still a spacing declaration; `normal` gives back the metrics the face's
84
+ designer chose, which is precisely what is meant to be preserved. */
85
+ :root[data-cursiva="1"]{ --ls:normal; --ws:normal; }
86
+ /* A COLOUR-VISION-SAFE PALETTE FOR THE MENUS AND THE HUD (ADR-0151) — Okabe-Ito.
87
+ 📏 The interface's meaning-by-colour sits in two tokens: `--accent` (selection, «on», choice) and `--good` (the right
88
+ answer revealed). The usual pair, yellow and green, is the one protans and deutans confuse: CIE76 ΔE of 48 and 55
89
+ after Machado's (2009) simulation. Orange and sky blue give 101, 111 and 87 (tritan) — the largest worst case among
90
+ the Okabe-Ito pairs measured — and every contrast stays ≥ 4.5:1 (the tightest is `--good` on the selected button,
91
+ 4.88:1). The gate is `tests/okabe-ito-palette.node.test.js`. */
92
+ :root[data-paleta="okabe-ito"]{ --accent:#E69F00; --focus:#E69F00; --good:#56B4E9; }
93
+ /* Typography: any face of the catalogue (its own menu in the pause); --font-custom brings the stack with its fallback */
67
94
  :root[data-fonte="custom"]{ --font:var(--font-custom,'Atkinson Hyperlegible'),var(--font-fallback); }
68
- /* Menu Tipografia: caixa branca de pré-visualização (pangrama), escrita escura */
95
+ /* Typography menu: a white preview box (pangram), dark text */
69
96
  .typo-preview{background:#fff;color:#14141f;border:2px solid var(--ink-soft);border-radius:8px;padding:.65rem .9rem;margin:.2rem 0 .6rem;font-size:1.3em;line-height:1.3;text-align:center}
70
- /* Tela de título (visual da v3): overlay TRANSPARENTE — a cena (céu/nuvens/grama) vem do canvas */
71
- #title-overlay{background:transparent;font-size:var(--ui-fs,16px)} /* UI do splash escala com o k inteiro do canvas (igual pausa/diálogos) — NÃO fica fixa em 16px */
72
- body.at-title #game-hud,body.at-title .start-tips,body.at-title .hud{display:none} /* HUD do jogo não vaza no menu inicial (display: filhos não conseguem re-exibir) */
97
+ /* Title screen: a TRANSPARENT overlay — the scene behind it comes from the canvas */
98
+ #title-overlay{background:transparent;font-size:var(--ui-fs,16px)} /* the splash UI scales with the canvas's integer k (like the pause and the dialogs) — it does NOT stay at 16px */
99
+ body.at-title #game-hud,body.at-title .start-tips,body.at-title .hud{display:none} /* the game's HUD does not leak into the start menu (display: children cannot show themselves again) */
73
100
  .title-wrap{display:flex;flex-direction:column;align-items:center;gap:12px;max-height:96%;}
74
- .game-title{color:#fff;font-size:2em;line-height:1.2;margin:0;text-align:center;letter-spacing:1px;text-shadow:2px 2px 0 #0d0d1a,-1px -1px 0 #0d0d1a}
101
+ .game-title{color:#fff;font-size:2em;line-height:1.2;margin:0;text-align:center;letter-spacing:var(--ls);text-shadow:2px 2px 0 #0d0d1a,-1px -1px 0 #0d0d1a}
75
102
  .title-block{display:inline-block}
76
- .game-byline{color:#f6f5f0;font-size:.8em;text-align:right;margin-top:2px;text-shadow:1px 1px 0 #0d0d1a}
77
- .game-version{color:#9999b3;font-size:.6em;text-align:right;letter-spacing:1px;margin-top:2px;text-shadow:1px 1px 0 #0d0d1a}
78
- .game-subtitle{color:#f6f5f0;font-size:.8em;margin:0 0 4px;text-shadow:1px 1px 0 #0d0d1a;text-align:center}
79
- /* Splash DENTRO do canvas, SEM rolagem. GESTALT (José): a11y no CABEÇALHO · menu no ESPAÇO DE TRABALHO · legenda no RODAPÉ */
103
+ .game-byline{color:#f6f5f0;font-size:1em;text-align:right;margin-top:2px;text-shadow:1px 1px 0 #0d0d1a}
104
+ .game-version{color:#9999b3;font-size:1em;text-align:right;letter-spacing:var(--ls);margin-top:2px;text-shadow:1px 1px 0 #0d0d1a}
105
+ .game-subtitle{color:#f6f5f0;font-size:1em;margin:0 0 4px;text-shadow:1px 1px 0 #0d0d1a;text-align:center}
106
+ /* The splash INSIDE the canvas, with NO scrolling. GESTALT (the Dev): a11y in the HEADER · menu in the WORKSPACE · legend in the FOOTER */
80
107
  .title-wrap{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;max-height:none}
81
- .title-legend{position:absolute;left:0;right:0;bottom:8px} /* RODAPÉ, como a legenda da pausa */
82
- .title-menu{display:flex;flex-direction:column;gap:.35em;align-items:stretch;padding:2px;width:13em;margin:0 auto} /* largura fixa ENXUTA */
108
+ .title-legend{position:absolute;left:0;right:0;bottom:8px} /* FOOTER, like the pause legend */
109
+ .title-menu{display:flex;flex-direction:column;gap:.35em;align-items:stretch;padding:2px;width:13em;margin:0 auto} /* a fixed, LEAN width */
83
110
  .title-menu[hidden]{display:none}
84
- /* O menu principal com o DOBRO da largura base (13em → 26em): a 13em os rótulos quebravam em DUAS linhas, e
85
- um botão de duas linhas muda de altura conforme o idioma — a mesma tela com uma geometria em pt-BR e outra
86
- em espanhol. Quem se orienta por alinhamento perde a referência; quem escuta nem percebe que ela existia. */
111
+ /* The main menu at TWICE the base width (13em → 26em): at 13em the labels wrapped onto TWO lines, and a two-line
112
+ button changes height with the language — the same screen with one geometry in pt-BR and another in Spanish.
113
+ Whoever finds their way by alignment loses the reference; whoever listens never knew it existed. */
87
114
  #tm-main{width:26em}
88
- /* ===================== SUBMENUS DA ABERTURA: LISTA VERTICAL COM ROLAGEM (ADR-0044) =====================
89
- Eram GRADES de duas colunas, e a seta anda em ordem de DOM: “para baixo” pulava para a coluna da direita,
90
- atravessando a tela. O anel do item 1 já estava certo no código (`nextTitleIndex` dá a volta) — era o
91
- LAYOUT que mentia sobre ele. Em lista, a ordem que se VÊ é a ordem em que se ANDA.
115
+ /* ===================== THE OPENING SUBMENUS: A VERTICAL LIST THAT SCROLLS (ADR-0044) =====================
116
+ They were two-column GRIDS, and the arrow moves in DOM order: “down” jumped to the right-hand column, across the
117
+ screen. The ring of item 1 was already right in the code (`nextTitleIndex` wraps around) — it was the LAYOUT that
118
+ lied about it. In a list, the order you SEE is the order you MOVE in.
92
119
 
93
- Onze frações não cabem no quadro, então a lista ROLA — foi o que o Dev pediu, e o preço é barato:
94
- `focus()` traz o item para dentro da janela sozinho, de modo que quem anda por teclado ou controle nunca
95
- perde o foco fora da vista.
120
+ Eleven fractions do not fit the frame, so the list SCROLLS — which is what the Dev asked for, and the price is low:
121
+ `focus()` brings the item into view by itself, so whoever moves by keyboard or controller never loses the focus
122
+ out of sight.
96
123
 
97
- O painel é OPACO pelo mesmo motivo do véu da pausa: por trás da abertura corre o modo de atração, e
98
- texto sobre quadro variável tem a razão de contraste que o quadro permitir — média de sorte, não garantia. */
124
+ The panel is OPAQUE for the same reason as the pause veil: the attract mode runs behind the opening, and text over a
125
+ changing frame has whatever contrast the frame allows — an average of luck, not a guarantee. */
99
126
  #tm-alf,#tm-mat,#tm-tab,#tm-fr,#tm-cen{width:26em;max-height:72%;overflow-y:auto;overflow-x:hidden;background:var(--bg-solid);border-radius:10px;padding:.5em .7em}
100
- /* O título do submenu fica GRUDADO no topo: numa lista que rola, um cabeçalho que sobe leva embora a única
101
- pista de “onde estou” que quem lê por resto de visão tem. */
127
+ /* The submenu's title STICKS to the top: in a scrolling list, a heading that scrolls away takes with it the only
128
+ “where am I” cue that someone reading with residual vision has. */
102
129
  #tm-alf .tm-title,#tm-mat .tm-title,#tm-tab .tm-title,#tm-fr .tm-title,#tm-cen .tm-title{position:sticky;top:-.5em;z-index:1;background:var(--bg-solid);padding:.35em 0 .25em;margin:0}
103
- /* …e por isso os itens precisam de MARGEM DE ROLAGEM: um cabeçalho grudado cobre o item que o navegador acaba
104
- de "trazer para a vista", porque para ele o item já estava dentro do quadro. MEDIDO no navegador antes de
105
- existir esta linha: dando a volta do último para o primeiro, o primeiro botão parava com o topo em 143px e
106
- o cabeçalho terminava em 155 — 12px encobertos, e a criança via um item cortado no lugar do foco. O valor
107
- cobre a altura do cabeçalho (34px ≈ 2,1em) com folga. */
130
+ /* …and that is why the items need a SCROLL MARGIN: a sticky heading covers the item the browser has just "brought into
131
+ view", because for the browser the item was already inside the frame. MEASURED in the browser before this line
132
+ existed: wrapping from the last item to the first, the first button stopped with its top at 143px while the heading
133
+ ended at 155 — 12px covered, and the child saw a cut-off item where the focus was. The value covers the heading's
134
+ height (34px ≈ 2.1em) with room to spare. */
108
135
  #tm-alf .title-btn,#tm-mat .title-btn,#tm-tab .title-btn,#tm-fr .title-btn,#tm-cen .title-btn{scroll-margin-top:2.4em;scroll-margin-bottom:.5em}
109
- /* As notações de fração continuam LADO A LADO: são cinco alternadores de UM grupo, e não itens da lista —
110
- virar coluna aqui alongaria a rolagem sem ganhar ordem nenhuma. */
136
+ /* The fraction notations stay SIDE BY SIDE: they are five toggles of ONE group, not list items — turning them into a
137
+ column here would lengthen the scroll without adding any order. */
111
138
  #tm-fr .frac-nots{display:flex;flex-direction:column;gap:.25em}
112
- /* AS CINCO NOTAÇÕES SÃO AJUSTE, NÃO ITEM DE MENU (pedido do Dev). Elas usavam `.title-btn` — a mesma classe
113
- dos botões que ABREM uma atividade — e ficavam empilhadas logo acima deles: cinco coisas com cara de
114
- "entrar" que na verdade ligam e desligam. A moldura (`fieldset`/`legend`) é a fronteira, e a marca ☑/☐ é o
115
- estado sem depender de cor (a cor sozinha reprova a WCAG 1.4.1). */
139
+ /* THE FIVE NOTATIONS ARE SETTINGS, NOT MENU ITEMS (the Dev's request). They used `.title-btn` — the same class as the
140
+ buttons that OPEN an activity — and were stacked right above them: five things that looked like "enter" and in fact
141
+ switch on and off. The frame (`fieldset`/`legend`) is the boundary, and the ☑/☐ mark is the state without relying
142
+ on colour (colour alone fails WCAG 1.4.1). */
116
143
  #tm-fr .frac-nots{border:2px solid var(--ink-soft);border-radius:10px;padding:.3em .5em .5em;margin:0 0 .45em}
117
- #tm-fr .frac-nots legend{padding:0 .4em;font-size:.8em;font-weight:700;color:var(--ink-soft)}
144
+ #tm-fr .frac-nots legend{padding:0 .4em;font-size:1em;font-weight:700;color:var(--ink-soft)}
118
145
  #tm-fr .fnot-opt{display:flex;align-items:center;gap:.5em;width:100%;min-height:44px;padding:.2em .4em;background:transparent;color:#fff;border:0;border-radius:8px;font:inherit;cursor:pointer;text-align:left}
119
146
  #tm-fr .fnot-opt:hover,#tm-fr .fnot-opt:focus-visible{background:#16233f}
120
147
  #tm-fr .fnot-marca{font-size:1.15em;line-height:1;min-width:1.1em}
121
148
  #tm-fr .fnot-opt[aria-checked="true"] .fnot-marca{color:var(--accent)}
122
149
  #tm-fr .fnot-sym{font-size:1em}
123
- #tm-fr .fnot-opt .fv{font-size:.8em}
124
- .tm-title{color:#fff;font-size:1em;margin:0 0 .1em;text-align:center;text-shadow:1px 1px 0 #0d0d1a} /* título do submenu */
125
- .title-btn{background:var(--accent);color:var(--accent-ink);border:3px solid #0d0d1a;font-family:inherit;font-weight:bold;font-size:.95em;padding:.4em .6em;border-radius:6px;cursor:pointer;min-width:0;width:100%;min-height:2.3em} /* contorno PRETO grosso (3px) = mesma cor do texto (José) */
126
- .title-btn.ghost{background:#e8862b;color:#0d0d1a;border:2px solid #0d0d1a} /* Voltar = preenchimento LARANJA */
127
- .act-sub{display:block;font-size:.72em;font-weight:600;opacity:.7;letter-spacing:.02em;margin-top:.06em;font-family:var(--font-math,inherit);white-space:nowrap} /* subtítulo de exemplo (2ª linha, NUNCA quebra — botão largo o bastante) */
128
- /* Seletor VERMELHO fixo (piscar removido a pedido do José). Especificidade via #title-overlay. */
150
+ #tm-fr .fnot-opt .fv{font-size:1em}
151
+ .tm-title{color:#fff;font-size:1em;margin:0 0 .1em;text-align:center;text-shadow:1px 1px 0 #0d0d1a} /* the submenu's title */
152
+ .title-btn{background:var(--accent);color:var(--accent-ink);border:3px solid #0d0d1a;font-family:inherit;font-weight:bold;font-size:1em;padding:.4em .6em;border-radius:6px;cursor:pointer;min-width:0;width:100%;min-height:2.3em} /* a thick BLACK outline (3px) = the same colour as the text (the Dev) */
153
+ .title-btn.ghost{background:#e8862b;color:#0d0d1a;border:2px solid #0d0d1a} /* Back = ORANGE fill */
154
+ .act-sub{display:block;font-size:1em;font-weight:600;opacity:.7;letter-spacing:var(--ls);margin-top:.06em;font-family:var(--font-math,inherit);white-space:nowrap} /* the example subtitle (2nd line, NEVER wraps — the button is wide enough) */
155
+ /* A fixed RED selector (blinking removed at the Dev's request). Specificity through #title-overlay. */
129
156
  #title-overlay .title-btn:focus-visible,#title-overlay .title-btn:focus{outline:4px solid #ff3b30;outline-offset:2px}
130
- #title-overlay .title-btn.act-fx{animation:titleAct .22s ease} /* efeito de ATIVAÇÃO (antes de trocar de tela) */
157
+ #title-overlay .title-btn.act-fx{animation:titleAct .22s ease} /* the ACTIVATION effect (before the screen changes) */
131
158
  @keyframes titleAct{0%{transform:scale(.92);filter:brightness(1.6)}60%{transform:scale(1.03)}100%{transform:scale(1)}}
132
159
  @media (prefers-reduced-motion: reduce){ #title-overlay .title-btn.act-fx{animation:none;filter:brightness(1.4)} }
133
160
  .title-btn.tab-on{box-shadow:inset 0 0 0 3px #14141f}
134
- /* As fileiras da tabuada eram DUAS linhas de números lado a lado, e o Dev cobrou de novo depois de ver o
135
- resultado: menu "misto" é menu onde "para baixo" às vezes anda para o lado. Viraram coluna, como todo o
136
- resto da abertura. O seletor ganhou o `#tm-tab` na frente de propósito — é o que deixa o gate de layout
137
- enxergar esta regra como sendo DE um submenu da abertura, em vez de uma classe solta que ninguém vigia. */
161
+ /* The times-table rows were TWO lines of numbers side by side, and the Dev objected again after seeing the result: a
162
+ "mixed" menu is a menu where "down" sometimes moves sideways. They became a column, like the rest of the opening.
163
+ The selector carries `#tm-tab` in front on purpose — that is what lets the layout gate see this rule as belonging TO
164
+ an opening submenu, instead of a loose class nobody watches. */
138
165
  #tm-tab .tab-row{display:flex;flex-direction:column;gap:.35em}
139
166
  #tm-tab .tab-row .title-btn{width:100%;padding:.4em .5em}
140
- /* RODAPÉ (mesmo estilo do menu de pausa): descrição no fundo do canvas, NÃO colada ao grupo de botões (José).
141
- Fundo fumê PRETO → contraste ≥7:1 entre o texto claro (#f6f5f0) e o fundo (≈#0a0a12). */
142
- .tm-desc:not(:empty){position:absolute;left:50%;transform:translateX(-50%);bottom:10px;max-width:88%;color:#f6f5f0;font-size:.8em;text-align:center;background:rgba(8,8,16,.92);padding:.35em .7em;border-radius:8px;line-height:1.25}
167
+ /* FOOTER (the same style as the pause menu): the description at the bottom of the canvas, NOT glued to the button group (the Dev).
168
+ A smoked BLACK background → contrast ≥7:1 between the light text (#f6f5f0) and the background (≈#0a0a12). */
169
+ .tm-desc:not(:empty){position:absolute;left:50%;transform:translateX(-50%);bottom:10px;max-width:88%;color:#f6f5f0;font-size:1em;text-align:center;background:rgba(8,8,16,.92);padding:.35em .7em;border-radius:8px;line-height:1.25}
143
170
  .tm-desc:empty{position:absolute;left:0;bottom:10px}
144
- /* Legenda de controles: mesmo visual/posição da legenda do menu de pausa (chips), em 2 LINHAS */
145
- .title-legend{display:flex;flex-direction:column;gap:.25em;align-items:center;margin:.5em 0 .1em;font-size:.82em;color:#c3cfe0}
171
+ /* Controls legend: the same look and place as the pause menu's legend (chips), on 2 LINES */
172
+ .title-legend{display:flex;flex-direction:column;gap:.25em;align-items:center;margin:.5em 0 .1em;font-size:1em;color:#c3cfe0}
146
173
  .title-legend .lg-row{display:flex;gap:1.1em;justify-content:center;flex-wrap:wrap}
147
174
  .title-legend .lg{display:inline-flex;align-items:center;gap:.35em}
148
- .title-legend .lg-ico{display:inline-flex;align-items:center;justify-content:center;min-width:1.35em;height:1.35em;padding:0 .2em;border-radius:.68em;font-weight:800;font-size:.9em;color:#fff;background:rgba(13,13,26,.85);text-shadow:0 1px 1px rgba(0,0,0,.55)}
149
- #title-icons{position:absolute;top:10px;left:50%;transform:translateX(-50%);display:flex;gap:.3em;justify-content:center;flex-wrap:nowrap;white-space:nowrap} /* CABEÇALHO: 10px do topo, UMA fileira */
150
- /* Seletor de jogadores = UM botão só ("◀ Nº de jogadores: X ▶"); o lado clicado decide +1/−1 */
151
- #np-btn{letter-spacing:.02em}
175
+ .title-legend .lg-ico{display:inline-flex;align-items:center;justify-content:center;min-width:1.35em;height:1.35em;padding:0 .2em;border-radius:.68em;font-weight:800;font-size:1em;color:#fff;background:rgba(13,13,26,.85);text-shadow:0 1px 1px rgba(0,0,0,.55)}
176
+ #title-icons{position:absolute;top:0;left:50%;transform:translateX(-50%);display:flex;gap:0;justify-content:center;flex-wrap:nowrap;white-space:nowrap} /* header: on the screen's top edge, giving that room to the game (interface log 2026-09-13), ONE row */
177
+ #title-icons.pause-icons{margin:0 0 calc(.35rem * var(--espaco-fixo,1))}
178
+ /* The NAME of the pointed icon, just below the row. Absolute, so the bar's height — the band the game must not draw
179
+ over (ADR-0148) — does not grow when a name appears; the explanation goes to the footer, not here. */
180
+ #title-icons .pause-icons-cap{position:absolute;top:100%;line-height:1.25;left:50%;transform:translateX(-50%);margin:0;text-align:center;font-size:1em;color:#f6f5f0;pointer-events:none;white-space:nowrap;min-height:0;padding:calc(var(--ui-fs,16px) * .2) calc(var(--ui-fs,16px) * .6)}
181
+ /* the padding stays when empty: the room `createGame` reserves under the bar reads it (issue #160) */
182
+ #title-icons .pause-icons-cap:not(:empty){background:rgba(8,8,16,.92);border-radius:8px}
183
+ /* Player-count selector = ONE button ("◀ No. of players: X ▶"); the side clicked decides +1/−1 */
184
+ #np-btn{letter-spacing:var(--ls)}
152
185
  #np-btn #np-n{display:inline-block;min-width:1.1em;text-align:center}
153
- /* Fração VERTICAL: pilha número/traço/número em HTML puro (zero dependência) */
186
+ /* VERTICAL fraction: a number/bar/number stack in plain HTML (zero dependencies) */
154
187
  .fv{display:inline-flex;flex-direction:column;align-items:center;vertical-align:middle;line-height:1.05;margin:0 .1em}
155
188
  .fv b{font-weight:800;padding:0 .25em}
156
189
  .fv b:first-child{border-bottom:2px solid currentColor}
157
- /* Fração como FIGURA (pizza/quadrado): SVG inline, 2-6 partes iguais; imprópria = várias unidades lado a lado */
158
- :root{--frac-fill:#f2a03d} /* laranja: alto contraste sobre branco + contorno preto (não depende só da cor — WCAG 1.4.1) */
190
+ /* A fraction as a FIGURE (pie/square): inline SVG, 2-6 equal parts; an improper one = several units side by side */
191
+ :root{--frac-fill:#f2a03d} /* orange: high contrast on white + a black outline (not colour alone — WCAG 1.4.1) */
159
192
  .frac-fig{display:inline-flex;align-items:center;gap:.25em;vertical-align:middle}
160
- .frac-shape{display:inline-flex;align-items:center;gap:.15em} /* círculo + quadrado da mesma fração, lado a lado */
161
- .frac-op{display:inline-flex;flex-direction:column;align-items:center;gap:.15em;vertical-align:middle} /* operando da conta: número EM CIMA, gráfico embaixo */
193
+ .frac-shape{display:inline-flex;align-items:center;gap:.15em} /* circle + square of the same fraction, side by side */
194
+ .frac-op{display:inline-flex;flex-direction:column;align-items:center;gap:.15em;vertical-align:middle} /* an operand of the sum: the number ON TOP, the figure below */
162
195
  .frac-svg{width:2.4em;height:2.4em;display:inline-block;vertical-align:middle}
163
196
  .quiz-choice .frac-svg{width:2.6em;height:2.6em}
164
197
  .quiz-prob .frac-svg{width:2.6em;height:2.6em}
165
198
  .quiz-dots{font-size:1.3em;letter-spacing:.15em;line-height:1.3;margin:.3rem 0;max-width:12em}
166
199
  @media (prefers-contrast: more){
167
- /* Aqui `--ink-soft` JÁ é branco: a moldura de "alterado" tem que deixar de ser branca, ou marcado e
168
- não-marcado viram a mesma moldura — justamente para a criança cujos ajustes têm mais chance de estar
169
- fora do padrão. Uma marca cuja visibilidade depende do tema não é uma marca (ADR-0029). */
200
+ /* Here `--ink-soft` is ALREADY white: the "changed" frame has to stop being white, or marked and unmarked become the
201
+ same frame — precisely for the child whose settings are most likely to be off the default. A mark whose
202
+ visibility depends on the theme is not a mark (ADR-0029). */
170
203
  :root{ --bg:#000; --panel:#000; --ink:#fff; --ink-soft:#fff; --accent:#ffe600; --changed:#ffe600; }
171
204
  }
172
205
  *{box-sizing:border-box}
206
+ /* A face with a floor above 16 px (`--fonte-escala`, written by the typography cycle and menu; ADR-0176 rule 4) enlarges
207
+ ITS OWN TEXT and not the whole document (interface log 2026-09-13, issue #172): the scale lives on `#game-region`'s
208
+ `font-size`, spacing bound to the text is written in `--ui-fs`, and the root stays 16 px so `rem` does not grow.
209
+ `--espaco-fixo` is the factor of the spaces that do NOT follow the scale — the ones the Dev saw shrink under a 25% browser
210
+ zoom while the text held «mantendo o design muito bom»: 1 at the base, down to that quarter at the 20 px floor. */
211
+ :root{--espaco-fixo:max(.25, 4 - 3 * var(--fonte-escala,1))}
173
212
  html,body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--font);font-size:16px;line-height:var(--lh);letter-spacing:var(--ls);word-spacing:var(--ws)}
174
- /* matemática em mono tabular (algarismos alinhados/legíveis) */
213
+ /* THE SPACING IS THE TEXT'S, WHEREVER THE TEXT IS (ADR-0149 erratum, issue #187): «Se dentro de um botão tem texto, as regras de
214
+ espaçamento valem para este texto, mesmo que seja uma única palavra.» The browser's own stylesheet gives controls
215
+ `letter-spacing: normal`, which beat the inheritance — measured: pause items and quiz options had none. Zero specificity, so a
216
+ rule that spaces a control on purpose still decides. */
217
+ :where(button,select,option,input,textarea){letter-spacing:inherit;word-spacing:inherit}
218
+ /* mathematics in tabular mono (aligned, legible digits) */
175
219
  .quiz-box--math .quiz-prob,.quiz-box--math .quiz-choice,#hud-coins,#hud-total{font-family:var(--font-math);font-variant-numeric:tabular-nums}
176
- /* espaçamento de parágrafo ≥2× só em blocos de leitura (não quebra HUD/menus) */
220
+ /* paragraph spacing ≥2× only in reading blocks (it does not break the HUD or the menus) */
177
221
  .overlay__card p + p{margin-top:2em}
178
- /* A página NUNCA rola (José): altura travada no viewport e overflow escondido — o excedente do canvas
179
- (tolerância de 5px lógicos/lado) é cortado pelo .stage-wrap, e os menus rolam DENTRO dos cards. */
222
+ /* The page NEVER scrolls (the Dev): height locked to the viewport and overflow hidden — the canvas's excess (a tolerance
223
+ of 5 logical px per side) is cut by .stage-wrap, and the menus scroll INSIDE their cards. */
180
224
  body{display:flex;flex-direction:column;height:100vh;height:100dvh;overflow:hidden}
181
225
  .sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
182
- /* O `z-index` ADOTOU O SLOT em 2026-09-07. Era `100`, um literal que estava CERTO e cuja tabela estava
183
- errada: o `Z` punha o skip-link em CAPTIONS(26000), abaixo dos modais. Ver `SKIP_LINK` em core/layers. */
226
+ /* The skip link sits on its SLOT, `--z-skip-link`, and not on a literal: above the modals and the transition, below only
227
+ the loop-crash notice and the debug panel. `tests/the-skip-link-outranks-the-transition.node.test.js` holds it (ADR-0102). */
184
228
  .skip-link{position:absolute;left:8px;top:-60px;background:var(--accent);color:var(--accent-ink);padding:.6em 1em;border-radius:0 0 10px 10px;font-weight:700;z-index:var(--z-skip-link);transition:top .15s}
185
229
  .skip-link:focus{top:0}
186
230
  :focus-visible{outline:4px solid var(--focus);outline-offset:2px;border-radius:6px}
187
231
 
188
232
  .topbar{max-width:var(--maxw);margin:0 auto;padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}
189
- body:not(.dbg) .topbar{display:none} /* título da PÁGINA só em ?debug=true (o jogo já mostra no splash); recupera a vertical */
190
- .title{font-size:1.3rem;margin:0}
191
- .ver{color:var(--ink-soft);font-weight:400;font-size:.9rem}
192
- .badge{margin:0;color:var(--accent-ink);background:var(--accent);border-radius:999px;padding:.2em .8em;font-weight:700;font-size:.8rem}
233
+ body:not(.dbg) .topbar{display:none} /* the PAGE title only under ?debug=true (the game already shows it on the splash); gives back the vertical room */
234
+ .title{font-size:1.3em;margin:0}
235
+ .ver{color:var(--ink-soft);font-weight:400;font-size:1em}
236
+ .badge{margin:0;color:var(--accent-ink);background:var(--accent);border-radius:999px;padding:.2em .8em;font-weight:700;font-size:1em}
193
237
 
194
238
  .hud{max-width:var(--maxw);margin:0 auto;padding:0 1rem .5rem;display:flex;gap:1.5rem;flex-wrap:wrap}
195
- .hud__item{margin:0;font-size:1.05rem}
196
- /* moedas/missão/poder migraram para dentro da tela de cada jogador; ficam sr-only (leitor de tela) */
239
+ .hud__item{margin:0;font-size:1.05em}
240
+ /* coins/mission/power moved into each player's screen; they stay sr-only (for the screen reader) */
197
241
  .hud__item--sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
198
- /* HUD por jogador SOBRE o canvas (DOM = alta definição, não pixela). Um por viewport; moedas na 1ª coluna, poder na 2ª. */
199
- #game-hud{position:absolute;inset:0;pointer-events:none;z-index:4;font-family:var(--font);font-size:var(--hud-fs,14px);font-weight:800}
200
- /* "Tela do jogador": um contêiner por jogador (posicionado na fatia do viewport dele). Hospeda HUD, e nas
201
- próximas etapas a pausa e os menus daquele jogador. O render segue compartilhado (um contexto WebGL). */
242
+ /* Per-player HUD OVER the canvas (DOM = high definition, no pixelation). One per viewport; coins in the 1st column, power in the 2nd. */
243
+ #game-hud{position:absolute;inset:0;pointer-events:none;z-index:4;font-family:var(--font);font-size:var(--hud-fs,16px);font-weight:800}
244
+ /* "Player screen": one container per player (placed on that player's slice of the viewport). It hosts the HUD, and the
245
+ pause and menus of that player. The render stays shared (one WebGL context). */
202
246
  .player-screen{position:absolute;pointer-events:none}
203
247
  .vphud{position:absolute;top:0;left:0;width:100%;display:flex;align-items:flex-start;gap:0;padding:.4em .55em;box-sizing:border-box;color:#fff;text-shadow:0 1px 2px #000,0 0 3px #000,0 0 6px #000;line-height:1.15}
204
248
  .vphud-obj,.vphud-power{flex:1 1 50%;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
205
249
  .vphud-ico{font-weight:400}
206
- /* jogador que saiu (MP): viewport preto com "Jogo abandonado" no centro; os outros seguem */
207
- .vphud-quit{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#000;color:#cdd6f2;font-family:var(--font);font-weight:800;font-size:var(--hud-fs,14px);text-align:center}
250
+ /* a player who left (multiplayer): a black viewport with "Game abandoned" in the middle; the others carry on */
251
+ .vphud-quit{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#000;color:#cdd6f2;font-family:var(--font);font-weight:800;font-size:var(--hud-fs,16px);text-align:center}
208
252
  .vphud-quit[hidden]{display:none}
209
- /* PAUSA dentro do canvas (tela = canvas) — sobreposta ao #game-region, não à página */
253
+ /* PAUSE inside the canvas (screen = canvas) — laid over #game-region, not over the page */
210
254
  .pause-incanvas{position:absolute;inset:0;z-index:6;display:flex;align-items:center;justify-content:center;background:var(--bg-solid);font-family:var(--font)}
211
255
  .pause-incanvas[hidden]{display:none}
212
- /* Etapa 2: menu de pausa POR TELA (dentro de cada .player-screen). Cada jogador vê e navega o seu. */
213
- .screen-pause{position:absolute;inset:0;z-index:6;display:flex;align-items:center;justify-content:center;background:var(--bg-solid);font-family:var(--font);font-size:var(--ui-fs,16px);pointer-events:auto} /* base = --ui-fs (16 no mínimo, escala com o canvas) */
256
+ /* The pause menu PER SCREEN (inside each .player-screen). Each player sees and moves through their own. */
257
+ .screen-pause{position:absolute;inset:0;z-index:6;display:flex;align-items:center;justify-content:center;background:var(--bg-solid);font-family:var(--font);font-size:var(--ui-fs,16px);pointer-events:auto} /* base = --ui-fs (16 at least, scales with the canvas) */
214
258
  .screen-pause[hidden]{display:none}
215
- .screen-pause .pause-card{max-width:94%;max-height:98%;padding:.5rem .7rem}
216
- .screen-pause .pause-card h2{font-size:1.2em;margin:.05rem 0 .28rem}
259
+ /* ADR-0163: seven 44 px items are 308 of the 360 px at 640×360 (measured). The title keeps the 16 px text floor with a tight
260
+ line (20 px, not 29) and the card may use the whole height. */
261
+ .screen-pause .pause-card{max-width:94%;max-height:100%;padding:.25rem .7rem}
262
+ /* ONE HEIGHT for every card of the menus (interface log, 2026-09-13): the root, its submenu, the panels and the help. The root's
263
+ six items fitted and its card shrank to them, 46 px shorter than the submenu at 640×360 (measured); it now holds the whole
264
+ height too, its items from the top, as a panel's rows are. */
265
+ .screen-pause .pause-card{height:100%;box-sizing:border-box}
266
+ .screen-pause .pause-card h2{font-size:1em;line-height:1.25;margin:0 0 .1rem}
217
267
  .screen-pause .pause-menu{gap:.3rem}
218
- /* O quadro por jogador aperta o PADDING, nunca a altura mínima: o quadro apertado é o do jogo com quatro
219
- crianças, onde os dedos disputam espaço — o pior lugar possível para encolher um alvo de toque. O cartão
220
- tem `overflow:auto` e rola; o botão não diminui. */
268
+ /* The per-player frame tightens the PADDING, never the minimum height: the tight frame is the one of a game with four
269
+ children, where fingers compete for room — the worst possible place to shrink a touch target. The card has
270
+ `overflow:auto` and scrolls; the button does not shrink. */
221
271
  .screen-pause .pm-btn{padding:.3rem .7rem}
222
- .screen-pause .pause-legend{margin:.28rem 0 0}
223
- /* Atalhos de a11y = botões do menu em forma de ícone, DENTRO do card (sem barra/sombra própria).
224
- Navegáveis por teclado (cima a partir de Continuar) e por toque/clique. */
225
- .pause-icons{display:flex;flex-wrap:wrap;gap:.4rem;justify-content:center;align-items:center;margin:.1rem 0 .35rem}
226
- /* ===================== A BARRA RÁPIDA NO HUD (ADR-0044, item 7) =====================
227
- Ela saiu do cartão de pausa e passou a viver na tela do jogador, disponível DURANTE a partida — que é
228
- quando uma criança precisa mudar um ajuste que está a atrapalhando, e não depois de pausar.
229
-
230
- É IRMÃ da `.screen-exp` e não filha, e a razão é o #82: `filter` de CSS desce para os descendentes e um
231
- filho não consegue cancelá-lo. Dentro da experiência, o modo empatia degradaria justamente o que existe
232
- para DAR acesso — e simulação não é acessibilidade, é o contrário dela.
233
-
234
- `pointer-events:auto` porque a `.player-screen` inteira é `none` (o jogo recebe o toque); os dez ícones
235
- são a exceção, como o cartão de pausa já era. */
236
- /* A ALTURA DA BARRA, num token: é ela que empurra o HUD para baixo. Sem isto os dois ficavam ancorados no
237
- topo e se sobrepunham — o HUD lido por cima dos ícones, que foi o que o Dev viu e chamou de péssimo. */
238
- .player-screen{--a11y-h:calc(var(--tap) + .5rem)}
272
+ .screen-pause .pause-legend{margin:.1rem 0 0}
273
+ /* ADR-0163: with 42 px items the seven-item submenu overflowed 640×360 by 28 px (measured). The gap goes, not the target:
274
+ centres stay 44 px apart, far above the 24 px the WCAG 2.5.8 spacing exception protects. */
275
+ .screen-pause .pause-menu{gap:2px}
276
+ /* a11y shortcuts = menu buttons shaped as icons, INSIDE the card (no bar or shadow of their own).
277
+ Reachable by keyboard (up from Continue) and by touch/click. */
278
+ .pause-icons{display:flex;flex-wrap:wrap;gap:0;justify-content:center;align-items:center;margin:.1rem 0 .35rem}
279
+ /* ===================== THE QUICK BAR IN THE HUD (ADR-0044, item 7) =====================
280
+ It lives on the player's screen, available DURING play — which is when a child needs to change a setting that is
281
+ getting in the way, and not after pausing.
282
+
283
+ It is a SIBLING of `.screen-exp` and not a child, and the reason is #82: a CSS `filter` reaches every descendant and a
284
+ child cannot cancel it. Inside the experience, the empathy mode would degrade exactly what exists to GIVE access — and
285
+ simulation is not accessibility, it is its opposite.
286
+
287
+ `pointer-events:auto` because the whole `.player-screen` is `none` (the game receives the touch); the icons are the
288
+ exception, as the pause card already was. */
289
+ /* THE BAR'S HEIGHT, in one token: it is what pushes the HUD down. Without it both were anchored to the top and overlapped
290
+ — the HUD read over the icons, which is what the Dev saw and called terrible. */
291
+ .player-screen{--a11y-h:calc(var(--alvo-min,44px) + .5rem)}
239
292
  .screen-a11y{position:absolute;left:0;right:0;top:0;height:var(--a11y-h);z-index:5;pointer-events:auto;font-family:var(--font);font-size:var(--ui-fs,16px)}
240
- .screen-a11y .pause-icons{flex-wrap:nowrap;white-space:nowrap;gap:.25rem;margin:0;height:100%}
241
- /* SÓ OS BOTÕES OCUPAM ESPAÇO. A explicação é ABSOLUTA e fica fora do fluxo — ela aparece por cima do jogo ao
242
- passar o mouse (ou quando o cursor do modo `accessibility` pousa num ícone) e some sem deixar buraco. Uma
243
- faixa de texto reservando altura na tela de jogo é o contrário do que uma barra de atalho serve. */
244
- .screen-a11y .pause-icons-cap{position:absolute;left:50%;transform:translateX(-50%);top:calc(var(--a11y-h) + .1rem);margin:0;max-width:92%;text-align:center;font-size:.8em;color:#f6f5f0;pointer-events:none}
293
+ .screen-a11y .pause-icons{flex-wrap:nowrap;white-space:nowrap;gap:0;margin:0;height:100%}
294
+ /* ONLY THE BUTTONS TAKE ROOM. The explanation is ABSOLUTE and stays out of the flow — it appears over the game on mouse
295
+ hover (or when the `accessibility` mode's cursor rests on an icon) and goes without leaving a hole. A strip of text
296
+ reserving height on the game screen is the opposite of what a shortcut bar is for. */
297
+ .screen-a11y .pause-icons-cap{position:absolute;left:50%;transform:translateX(-50%);top:calc(var(--a11y-h) + .1rem);margin:0;max-width:92%;text-align:center;font-size:1em;color:#f6f5f0;pointer-events:none}
245
298
  .screen-a11y .pause-icons-cap:not(:empty){background:rgba(8,8,16,.92);border-radius:8px;padding:.2em .6em}
246
- /* O HUD desce para DEBAIXO da barra. É a mesma conta, e é por isso que ela mora num token: as duas medidas
247
- não podem divergir sem que uma tape a outra. */
299
+ /* The HUD moves BELOW the bar. It is the same sum, and that is why it lives in a token: the two measures cannot
300
+ diverge without one covering the other. */
248
301
  .screen-exp .vphud{top:var(--a11y-h)}
249
- .pi-btn{width:var(--tap);height:var(--tap);min-width:var(--tap);min-height:var(--tap);border-radius:10px;border:2px solid var(--ink-soft);background:#1a2740;font-size:1.25em;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}
250
- /* Wizard de gamepad: demonstração com ANIMAÇÃO REAL (frames do jogo trocados via JS) + deslocamento CSS */
251
- #padwiz-demo{height:86px;display:flex;align-items:flex-end;justify-content:center;position:relative;margin:.15rem 0 .4rem;overflow:hidden}
252
- #padwiz-demo-img{height:64px;image-rendering:pixelated}
253
- #padwiz-demo-fx{position:absolute;top:2px;font-size:1.5em;line-height:1}
254
- #padwiz-demo.pw-left #padwiz-demo-img{animation:pwSlideL 1.4s linear infinite}
255
- #padwiz-demo.pw-right #padwiz-demo-img{animation:pwSlideR 1.4s linear infinite}
256
- #padwiz-demo.pw-up #padwiz-demo-img{animation:pwClimbUp 1.4s linear infinite}
257
- #padwiz-demo.pw-down #padwiz-demo-img{animation:pwClimbDown 1.4s linear infinite}
258
- #padwiz-demo.pw-jump #padwiz-demo-img{animation:pwJump .9s cubic-bezier(.3,0,.7,1) infinite}
259
- #padwiz-demo.pw-run #padwiz-demo-img{animation:pwSlideR .8s linear infinite}
260
- #padwiz-demo.pw-swap,#padwiz-demo.pw-start{align-items:center}
261
- #padwiz-demo.pw-swap #padwiz-demo-fx{position:static;white-space:nowrap;font-size:1.7em;animation:pwIcons 4s linear infinite}
262
- #padwiz-demo.pw-especial #padwiz-demo-fx{animation:pwPulse .8s ease-in-out infinite}
263
- #padwiz-demo.pw-start #padwiz-demo-fx{position:static;font-weight:800;font-size:1.9em;letter-spacing:.1em;animation:pwBlink 1s steps(2,end) infinite}
264
- @keyframes pwSlideL{0%{translate:34px 0}100%{translate:-34px 0}}
265
- @keyframes pwSlideR{0%{translate:-34px 0}100%{translate:34px 0}}
266
- @keyframes pwClimbUp{0%{translate:0 22px}100%{translate:0 -22px}}
267
- @keyframes pwClimbDown{0%{translate:0 -22px}100%{translate:0 22px}}
268
- @keyframes pwJump{0%,100%{translate:0 0}35%{translate:0 -26px}55%{translate:0 -22px}}
269
- @keyframes pwIcons{0%{translate:60px 0}100%{translate:-60px 0}}
270
- @keyframes pwPulse{0%,100%{scale:1;opacity:.7}50%{scale:1.5;opacity:1}}
271
- @keyframes pwBlink{0%,100%{opacity:1}50%{opacity:.25}}
272
- @media (prefers-reduced-motion: reduce){ #padwiz-demo *{animation:none !important} }
273
- .pi-btn.pi-on{background:var(--accent);border-color:var(--accent)}
274
- /* Modo TEA (🧩): pi-on preenchido de amarelo = silencioso · fundo branco = calmo · base (azul) = off.
275
- (fundo, não borda — a borda é reservada ao realce de seleção :focus/.pi-sel e sobreporia o sinal.) */
302
+ .pi-btn{width:var(--alvo-min,44px);height:var(--alvo-min,44px);min-width:var(--alvo-min,44px);min-height:var(--alvo-min,44px);border-radius:10px;border:2px solid var(--ink-soft);background:#1a2740;color:#f6f5f0;font-size:1.25em;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}
303
+ /* Gamepad wizard: a demonstration with REAL ANIMATION (game frames swapped by JS) + a CSS offset */
304
+ /* ADR-0159 rule 10 / WCAG 1.4.1: «on» is not colour alone — a thick stripe along the base appears with it. */
305
+ .pi-btn.pi-on{background:var(--accent);border-color:var(--accent);box-shadow:inset 0 -5px 0 var(--accent-ink)}
306
+ /* ASD mode (🧩): pi-on filled yellow = silent · white background = calm · base (blue) = off.
307
+ (the background, not the border — the border is kept for the selection highlight :focus/.pi-sel and would hide the signal.) */
276
308
  .pi-btn.pi-calm{background:#fff;border-color:var(--ink-soft)}
277
- /* Correção de daltonismo (🚥): fundo bicolor "diagnóstico" — pares escolhidos por busca (simulação Machado
278
- 2009, ΔE Lab) p/ que quem TEM a deficiência-alvo veja o maior contraste e as outras duas o menor. Tritan
279
- (eixo azul-amarelo, isolado) separa limpo com vermelho/verde; protan e deutan compartilham o eixo
280
- vermelho-verde → separação só PARCIAL (limite físico). off = base (azul, borda cinza); borda clara = ativo. */
309
+ /* Colour-vision correction (🚥): a two-colour "diagnostic" background — pairs chosen by search (Machado's 2009 simulation,
310
+ Lab ΔE) so that whoever HAS the target deficiency sees the largest contrast and the other two the smallest. Tritan
311
+ (the blue-yellow axis, on its own) separates cleanly with red/green; protan and deutan share the red-green axis
312
+ → only a PARTIAL separation (a physical limit). off = base (blue, grey border); a light border = active. */
281
313
  .pi-btn.pi-cvd-protan{background:linear-gradient(90deg,#b3671b 0 50%,#b31b41 50% 100%);border-color:var(--ink)}
282
314
  .pi-btn.pi-cvd-deuter{background:linear-gradient(90deg,#0000f2 0 50%,#aa61f2 50% 100%);border-color:var(--ink)}
283
315
  .pi-btn.pi-cvd-tritan{background:linear-gradient(90deg,#f23d00 0 50%,#1bb341 50% 100%);border-color:var(--ink)}
284
316
  .pi-btn.pi-dis{opacity:.35;cursor:not-allowed}
285
- .pi-btn.pi-soon{opacity:.55}
286
317
  .pi-btn.pi-sel,.pi-btn:focus,.pi-btn:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
287
- .pause-icons-cap{text-align:center;margin:0 0 .3rem;font-size:.82em;color:var(--ink-soft);min-height:1.1em}
288
- /* `scrollbar-gutter: stable both-edges` — MEDIDO no navegador depois do item 6: com a lista em 44 px o
289
- cartão passa a rolar, a barra de rolagem come largura de UM lado só, e a lista centrada saía 7,5 px do
290
- centro. Reservar a calha nos dois lados devolve a simetria, role ou não. */
318
+ .pause-icons-cap{text-align:center;margin:0 0 .3rem;font-size:1em;color:var(--ink-soft);min-height:1.1em}
319
+ /* `scrollbar-gutter: stable both-edges` — MEASURED in the browser after item 6: with the list at 44 px the card starts
320
+ scrolling, the scrollbar eats width on ONE side only, and the centred list sat 7.5 px off centre. Reserving the gutter
321
+ on both sides gives the symmetry back, scrolling or not. */
291
322
  .pause-card{background:#0e1626;border:2px solid #ffd23f;border-radius:14px;padding:.8rem 1rem;max-width:88%;max-height:92%;overflow:auto;scrollbar-gutter:stable both-edges;text-align:center;box-shadow:0 8px 30px rgba(0,0,0,.5)}
292
323
  .pause-card h2{margin:.1rem 0 .6rem;color:#ffd23f}
293
- /* ===================== A LISTA DE PAUSA (ADR-0044, item 6) =====================
294
- Era `grid-template-columns:1fr 1fr`, e a grade contava a mesma mentira dos submenus da abertura: a seta
295
- anda em ordem de DOM, então "para baixo" pulava para a coluna da direita. Uma coluna, e o que se vê volta
296
- a ser a ordem em que se anda.
297
- CENTRADA E MAIS LARGA: 26rem contra os 262 px medidos antes — o número está no gate, não na opinião.
298
- `width` e não `min(26rem,100%)`: com a barra de ícones fora do cartão (item 7), o cartão passou a se
299
- encolher ao conteúdo, e um `100%` medido contra ele virava circular — a lista caiu para 182 px. Quem
300
- declara a largura é a LISTA; o cartão a acompanha até o `max-width` dele. */
301
- .pause-menu{display:flex;flex-direction:column;gap:.45rem;width:26rem;max-width:100%;margin:0 auto}
302
- /* A lista ESCONDIDA tem de sumir de verdade: `display:grid` de autor vence o `[hidden]{display:none}` do
303
- navegador, e sem esta linha as duas listas do cartão de pausa apareceriam empilhadas (ADR-0044, item 5). */
324
+ /* ===================== THE PAUSE LIST (ADR-0044, item 6) =====================
325
+ It was `grid-template-columns:1fr 1fr`, and the grid told the same lie as the opening submenus: the arrow moves in
326
+ DOM order, so "down" jumped to the right-hand column. One column, and what you see is again the order you move in.
327
+ CENTRED AND WIDER: 26 letters against the 262 px measured before — the number is in the gate, not in an opinion.
328
+ ⚠️ IN `em`, NOT `rem` (pointed out by the Dev): the menus' letters grow with the region (`--ui-fs`) and `rem` stays at the
329
+ root's 16 px — measured at 1920×1080, 48 px letters in a 416 px list, and every item wrapped onto two lines.
330
+ `width` and not `min(26em,100%)`: with the icon bar out of the card (item 7), the card shrinks to its content, and a
331
+ `100%` measured against it became circular — the list fell to 182 px. The LIST declares the width; the card follows
332
+ it up to its own `max-width`. */
333
+ .pause-menu{display:flex;flex-direction:column;gap:.45rem;width:26em;max-width:100%;margin:0 auto}
334
+ /* The HIDDEN list has to really disappear: an author's `display:grid` beats the browser's `[hidden]{display:none}`, and
335
+ without this line the two lists of the pause card would show stacked (ADR-0044, item 5). */
304
336
  .pause-menu[hidden]{display:none}
305
- /* 44 px NÃO é o mínimo da WCAG — o 2.5.8 pede 24×24, e o cartão já passava nisso com folga. 44 é a
306
- recomendação da Apple (HIG). `min-height` e não `padding` porque a altura de antes (35,6 px) não estava
307
- declarada em lugar nenhum: ela RESULTAVA da soma de padding, fonte e entrelinha. Um alvo que ninguém
308
- escreveu é um alvo que ninguém defende.
309
-
310
- ⚠️ ESTA LINHA DIZIA TAMBÉM «e este projeto trata piso como piso», e essa metade morreu no ADR-0095: o
311
- piso deixou de ser um número único e passou a ser a régua abaixo. Fica o resto, que continua a valer. */
312
- /* ⚠️ O ALVO DO ITEM DE MENU SEGUE A RÉGUA DO ADR-0095, e não um literal.
313
- Era `min-height:44px` cravado. O registro fixou que o alvo é função da ALTURA DA TELA — 24 px (WCAG
314
- 2.5.8, AA) abaixo de 540, 34 a partir de 540, 44 (2.5.5, AAA) a partir de 720 — porque um alvo grande
315
- que exige ROLAGEM para ser alcançado pode custar mais dedo do que um menor que está à vista.
316
-
317
- ⚠️ E ELE USA `--alvo-min` E NÃO `--tap`, que são coisas diferentes: `--tap` é o tamanho PREFERIDO e
318
- cresce com a escala do canvas (22 × k, nunca menos de 44); `--alvo-min` é o CHÃO por altura. Um botão
319
- isolado pode ser o preferido; um item de LISTA, que tem de caber inteiro, usa o chão.
320
-
321
- O `44px` do fallback é o comportamento de antes, para o caso de `layout()` não ter corrido — que era
322
- exatamente o que acontecia no `quiz.html` até 07/09. */
323
- .pm-btn{background:#1a2740;color:#eaf2f8;border:1px solid #3a4a6a;border-radius:10px;padding:.5rem .8rem;min-height:var(--alvo-min,44px);display:flex;align-items:center;justify-content:center;font:inherit;font-weight:700;cursor:pointer;white-space:nowrap}
337
+ /* 44 px is NOT the WCAG minimum — 2.5.8 asks for 24×24, and the card already passed that with room to spare. 44 is
338
+ Apple's recommendation (HIG). `min-height` and not `padding` because the earlier height (35.6 px) was declared
339
+ nowhere: it RESULTED from the sum of padding, font and line height. A target nobody wrote down is a target nobody
340
+ defends. */
341
+ /* The menu item's target is `--alvo-min`, never a literal. ADR-0163 superseded ADR-0095's height ruler (24/34/44 px):
342
+ the engine forces the resolution, no screen is under 640×360, and the floor is 22 × k — 44 px there, growing with the
343
+ scale. `applyScale` (`ui/layout`) writes it on the game region; the 44 px fallback is that same floor at k = 2. */
344
+ /* ADR-0159 rule 8 / WCAG 1.4.11: the item's border is its boundary against the card (#0e1626). #3a4a6a measured 2.04:1;
345
+ #6a7a96 is 4.2:1. */
346
+ .pm-btn{background:#1a2740;color:#eaf2f8;border:1px solid #6a7a96;border-radius:10px;padding:.5rem .8rem;min-height:var(--alvo-min,44px);display:flex;align-items:center;justify-content:center;font:inherit;font-weight:700;cursor:pointer;white-space:nowrap}
347
+ /* ADR-0161: a locked item stays in the list, visibly muted; the cursor still lands on it and it says its reason. */
348
+ .pm-btn[aria-disabled="true"]{color:#9aa6b8;border-style:dashed;cursor:not-allowed}
324
349
  .pm-btn:hover,.pm-btn:focus,.pm-btn.pm-sel{background:#2a3a5e;border-color:#ffd23f;outline:2px solid #ffd23f;outline-offset:1px}
325
- /* Legenda sim/não: ícone do botão (conforme layout do controle) + a palavra. Sony/Nintendo invertem 0↔1. */
326
- .pause-legend{display:flex;gap:1.1rem;justify-content:center;margin:.7rem 0 .1rem;font-size:.82em;color:#c3cfe0}
350
+ /* ADR-0167: no item shows a position number — the place is SPOKEN after the name («…, 2 de 6»), never drawn.
351
+ ADR-0159 rule 12: a pause item's glyph is drawn with empty alternative text, out of the name. */
352
+ .pm-btn[data-glifo]::before{content:attr(data-glifo) / "";margin-inline-end:.5em}
353
+ /* Yes/no legend: the button's glyph (from the pad's design) + the word. By POSITION on every design — yes is the south button
354
+ (A · ✕ · B), no is the east one (B · ◯ · A); no design swaps them (the Dev's association, ADR-0013 erratum). */
355
+ .pause-legend{display:flex;gap:1.1rem;justify-content:center;margin:.7rem 0 .1rem;font-size:1em;color:#c3cfe0}
327
356
  .pause-legend .lg{display:inline-flex;align-items:center;gap:.35rem}
328
- .pause-legend .lg-ico{display:inline-flex;align-items:center;justify-content:center;width:1.35rem;height:1.35rem;border-radius:50%;font-weight:800;font-size:.8rem;color:#fff;text-shadow:0 1px 1px rgba(0,0,0,.55)}
357
+ .pause-legend .lg-ico{display:inline-flex;align-items:center;justify-content:center;width:1.35rem;height:1.35rem;border-radius:50%;font-weight:800;font-size:1em;color:#fff;text-shadow:0 1px 1px rgba(0,0,0,.55)}
329
358
  .hud__item strong{font-variant-numeric:tabular-nums}
330
359
  .hud__fps{color:var(--ink-soft)}
331
360
 
332
361
  main{flex:1;display:flex;flex-direction:column;width:100%;margin:0 auto;padding:0 .25rem .25rem;min-height:0;overflow:hidden}
333
- /* tela = prioridade: ocupa todo o espaço; o excedente (até 5px×k por lado) é cortado sem rolagem */
362
+ /* screen = priority: it takes all the room; the excess (up to 5px×k per side) is cut without scrolling */
334
363
  .stage-wrap{flex:1;display:flex;align-items:center;justify-content:center;min-height:0;padding:0;overflow:hidden}
335
364
  .stage{position:relative;display:flex;align-items:center}
336
- /* ===== A CAMADA DOM (issue #82) =====
337
- Tudo o que não é a canvas. Existe para o filtro de acessibilidade poder cair numa superfície que contém os
338
- MENUS e não contém o mundo — filtro de PIXI não alcança DOM, e filtrar o `#game-region` inteiro aplicaria
339
- duas vezes na canvas.
365
+ /* ===== THE DOM LAYER (issue #82) =====
366
+ Everything that is not the canvas. It exists so the accessibility filter can land on a surface that holds the MENUS
367
+ and not the world — a PIXI filter does not reach the DOM, and filtering the whole `#game-region` would apply twice
368
+ on the canvas.
340
369
 
341
- `pointer-events:none` porque o invólucro cobre a região inteira e não pode engolir clique; os quatro filhos
342
- que precisam de clique e não o declaravam (herdavam do `#game-region`) ganham `auto` logo abaixo.
370
+ `pointer-events:none` because the wrapper covers the whole region and must not swallow clicks; the four children
371
+ that need clicks and did not declare it (they inherited it from `#game-region`) get `auto` just below.
343
372
 
344
- `z-index:1`: acima da canvas, ABAIXO dos dois pseudo-elementos do CRT (vinheta em 5, scanline em 500), que
345
- ficam no `#game-region`. O CRT é efeito de tela e passa por cima de tudo — o que a scanline já fazia por
346
- decisão do Dev, e a vinheta agora acompanha. */
373
+ `z-index:1`: above the canvas, BELOW the two CRT pseudo-elements (vignette at 5, scanline at 500), which sit on
374
+ `#game-region`. The CRT is a screen effect and goes over everything — which the scanline already did by the Dev's
375
+ decision, and the vignette now follows. */
347
376
  #dom-layer{position:absolute;inset:0;z-index:1;pointer-events:none}
348
377
 
349
- /* ===== ALTO CONTRASTE NO DOM (issue #83) =====
350
- O alto contraste NÃO é filtro: ele é Renderização Direta, e repinta as TEXTURAS da canvas. No DOM não há
351
- textura para repintar — há que escrever o equivalente, e é isto.
378
+ /* ===== HIGH CONTRAST IN THE DOM (issue #83) =====
379
+ High contrast is NOT a filter: it is Direct Rendering, and it repaints the canvas's TEXTURES. The DOM has no texture
380
+ to repaint — the equivalent has to be written, and this is it.
352
381
 
353
- MEDIDO, não estimado (WCAG 1.4.3, razão sobre sRGB linearizado). O que falhava, e só no nível 7:1:
382
+ MEASURED, not estimated (WCAG 1.4.3, the ratio over linearised sRGB). What failed, and only at the 7:1 level:
354
383
 
355
- · o VÉU do painel de pausa é `rgba(4,7,15,.72)` — translúcido. A razão do texto sobre ele DEPENDE do
356
- jogo por trás: 19,17:1 sobre um quadro preto e 8,07:1 sobre um branco. Com `--ink-soft`, `--accent` e
357
- `--good` a conta cai a 5,92 / 5,94 / 5,11:1 — AA, não AAA. Nos níveis 3:1 e 4,5:1 nada falhava.
358
- · o botão SELECIONADO é `#2a3a5e`, e `--good` sobre ele dá 6,70:1.
384
+ · the pause panel's VEIL was `rgba(4,7,15,.72)` — translucent. The text's ratio over it DEPENDED on the game behind:
385
+ 19.17:1 over a black frame and 8.07:1 over a white one. With `--ink-soft`, `--accent` and `--good` the sum fell to
386
+ 5.92 / 5.94 / 5.11:1 — AA, not AAA. At the 3:1 and 4.5:1 levels nothing failed.
387
+ · the SELECTED button is `#2a3a5e`, and `--good` on it gives 6.70:1.
359
388
 
360
- Duas mudanças, e nenhuma inventa cor:
389
+ Two changes, and neither invents a colour:
361
390
 
362
- 1. O VÉU FICA OPACO. É o que "alto contraste" quer dizer: sai o meio-tom, e com ele a dependência do que
363
- está atrás. Sozinha, esta já leva tudo a AAA menos um caso.
364
- 2. O CURSOR INVERTE — fundo `--accent`, texto `--accent-ink`, 12,71:1. Escurecer o selecionado o
365
- aproximaria do não-selecionado (`#1a2740`) e a criança PERDERIA O CURSOR; inverter resolve as duas
366
- coisas de uma vez, e é o padrão de alto contraste de qualquer sistema operacional.
391
+ 1. THE VEIL IS OPAQUE. That is what "high contrast" means: the half-tone goes, and with it the dependence on what is
392
+ behind. On its own this takes everything to AAA but one case.
393
+ 2. THE CURSOR INVERTS — `--accent` background, `--accent-ink` text, 12.71:1. Darkening the selected item would bring
394
+ it closer to the unselected one (`#1a2740`) and the child would LOSE THE CURSOR; inverting solves both at once, and
395
+ it is the high-contrast pattern of every operating system.
367
396
 
368
- Resultado: o pior par do menu vai de 5,11:1 para 10,29:1 (`--ink-soft` sobre botão). Margem de +47% sobre
369
- o 7:1. `tests/contraste-menu.node.test.js` afirma isso a cada rodada, com as razões calculadas do próprio
370
- CSS — não copiadas para dentro do teste.
397
+ Result: the worst pair of the menu goes from 5.11:1 to 10.29:1 (`--ink-soft` on a button). A margin of +47% over
398
+ 7:1. `tests/menu-contrast-measured.node.test.js` asserts it on every run, with the ratios computed from this CSS
399
+ itself — not copied into the test.
371
400
 
372
- ⚠️ VALE PARA OS TRÊS NÍVEIS, e não só para o 7:1: nos outros dois o menu já passava, mas passava POR SORTE
373
- do que estivesse na tela. Determinismo é ganho em todos. */
374
- /* (A regra do véu SAIU daqui em 2026-08-26: ele passou a ser opaco NA BASE, por decisão do Dev — os menus
375
- de título e de pausa têm de estar em 7:1 DESDE O INÍCIO, porque é justamente neles que a pessoa com
376
- deficiência ajusta os controles para si. Um contraste que só chega depois de achar o ajuste chega tarde.
377
- Sobra aqui o que é específico do modo: o cursor invertido.) */
401
+ ⚠️ IT HOLDS FOR ALL THREE LEVELS, not only 7:1: at the other two the menu already passed, but it passed BY THE LUCK
402
+ of whatever was on screen. Determinism is a gain at every level. */
403
+ /* (The veil's rule is not here: the veil is opaque AT THE BASE, by the Dev's decision — the title and pause menus have to
404
+ be at 7:1 FROM THE START, because they are precisely where a person with a disability adjusts the controls for
405
+ themselves. A contrast that only arrives after finding the setting arrives late.
406
+ What is left here is what is specific to the mode: the inverted cursor.) */
378
407
  #dom-layer.hc .pm-btn{background:var(--panel-btn)}
379
408
  #dom-layer.hc .pm-btn:hover,
380
409
  #dom-layer.hc .pm-btn:focus,
@@ -384,63 +413,76 @@ main{flex:1;display:flex;flex-direction:column;width:100%;margin:0 auto;padding:
384
413
  .game-region{position:relative;background:#05070f;box-shadow:0 0 0 3px var(--ink-soft);border-radius:8px;overflow:hidden;flex:none}
385
414
  .libras-slot{flex:none;width:0;height:0;background:#0b1020;border-radius:8px;overflow:hidden}
386
415
  .game-region:focus-visible{outline:4px solid var(--focus);outline-offset:3px}
387
- /* ===== O AVISO DE ALCANCE (issue #112) =====
388
- Reaproveita `.overlay` e `.overlay__card` inteiros — o cartão nasce com a mesma casca dos outros diálogos,
389
- e é isso que o faz parecer parte do jogo em vez de um erro do navegador. Só o destaque do título é próprio. */
416
+ /* ===== THE REACH NOTICE (issue #112) =====
417
+ It reuses `.overlay` and `.overlay__card` whole — the card is born with the same shell as the other dialogs, and
418
+ that is what makes it look like part of the game instead of a browser error. Only the title's emphasis is its own. */
390
419
  #reach-notice .reach-notice__titulo{font-weight:700;margin:0 0 .5rem}
391
420
  #reach-notice p{margin:0 0 .5rem}
392
421
  #reach-notice button{margin-top:.75rem}
393
- /* ===== O LAÇO PAROU (ADR-0054, issue #109) =====
394
- O TEXTO VEM DO ATRIBUTO, e é esse o ponto: `ui/loop-crash` escreve a frase JÁ TRADUZIDA em
395
- `data-incl-parou`, e o CSS só a mostra. Um aviso cravado aqui estaria em inglês para uma criança
396
- brasileira — o defeito que o pilar 3 existe para impedir.
397
- ⚠️ E AS CORES SÃO CRUAS, DE PROPÓSITO: nada de `var(--…)`. Este aviso aparece justamente quando alguma
398
- coisa quebrou, e a máquina de temas é candidata plausível. Branco sobre vinho dá 9,5:1, acima do 7:1 do
399
- 1.4.6, e não depende de nada ter sobrevivido. */
400
- /* ⚠️ ERA UM `::after` COM `content: attr(...)`, E NUNCA APARECERIA. Medido no arranque real: o
401
- `.game-region.crt-scan-1::after` logo abaixo é a scanline do CRT, ligada por padrão — e um elemento tem UM
402
- `::after` só. As duas regras não se empilham; a do CRT vem depois e vence. O `::before` está tomado pela
403
- vinheta. Agora é um ELEMENTO, que não disputa lugar com ninguém — e cujo texto entra na árvore de
404
- acessibilidade, coisa que `content` não garante. `z-index` acima do 500 da scanline, de propósito. */
422
+ /* ===== THE LOOP STOPPED (ADR-0054, issue #109) =====
423
+ THE TEXT COMES FROM THE SCRIPT, and that is the point: `ui/loop-crash` writes the sentence ALREADY TRANSLATED (from
424
+ `t()`, through `textContent`), and the CSS only shows it. A notice hard-coded here would be in English for a Brazilian
425
+ child — the defect pillar 3 exists to prevent.
426
+ ⚠️ AND THE COLOURS ARE RAW, ON PURPOSE: no `var(--…)`. This notice appears exactly when something broke, and the
427
+ theming machinery is a plausible suspect. White on wine gives 9.5:1, above the 7:1 of 1.4.6, and does not depend on
428
+ anything having survived. */
429
+ /* ⚠️ IT IS AN ELEMENT, NOT A `::after` WITH `content: attr(...)` — that version would never show. The
430
+ `.game-region.crt-scan-1::after` just below is the CRT scanline, on by default — and an element has ONE `::after`
431
+ only. The two rules do not stack; the CRT's comes later and wins. The `::before` is taken by the vignette. An
432
+ ELEMENT competes with nobody for its place — and its text enters the accessibility tree, which `content` does not
433
+ guarantee. Its slot, `--z-loop-crash`, is above the scanline's 500 on purpose. */
405
434
  #incl-parou{
406
435
  position:absolute;inset:auto 0 0 0;z-index:var(--z-loop-crash);
407
436
  padding:14px 18px;
408
437
  background:#7f1d1d;color:#fff;border-top:3px solid #fff;
409
- font:700 15px/1.35 system-ui,-apple-system,"Segoe UI",sans-serif;
438
+ font:700 1em/1.35 system-ui,-apple-system,"Segoe UI",sans-serif;
410
439
  text-align:center;text-wrap:balance
411
440
  }
412
441
  .pixi-mount,.pixi-mount canvas{display:block;width:100%;height:100%}
413
- /* pixel-art nítida ao escalar */
442
+ /* crisp pixel art when scaling */
414
443
  .pixi-mount canvas{image-rendering:pixelated;image-rendering:crisp-edges}
415
- /* L2: Estética CRT (menu Sensibilidade visual) em 3 níveis: -1=pequeno, -2=grande. z-index 5 = sobre o
416
- canvas/HUD do jogo, ABAIXO da pausa in-canvas (6) e dos diálogos (60) → menus nunca perdem legibilidade. */
444
+ /* The CRT look (visual sensitivity menu) in 3 levels: -1=small, -2=large. z-index 5 = over the game's canvas/HUD, BELOW the
445
+ in-canvas pause (6) and the dialogs (60) → the menus never lose legibility. */
417
446
  .game-region.crt-scan-1::after,
418
447
  .game-region.crt-vig-1::before{content:'';position:absolute;inset:0;z-index:5;pointer-events:none}
419
- /* Scanlines ALINHADAS: período = 1 pixel LÓGICO do jogo (k px), arredondado p/ pixel FÍSICO (dpr) e
420
- linha = 1 pixel físico — o JS (layout/applyCrt) calcula --scan-per/--scan-line; sem isso o gradiente
421
- 1px/3px em px CSS caía fora da grade (linhas desiguais em telas com escala do Windows). */
422
- .game-region.crt-scan-1::after{z-index:500;background:repeating-linear-gradient(to bottom, rgba(0,0,0,.16) 0 var(--scan-line,1px), transparent var(--scan-line,1px) var(--scan-per,3px))} /* z-index alto = scanlines POR CIMA de tudo (canvas E menus DOM), pedido do José */
448
+ /* ALIGNED scanlines: period = 1 LOGICAL game pixel (k px), rounded to a PHYSICAL pixel (dpr), and line = 1 physical
449
+ pixel — the JS (`render/crt`, applyCrt) computes --scan-per/--scan-line; without it the 1px/3px gradient in CSS px
450
+ fell off the grid (uneven lines on screens with Windows scaling). */
451
+ .game-region.crt-scan-1::after{z-index:500;background:repeating-linear-gradient(to bottom, rgba(0,0,0,.16) 0 var(--scan-line,1px), transparent var(--scan-line,1px) var(--scan-per,3px))} /* a high z-index = scanlines OVER everything (canvas AND DOM menus), the Dev's request */
423
452
  .game-region.crt-vig-1::before{background:radial-gradient(ellipse at center, transparent 60%, rgba(0,0,0,.34) 100%)}
424
- .game-region.crt-round-0{border-radius:0} /* tela quadrada */
425
- .game-region.crt-round-2{border-radius:24px} /* nível 1 (pequeno) = o padrão de 8px, sem classe */
453
+ .game-region.crt-round-0{border-radius:0} /* square screen */
454
+ .game-region.crt-round-2{border-radius:24px} /* level 1 (small) = the 8px default, no class */
426
455
  @media (prefers-reduced-transparency: reduce){ .game-region.crt-scan-1::after,.game-region.crt-vig-1::before{display:none} }
427
456
 
428
- /* dicas de início sobre o canvas */
457
+ /* start tips over the canvas */
429
458
  .start-tips{position:absolute;left:50%;top:14%;transform:translateX(-50%);
430
459
  display:flex;flex-direction:column;gap:.5rem;align-items:center;pointer-events:none;
431
460
  transition:opacity .5s ease;z-index:6;max-width:92%}
432
461
  .start-tips p{margin:0;background:rgba(5,7,15,.85);color:#fff;border:2px solid rgba(255,255,255,.45);
433
- border-radius:10px;padding:.4em .9em;font-size:1.05rem;font-weight:600;text-align:center}
462
+ border-radius:10px;padding:.4em .9em;font-size:1.05em;font-weight:600;text-align:center}
434
463
  .start-tips kbd{background:var(--accent);color:var(--accent-ink);border-radius:6px;padding:.05em .5em;font-weight:800}
435
464
  .start-tips.hide{opacity:0}
436
465
  @media (prefers-reduced-motion: reduce){ .start-tips{transition:none} }
437
466
 
438
- /* seletor de modo */
467
+ /* mode selector */
439
468
  .modes{max-width:var(--maxw);margin:0 auto .5rem;padding:0 1rem;display:flex;gap:.5rem;flex-wrap:wrap}
440
- .mode-btn{min-height:var(--tap);padding:.4em .9em;font:inherit;font-weight:700;color:var(--ink);background:var(--panel);border:2px solid var(--ink-soft);border-radius:999px;cursor:pointer}
469
+ .mode-btn{min-height:var(--alvo-min,44px);padding:.4em .9em;font:inherit;font-weight:700;color:var(--ink);background:var(--panel);border:2px solid var(--ink-soft);border-radius:999px;cursor:pointer}
441
470
  .mode-btn.is-on{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
442
- /* TOGGLE (switch): substitui os botões "ícone + Ligado/Desligado". Estado = trilho + manopla que desliza.
443
- Semântica de botão de alternância via aria-pressed (o texto interno fica oculto por font-size:0). */
471
+ /* STEPS ⯇ ⯈ (ADR-0151): choosing between positions with left and right. The arrows are FINGER targets and follow the
472
+ target ruler (`--alvo-min`, ADR-0163); the focus belongs to the whole control, and the end that cannot move is dimmed. */
473
+ .passos{display:inline-flex;align-items:center;gap:.25rem;min-height:var(--alvo-min,44px);border:2px solid var(--ink-soft);border-radius:8px;padding:0 .15rem;background:var(--panel-btn);color:var(--ink);font-weight:700;user-select:none;-webkit-user-select:none}
474
+ .passos:focus,.passos:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
475
+ .passo-seta{display:inline-flex;align-items:center;justify-content:center;min-width:var(--alvo-min,44px);min-height:var(--alvo-min,44px);cursor:pointer;font-size:1.1em;touch-action:manipulation}
476
+ .passo-seta.no-limite{opacity:.35;cursor:default}
477
+ .passo-valor{min-width:6ch;text-align:center;flex:1}
478
+ /* «◀ Label: value ▶» takes the whole ROW (ADR-0130 erratum): there is no label on the left competing for the room. */
479
+ /* 🔴 AND NO BOX INSIDE THE BOX: the ROW is the item. The first version kept `.passos`'s border and background, and the
480
+ text wrapped onto four lines inside a box beside the hint — the Dev: «Por que continua desenhando os botões de seleção
481
+ de <=5 itens do jeito errado?!». On one line, `◀ Label: value ▶`, with no wrapping. */
482
+ .ctrl-row--passos .passos{flex:1;justify-content:space-between;border:0;background:transparent;padding:0;white-space:nowrap}
483
+ .ctrl-row--passos .passo-valor{white-space:nowrap}
484
+ /* TOGGLE (switch): replaces the "icon + On/Off" buttons. State = a track + a knob that slides.
485
+ Toggle-button semantics through aria-pressed (the inner text is hidden by font-size:0). */
444
486
  .mode-btn.switch{--sw-w:52px;--sw-h:28px;position:relative;width:var(--sw-w);min-width:var(--sw-w);height:var(--sw-h);min-height:var(--sw-h);padding:0;flex:0 0 auto;border-radius:999px;border:2px solid var(--ink-soft);background:#0e1326;color:transparent;font-size:0;transition:background .18s,border-color .18s}
445
487
  .mode-btn.switch::after{content:"";position:absolute;top:50%;left:3px;transform:translateY(-50%);width:calc(var(--sw-h) - 10px);height:calc(var(--sw-h) - 10px);border-radius:50%;background:var(--ink-soft);transition:left .18s,background .18s}
446
488
  .mode-btn.switch[aria-pressed="true"]{background:var(--accent);border-color:var(--accent)}
@@ -448,33 +490,33 @@ main{flex:1;display:flex;flex-direction:column;width:100%;margin:0 auto;padding:
448
490
  .mode-btn.switch:focus-visible,.mode-btn.switch:focus{outline:3px solid var(--accent);outline-offset:2px}
449
491
  @media (prefers-reduced-motion: reduce){ .mode-btn.switch,.mode-btn.switch::after{transition:none} }
450
492
 
451
- /* desafio Soma-Sub (overlay sobre o canvas) */
493
+ /* the quiz challenge (an overlay over the canvas) */
452
494
  .quiz{position:absolute;inset:0;z-index:12;display:grid;place-items:center;background:rgba(0,0,0,.55)}
453
495
  .quiz-box{position:relative;background:#14141f;color:var(--ink);border:3px solid var(--accent);border-radius:12px;padding:1rem 1.1rem;max-width:90%;text-align:center}
454
- /* 3 luzes de progresso (canto sup. direito): apagada = cinza; acesa = amarela com luz acesa em volta */
496
+ /* 3 progress lights (top right corner): off = grey; on = yellow with a glow around it */
455
497
  .quiz-wins{position:absolute;top:.5rem;right:.6rem;display:flex;gap:.4rem}
456
498
  .qw-dot{width:.95rem;height:.95rem;border-radius:50%;background:#3a4152;border:2px solid #0d0d1a}
457
- .qw-dot.on{background:var(--accent);border-color:#8a6d00;box-shadow:0 0 .55rem .12rem var(--accent)} /* iluminação em volta (luz acesa) */
499
+ .qw-dot.on{background:var(--accent);border-color:#8a6d00;box-shadow:0 0 .55rem .12rem var(--accent)} /* the glow around it (a light that is on) */
458
500
  .quiz-wins.celebrate .qw-dot.on{animation:qwPop .6s ease}
459
501
  @keyframes qwPop{0%{transform:scale(1)}45%{transform:scale(1.4);box-shadow:0 0 .9rem .3rem var(--accent)}100%{transform:scale(1)}}
460
502
  @media (prefers-reduced-motion:reduce){ .quiz-wins.celebrate .qw-dot.on{animation:none} }
461
503
  .quiz-shape{color:var(--accent);font-weight:800;text-transform:capitalize}
462
- .quiz-prob{font-size:1.6rem;font-weight:800;margin:.4rem 0 .8rem}
504
+ .quiz-prob{font-size:1.6em;font-weight:800;margin:.4rem 0 .8rem}
463
505
  .quiz-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.4rem}
464
- .quiz-choice{min-height:var(--tap);min-width:var(--tap);font:inherit;font-size:1.2rem;font-weight:700;color:var(--ink);background:#131a30;border:2px solid var(--ink-soft);border-radius:8px;cursor:pointer}
506
+ .quiz-choice{min-height:var(--alvo-min,44px);min-width:var(--alvo-min,44px);font:inherit;font-size:1.2em;font-weight:700;color:var(--ink);background:#131a30;border:2px solid var(--ink-soft);border-radius:8px;cursor:pointer}
465
507
  .quiz-choice.sel{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
466
508
  .quiz-choice.reveal{outline:3px solid var(--good);outline-offset:2px}
467
- .quiz-hint{font-size:.85rem;margin-top:.6rem;color:var(--ink-soft)}
468
- .quiz-emoji{font-size:2.4rem;line-height:1}
469
- /* Palavra do topo = emoji SELECIONÁVEL (pular sobre ela repete a fala / VLibras gesticula) */
470
- .quiz-word{font-size:2.4rem;line-height:1;background:transparent;border:2px solid transparent;border-radius:12px;padding:.05em .2em;cursor:pointer}
509
+ .quiz-hint{font-size:1em;margin-top:.6rem;color:var(--ink-soft)}
510
+ .quiz-emoji{font-size:2.4em;line-height:1}
511
+ /* The top word = a SELECTABLE emoji (jumping on it repeats the speech / VLibras signs it) */
512
+ .quiz-word{font-size:2.4em;line-height:1;background:transparent;border:2px solid transparent;border-radius:12px;padding:.05em .2em;cursor:pointer}
471
513
  .quiz-word.sel{border-color:var(--accent);background:rgba(255,230,0,.12)}
472
- .quiz-letter{font-size:.8rem;color:var(--ink-soft);margin:.1rem 0 .4rem}
514
+ .quiz-letter{font-size:1em;color:var(--ink-soft);margin:.1rem 0 .4rem}
473
515
  .silaba-boxes{display:flex;gap:.4rem;justify-content:center;margin-bottom:.5rem}
474
- .silaba-box{min-width:34px;min-height:28px;border:2px dashed var(--ink-soft);border-radius:6px;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.15rem}
516
+ .silaba-box{min-width:34px;min-height:28px;border:2px dashed var(--ink-soft);border-radius:6px;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.15em}
475
517
  .silaba-box.filled{border-style:solid;border-color:var(--accent);background:rgba(255,255,255,.08)}
476
518
  .silaba-actions{display:flex;gap:.4rem;justify-content:center;margin-top:.4rem}
477
- /* E8: cela Braille */
519
+ /* a Braille cell */
478
520
  .bcells{display:flex;gap:.5rem;justify-content:center;flex-wrap:wrap;margin:.4rem 0}
479
521
  .bcell{display:flex;flex-direction:column;align-items:center;gap:.2rem}
480
522
  .bcell-grid{display:grid;grid-template-columns:repeat(2,10px);grid-auto-rows:10px;gap:3px;padding:4px;background:#0e1326;border:1px solid var(--ink-soft);border-radius:4px}
@@ -484,94 +526,241 @@ main{flex:1;display:flex;flex-direction:column;width:100%;margin:0 auto;padding:
484
526
  @media (prefers-contrast: more){ .quiz-box{background:#000} .quiz-choice{background:#000} .quiz-choice.sel{background:#fff;color:#000} }
485
527
 
486
528
  .opts{max-width:var(--maxw);margin:0 auto .5rem;padding:0 1rem;display:flex;gap:.4rem;flex-wrap:wrap;justify-content:center}
487
- /* barra de controles compacta → cabe em UMA fileira em telas comuns (não afeta botões de overlay) */
488
- .opts .mode-btn{padding:.35em .65em;font-size:.92rem;white-space:nowrap}
529
+ /* a compact controls bar → fits on ONE row on common screens (does not affect overlay buttons) */
530
+ .opts .mode-btn{padding:.35em .65em;font-size:1em;white-space:nowrap}
489
531
  .caption{position:absolute;left:50%;bottom:8px;transform:translateX(-50%);background:rgba(0,0,0,.82);color:#fff;
490
- border:2px solid rgba(255,255,255,.5);border-radius:8px;padding:.25em .7em;font-weight:700;font-size:.95rem;
532
+ border:2px solid rgba(255,255,255,.5);border-radius:8px;padding:.25em .7em;font-weight:700;font-size:1em;
491
533
  z-index:8;pointer-events:none;max-width:90%;opacity:0;transition:opacity .15s}
492
534
  .caption.show{opacity:1}
493
535
  @media (prefers-reduced-motion: reduce){ .caption{transition:none} }
494
536
 
495
537
  .help{max-width:var(--maxw);margin:1rem auto 0;color:var(--ink-soft)}
496
- .help summary{cursor:pointer;font-weight:700;color:var(--ink);min-height:var(--tap);display:flex;align-items:center}
538
+ .help summary{cursor:pointer;font-weight:700;color:var(--ink);min-height:var(--alvo-min,44px);display:flex;align-items:center}
497
539
  .help ul{padding-left:1.1rem}
498
540
  .help li{margin:.3rem 0}
499
541
 
500
- .btn{min-height:var(--tap);min-width:var(--tap);padding:.5em 1em;font:inherit;font-weight:600;color:var(--ink);background:var(--panel);border:2px solid var(--ink-soft);border-radius:10px;cursor:pointer}
542
+ .btn{min-height:var(--alvo-min,44px);min-width:var(--alvo-min,44px);padding:.5em 1em;font:inherit;font-weight:600;color:var(--ink);background:var(--panel);border:2px solid var(--ink-soft);border-radius:10px;cursor:pointer}
501
543
  .btn--primary{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
502
544
 
503
545
  .overlay{position:fixed;inset:0;z-index:50;display:grid;place-items:center;background:rgba(0,0,0,.7);padding:1rem}
504
- /* "tela = canvas": os diálogos de a11y são reparentados para dentro do #game-region (JS) e ficam
505
- presos aos limites do canvas; o último aberto sobe (z-index via JS). Só afeta os que estão dentro. */
546
+ /* "screen = canvas": the a11y dialogs are re-parented into #game-region (JS) and stay held within the canvas's bounds;
547
+ the last one opened goes on top (z-index by JS). Only affects the ones inside. */
506
548
  #game-region .overlay{position:absolute;z-index:60;padding:.6rem}
507
- #game-region .overlay__card{max-height:94%;max-width:96%}
508
- /* Rodapé de explicação: branco sobre preto translúcido 0,82 → contraste do branco >7:1 mesmo sobre 100% branco
509
- (composição: 1-0,82=0,18 → L≈0,027 → ~13:1), sem ser 100% opaco. Fixo no rodapé do card. */
510
- .opt-explain{position:sticky;bottom:calc(-1 * var(--card-pad,1.5rem));margin:.8rem calc(-1 * var(--card-pad,1.5rem)) calc(-1 * var(--card-pad,1.5rem));padding:.6rem .9rem;min-height:2.8rem;display:flex;align-items:center;text-align:left;
511
- background:rgba(0,0,0,.82);color:#fff;font-size:.9em;line-height:1.35;border-top:1px solid rgba(255,255,255,.18);border-radius:0 0 9px 9px;backdrop-filter:blur(1px)}
549
+ /* THE QUIZ STARTS BELOW THE QUICK BAR (ADR-0148). The engine declares `--barra-a11y-h` on `#game-region`; the bar sits
550
+ 10 px from the top (`#title-icons`), and the statement was drawn behind it — measured on a screenshot of the Dev's. */
551
+ /* Since issue #160 the variable is the WHOLE room (the bar's offset, the bar, the icon name line and a light gap): read as is. */
552
+ .quiz-app{padding-top:var(--barra-a11y-h,0px);padding-bottom:var(--rodape-h,0px)} /* the footer band is its own zone (ADR-0164) */
553
+ /* ADR-0163: at 640×360 the bar, the statement, four 44 px options and the footer band had 404 px to fit in 360 (measured).
554
+ The spacing goes, not the targets or the 16 px floor: the statement keeps its size on a 1.25 line and no outer margins. */
555
+ .quiz-pergunta{margin:0 0 calc(.25rem * var(--espaco-fixo,1));line-height:1.25}
556
+ /* The quiz's MENU button (ADR-0166 erratum), in the top-left corner the bar leaves free: the engine's target size. */
557
+ /* THE QUICK PAUSE (ADR-0155): PAUSED in the middle of the frozen screen — THE WORD ONLY, white, with a BLACK OUTLINE ON
558
+ THE LETTERS and no box: «Borda nas letras, não numa caixa» (the Dev, the record's erratum). The outline is what keeps it
559
+ legible over a light scene; `paint-order` puts the stroke UNDER the fill, so the letter does not get thinner, and the
560
+ shadow in eight directions covers browsers without `-webkit-text-stroke`. z-index 12, the same literal as the quiz
561
+ overlay (`.quiz`), not yet a slot: over the content by document order, under the pad (14) and the panels (60). The
562
+ right slot is `--z-game-msg`, and adopting it alone would put PAUSED over a panel. No pointer events. */
563
+ .pausa-rapida{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:12;pointer-events:none;
564
+ color:#fff;-webkit-text-stroke:.08em #000;paint-order:stroke fill;
565
+ text-shadow:2px 0 #000,-2px 0 #000,0 2px #000,0 -2px #000,2px 2px #000,-2px 2px #000,2px -2px #000,-2px -2px #000;
566
+ font-family:var(--font);font-weight:800;font-size:calc(var(--ui-fs,16px)*2);letter-spacing:var(--ls);white-space:nowrap}
567
+ .pausa-rapida[hidden]{display:none}
568
+ /* WHAT THE SCAN IS OFFERING (ADR-0218, #201): with «um botão só», the child does not choose — they wait, and what they
569
+ wait for has to be in view. The SAME outlined white letters as the quick pause, no box, at the TOP of the region,
570
+ below the bar's band (`--barra-a11y-h`), which is the zone no game uses. No pointer events: it is a notice, not a
571
+ control — what fires it is its single button, wherever that is. */
572
+ /* ⚠️ `--scan-top` and NOT `--barra-a11y-h`: this label makes the band grow, and placing it by the band made a loop — it
573
+ pushed the band, the band pushed it, and it went down the screen on every measure (caught by a test case). `--scan-top`
574
+ is where the bar ends, and does not depend on it (`ui/top-band` writes both). */
575
+ .scan-now{position:absolute;left:50%;top:var(--scan-top,0px);transform:translateX(-50%);z-index:12;
576
+ pointer-events:none;color:#fff;-webkit-text-stroke:.06em #000;paint-order:stroke fill;
577
+ text-shadow:2px 0 #000,-2px 0 #000,0 2px #000,0 -2px #000,2px 2px #000,-2px 2px #000,2px -2px #000,-2px -2px #000;
578
+ font-family:var(--font);font-weight:800;font-size:calc(var(--ui-fs,16px)*1.5);letter-spacing:var(--ls);white-space:nowrap}
579
+ .scan-now[hidden]{display:none}
580
+ /* THE FOOTER LEGEND of the quick pause (ADR-0155 erratum): the same outlined white letters, no box, right ABOVE the pad's
581
+ START pill — which stays in view, because it is the way out for someone who only has a finger. ⚠️ `left`/`right` and
582
+ not `left:50%` + `translate`: with that, the box shrank to HALF of the region (measured: 271 px, three lines, over
583
+ PAUSED). */
584
+ /* 🔴 The footer is ONE column (2026-09-12): the explanation of the pointed bar icon above the quick-pause legend. Two
585
+ absolute strips covered each other as soon as one wrapped. */
586
+ /* 🔴 ADR-0164 (2026-09-12): the footer is at the LOWEST edge of the region, over a darkened band, and holds at most TWO
587
+ lines of text. The Dev saw a three-line explanation in the middle of the screen, over a quiz option, with outlined
588
+ letters and no background. White on black at .82 over pure white composes to ~13:1 (the panel footer's arithmetic).
589
+ With the quick-pause legend also showing, each keeps ONE line, so the band never grows past two.
590
+ `--rodape-h` is the room it takes, declared so a game's workspace can end above it (the `--barra-a11y-h` model). */
591
+ #game-region{--rodape-h:calc(var(--ui-fs,16px) * 2.6 + 8px)}
592
+ /* ADR-0163 rule 3: the region's text grows with the scale the engine forces — 16 px at 640×360, 32 at 1280×720 — times the
593
+ communication cycle's type scale, which the root size also carries. Without it everything in the region read the ROOT
594
+ 16 px: measured at 1280×720, quiz options at 16 px and the bar's emoji at 20 px under a `--ui-fs` of 32. */
595
+ #game-region{font-size:calc(var(--ui-fs,16px) * var(--fonte-escala,1))}
596
+ /* ADR-0164 as the Dev corrected it: the EXPLANATION stands on a full-width dark band at the lowest edge (rule 2, rule 4);
597
+ the BUTTON LEGEND runs the full width with NO band, a dark background only behind each «name: function» (rule 3), and
598
+ sits above the explanation. The column itself paints nothing. Padding adds to 8 px, so two lines fit `--rodape-h`. */
599
+ /* THE HUD the engine mounts from a cartridge's `hud` (ADR-0168, ADR-0175; issue #162): two columns level with the quick bar —
600
+ points and mission top left, power top right — each narrowed by the root so it never reaches the bar. State on dark chips, like the
601
+ icon's name; no pointer events, so a finger passes through to the game. */
602
+ .hud-faixa{position:absolute;z-index:12;margin:0;pointer-events:none;font-size:var(--ui-fs,16px);line-height:1.25;display:flex;gap:2px}
603
+ .hud-faixa[hidden]{display:none}
604
+ .hud-esquerda{top:0;left:4px;flex-direction:column;align-items:flex-start}
605
+ .hud-direita{top:0;right:4px;flex-direction:column;align-items:flex-end;text-align:right}
606
+ /* The learning bars (ADR-0049 §5): one ten-segment bar per skill, side by side, centred at the bottom — under the footer
607
+ column, which comes later in the region on the same layer and covers them. Okabe-Ito colours, and a second cue beside
608
+ each, so no state is told by colour alone (WCAG 1.4.1): green carries a dot, red stripes, an empty slot only its outline;
609
+ a purple bar a ▲, an orange one a ▼. */
610
+ .hud-aprendizagem{left:50%;bottom:4px;transform:translateX(-50%);flex-direction:row;gap:.75em}
611
+ /* The explanation band is 82% opaque: the bars showed through under its words. While it shows they are not drawn at all —
612
+ the explanation has priority (ADR-0168 §3), and a segment behind a letter is noise for the child reading it. */
613
+ .game-region:has(.barra-explicacao:not([hidden])) .hud-aprendizagem,#game-region:has(.barra-explicacao:not([hidden])) .hud-aprendizagem{visibility:hidden}
614
+ .hud-barra{display:flex;align-items:center;gap:.15em;padding:.2em .3em;background:rgba(8,8,16,.92);border-radius:8px}
615
+ .hud-seg{display:block;width:.8em;height:1em;border-radius:2px;box-sizing:border-box}
616
+ .hud-seg[data-seg="vazio"]{border:1px solid #8a8f98}
617
+ .hud-seg[data-seg="azul"]{background:#0072B2}
618
+ .hud-seg[data-seg="verde"]{background:radial-gradient(circle,#08080f 0 .14em,transparent .16em),#009E73}
619
+ .hud-seg[data-seg="vermelho"]{background:repeating-linear-gradient(45deg,#08080f 0 .12em,transparent .12em .3em),#D55E00}
620
+ .hud-barra[data-cor="roxa"] .hud-seg:not([data-seg="vazio"]){background:#CC79A7}
621
+ .hud-barra[data-cor="laranja"] .hud-seg:not([data-seg="vazio"]){background:#E69F00}
622
+ .hud-barra[data-cor="roxa"]::after,.hud-barra[data-cor="laranja"]::after{color:#f6f5f0;font-size:1em;line-height:1;margin-left:.15em}
623
+ .hud-barra[data-cor="roxa"]::after{content:"▲"}
624
+ .hud-barra[data-cor="laranja"]::after{content:"▼"}
625
+ .hud-numero{margin:0;padding:0 .3em;color:#f6f5f0;background:rgba(8,8,16,.92);border-radius:8px;max-width:100%;overflow-wrap:anywhere}
626
+ .rodape-da-tela{position:absolute;left:0;right:0;bottom:0;z-index:12;display:flex;flex-direction:column;gap:0;pointer-events:none}
627
+ .rodape-da-tela:not(:has(> :not([hidden]))){display:none}
628
+ .pausa-legenda,.barra-explicacao{color:#fff;font-family:var(--font);font-weight:700;font-size:var(--ui-fs,16px);
629
+ line-height:1.3;text-align:center;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
630
+ .barra-explicacao{order:2;padding:4px .6em;background:rgba(0,0,0,.82)}
631
+ .pausa-legenda{order:1;padding:0 .6em}
632
+ .rodape-da-tela:not(:has(> .barra-explicacao:not([hidden]))) > .pausa-legenda{padding-bottom:8px}
633
+ .pausa-legenda .lg-nome{background:rgba(0,0,0,.82);padding:0 .35em;border-radius:4px;-webkit-box-decoration-break:clone;box-decoration-break:clone}
634
+ /* The SOUND CAPTION (study item D3) tops the column — ADR-0164 rule 4: «the sound caption above, the explanation below
635
+ it» — on a dark background behind its words only, two lines at most (rule 5). */
636
+ .legenda-de-som{order:0;align-self:center;max-width:100%;box-sizing:border-box;margin:0 0 4px;padding:2px .6em;border-radius:6px;
637
+ background:rgba(0,0,0,.82);color:#fff;font-family:var(--font);font-weight:700;font-size:var(--ui-fs,16px);line-height:1.3;
638
+ text-align:center;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
639
+ /* two or more lines of the footer showing at once: one line each, so the footer does not climb into the workspace */
640
+ .rodape-da-tela:has(> :not([hidden]) ~ :not([hidden])) > *{-webkit-line-clamp:1}
641
+ .pausa-legenda[hidden],.barra-explicacao[hidden],.legenda-de-som[hidden]{display:none}
642
+ /* A PANEL WEARS THE PAUSE CARD (interface log, 2026-09-13). The Dev: the settings submenu «mantém a mesma altura e identidade
643
+ visual», and every panel it opens had «outra identidade visual, com alturas menores, título maior e cores diferentes».
644
+ So a panel in the region takes `.screen-pause .pause-card` as it is: the whole height, the same dark card and gold border,
645
+ the gold title at the text size, items of `.pm-btn`'s colour, border and radius with the same 2 px gaps. It is at least
646
+ the pause card's width and grows only when a row needs it — a steps row never wraps (ADR-0130 erratum), and with the BDA
647
+ spacing (ADR-0149) «◀ Realce de contraste: desligado ▶» is wider than the pause list's 26em. */
648
+ #game-region .overlay__card{background:#0e1626;border:2px solid #ffd23f;border-radius:14px;padding:.25rem .7rem;width:auto;
649
+ max-width:94%;height:100%;max-height:100%;box-sizing:border-box;
650
+ scrollbar-gutter:stable both-edges;box-shadow:0 8px 30px rgba(0,0,0,.5);scroll-padding-bottom:var(--rodape-h,50px)}
651
+ #game-region .overlay__card h2{font-size:1em;line-height:1.25;margin:0 0 .1rem;color:#ffd23f}
652
+ #game-region .overlay__back{width:100%;margin:0 0 2px;justify-content:center;background:#1a2740;border:1px solid #6a7a96;border-radius:10px;color:#eaf2f8}
653
+ #game-region .overlay__back:hover,#game-region .overlay__back:focus{background:#2a3a5e;border-color:#ffd23f;outline:2px solid #ffd23f;outline-offset:1px}
654
+ #game-region .ctrl-list{gap:2px}
655
+ /* the pause list's width is the floor, as `.pause-menu` declares it: the card follows with the same padding and scrollbar gutters */
656
+ #game-region .overlay__back,#game-region .ctrl-list{min-width:26em;max-width:100%} /* em: grows with the menu's text, like the pause list */
657
+ #game-region .ctrl-row{box-sizing:border-box;min-height:var(--alvo-min,44px);padding:.3rem .7rem;background:#1a2740;border:1px solid #6a7a96;border-radius:10px;color:#eaf2f8;font-weight:700}
658
+ #game-region .overlay__card > .ctrl-row{margin-top:2px}
659
+ #game-region .ctrl-row:hover,#game-region .ctrl-row:focus-within{background:#2a3a5e;border-color:#ffd23f}
660
+ /* The card runs under the explanation band, as the pause card runs under its legend: the room at the end of the card and
661
+ the scroll padding let the last row, and the focused one, come to rest above the band. */
662
+ #game-region .overlay__card::after{content:"";display:block;height:var(--rodape-h,50px)}
663
+ /* HELP IS A SLIDE SHOW (interface log, 2026-09-13; `ui/help-panel`): «textos, figuras e no máximo animações», not a menu. One stop
664
+ with the page arrows at its sides; the slide holds the child's key drawn as a key cap, the game's word and its sentence, and
665
+ dots that say where the child is by fill and not by colour alone. The key cap presses itself now and then — the one animation,
666
+ gone under reduced motion. */
667
+ /* a slide explains itself: no footer band telling the child to point at an option, and no room kept for it */
668
+ #help .opt-explain,#help .overlay__card::after{display:none}
669
+ .slides{display:flex;align-items:stretch;gap:.25rem;min-height:11em;border:1px solid #6a7a96;border-radius:10px;background:#1a2740;color:#eaf2f8}
670
+ .slides:focus,.slides:focus-visible{outline:2px solid #ffd23f;outline-offset:1px;border-color:#ffd23f}
671
+ .slides .passo-seta{align-self:center;color:#ffd23f;font-size:1.3em}
672
+ .slide{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.45em;padding:.5em .2em;text-align:center}
673
+ .slide-tecla{display:inline-flex;align-items:center;justify-content:center;min-width:3em;min-height:2em;padding:.15em .6em;font:inherit;font-size:1.4em;
674
+ font-weight:800;color:#0e1626;background:#eaf2f8;border-radius:10px;box-shadow:0 .22em 0 #6a7a96;animation:tecla-aperta 2.4s ease-in-out infinite}
675
+ .slide-tecla[data-sem-tecla]{color:#c3cfe0;background:transparent;border:2px dashed #6a7a96;box-shadow:none;animation:none}
676
+ @keyframes tecla-aperta{0%,70%,100%{transform:translateY(0);box-shadow:0 .22em 0 #6a7a96}82%{transform:translateY(.16em);box-shadow:0 .06em 0 #6a7a96}}
677
+ @media (prefers-reduced-motion: reduce){ .slide-tecla{animation:none} }
678
+ /* a cartridge's «how to play» figure (ADR-0195): the surface the game draws on, crisp at the pixel scale */
679
+ .slide-figura{display:block;width:min(100%,16em);height:7em;image-rendering:pixelated}
680
+ .slide-palavra{margin:0;font-size:1.2em;font-weight:800;color:#ffd23f}
681
+ .slide-texto{margin:0;max-width:28em;line-height:1.35}
682
+ .slide-pontos{display:flex;gap:.45em;justify-content:center;margin-top:.2em}
683
+ .slide-ponto{width:.6em;height:.6em;border-radius:50%;border:1px solid #eaf2f8;box-sizing:border-box}
684
+ .slide-ponto.is-on{background:#ffd23f;border-color:#ffd23f}
685
+ /* Explanation footer: white on 0.82 translucent black → the white's contrast is >7:1 even over 100% white
686
+ (composition: 1-0.82=0.18 → L≈0.027 → ~13:1), without being 100% opaque. Fixed at the card's foot. */
687
+ .opt-explain{position:sticky;bottom:calc(-1 * var(--card-pad,1.5rem));margin:.8rem calc(-1 * var(--card-pad,1.5rem)) calc(-1 * var(--card-pad,1.5rem));padding:.6rem .9rem;min-height:2.8rem;text-align:left;
688
+ background:rgba(0,0,0,.82);color:#fff;font-size:1em;line-height:1.35;border-top:1px solid rgba(255,255,255,.18);border-radius:0 0 9px 9px;backdrop-filter:blur(1px);
689
+ /* ADR-0164: two lines at most — a longer explanation is cut here and has to be rewritten to fit */
690
+ display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
691
+ /* ADR-0164 rule 1: a panel's explanation is a footer of the SCREEN, not of the card — «está ajustado ao menu, não ao
692
+ canvas», the Dev on a screenshot. The card sets no position, so the overlay (the region's size) is the containing block:
693
+ the band lands at the region's lowest edge, side to side, and does not scroll with the card. The card runs under it,
694
+ the pause card's height (see the panel rules above). */
695
+ #game-region .opt-explain{position:absolute;left:0;right:0;bottom:0;z-index:1;margin:0;padding:4px .6em;min-height:0;
696
+ border:0;border-radius:0;text-align:center;line-height:1.3;font-size:var(--ui-fs,16px)}
697
+ #game-region .overlay{padding:0}
512
698
  #game-region .overlay__actions{position:static;background:transparent;padding:.5rem 0 0;margin:0}
513
- #visual{background:rgba(0,0,0,.28);align-items:start;padding-top:3.5rem} /* cor: fundo translúcido p/ ver o efeito imediato no jogo */
699
+ #visual{background:rgba(0,0,0,.28)} /* colour: a translucent background, to see the effect on the game at once */
514
700
 
515
- /* Indicador de simulação (canto sup. dir.): branca=cegueira, verde=baixa visão. Duplo toque volta ao normal. */
516
- #viz-indicator{position:absolute;top:6px;right:6px;z-index:20;width:16px;height:16px;border-radius:50%;border:2px solid rgba(0,0,0,.6);padding:0;cursor:pointer;box-shadow:0 1px 4px rgba(0,0,0,.7)} /* DENTRO do canvas (game-region) — funciona como botão */
701
+ /* Simulation indicator (top right corner): white=blindness, green=low vision. A double tap returns to normal. */
702
+ #viz-indicator{position:absolute;top:6px;right:6px;z-index:20;width:16px;height:16px;border-radius:50%;border:2px solid rgba(0,0,0,.6);padding:0;cursor:pointer;box-shadow:0 1px 4px rgba(0,0,0,.7)} /* INSIDE the canvas (game-region) — it works as a button */
517
703
  #viz-indicator.blind{background:#fff}
518
704
  #viz-indicator.low{background:#36d36a}
519
- /* Baixa visão — 5 simulações (desfoque vem do filter na canvas; aqui só os overlays) */
705
+ /* Low vision — 5 simulations (the blur comes from the filter on the canvas; only the overlays are here) */
520
706
  #viz-overlay{position:absolute;inset:0;z-index:8;pointer-events:none}
521
- #viz-overlay.lv-blur{background:none} /* miopia/astigmatismo: só desfoque */
522
- #viz-overlay.lv-haze{background:rgba(244,246,250,.42)} /* catarata: película esbranquiçada */
523
- #viz-overlay.lv-tunnel{background:radial-gradient(circle at 50% 50%, transparent 0 15%, rgba(0,0,0,.55) 27%, rgba(0,0,0,.99) 42%)} /* glaucoma: visão de túnel */
524
- #viz-overlay.lv-macular{background:radial-gradient(circle at 50% 50%, rgba(12,12,15,.95) 0 10%, rgba(12,12,15,.55) 17%, transparent 28%)} /* degeneração macular: borrão central */
525
- #viz-overlay.lv-diabetic{background: /* retinopatia diabética: manchas dispersas */
707
+ #viz-overlay.lv-blur{background:none} /* myopia/astigmatism: blur only */
708
+ #viz-overlay.lv-haze{background:rgba(244,246,250,.42)} /* cataract: a whitish film */
709
+ #viz-overlay.lv-tunnel{background:radial-gradient(circle at 50% 50%, transparent 0 15%, rgba(0,0,0,.55) 27%, rgba(0,0,0,.99) 42%)} /* glaucoma: tunnel vision */
710
+ #viz-overlay.lv-macular{background:radial-gradient(circle at 50% 50%, rgba(12,12,15,.95) 0 10%, rgba(12,12,15,.55) 17%, transparent 28%)} /* macular degeneration: a central blur */
711
+ #viz-overlay.lv-diabetic{background: /* diabetic retinopathy: scattered spots */
526
712
  radial-gradient(circle at 22% 30%, rgba(10,10,14,.95) 0 4%, transparent 11%),
527
713
  radial-gradient(circle at 64% 22%, rgba(10,10,14,.9) 0 3%, transparent 9%),
528
714
  radial-gradient(circle at 80% 58%, rgba(10,10,14,.95) 0 5%, transparent 12%),
529
715
  radial-gradient(circle at 40% 70%, rgba(10,10,14,.9) 0 4%, transparent 10%),
530
716
  radial-gradient(circle at 16% 80%, rgba(10,10,14,.85) 0 3%, transparent 9%),
531
717
  radial-gradient(circle at 54% 48%, rgba(10,10,14,.8) 0 3%, transparent 8%)}
532
- /* Cegueira total: a canvas vira preta (filter brightness(0)); escondemos HUD e controles na tela */
718
+ /* Total blindness: the canvas turns black (filter brightness(0)); we hide the HUD and the on-screen controls */
533
719
  body.blind-mode .hud, body.blind-mode #touch-controls, body.blind-mode #start-tips, body.blind-mode #caption{visibility:hidden}
534
720
  [hidden]{display:none!important}
535
- /* CAIXA ALTA (menu de CAA, ADR-0028). O jogo tem DOIS caminhos de texto e por isso dois mecanismos, que não
536
- são redundância: o `disp()` do main.js cobre o que a PIXI desenha na canvas, e esta regra cobre o que o
537
- navegador desenha no DOM — menus, HUD, legendas. O botão só ligava o primeiro, então a criança escolhia
538
- "maiúsculas" e os menus continuavam mistos.
539
- `text-transform` e NÃO transformar o texto: o conteúdo acessível fica intacto, e um leitor de tela não passa
540
- a soletrar letra por letra, que é o que ALL CAPS de verdade provoca em NVDA/JAWS. */
541
- /* Alternativas do quiz (segundo consumidor): altura mínima em MILÍMETROS REAIS, calculada por
542
- `input/touch.padPxPerMm` — WCAG 2.5.5 / GAG. O valor chega em `--quiz-alt-min`. */
543
- .quiz-alt{min-height:var(--quiz-alt-min,44px);display:block;width:100%;margin:.25rem 0}
544
- .quiz-alts{display:flex;flex-direction:column;gap:.25rem}
721
+ /* CAPITAL LETTERS (the AAC menu, ADR-0028). What a game draws on the canvas is the game's to capitalise; this rule covers
722
+ what the browser draws in the DOM — menus, HUD, captions. `createGame` writes `data-letras` on the root (ADR-0149 §1).
723
+ `text-transform` and NOT transforming the text: the accessible content stays intact, and a screen reader does not start
724
+ spelling letter by letter, which is what real ALL CAPS causes in NVDA/JAWS. */
725
+ /* Quiz options take the ENGINE's target floor (ADR-0163 rule 2): 44 px at 640×360, growing with the scale. They had
726
+ 9 mm computed by the quiz (54 px on a desktop), and four of them pushed the last one out of a 360 px region. */
727
+ .quiz-alt{min-height:var(--alvo-min,44px);display:block;width:100%;margin:0;padding:calc(var(--ui-fs,16px) * .4) calc(var(--ui-fs,16px) * .9)} /* the list gap spaces them (#160); padding in `--ui-fs`, so a larger face grows the text only (#172) */
728
+ /* the marked option is not colour alone either (ADR-0159 rule 10): the same base stripe as an icon switched on */
729
+ .quiz-alt.is-on{box-shadow:inset 0 0 0 3px var(--accent-ink)} /* a ring, not a bottom strip: the strip left the fill looking shifted up (#166) */
730
+ .quiz-alts{display:flex;flex-direction:column;gap:calc(.25rem * var(--espaco-fixo,1))}
545
731
  :root[data-letras="upper"] body,
546
732
  :root[data-letras="upper"] button,
547
733
  :root[data-letras="upper"] select,
548
734
  :root[data-letras="upper"] option,
549
735
  :root[data-letras="upper"] input,
550
736
  :root[data-letras="upper"] textarea{text-transform:uppercase}
551
- /* Os controles de formulário estão na lista porque a folha do NAVEGADOR lhes impõe `text-transform:none`, e
552
- `none` numa regra do UA vence a herança. Sem eles a caixa alta pegava no texto das telas e falhava em cada
553
- BOTÃO — que é justamente onde os rótulos dos menus moram. Foi o que o Dev viu: "não torna todas as letras
554
- do menu maiúsculas". */
555
- /* menus nunca ultrapassam a tela: limitados à altura do viewport e roláveis (rodapé de ações fica fixo embaixo) */
737
+ /* The form controls are on the list because the BROWSER's stylesheet imposes `text-transform:none` on them, and `none`
738
+ in a UA rule beats inheritance. Without them the capitals took the screens' text and failed on every BUTTON — which
739
+ is exactly where the menus' labels live. It is what the Dev saw: «não torna todas as letras do menu maiúsculas». */
740
+ /* menus never overflow the screen: limited to the viewport's height and scrollable (the actions footer stays fixed at the bottom) */
556
741
  .overlay__card{background:var(--panel);border:3px solid var(--accent);border-radius:12px;padding:1.5rem;max-width:420px;width:100%;text-align:center;font-size:var(--ui-fs,16px);
557
- max-height:92dvh;overflow-y:auto;overscroll-behavior:contain} /* base = --ui-fs (16 mín, escala com o canvas); internos em em */
742
+ max-height:92dvh;overflow-y:auto;overscroll-behavior:contain} /* base = --ui-fs (16 min, scales with the canvas); inner sizes in em */
558
743
  .overlay__card h2{margin-top:0}
744
+ /* ADR-0158: «Voltar» is the panel's item 1 — a full-width row above the list, not a pill at the bottom. */
745
+ .overlay__back{display:flex;align-items:center;width:100%;margin:0 0 .45rem;text-align:left;border-radius:8px}
746
+ /* ADR-0167: a panel's stops draw no number; «Voltar»'s glyph stays, out of the accessible name (ADR-0159 rule 12). */
747
+ .overlay__card button[data-glifo]::before{content:attr(data-glifo) / "";margin-inline-end:.5em}
559
748
  .topbar__right{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap}
560
749
  .title-card{text-align:center}
561
- .title-big{font-size:2rem;margin:.2rem 0;color:var(--accent)}
750
+ .title-big{font-size:2em;margin:.2rem 0;color:var(--accent)}
562
751
  .title-by{color:var(--ink-soft);margin:.2rem 0 1rem}
563
- .title-card .btn{margin-top:.4rem;font-size:1.1rem;padding:.6em 1.6em}
752
+ .title-card .btn{margin-top:.4rem;font-size:1.1em;padding:.6em 1.6em}
564
753
  .overlay__actions{display:flex;gap:.6rem;flex-wrap:wrap;margin-top:1rem;justify-content:flex-end;
565
754
  position:sticky;bottom:-1.5rem;background:var(--panel);padding:.6rem 0 1.5rem;margin-bottom:-1.5rem}
566
- .opt-hint{color:var(--ink-soft);font-size:.9em;margin:.2rem 0 .8rem}
567
- .panel-sub{text-align:left;font-size:1rem;margin:1rem 0 .4rem;border-bottom:1px solid var(--accent);padding-bottom:.2rem}
755
+ .opt-hint{color:var(--ink-soft);font-size:1em;margin:.2rem 0 .8rem}
756
+ .panel-sub{text-align:left;font-size:1em;margin:1rem 0 .4rem;border-bottom:1px solid var(--accent);padding-bottom:.2rem}
568
757
  .panel-sub:first-of-type{margin-top:.4rem}
569
- .panel-sub__tag{color:var(--ink-soft);font-size:.78em;font-weight:400}
570
- .vol{width:140px;max-width:45%;accent-color:var(--accent);height:1.5rem;cursor:pointer} /* barra de volume (range) */
571
- /* Caixas de seleção com a IDENTIDADE do jogo: fonte escolhida, cores e tamanho (não o estilo do SO) */
758
+ .panel-sub__tag{color:var(--ink-soft);font-size:1em;font-weight:400}
759
+ .vol{width:140px;max-width:45%;accent-color:var(--accent);height:1.5rem;cursor:pointer} /* the volume bar (range) */
760
+ /* Select boxes with the game's IDENTITY: the chosen face, colours and size (not the OS style) */
572
761
  select.vol, .overlay__card select, .ctrl-col select{
573
- font-family:var(--font);font-size:.95em;font-weight:600;color:var(--ink);
574
- width:auto;max-width:100%;height:auto;min-height:var(--tap);
762
+ font-family:var(--font);font-size:1em;font-weight:600;color:var(--ink);
763
+ width:auto;max-width:100%;height:auto;min-height:var(--alvo-min,44px);
575
764
  background:#0e1326;border:2px solid var(--ink-soft);border-radius:8px;
576
765
  padding:.35em 2em .35em .7em;cursor:pointer;
577
766
  -webkit-appearance:none;-moz-appearance:none;appearance:none;
@@ -580,52 +769,73 @@ select.vol, .overlay__card select, .ctrl-col select{
580
769
  select.vol:focus, .overlay__card select:focus{outline:3px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
581
770
  .overlay__card select option{background:#0e1326;color:var(--ink);font-weight:600}
582
771
  .ctrl-players{display:flex;gap:.4rem;flex-wrap:wrap;justify-content:center;margin-bottom:.7rem}
583
- .ctrl-players .mode-btn{padding:.3em .7em;font-size:.95rem}
772
+ .ctrl-players .mode-btn{padding:.3em .7em;font-size:1em}
584
773
  .ctrl-list{display:flex;flex-direction:column;gap:.45rem;text-align:left}
585
774
  .ctrl-row{display:flex;align-items:center;justify-content:space-between;gap:.6rem;background:#0e1326;border:2px solid var(--ink-soft);border-radius:8px;padding:.4rem .6rem}
586
- /* ADR-0029 — SAIU DO PADRÃO. Dois canais visuais no mesmo lugar: a COR da moldura e a FORMA, que é uma
587
- moldura DUPLA (borda, respiro, anel). O anel transparente de 2px revela o fundo do próprio elemento e é o
588
- que cria o respiro; sem ele os dois anéis colariam e viraria só uma borda mais grossa — uma diferença de
589
- espessura que ninguém percebe sem ter o não-marcado ao lado para comparar. A contagem de anéis sobrevive a
590
- escala de cinza, a daltonismo e a toda paleta do jogo, porque não é uma matiz. */
775
+ /* ADR-0029 — LEFT THE DEFAULT. Two visual channels in the same place: the frame's COLOUR and its SHAPE, which is a
776
+ DOUBLE frame (border, gap, ring). The transparent 2px ring reveals the element's own background and is what makes
777
+ the gap; without it the two rings would touch and become just a thicker border — a difference in thickness nobody
778
+ notices without the unmarked one beside it for comparison. The ring count survives greyscale, colour-vision
779
+ deficiency and every palette of the game, because it is not a hue. */
591
780
  .is-changed{border-color:var(--changed)!important;box-shadow:inset 0 0 0 2px transparent,inset 0 0 0 4px var(--changed)}
592
- /* A marca CEDE ao foco: perder o lugar é pior que perder uma dica. */
781
+ /* The mark YIELDS to the focus: losing your place is worse than losing a hint. */
593
782
  .is-changed:focus-visible,.is-changed:focus{box-shadow:none}
594
783
  .ctrl-row kbd{background:var(--ink);color:var(--bg);border-radius:5px;padding:.05em .45em;font-weight:700}
595
- .ctrl-row.row-off{opacity:.42} /* item desabilitado (ex.: modo de teclado indisponível) = só cinza claro, sem texto extra */
784
+ .ctrl-row.row-off{opacity:.42} /* a disabled item (e.g. an unavailable keyboard mode) = light grey only, no extra text */
596
785
  .ctrl-row .mode-btn[disabled]{cursor:not-allowed;opacity:.7}
597
786
  .ctrl-row.ctrl-col{flex-direction:column;align-items:stretch;gap:.4rem}
598
787
  .ctrl-row.ctrl-col label{font-weight:700}
599
788
  .pad-presets{display:flex;gap:.5rem;flex-wrap:wrap}
600
- .pad-tag{font-size:.8rem;font-weight:700;padding:.05em .5em;border-radius:999px;background:#20304e;color:#bcd}
789
+ .pad-tag{font-size:1em;font-weight:700;padding:.05em .5em;border-radius:999px;background:#20304e;color:#bcd}
601
790
  .pad-tag[data-who="crianca"]{background:#2a4a2e;color:#bfe9c2}
602
791
  .pad-tag[data-who="adulto"]{background:#2a3a5e;color:#c3d4f0}
603
- .pad-warn{font-size:.85rem;color:#ffdf9e;background:#3a2e12;border:1px solid #6a5220;border-radius:8px;padding:.45rem .6rem}
604
- .ctrl-col input[type=range]{width:100%;min-height:var(--tap);accent-color:var(--accent)}
605
-
606
- /* E13: controles de toque (mobile) — overlay nas bordas inferiores, não cobre o centro */
607
- .touch{position:absolute;inset:auto 0 0 0;z-index:14;display:flex;justify-content:space-between;align-items:flex-end;gap:8px;padding:6px 8px;pointer-events:none}
608
- .touch-pad{display:flex;gap:8px;pointer-events:auto}
609
- .touch-btn{width:56px;height:56px;min-width:var(--tap);min-height:var(--tap);border-radius:12px;border:2px solid rgba(255,255,255,.75);background:rgba(13,17,32,.92);color:#fff;font-size:1.4rem;font-weight:800;line-height:1;display:flex;align-items:center;justify-content:center;touch-action:none;-webkit-user-select:none;user-select:none;cursor:pointer}
792
+ .pad-warn{font-size:1em;color:#ffdf9e;background:#3a2e12;border:1px solid #6a5220;border-radius:8px;padding:.45rem .6rem}
793
+ .ctrl-col input[type=range]{width:100%;min-height:var(--alvo-min,44px);accent-color:var(--accent)}
794
+
795
+ /* touch controls (mobile) — an overlay on the bottom edges, not covering the centre */
796
+ .touch{position:absolute;inset:0;z-index:14;display:flex;justify-content:space-between;align-items:flex-end;gap:8px;padding:6px 8px;pointer-events:none}
797
+ /* ADR-0160: the shoulders in the TOP corners of the region, the trigger (2) above the bumper (1). `.touch` covers the whole
798
+ region since then (`inset:0`, still `pointer-events:none`) so a corner is the region's corner, not the pad strip's. */
799
+ .touch-ombros{position:absolute;top:8px;display:flex;flex-direction:column;gap:6px;pointer-events:auto}
800
+ .touch-ombros--esq{left:8px}
801
+ .touch-ombros--dir{right:8px}
802
+ /* ADR-0160: the action buttons sit by ACTION NUMBER — 1 and 4 on top, 2 and 3 below — whatever slot fires them.
803
+ `margin-left:auto` keeps the block on the right when the game names no direction (ADR-0162). */
804
+ .touch-pad{display:grid;grid-template-areas:"a1 a4" "a2 a3";gap:8px;margin-left:auto;pointer-events:auto}
805
+ .touch-btn[data-acao="action1"]{grid-area:a1}
806
+ .touch-btn[data-acao="action4"]{grid-area:a4}
807
+ .touch-btn[data-acao="action2"]{grid-area:a2}
808
+ .touch-btn[data-acao="action3"]{grid-area:a3}
809
+ .touch-btn{width:56px;height:56px;min-width:var(--alvo-min,44px);min-height:var(--alvo-min,44px);border-radius:12px;border:2px solid rgba(255,255,255,.75);background:rgba(13,17,32,.92);color:#fff;font-size:1.4em;font-weight:800;line-height:1;display:flex;align-items:center;justify-content:center;touch-action:none;-webkit-user-select:none;user-select:none;cursor:pointer}
610
810
  .touch-btn:active{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
611
811
  .touch-jump{background:rgba(18,74,52,.94)}
612
- /* Botões de ação em LOSANGO (4 bolhas: 0 baixo, 1 direita, 2 esquerda, 3 cima) + START pílula */
812
+ /* Action buttons in a DIAMOND (4 bubbles: 0 bottom, 1 right, 2 left, 3 top) + a START pill */
613
813
  .touch-actions{align-items:center}
614
- /* Tamanho FÍSICO (mm), não px: --pad-btn e --pad-diam são calculados no JS a partir de mm reais
615
- (referência: iPhone 16 ocupando a tela toda). Config em A12e motora. Fallback antes do JS rodar. */
814
+ /* PHYSICAL size (mm), not px: --pad-btn and --pad-diam are computed by `input/touch` from real millimetres
815
+ (reference: an iPhone 16 filling the screen). These are the fallbacks before the JS runs. */
616
816
  .pad-diamond{position:relative;width:var(--pad-diam,182px);height:var(--pad-diam,182px);pointer-events:none}
617
817
  .pad-b{position:absolute;width:var(--pad-btn,66px);height:var(--pad-btn,66px);border-radius:50%;font-size:calc(var(--pad-btn,66px)*.42);font-weight:800;pointer-events:auto;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center}
618
818
  .pad-top{top:0;left:50%;transform:translateX(-50%)}
619
819
  .pad-bottom{bottom:0;left:50%;transform:translateX(-50%)}
620
820
  .pad-left{left:0;top:50%;transform:translateY(-50%)}
621
821
  .pad-right{right:0;top:50%;transform:translateY(-50%)}
622
- .touch-start{position:absolute;left:50%;bottom:6px;transform:translateX(-50%);min-height:calc(var(--pad-btn,66px)*.7);box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;pointer-events:auto;border-radius:999px;padding:0 22px;font-weight:800;font-size:.82rem;letter-spacing:.08em;background:rgba(13,17,32,.92);color:#fff;border:2px solid rgba(255,255,255,.75);cursor:pointer;z-index:15}
822
+ /* `width:auto`: the pill is also a `.touch-btn`, whose fixed 56px cut the word — measured in the dist, «START» with 66px
823
+ of text in a 56px button at the cursive hand's 1.25 scale (ADR-0149). The pill grows with the word, and the floor is the target. */
824
+ /* The two system pills, SELECT and START, in a container at the centre (ADR-0155). Inside it they no longer place
825
+ themselves: the container puts them side by side, and each keeps the width of its text. */
826
+ /* 🔴 WITH A PANEL OPEN, THE PAD SITS ABOVE IT (ADR-0157): its directional is what moves in the panel. The panel's veil
827
+ (`#game-region .overlay`, 60) covered the pad (14), and a tap on an arrow landed on the veil. `--z-menu-max` is the top
828
+ of the menu band, and that is the pad's role while a menu is open — a slot and not a new literal. */
829
+ #game-region:has(.overlay:not([hidden])) .touch{z-index:var(--z-menu-max)}
830
+ .touch-sistema{position:absolute;left:50%;bottom:6px;transform:translateX(-50%);display:flex;gap:10px;pointer-events:none}
831
+ .touch-sistema .touch-start,.touch-sistema .touch-select{position:static;transform:none}
832
+ .touch-start,.touch-select{position:absolute;left:50%;bottom:6px;transform:translateX(-50%);width:auto;min-width:var(--alvo-min,44px);white-space:nowrap;min-height:calc(var(--pad-btn,66px)*.7);box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;pointer-events:auto;border-radius:999px;padding:0 22px;font-weight:800;font-size:1em;letter-spacing:var(--ls);background:rgba(13,17,32,.92);color:#fff;border:2px solid rgba(255,255,255,.75);cursor:pointer;z-index:15}
623
833
  .touch-start:active{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
624
- /* joystick digital: base (círculo maior) + manopla (círculo menor) */
625
- /* Direcional (analógico/"alavanca"): base = superfície + deslocamento; manopla = superfície de contato. Ambos em mm (JS). */
834
+ /* digital joystick: base (larger circle) + knob (smaller circle) */
835
+ /* Directional (analogue/"lever"): base = surface + travel; knob = contact surface. Both in mm (JS). */
626
836
  .touch-stick{position:relative;width:var(--stick-base,124px);height:var(--stick-base,124px);border-radius:50%;border:3px solid rgba(255,255,255,.7);background:rgba(13,17,32,.85);touch-action:none;pointer-events:auto;-webkit-user-select:none;user-select:none}
627
837
  .touch-knob{position:absolute;left:50%;top:50%;width:var(--stick-knob,58px);height:var(--stick-knob,58px);margin:calc(var(--stick-knob,58px)/-2) 0 0 calc(var(--stick-knob,58px)/-2);border-radius:50%;background:rgba(255,255,255,.88);box-shadow:0 0 0 2px rgba(0,0,0,.45);transition:transform .04s linear;pointer-events:none}
628
- /* D-pad em cruz (estilo alternativo): 4 braços + miolo; tamanho do braço em mm (JS → --dpad-arm-l/w, --dpad-span) */
838
+ /* Cross D-pad (an alternative style): 4 arms + a core; the arm's size in mm (JS → --dpad-arm-l/w, --dpad-span) */
629
839
  .touch-cross{position:relative;width:var(--dpad-span,120px);height:var(--dpad-span,120px);touch-action:none;pointer-events:auto;-webkit-user-select:none;user-select:none}
630
840
  .touch-cross[hidden]{display:none}
631
841
  .dpad-arm{position:absolute;display:flex;align-items:center;justify-content:center;background:rgba(13,17,32,.92);border:2px solid rgba(255,255,255,.75);color:rgba(255,255,255,.85);font-size:calc(var(--dpad-arm-w,34px)*.5);line-height:1;pointer-events:none}
@@ -641,4 +851,4 @@ select.vol:focus, .overlay__card select:focus{outline:3px solid var(--accent);ou
641
851
  @media (prefers-reduced-motion: reduce){ .touch-knob{transition:none} }
642
852
  @media (prefers-contrast: more){ .touch-btn{background:#000;border-color:#fff} .touch-btn:active{background:#fff;color:#000} .touch-stick{background:#000;border-color:#fff} .touch-knob{background:#fff} }
643
853
 
644
- @media (max-width:560px){.title{font-size:1.1rem}.hud{gap:1rem}}
854
+ @media (max-width:560px){.title{font-size:1.1em}.hud{gap:1rem}}