@classytic/labs 0.1.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 (547) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -0
  3. package/dist/biology/enzyme-rate/index.d.mts +1 -0
  4. package/dist/biology/enzyme-rate/preset.d.mts +25 -0
  5. package/dist/biology/enzyme-rate/preset.mjs +256 -0
  6. package/dist/biology/genetic-cross/core.d.mts +64 -0
  7. package/dist/biology/genetic-cross/core.mjs +147 -0
  8. package/dist/biology/genetic-cross/grid.mjs +239 -0
  9. package/dist/biology/genetic-cross/index.d.mts +3 -0
  10. package/dist/biology/genetic-cross/preset.d.mts +26 -0
  11. package/dist/biology/genetic-cross/preset.mjs +184 -0
  12. package/dist/biology/genetic-cross/sex-linked.d.mts +27 -0
  13. package/dist/biology/genetic-cross/sex-linked.mjs +226 -0
  14. package/dist/biology/index.d.mts +11 -0
  15. package/dist/biology/index.mjs +12 -0
  16. package/dist/biology/photosynthesis-factors/index.d.mts +1 -0
  17. package/dist/biology/photosynthesis-factors/preset.d.mts +25 -0
  18. package/dist/biology/photosynthesis-factors/preset.mjs +270 -0
  19. package/dist/biology/punnett-cross/index.d.mts +1 -0
  20. package/dist/biology/punnett-cross/preset.d.mts +27 -0
  21. package/dist/biology/punnett-cross/preset.mjs +21 -0
  22. package/dist/biology/respiration/index.d.mts +1 -0
  23. package/dist/biology/respiration/preset.d.mts +17 -0
  24. package/dist/biology/respiration/preset.mjs +179 -0
  25. package/dist/biology/sequence/central-dogma.d.mts +17 -0
  26. package/dist/biology/sequence/central-dogma.mjs +339 -0
  27. package/dist/biology/sequence/core.d.mts +38 -0
  28. package/dist/biology/sequence/core.mjs +178 -0
  29. package/dist/biology/sequence/index.d.mts +3 -0
  30. package/dist/biology/sequence/preset.d.mts +20 -0
  31. package/dist/biology/sequence/preset.mjs +235 -0
  32. package/dist/blocks/accounting.d.mts +142 -0
  33. package/dist/blocks/accounting.mjs +446 -0
  34. package/dist/blocks/authoring.d.mts +12 -0
  35. package/dist/blocks/authoring.mjs +705 -0
  36. package/dist/blocks/biology.d.mts +197 -0
  37. package/dist/blocks/biology.mjs +513 -0
  38. package/dist/blocks/chem.d.mts +128 -0
  39. package/dist/blocks/chem.mjs +486 -0
  40. package/dist/blocks/circuits.d.mts +86 -0
  41. package/dist/blocks/circuits.mjs +348 -0
  42. package/dist/blocks/discrete.d.mts +62 -0
  43. package/dist/blocks/discrete.mjs +314 -0
  44. package/dist/blocks/economics.d.mts +56 -0
  45. package/dist/blocks/economics.mjs +203 -0
  46. package/dist/blocks/geography.d.mts +58 -0
  47. package/dist/blocks/geography.mjs +115 -0
  48. package/dist/blocks/geometry.d.mts +28 -0
  49. package/dist/blocks/geometry.mjs +160 -0
  50. package/dist/blocks/ict.d.mts +65 -0
  51. package/dist/blocks/ict.mjs +197 -0
  52. package/dist/blocks/index.d.mts +4555 -0
  53. package/dist/blocks/index.mjs +120 -0
  54. package/dist/blocks/lab-block.d.mts +16 -0
  55. package/dist/blocks/lab-block.mjs +74 -0
  56. package/dist/blocks/lab-config.d.mts +23 -0
  57. package/dist/blocks/lab-config.mjs +200 -0
  58. package/dist/blocks/lab-gallery.d.mts +30 -0
  59. package/dist/blocks/lab-gallery.mjs +208 -0
  60. package/dist/blocks/language.d.mts +349 -0
  61. package/dist/blocks/language.mjs +750 -0
  62. package/dist/blocks/lesson.d.mts +43 -0
  63. package/dist/blocks/lesson.mjs +140 -0
  64. package/dist/blocks/math.d.mts +411 -0
  65. package/dist/blocks/math.mjs +1536 -0
  66. package/dist/blocks/ml.d.mts +84 -0
  67. package/dist/blocks/ml.mjs +146 -0
  68. package/dist/blocks/physics.d.mts +259 -0
  69. package/dist/blocks/physics.mjs +868 -0
  70. package/dist/blocks/statistics.d.mts +29 -0
  71. package/dist/blocks/statistics.mjs +123 -0
  72. package/dist/catalog/index.d.mts +3 -0
  73. package/dist/catalog/index.mjs +8 -0
  74. package/dist/catalog/registry.d.mts +46 -0
  75. package/dist/catalog/registry.mjs +56 -0
  76. package/dist/catalog/templates.d.mts +11 -0
  77. package/dist/catalog/templates.mjs +141 -0
  78. package/dist/chem/battery.d.mts +16 -0
  79. package/dist/chem/battery.mjs +311 -0
  80. package/dist/chem/bohr-atom.d.mts +16 -0
  81. package/dist/chem/bohr-atom.mjs +212 -0
  82. package/dist/chem/diffusion/asset.mjs +76 -0
  83. package/dist/chem/diffusion/index.d.mts +1 -0
  84. package/dist/chem/diffusion/preset.d.mts +15 -0
  85. package/dist/chem/diffusion/preset.mjs +188 -0
  86. package/dist/chem/electrochem/index.d.mts +1 -0
  87. package/dist/chem/electrochem/preset.d.mts +23 -0
  88. package/dist/chem/electrochem/preset.mjs +402 -0
  89. package/dist/chem/equilibrium/index.d.mts +1 -0
  90. package/dist/chem/equilibrium/preset.d.mts +36 -0
  91. package/dist/chem/equilibrium/preset.mjs +416 -0
  92. package/dist/chem/gas-box/index.d.mts +1 -0
  93. package/dist/chem/gas-box/preset.d.mts +27 -0
  94. package/dist/chem/gas-box/preset.mjs +395 -0
  95. package/dist/chem/index.d.mts +16 -0
  96. package/dist/chem/index.mjs +17 -0
  97. package/dist/chem/kinetics/index.d.mts +1 -0
  98. package/dist/chem/kinetics/preset.d.mts +31 -0
  99. package/dist/chem/kinetics/preset.mjs +478 -0
  100. package/dist/chem/periodic-trends/index.d.mts +1 -0
  101. package/dist/chem/periodic-trends/preset.d.mts +21 -0
  102. package/dist/chem/periodic-trends/preset.mjs +831 -0
  103. package/dist/chem/reaction-lab.d.mts +18 -0
  104. package/dist/chem/reaction-lab.mjs +165 -0
  105. package/dist/chem/reaction-profile.d.mts +21 -0
  106. package/dist/chem/reaction-profile.mjs +287 -0
  107. package/dist/chem/solution/dilution.d.mts +27 -0
  108. package/dist/chem/solution/dilution.mjs +199 -0
  109. package/dist/chem/solution/field.d.mts +30 -0
  110. package/dist/chem/solution/field.mjs +145 -0
  111. package/dist/chem/solution/index.d.mts +3 -0
  112. package/dist/chem/solution/solution-box.d.mts +28 -0
  113. package/dist/chem/solution/solution-box.mjs +140 -0
  114. package/dist/chem/stoichiometry/index.d.mts +1 -0
  115. package/dist/chem/stoichiometry/preset.d.mts +29 -0
  116. package/dist/chem/stoichiometry/preset.mjs +392 -0
  117. package/dist/chem/titration/index.d.mts +1 -0
  118. package/dist/chem/titration/preset.d.mts +29 -0
  119. package/dist/chem/titration/preset.mjs +436 -0
  120. package/dist/circuits/ac-dc/asset.mjs +295 -0
  121. package/dist/circuits/ac-dc/index.d.mts +1 -0
  122. package/dist/circuits/ac-dc/preset.d.mts +16 -0
  123. package/dist/circuits/ac-dc/preset.mjs +134 -0
  124. package/dist/circuits/capacitor-leak/index.d.mts +1 -0
  125. package/dist/circuits/capacitor-leak/preset.d.mts +32 -0
  126. package/dist/circuits/capacitor-leak/preset.mjs +271 -0
  127. package/dist/circuits/circuit/asset.d.mts +6 -0
  128. package/dist/circuits/circuit/asset.mjs +367 -0
  129. package/dist/circuits/circuit/index.d.mts +2 -0
  130. package/dist/circuits/circuit/preset.d.mts +46 -0
  131. package/dist/circuits/circuit/preset.mjs +235 -0
  132. package/dist/circuits/circuit-builder.d.mts +30 -0
  133. package/dist/circuits/circuit-builder.mjs +412 -0
  134. package/dist/circuits/circuit-lab.d.mts +20 -0
  135. package/dist/circuits/circuit-lab.mjs +400 -0
  136. package/dist/circuits/index.d.mts +7 -0
  137. package/dist/circuits/index.mjs +8 -0
  138. package/dist/commerce/accounting/core.d.mts +48 -0
  139. package/dist/commerce/accounting/core.mjs +57 -0
  140. package/dist/commerce/accounting/equation-balance.d.mts +35 -0
  141. package/dist/commerce/accounting/equation-balance.mjs +292 -0
  142. package/dist/commerce/accounting/index.d.mts +4 -0
  143. package/dist/commerce/accounting/journal-poster.d.mts +29 -0
  144. package/dist/commerce/accounting/journal-poster.mjs +472 -0
  145. package/dist/commerce/accounting/statement-sorter.d.mts +25 -0
  146. package/dist/commerce/accounting/statement-sorter.mjs +304 -0
  147. package/dist/commerce/economics/core.d.mts +33 -0
  148. package/dist/commerce/economics/core.mjs +26 -0
  149. package/dist/commerce/economics/demand-shift-vs-move.d.mts +35 -0
  150. package/dist/commerce/economics/demand-shift-vs-move.mjs +324 -0
  151. package/dist/commerce/economics/elasticity-revenue.d.mts +31 -0
  152. package/dist/commerce/economics/elasticity-revenue.mjs +253 -0
  153. package/dist/commerce/economics/index.d.mts +4 -0
  154. package/dist/commerce/economics/market-equilibrium.d.mts +33 -0
  155. package/dist/commerce/economics/market-equilibrium.mjs +340 -0
  156. package/dist/commerce/index.d.mts +9 -0
  157. package/dist/commerce/index.mjs +10 -0
  158. package/dist/core/easing.d.mts +28 -0
  159. package/dist/core/easing.mjs +66 -0
  160. package/dist/core/index.d.mts +10 -0
  161. package/dist/core/index.mjs +11 -0
  162. package/dist/core/numeric.d.mts +37 -0
  163. package/dist/core/numeric.mjs +75 -0
  164. package/dist/core/reactive.d.mts +24 -0
  165. package/dist/core/reactive.mjs +51 -0
  166. package/dist/core/rng.d.mts +21 -0
  167. package/dist/core/rng.mjs +39 -0
  168. package/dist/core/tex.d.mts +14 -0
  169. package/dist/core/tex.mjs +44 -0
  170. package/dist/core/timeline.d.mts +34 -0
  171. package/dist/core/timeline.mjs +77 -0
  172. package/dist/core/util.d.mts +19 -0
  173. package/dist/core/util.mjs +31 -0
  174. package/dist/discrete/arrangements/preset.d.mts +28 -0
  175. package/dist/discrete/arrangements/preset.mjs +304 -0
  176. package/dist/discrete/bayes/preset.d.mts +33 -0
  177. package/dist/discrete/bayes/preset.mjs +476 -0
  178. package/dist/discrete/binomial/preset.d.mts +25 -0
  179. package/dist/discrete/binomial/preset.mjs +333 -0
  180. package/dist/discrete/core/combinatorics.d.mts +23 -0
  181. package/dist/discrete/core/combinatorics.mjs +57 -0
  182. package/dist/discrete/core/inclusionExclusion.d.mts +19 -0
  183. package/dist/discrete/core/inclusionExclusion.mjs +30 -0
  184. package/dist/discrete/core/pigeonhole.d.mts +15 -0
  185. package/dist/discrete/core/pigeonhole.mjs +24 -0
  186. package/dist/discrete/core/probability.d.mts +29 -0
  187. package/dist/discrete/core/probability.mjs +43 -0
  188. package/dist/discrete/core/sets.d.mts +21 -0
  189. package/dist/discrete/core/sets.mjs +45 -0
  190. package/dist/discrete/counting-slots/preset.d.mts +30 -0
  191. package/dist/discrete/counting-slots/preset.mjs +553 -0
  192. package/dist/discrete/counting-tree/index.d.mts +1 -0
  193. package/dist/discrete/counting-tree/preset.d.mts +44 -0
  194. package/dist/discrete/counting-tree/preset.mjs +364 -0
  195. package/dist/discrete/expected-value/preset.d.mts +28 -0
  196. package/dist/discrete/expected-value/preset.mjs +352 -0
  197. package/dist/discrete/hypergeometric/preset.d.mts +25 -0
  198. package/dist/discrete/hypergeometric/preset.mjs +330 -0
  199. package/dist/discrete/index.d.mts +26 -0
  200. package/dist/discrete/index.mjs +27 -0
  201. package/dist/discrete/karnaugh/index.d.mts +1 -0
  202. package/dist/discrete/karnaugh/preset.d.mts +30 -0
  203. package/dist/discrete/karnaugh/preset.mjs +452 -0
  204. package/dist/discrete/lln/asset.mjs +206 -0
  205. package/dist/discrete/lln/index.d.mts +1 -0
  206. package/dist/discrete/lln/preset.d.mts +17 -0
  207. package/dist/discrete/lln/preset.mjs +152 -0
  208. package/dist/discrete/logic-circuit/index.d.mts +1 -0
  209. package/dist/discrete/logic-circuit/preset.d.mts +47 -0
  210. package/dist/discrete/logic-circuit/preset.mjs +307 -0
  211. package/dist/discrete/monte-carlo/index.d.mts +1 -0
  212. package/dist/discrete/monte-carlo/preset.d.mts +64 -0
  213. package/dist/discrete/monte-carlo/preset.mjs +446 -0
  214. package/dist/discrete/monty-hall/index.d.mts +1 -0
  215. package/dist/discrete/monty-hall/preset.d.mts +23 -0
  216. package/dist/discrete/monty-hall/preset.mjs +491 -0
  217. package/dist/discrete/outcome-builder/preset.d.mts +24 -0
  218. package/dist/discrete/outcome-builder/preset.mjs +283 -0
  219. package/dist/discrete/pascal/preset.d.mts +24 -0
  220. package/dist/discrete/pascal/preset.mjs +372 -0
  221. package/dist/discrete/sample-space/index.d.mts +1 -0
  222. package/dist/discrete/sample-space/preset.d.mts +42 -0
  223. package/dist/discrete/sample-space/preset.mjs +395 -0
  224. package/dist/discrete/selection/preset.d.mts +33 -0
  225. package/dist/discrete/selection/preset.mjs +406 -0
  226. package/dist/discrete/truth-table/index.d.mts +1 -0
  227. package/dist/discrete/truth-table/preset.d.mts +30 -0
  228. package/dist/discrete/truth-table/preset.mjs +456 -0
  229. package/dist/discrete/venn/index.d.mts +1 -0
  230. package/dist/discrete/venn/preset.d.mts +32 -0
  231. package/dist/discrete/venn/preset.mjs +461 -0
  232. package/dist/geography/cycle-lab/index.d.mts +1 -0
  233. package/dist/geography/cycle-lab/preset.d.mts +25 -0
  234. package/dist/geography/cycle-lab/preset.mjs +254 -0
  235. package/dist/geography/cycles.d.mts +21 -0
  236. package/dist/geography/cycles.mjs +205 -0
  237. package/dist/geography/index.d.mts +4 -0
  238. package/dist/geography/index.mjs +5 -0
  239. package/dist/geometry/board/index.d.mts +1 -0
  240. package/dist/geometry/board/preset.d.mts +71 -0
  241. package/dist/geometry/board/preset.mjs +148 -0
  242. package/dist/geometry/builder.d.mts +18 -0
  243. package/dist/geometry/builder.mjs +332 -0
  244. package/dist/geometry/index.d.mts +4 -0
  245. package/dist/geometry/index.mjs +5 -0
  246. package/dist/geometry/intersecting-circles.d.mts +17 -0
  247. package/dist/geometry/intersecting-circles.mjs +104 -0
  248. package/dist/ict/index.d.mts +5 -0
  249. package/dist/ict/index.mjs +6 -0
  250. package/dist/ict/number-systems/base-odometer.d.mts +34 -0
  251. package/dist/ict/number-systems/base-odometer.mjs +160 -0
  252. package/dist/ict/number-systems/bit-grouper.d.mts +32 -0
  253. package/dist/ict/number-systems/bit-grouper.mjs +190 -0
  254. package/dist/ict/number-systems/index.d.mts +4 -0
  255. package/dist/ict/number-systems/place-value-dial.d.mts +29 -0
  256. package/dist/ict/number-systems/place-value-dial.mjs +153 -0
  257. package/dist/ict/number-systems/wheel.d.mts +73 -0
  258. package/dist/ict/number-systems/wheel.mjs +279 -0
  259. package/dist/index.d.mts +10 -0
  260. package/dist/index.mjs +11 -0
  261. package/dist/kit/anim.mjs +52 -0
  262. package/dist/kit/annotate.mjs +116 -0
  263. package/dist/kit/answer-check.d.mts +38 -0
  264. package/dist/kit/answer-check.mjs +65 -0
  265. package/dist/kit/asset-util.mjs +15 -0
  266. package/dist/kit/controls.mjs +77 -0
  267. package/dist/kit/cycle.d.mts +44 -0
  268. package/dist/kit/cycle.mjs +188 -0
  269. package/dist/kit/diagram.mjs +176 -0
  270. package/dist/kit/electronics.mjs +357 -0
  271. package/dist/kit/expr-analysis.d.mts +37 -0
  272. package/dist/kit/expr-analysis.mjs +111 -0
  273. package/dist/kit/frame.d.mts +70 -0
  274. package/dist/kit/frame.mjs +205 -0
  275. package/dist/kit/freq-tree.mjs +99 -0
  276. package/dist/kit/gameshow.mjs +315 -0
  277. package/dist/kit/index.d.mts +5 -0
  278. package/dist/kit/index.mjs +6 -0
  279. package/dist/kit/logic-gates.d.mts +6 -0
  280. package/dist/kit/logic-gates.mjs +210 -0
  281. package/dist/kit/molecules.mjs +178 -0
  282. package/dist/kit/pedagogy.d.mts +126 -0
  283. package/dist/kit/pedagogy.mjs +331 -0
  284. package/dist/kit/play.d.mts +21 -0
  285. package/dist/kit/play.mjs +52 -0
  286. package/dist/kit/probability.mjs +141 -0
  287. package/dist/kit/proportion.mjs +112 -0
  288. package/dist/kit/reaction.mjs +102 -0
  289. package/dist/kit/rich.d.mts +10 -0
  290. package/dist/kit/rich.mjs +21 -0
  291. package/dist/kit/scale.mjs +230 -0
  292. package/dist/kit/space.mjs +326 -0
  293. package/dist/kit/steps.d.mts +24 -0
  294. package/dist/kit/steps.mjs +57 -0
  295. package/dist/kit/thermal.mjs +289 -0
  296. package/dist/language/agreement/index.d.mts +1 -0
  297. package/dist/language/agreement/preset.d.mts +27 -0
  298. package/dist/language/agreement/preset.mjs +113 -0
  299. package/dist/language/article-lens/index.d.mts +1 -0
  300. package/dist/language/article-lens/preset.d.mts +31 -0
  301. package/dist/language/article-lens/preset.mjs +125 -0
  302. package/dist/language/deck.d.mts +45 -0
  303. package/dist/language/deck.mjs +61 -0
  304. package/dist/language/icon.d.mts +40 -0
  305. package/dist/language/icon.mjs +73 -0
  306. package/dist/language/index.d.mts +10 -0
  307. package/dist/language/index.mjs +11 -0
  308. package/dist/language/preposition-scene/index.d.mts +1 -0
  309. package/dist/language/preposition-scene/preset.d.mts +34 -0
  310. package/dist/language/preposition-scene/preset.mjs +234 -0
  311. package/dist/language/sentence-builder/index.d.mts +1 -0
  312. package/dist/language/sentence-builder/preset.d.mts +32 -0
  313. package/dist/language/sentence-builder/preset.mjs +122 -0
  314. package/dist/language/transform/index.d.mts +1 -0
  315. package/dist/language/transform/preset.d.mts +31 -0
  316. package/dist/language/transform/preset.mjs +137 -0
  317. package/dist/language/ui.d.mts +53 -0
  318. package/dist/language/ui.mjs +88 -0
  319. package/dist/language/word-match/index.d.mts +1 -0
  320. package/dist/language/word-match/preset.d.mts +22 -0
  321. package/dist/language/word-match/preset.mjs +148 -0
  322. package/dist/math/area-model/asset.d.mts +6 -0
  323. package/dist/math/area-model/asset.mjs +270 -0
  324. package/dist/math/area-model/index.d.mts +2 -0
  325. package/dist/math/area-model/preset.d.mts +29 -0
  326. package/dist/math/area-model/preset.mjs +243 -0
  327. package/dist/math/balance-algebra/asset.d.mts +6 -0
  328. package/dist/math/balance-algebra/asset.mjs +150 -0
  329. package/dist/math/balance-algebra/index.d.mts +2 -0
  330. package/dist/math/balance-algebra/preset.d.mts +30 -0
  331. package/dist/math/balance-algebra/preset.mjs +228 -0
  332. package/dist/math/derivation.d.mts +22 -0
  333. package/dist/math/derivation.mjs +113 -0
  334. package/dist/math/derivative-explorer/index.d.mts +1 -0
  335. package/dist/math/derivative-explorer/preset.d.mts +19 -0
  336. package/dist/math/derivative-explorer/preset.mjs +227 -0
  337. package/dist/math/function-machine/index.d.mts +1 -0
  338. package/dist/math/function-machine/preset.d.mts +21 -0
  339. package/dist/math/function-machine/preset.mjs +177 -0
  340. package/dist/math/gradient-descent.d.mts +23 -0
  341. package/dist/math/gradient-descent.mjs +473 -0
  342. package/dist/math/grapher/index.d.mts +1 -0
  343. package/dist/math/grapher/preset.d.mts +40 -0
  344. package/dist/math/grapher/preset.mjs +313 -0
  345. package/dist/math/harmonic-form/index.d.mts +1 -0
  346. package/dist/math/harmonic-form/preset.d.mts +21 -0
  347. package/dist/math/harmonic-form/preset.mjs +387 -0
  348. package/dist/math/index.d.mts +25 -0
  349. package/dist/math/index.mjs +26 -0
  350. package/dist/math/integral-explorer/index.d.mts +1 -0
  351. package/dist/math/integral-explorer/preset.d.mts +23 -0
  352. package/dist/math/integral-explorer/preset.mjs +217 -0
  353. package/dist/math/interactive/index.d.mts +1 -0
  354. package/dist/math/interactive/preset.d.mts +72 -0
  355. package/dist/math/interactive/preset.mjs +202 -0
  356. package/dist/math/limit-explorer/index.d.mts +1 -0
  357. package/dist/math/limit-explorer/preset.d.mts +19 -0
  358. package/dist/math/limit-explorer/preset.mjs +216 -0
  359. package/dist/math/linear-system/index.d.mts +1 -0
  360. package/dist/math/linear-system/preset.d.mts +28 -0
  361. package/dist/math/linear-system/preset.mjs +164 -0
  362. package/dist/math/mystery-bucket/asset.d.mts +6 -0
  363. package/dist/math/mystery-bucket/asset.mjs +145 -0
  364. package/dist/math/mystery-bucket/index.d.mts +2 -0
  365. package/dist/math/mystery-bucket/preset.d.mts +36 -0
  366. package/dist/math/mystery-bucket/preset.mjs +116 -0
  367. package/dist/math/number-line/index.d.mts +1 -0
  368. package/dist/math/number-line/preset.d.mts +24 -0
  369. package/dist/math/number-line/preset.mjs +142 -0
  370. package/dist/math/parabola/index.d.mts +1 -0
  371. package/dist/math/parabola/preset.d.mts +13 -0
  372. package/dist/math/parabola/preset.mjs +79 -0
  373. package/dist/math/pattern/asset.d.mts +6 -0
  374. package/dist/math/pattern/asset.mjs +102 -0
  375. package/dist/math/pattern/index.d.mts +2 -0
  376. package/dist/math/pattern/preset.d.mts +32 -0
  377. package/dist/math/pattern/preset.mjs +294 -0
  378. package/dist/math/triangle-trig/index.d.mts +1 -0
  379. package/dist/math/triangle-trig/preset.d.mts +47 -0
  380. package/dist/math/triangle-trig/preset.mjs +245 -0
  381. package/dist/math/trig-explorer.d.mts +18 -0
  382. package/dist/math/trig-explorer.mjs +209 -0
  383. package/dist/ml/boundary/index.d.mts +1 -0
  384. package/dist/ml/boundary/preset.d.mts +24 -0
  385. package/dist/ml/boundary/preset.mjs +385 -0
  386. package/dist/ml/classifier/index.d.mts +1 -0
  387. package/dist/ml/classifier/preset.d.mts +25 -0
  388. package/dist/ml/classifier/preset.mjs +315 -0
  389. package/dist/ml/index.d.mts +6 -0
  390. package/dist/ml/index.mjs +7 -0
  391. package/dist/ml/kmeans/index.d.mts +1 -0
  392. package/dist/ml/kmeans/preset.d.mts +33 -0
  393. package/dist/ml/kmeans/preset.mjs +236 -0
  394. package/dist/ml/knn/index.d.mts +1 -0
  395. package/dist/ml/knn/preset.d.mts +28 -0
  396. package/dist/ml/knn/preset.mjs +279 -0
  397. package/dist/ml/regression/index.d.mts +1 -0
  398. package/dist/ml/regression/preset.d.mts +32 -0
  399. package/dist/ml/regression/preset.mjs +394 -0
  400. package/dist/physics/atwood/index.d.mts +1 -0
  401. package/dist/physics/atwood/preset.d.mts +23 -0
  402. package/dist/physics/atwood/preset.mjs +312 -0
  403. package/dist/physics/bullet-walls/index.d.mts +1 -0
  404. package/dist/physics/bullet-walls/preset.d.mts +28 -0
  405. package/dist/physics/bullet-walls/preset.mjs +373 -0
  406. package/dist/physics/carnot/index.d.mts +1 -0
  407. package/dist/physics/carnot/preset.d.mts +27 -0
  408. package/dist/physics/carnot/preset.mjs +427 -0
  409. package/dist/physics/circular-motion/index.d.mts +1 -0
  410. package/dist/physics/circular-motion/preset.d.mts +25 -0
  411. package/dist/physics/circular-motion/preset.mjs +293 -0
  412. package/dist/physics/collision-track/index.d.mts +1 -0
  413. package/dist/physics/collision-track/preset.d.mts +27 -0
  414. package/dist/physics/collision-track/preset.mjs +352 -0
  415. package/dist/physics/efficiency/index.d.mts +1 -0
  416. package/dist/physics/efficiency/preset.d.mts +33 -0
  417. package/dist/physics/efficiency/preset.mjs +343 -0
  418. package/dist/physics/electric-field/index.d.mts +1 -0
  419. package/dist/physics/electric-field/preset.d.mts +15 -0
  420. package/dist/physics/electric-field/preset.mjs +306 -0
  421. package/dist/physics/energy-skate/index.d.mts +1 -0
  422. package/dist/physics/energy-skate/preset.d.mts +25 -0
  423. package/dist/physics/energy-skate/preset.mjs +254 -0
  424. package/dist/physics/entropy/index.d.mts +1 -0
  425. package/dist/physics/entropy/preset.d.mts +18 -0
  426. package/dist/physics/entropy/preset.mjs +416 -0
  427. package/dist/physics/expansion/index.d.mts +1 -0
  428. package/dist/physics/expansion/preset.d.mts +26 -0
  429. package/dist/physics/expansion/preset.mjs +609 -0
  430. package/dist/physics/exponential/asset.mjs +221 -0
  431. package/dist/physics/exponential/index.d.mts +1 -0
  432. package/dist/physics/exponential/preset.d.mts +17 -0
  433. package/dist/physics/exponential/preset.mjs +182 -0
  434. package/dist/physics/gas-process/index.d.mts +1 -0
  435. package/dist/physics/gas-process/preset.d.mts +30 -0
  436. package/dist/physics/gas-process/preset.mjs +384 -0
  437. package/dist/physics/gravitation/index.d.mts +1 -0
  438. package/dist/physics/gravitation/preset.d.mts +24 -0
  439. package/dist/physics/gravitation/preset.mjs +345 -0
  440. package/dist/physics/gravity-drop.d.mts +9 -0
  441. package/dist/physics/gravity-drop.mjs +187 -0
  442. package/dist/physics/heat-transfer/index.d.mts +1 -0
  443. package/dist/physics/heat-transfer/preset.d.mts +27 -0
  444. package/dist/physics/heat-transfer/preset.mjs +626 -0
  445. package/dist/physics/impulse/index.d.mts +1 -0
  446. package/dist/physics/impulse/preset.d.mts +29 -0
  447. package/dist/physics/impulse/preset.mjs +453 -0
  448. package/dist/physics/index.d.mts +43 -0
  449. package/dist/physics/index.mjs +44 -0
  450. package/dist/physics/kepler/index.d.mts +1 -0
  451. package/dist/physics/kepler/preset.d.mts +27 -0
  452. package/dist/physics/kepler/preset.mjs +257 -0
  453. package/dist/physics/lever/asset.d.mts +6 -0
  454. package/dist/physics/lever/asset.mjs +220 -0
  455. package/dist/physics/lever/index.d.mts +2 -0
  456. package/dist/physics/lever/preset.d.mts +31 -0
  457. package/dist/physics/lever/preset.mjs +261 -0
  458. package/dist/physics/lorentz/index.d.mts +1 -0
  459. package/dist/physics/lorentz/preset.d.mts +29 -0
  460. package/dist/physics/lorentz/preset.mjs +367 -0
  461. package/dist/physics/magnetism/index.d.mts +1 -0
  462. package/dist/physics/magnetism/preset.d.mts +15 -0
  463. package/dist/physics/magnetism/preset.mjs +334 -0
  464. package/dist/physics/optics/asset.d.mts +6 -0
  465. package/dist/physics/optics/asset.mjs +234 -0
  466. package/dist/physics/optics/index.d.mts +2 -0
  467. package/dist/physics/optics/preset.d.mts +14 -0
  468. package/dist/physics/optics/preset.mjs +202 -0
  469. package/dist/physics/orbit-lab.d.mts +6 -0
  470. package/dist/physics/orbit-lab.mjs +222 -0
  471. package/dist/physics/projectile-lab.d.mts +10 -0
  472. package/dist/physics/projectile-lab.mjs +354 -0
  473. package/dist/physics/rain-relative/index.d.mts +1 -0
  474. package/dist/physics/rain-relative/preset.d.mts +19 -0
  475. package/dist/physics/rain-relative/preset.mjs +358 -0
  476. package/dist/physics/ramp-forces/index.d.mts +1 -0
  477. package/dist/physics/ramp-forces/preset.d.mts +36 -0
  478. package/dist/physics/ramp-forces/preset.mjs +550 -0
  479. package/dist/physics/river-boat.d.mts +22 -0
  480. package/dist/physics/river-boat.mjs +498 -0
  481. package/dist/physics/shm/index.d.mts +1 -0
  482. package/dist/physics/shm/preset.d.mts +33 -0
  483. package/dist/physics/shm/preset.mjs +554 -0
  484. package/dist/physics/stopping-distance/index.d.mts +1 -0
  485. package/dist/physics/stopping-distance/preset.d.mts +29 -0
  486. package/dist/physics/stopping-distance/preset.mjs +662 -0
  487. package/dist/physics/temperature-scales/index.d.mts +1 -0
  488. package/dist/physics/temperature-scales/preset.d.mts +15 -0
  489. package/dist/physics/temperature-scales/preset.mjs +353 -0
  490. package/dist/physics/terminal-velocity/index.d.mts +1 -0
  491. package/dist/physics/terminal-velocity/preset.d.mts +26 -0
  492. package/dist/physics/terminal-velocity/preset.mjs +404 -0
  493. package/dist/physics/thermal/index.d.mts +1 -0
  494. package/dist/physics/thermal/preset.d.mts +44 -0
  495. package/dist/physics/thermal/preset.mjs +373 -0
  496. package/dist/physics/vector-board/index.d.mts +1 -0
  497. package/dist/physics/vector-board/preset.d.mts +65 -0
  498. package/dist/physics/vector-board/preset.mjs +273 -0
  499. package/dist/physics/vector-board/view.d.mts +49 -0
  500. package/dist/physics/vector-board/view.mjs +58 -0
  501. package/dist/physics/vector-scene.d.mts +41 -0
  502. package/dist/physics/vector-scene.mjs +211 -0
  503. package/dist/physics/vector-types/index.d.mts +1 -0
  504. package/dist/physics/vector-types/preset.d.mts +27 -0
  505. package/dist/physics/vector-types/preset.mjs +192 -0
  506. package/dist/physics/water-density/index.d.mts +1 -0
  507. package/dist/physics/water-density/preset.d.mts +18 -0
  508. package/dist/physics/water-density/preset.mjs +439 -0
  509. package/dist/physics/waves/core.mjs +33 -0
  510. package/dist/physics/waves/doppler.d.mts +23 -0
  511. package/dist/physics/waves/doppler.mjs +260 -0
  512. package/dist/physics/waves/index.d.mts +4 -0
  513. package/dist/physics/waves/preset.d.mts +30 -0
  514. package/dist/physics/waves/preset.mjs +488 -0
  515. package/dist/physics/waves/ripple.d.mts +26 -0
  516. package/dist/physics/waves/ripple.mjs +234 -0
  517. package/dist/physics/waves/string.d.mts +29 -0
  518. package/dist/physics/waves/string.mjs +289 -0
  519. package/dist/physics/work-energy/index.d.mts +1 -0
  520. package/dist/physics/work-energy/preset.d.mts +17 -0
  521. package/dist/physics/work-energy/preset.mjs +341 -0
  522. package/dist/schemas/index.d.mts +235 -0
  523. package/dist/schemas/index.mjs +145 -0
  524. package/dist/statistics/center-spread/preset.d.mts +34 -0
  525. package/dist/statistics/center-spread/preset.mjs +323 -0
  526. package/dist/statistics/core/descriptive.d.mts +35 -0
  527. package/dist/statistics/core/descriptive.mjs +64 -0
  528. package/dist/statistics/core/normal.d.mts +21 -0
  529. package/dist/statistics/core/normal.mjs +37 -0
  530. package/dist/statistics/core/sequences.d.mts +27 -0
  531. package/dist/statistics/core/sequences.mjs +35 -0
  532. package/dist/statistics/galton/preset.d.mts +27 -0
  533. package/dist/statistics/galton/preset.mjs +331 -0
  534. package/dist/statistics/histogram/preset.d.mts +27 -0
  535. package/dist/statistics/histogram/preset.mjs +385 -0
  536. package/dist/statistics/index.d.mts +11 -0
  537. package/dist/statistics/index.mjs +12 -0
  538. package/dist/statistics/normal/preset.d.mts +30 -0
  539. package/dist/statistics/normal/preset.mjs +400 -0
  540. package/dist/statistics/sampling/preset.d.mts +32 -0
  541. package/dist/statistics/sampling/preset.mjs +406 -0
  542. package/dist/statistics/sequence/preset.d.mts +28 -0
  543. package/dist/statistics/sequence/preset.mjs +302 -0
  544. package/dist/statistics/z-table/preset.d.mts +28 -0
  545. package/dist/statistics/z-table/preset.mjs +348 -0
  546. package/package.json +266 -0
  547. package/styles.css +267 -0
package/package.json ADDED
@@ -0,0 +1,266 @@
1
+ {
2
+ "name": "@classytic/labs",
3
+ "version": "0.1.0",
4
+ "description": "Interactive learning lab — authorable, domain-organized interactive lessons (math, physics, chemistry, circuits, geometry…) built on the @classytic/stage engine. Per-domain subpaths; lesson blocks + presets creators compose and sell.",
5
+ "author": "Classytic",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "sideEffects": [
9
+ "**/*.css"
10
+ ],
11
+ "engines": {
12
+ "node": ">=22"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.mts",
20
+ "default": "./dist/index.mjs"
21
+ },
22
+ "./core": {
23
+ "types": "./dist/core/index.d.mts",
24
+ "default": "./dist/core/index.mjs"
25
+ },
26
+ "./physics": {
27
+ "types": "./dist/physics/index.d.mts",
28
+ "default": "./dist/physics/index.mjs"
29
+ },
30
+ "./math": {
31
+ "types": "./dist/math/index.d.mts",
32
+ "default": "./dist/math/index.mjs"
33
+ },
34
+ "./chem": {
35
+ "types": "./dist/chem/index.d.mts",
36
+ "default": "./dist/chem/index.mjs"
37
+ },
38
+ "./circuits": {
39
+ "types": "./dist/circuits/index.d.mts",
40
+ "default": "./dist/circuits/index.mjs"
41
+ },
42
+ "./geometry": {
43
+ "types": "./dist/geometry/index.d.mts",
44
+ "default": "./dist/geometry/index.mjs"
45
+ },
46
+ "./language": {
47
+ "types": "./dist/language/index.d.mts",
48
+ "default": "./dist/language/index.mjs"
49
+ },
50
+ "./ict": {
51
+ "types": "./dist/ict/index.d.mts",
52
+ "default": "./dist/ict/index.mjs"
53
+ },
54
+ "./commerce": {
55
+ "types": "./dist/commerce/index.d.mts",
56
+ "default": "./dist/commerce/index.mjs"
57
+ },
58
+ "./biology": {
59
+ "types": "./dist/biology/index.d.mts",
60
+ "default": "./dist/biology/index.mjs"
61
+ },
62
+ "./geography": {
63
+ "types": "./dist/geography/index.d.mts",
64
+ "default": "./dist/geography/index.mjs"
65
+ },
66
+ "./discrete": {
67
+ "types": "./dist/discrete/index.d.mts",
68
+ "default": "./dist/discrete/index.mjs"
69
+ },
70
+ "./statistics": {
71
+ "types": "./dist/statistics/index.d.mts",
72
+ "default": "./dist/statistics/index.mjs"
73
+ },
74
+ "./ml": {
75
+ "types": "./dist/ml/index.d.mts",
76
+ "default": "./dist/ml/index.mjs"
77
+ },
78
+ "./catalog": {
79
+ "types": "./dist/catalog/index.d.mts",
80
+ "default": "./dist/catalog/index.mjs"
81
+ },
82
+ "./kit": {
83
+ "types": "./dist/kit/index.d.mts",
84
+ "default": "./dist/kit/index.mjs"
85
+ },
86
+ "./blocks": {
87
+ "types": "./dist/blocks/index.d.mts",
88
+ "default": "./dist/blocks/index.mjs"
89
+ },
90
+ "./blocks/lesson": {
91
+ "types": "./dist/blocks/lesson.d.mts",
92
+ "default": "./dist/blocks/lesson.mjs"
93
+ },
94
+ "./blocks/math": {
95
+ "types": "./dist/blocks/math.d.mts",
96
+ "default": "./dist/blocks/math.mjs"
97
+ },
98
+ "./blocks/physics": {
99
+ "types": "./dist/blocks/physics.d.mts",
100
+ "default": "./dist/blocks/physics.mjs"
101
+ },
102
+ "./blocks/chem": {
103
+ "types": "./dist/blocks/chem.d.mts",
104
+ "default": "./dist/blocks/chem.mjs"
105
+ },
106
+ "./blocks/circuits": {
107
+ "types": "./dist/blocks/circuits.d.mts",
108
+ "default": "./dist/blocks/circuits.mjs"
109
+ },
110
+ "./blocks/geometry": {
111
+ "types": "./dist/blocks/geometry.d.mts",
112
+ "default": "./dist/blocks/geometry.mjs"
113
+ },
114
+ "./blocks/ict": {
115
+ "types": "./dist/blocks/ict.d.mts",
116
+ "default": "./dist/blocks/ict.mjs"
117
+ },
118
+ "./blocks/language": {
119
+ "types": "./dist/blocks/language.d.mts",
120
+ "default": "./dist/blocks/language.mjs"
121
+ },
122
+ "./blocks/accounting": {
123
+ "types": "./dist/blocks/accounting.d.mts",
124
+ "default": "./dist/blocks/accounting.mjs"
125
+ },
126
+ "./blocks/economics": {
127
+ "types": "./dist/blocks/economics.d.mts",
128
+ "default": "./dist/blocks/economics.mjs"
129
+ },
130
+ "./blocks/biology": {
131
+ "types": "./dist/blocks/biology.d.mts",
132
+ "default": "./dist/blocks/biology.mjs"
133
+ },
134
+ "./blocks/geography": {
135
+ "types": "./dist/blocks/geography.d.mts",
136
+ "default": "./dist/blocks/geography.mjs"
137
+ },
138
+ "./blocks/ml": {
139
+ "types": "./dist/blocks/ml.d.mts",
140
+ "default": "./dist/blocks/ml.mjs"
141
+ },
142
+ "./blocks/discrete": {
143
+ "types": "./dist/blocks/discrete.d.mts",
144
+ "default": "./dist/blocks/discrete.mjs"
145
+ },
146
+ "./blocks/statistics": {
147
+ "types": "./dist/blocks/statistics.d.mts",
148
+ "default": "./dist/blocks/statistics.mjs"
149
+ },
150
+ "./schemas": {
151
+ "types": "./dist/schemas/index.d.mts",
152
+ "default": "./dist/schemas/index.mjs"
153
+ },
154
+ "./styles.css": "./styles.css",
155
+ "./package.json": "./package.json"
156
+ },
157
+ "main": "./dist/index.mjs",
158
+ "module": "./dist/index.mjs",
159
+ "types": "./dist/index.d.mts",
160
+ "files": [
161
+ "dist",
162
+ "styles.css",
163
+ "LICENSE",
164
+ "README.md"
165
+ ],
166
+ "repository": {
167
+ "type": "git",
168
+ "url": "git+https://github.com/classytic/labs.git"
169
+ },
170
+ "homepage": "https://github.com/classytic/labs#readme",
171
+ "scripts": {
172
+ "build": "tsdown",
173
+ "dev": "tsdown --watch",
174
+ "typecheck": "tsc --noEmit",
175
+ "test:unit": "vitest run tests/core.test.ts tests/catalog.test.ts tests/stage-templates.test.ts",
176
+ "test:package": "vitest run tests/widgets.test.tsx",
177
+ "pretest": "npm run build",
178
+ "test": "vitest run",
179
+ "test:watch": "vitest",
180
+ "gallery": "npm run build && node tests/gallery/rasterize.mjs",
181
+ "gallery:svg": "vitest run tests/gallery.test.tsx",
182
+ "lint": "tsc --noEmit",
183
+ "verify": "npm run typecheck && npm test",
184
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
185
+ "changeset": "changeset",
186
+ "version-packages": "changeset version",
187
+ "release": "npm run build && changeset publish",
188
+ "push": "classytic-push",
189
+ "prepublishOnly": "npm run typecheck && npm run build && npm test"
190
+ },
191
+ "peerDependencies": {
192
+ "@classytic/cms": ">=0.2.1",
193
+ "@classytic/cms-ui": ">=0.3.1",
194
+ "@classytic/stage": ">=0.1.0",
195
+ "clsx": ">=2",
196
+ "katex": ">=0.16",
197
+ "lucide-react": ">=0.4",
198
+ "react": ">=19",
199
+ "react-dom": ">=19",
200
+ "tailwind-merge": ">=3",
201
+ "zod": ">=4"
202
+ },
203
+ "peerDependenciesMeta": {
204
+ "lucide-react": {
205
+ "optional": true
206
+ },
207
+ "zod": {
208
+ "optional": true
209
+ },
210
+ "katex": {
211
+ "optional": true
212
+ },
213
+ "@classytic/cms-ui": {
214
+ "optional": true
215
+ },
216
+ "@classytic/cms": {
217
+ "optional": true
218
+ }
219
+ },
220
+ "devDependencies": {
221
+ "@changesets/cli": "^2.27.9",
222
+ "@classytic/cms-ui": "^0.3.1",
223
+ "@classytic/dev-tools": "^0.2.0",
224
+ "@classytic/stage": "^0.1.0",
225
+ "@testing-library/react": "^16.3.2",
226
+ "@types/node": "^22.0.0",
227
+ "@types/react": "^19.2.0",
228
+ "@types/react-dom": "^19.2.0",
229
+ "clsx": "^2.1.1",
230
+ "happy-dom": "^20.0.0",
231
+ "lucide-react": "^0.563.0",
232
+ "mafs": "^0.21.0",
233
+ "playwright": "^1.61.0",
234
+ "react": "^19.2.0",
235
+ "react-dom": "^19.2.0",
236
+ "tailwind-merge": "^3.5.0",
237
+ "tsdown": "^0.22.0",
238
+ "typescript": "^5.7.0",
239
+ "vitest": "^4.1.0",
240
+ "zod": "^4.1.0"
241
+ },
242
+ "keywords": [
243
+ "react",
244
+ "visualization",
245
+ "interactive",
246
+ "education",
247
+ "learning",
248
+ "math",
249
+ "calculus",
250
+ "derivative",
251
+ "integral",
252
+ "limit",
253
+ "gradient-descent",
254
+ "physics",
255
+ "chemistry",
256
+ "equation",
257
+ "graph",
258
+ "plot",
259
+ "symbolic-math",
260
+ "katex",
261
+ "canvas",
262
+ "manim",
263
+ "desmos",
264
+ "science"
265
+ ]
266
+ }
package/styles.css ADDED
@@ -0,0 +1,267 @@
1
+ /**
2
+ * @classytic/labs — theme tokens + control-UI kit CSS.
3
+ *
4
+ * Import once in your app's global CSS (after `@import "tailwindcss";`):
5
+ * @import "@classytic/labs/styles.css";
6
+ *
7
+ * Ships NO precompiled utility CSS — `@source` lets YOUR build scan the package
8
+ * for Tailwind classes. The `:root` tokens are overridable defaults. The
9
+ * `.lab-*` control kit consumes the HOST's shadcn tokens (--foreground/--border/
10
+ * --primary/--muted/--success…) with literal fallbacks, so it adopts your theme
11
+ * + dark mode automatically — override those in your own globals.css.
12
+ */
13
+
14
+ @source "./dist/**/*.mjs";
15
+
16
+ :root {
17
+ /* Legacy canvas compatibility tokens (used by widgets not yet migrated to stage). */
18
+ --sciviz-stage: oklch(0.16 0.02 255);
19
+ --sciviz-grid: oklch(0.55 0.02 255 / 0.5);
20
+ --sciviz-axis: oklch(0.7 0.02 255);
21
+ --sciviz-accent: oklch(0.72 0.15 250);
22
+ --sciviz-accent-2: oklch(0.78 0.16 50);
23
+ --sciviz-good: oklch(0.72 0.17 150);
24
+ /* Previously referenced in code with only inline fallbacks — define them so
25
+ legacy widgets theme correctly until migrated to stage. DEPRECATED. */
26
+ --sciviz-text: oklch(0.92 0.01 255);
27
+ --sciviz-text-dim: oklch(0.7 0.02 255);
28
+ --sciviz-warn: oklch(0.82 0.16 85);
29
+ }
30
+
31
+ /* ── Control-UI kit ─────────────────────────────────────────────────────────
32
+ Shipped (not runtime-injected). Consumes host shadcn tokens; fallbacks keep
33
+ it usable standalone. Override via your globals.css like any shadcn component. */
34
+ .lab-bar { display: flex; align-items: center; gap: 13px; flex-wrap: wrap; padding: 12px 2px 2px; font-size: 14px; color: var(--foreground, currentColor); }
35
+ .lab-bar .sep { opacity: .6; }
36
+ .lab-stepper { display: inline-flex; align-items: center; border: 1.5px solid var(--border, color-mix(in oklab, currentColor 28%, transparent)); border-radius: 11px; overflow: hidden; background: var(--muted, color-mix(in oklab, currentColor 6%, transparent)); }
37
+ .lab-stepper button { width: 32px; height: 32px; border: 0; background: transparent; color: inherit; font-size: 18px; font-weight: 700; line-height: 1; cursor: pointer; transition: background .12s; display: flex; align-items: center; justify-content: center; }
38
+ .lab-stepper button:hover { background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 18%, transparent); }
39
+ .lab-stepper button:active { background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 32%, transparent); }
40
+ .lab-stepper b { min-width: 30px; text-align: center; font-size: 16px; font-weight: 800; padding: 0 4px; font-variant-numeric: tabular-nums; }
41
+ .lab-btn { padding: 9px 22px; border-radius: 999px; border: 0; background: var(--primary, oklch(0.59 0.22 261)); color: var(--primary-foreground, #fff); font-weight: 700; font-size: 14px; cursor: pointer; transition: transform .1s, filter .12s; }
42
+ .lab-btn:hover:not(:disabled) { filter: brightness(1.07); }
43
+ .lab-btn:active:not(:disabled) { transform: translateY(1px); }
44
+ .lab-btn:disabled { opacity: .45; cursor: not-allowed; }
45
+ .lab-pill { font-weight: 700; padding: 5px 13px; border-radius: 999px; font-size: 13px; }
46
+ .lab-pill[data-state="ok"] { color: var(--success, oklch(0.62 0.17 150)); background: color-mix(in oklab, var(--success, oklch(0.62 0.17 150)) 15%, transparent); }
47
+ .lab-pill[data-state="no"] { color: var(--muted-foreground, color-mix(in oklab, currentColor 60%, transparent)); background: var(--muted, color-mix(in oklab, currentColor 8%, transparent)); }
48
+ .lab-chip { padding: 10px 14px; border-radius: 10px; border: 1.5px solid var(--border, color-mix(in oklab, currentColor 28%, transparent)); background: transparent; color: inherit; font-size: 14px; font-weight: 600; cursor: pointer; transition: background .12s, border-color .12s; }
49
+ .lab-chip:hover { border-color: var(--primary, oklch(0.59 0.22 261)); }
50
+ .lab-chip[data-sel="true"] { border-color: var(--primary, oklch(0.59 0.22 261)); background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 14%, transparent); }
51
+ .lab-slider { -webkit-appearance: none; appearance: none; height: 6px; border-radius: 999px; background: var(--muted, color-mix(in oklab, currentColor 18%, transparent)); outline: none; cursor: pointer; }
52
+ .lab-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; border-radius: 50%; background: var(--primary, oklch(0.59 0.22 261)); border: 2px solid var(--background, #fff); box-shadow: 0 1px 3px rgba(0, 0, 0, .3); cursor: pointer; }
53
+ .lab-slider::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: var(--primary, oklch(0.59 0.22 261)); border: 2px solid var(--background, #fff); cursor: pointer; }
54
+ .lab-slider:focus-visible { outline: 2px solid var(--primary, oklch(0.59 0.22 261)); outline-offset: 3px; }
55
+
56
+ /* ── pedagogy kit (objectives / hints / misconception) ──────────────────────── */
57
+ .lab-objectives { margin: 0 0 12px; padding: 8px 12px; border-radius: 10px; border: 1px solid var(--border, color-mix(in oklab, currentColor 18%, transparent)); background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 6%, transparent); }
58
+ .lab-objectives-h { font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted-foreground, color-mix(in oklab, currentColor 60%, transparent)); }
59
+ .lab-objectives ul { margin: 4px 0 0; padding-left: 18px; }
60
+ .lab-objectives li { font-size: 13.5px; color: var(--foreground, currentColor); margin: 1px 0; }
61
+ .lab-hints { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
62
+ .lab-hint { margin: 0; font-size: 13.5px; color: var(--foreground, currentColor); padding: 7px 11px; border-radius: 9px; background: color-mix(in oklab, var(--warning, oklch(0.8 0.16 85)) 16%, transparent); max-width: 60ch; }
63
+ .lab-hint-btn { align-self: flex-start; padding: 6px 14px; border-radius: 999px; border: 1.5px dashed var(--border, color-mix(in oklab, currentColor 30%, transparent)); background: transparent; color: var(--muted-foreground, color-mix(in oklab, currentColor 60%, transparent)); font-size: 13px; font-weight: 600; cursor: pointer; transition: border-color .12s, color .12s; }
64
+ .lab-hint-btn:hover { border-color: var(--primary, oklch(0.59 0.22 261)); color: var(--foreground, currentColor); }
65
+ .lab-misconception { font-size: 13.5px; font-weight: 600; padding: 5px 12px; border-radius: 999px; color: var(--warning-foreground, oklch(0.45 0.13 75)); background: color-mix(in oklab, var(--warning, oklch(0.8 0.16 85)) 22%, transparent); }
66
+
67
+ /* shared "Show answer" escape hatch (kit/pedagogy RevealSolution) */
68
+ .lab-reveal-btn { align-self: flex-start; padding: 5px 12px; border-radius: 999px; border: 1.5px dashed var(--border, color-mix(in oklab, currentColor 30%, transparent)); background: transparent; color: var(--muted-foreground, color-mix(in oklab, currentColor 60%, transparent)); font-size: 12.5px; font-weight: 600; cursor: pointer; transition: border-color .12s, color .12s; }
69
+ .lab-reveal-btn:hover { border-color: var(--warning, oklch(0.8 0.16 85)); color: var(--foreground, currentColor); }
70
+ .lab-solution { margin-top: 8px; max-width: 64ch; padding: 8px 12px; border-radius: 10px; border: 1px solid color-mix(in oklab, var(--warning, oklch(0.8 0.16 85)) 45%, transparent); background: color-mix(in oklab, var(--warning, oklch(0.8 0.16 85)) 12%, transparent); }
71
+ .lab-solution-h { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--warning-foreground, oklch(0.45 0.13 75)); }
72
+ .lab-solution-body { margin-top: 4px; font-size: 14px; font-weight: 600; color: var(--foreground, currentColor); }
73
+ .lab-solution-note { margin: 4px 0 0; font-size: 11px; opacity: .7; }
74
+
75
+ /* ── Challenge: the shared predict / classify / explain activity (kit/pedagogy) ── */
76
+ .lab-challenge { display: flex; flex-direction: column; gap: 12px; max-width: 64ch; padding: 12px 14px; border-radius: 12px; border: 1px solid var(--border, color-mix(in oklab, currentColor 14%, transparent)); background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 5%, transparent); }
77
+ .lab-challenge-h { font-size: 11px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--muted-foreground, color-mix(in oklab, currentColor 60%, transparent)); }
78
+ .lab-challenge-count { font-variant-numeric: tabular-nums; }
79
+ .lab-challenge-q { display: flex; flex-direction: column; gap: 7px; align-items: flex-start; }
80
+ .lab-challenge-prompt { font-size: 14px; font-weight: 600; color: var(--foreground, currentColor); }
81
+ .lab-choices { display: flex; flex-wrap: wrap; gap: 8px; }
82
+ .lab-choice { padding: 7px 14px; border-radius: 999px; border: 1.5px solid var(--border, color-mix(in oklab, currentColor 22%, transparent)); background: var(--card, transparent); color: var(--foreground, currentColor); font-size: 13.5px; font-weight: 600; cursor: pointer; transition: border-color .12s, background .12s, color .12s; }
83
+ .lab-choice:hover { border-color: var(--primary, oklch(0.59 0.22 261)); }
84
+ .lab-choice[data-picked] { border-color: var(--primary, oklch(0.59 0.22 261)); background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 12%, transparent); }
85
+ .lab-choice[data-tone="correct"] { border-color: var(--success, oklch(0.62 0.17 150)); background: color-mix(in oklab, var(--success, oklch(0.62 0.17 150)) 16%, transparent); color: var(--success, oklch(0.62 0.17 150)); }
86
+ .lab-choice[data-tone="wrong"] { border-color: var(--destructive, oklch(0.58 0.22 27)); background: color-mix(in oklab, var(--destructive, oklch(0.58 0.22 27)) 14%, transparent); color: var(--destructive, oklch(0.58 0.22 27)); }
87
+
88
+ /* AskBox — typed-answer + Check (engine + representation plug-ins) */
89
+ .lab-ask-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
90
+ .lab-input { padding: 7px 11px; border-radius: 9px; border: 1.5px solid var(--border, color-mix(in oklab, currentColor 22%, transparent)); background: var(--card, transparent); color: var(--foreground, currentColor); font-size: 14px; min-width: 140px; font-variant-numeric: tabular-nums; }
91
+ .lab-input:focus { outline: none; border-color: var(--primary, oklch(0.59 0.22 261)); }
92
+
93
+ /* ── Lab frame — the shared layout shell every lab composes into ──────────────
94
+ ONE consistent grid: header (title + one-line prompt) → figure-dominant body
95
+ (+ optional narrow aside) → a single controls bar → a quiet footer. Replaces
96
+ the per-lab inline-styled layouts that made labs look like different products.
97
+ All spacing/type/colour from tokens; objectives collapse (reveal-on-action). */
98
+ .lab-frame { display: flex; flex-direction: column; gap: 16px; color: var(--foreground, currentColor); }
99
+ .lab-frame-head { display: flex; flex-direction: column; gap: 3px; }
100
+ .lab-title { margin: 0; font-size: 18px; font-weight: 750; letter-spacing: -0.01em; color: var(--foreground, currentColor); }
101
+ .lab-prompt { margin: 0; font-size: 14px; line-height: 1.45; color: var(--muted-foreground, color-mix(in oklab, currentColor 58%, transparent)); }
102
+ .lab-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; align-items: start; }
103
+ .lab-body[data-aside="true"] { grid-template-columns: minmax(0, 1.25fr) minmax(220px, 0.75fr); }
104
+ @media (max-width: 680px) { .lab-body[data-aside="true"] { grid-template-columns: minmax(0, 1fr); } }
105
+ .lab-figure { min-width: 0; }
106
+ .lab-aside { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
107
+ /* one tidy responsive grid — fields align in columns instead of ragged wrapping */
108
+ .lab-controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(185px, 1fr)); gap: 14px 20px; align-items: end; padding: 14px 16px; border-radius: 14px; border: 1px solid var(--border, color-mix(in oklab, currentColor 12%, transparent)); background: var(--muted, color-mix(in oklab, currentColor 4%, transparent)); }
109
+ /* actions/status (anything that isn't a labelled Field) sit left in their cell, never stretched,
110
+ and align to the SAME bottom baseline as the labelled fields so a mixed control bar reads as one row */
111
+ .lab-controls > :not(.lab-field) { justify-self: start; align-self: end; }
112
+ /* a Field's inline chip-group row wraps inside its cell instead of overflowing onto the next control */
113
+ .lab-field-row { flex-wrap: wrap; }
114
+ .lab-foot { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
115
+
116
+ /* a labelled control: small caps label, then control + value on one row, filling its cell */
117
+ .lab-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
118
+ .lab-field-label { font-size: 11px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted-foreground, color-mix(in oklab, currentColor 55%, transparent)); }
119
+ .lab-field-row { display: inline-flex; align-items: center; gap: 9px; }
120
+ /* inside a Field the row fills the cell so the slider can grow and the value pins right */
121
+ .lab-field > .lab-field-row { display: flex; width: 100%; }
122
+ .lab-field-val { font-size: 14px; font-weight: 800; font-variant-numeric: tabular-nums; min-width: 3.4em; text-align: right; }
123
+ .lab-field > .lab-field-row > .lab-field-val { margin-left: auto; }
124
+ .lab-field .lab-slider { flex: 1 1 auto; width: auto; min-width: 60px; }
125
+ /* creator-locked control: visible but frozen (the interactive subtree is `inert`) */
126
+ .lab-locked-wrap { display: contents; }
127
+ .lab-field[data-locked="true"] .lab-field-row { opacity: .62; }
128
+ .lab-field-lock { display: inline-block; width: .82em; height: .82em; margin-left: .3em; vertical-align: -.05em; opacity: .7; }
129
+
130
+ /* highlighted readout — replaces ad-hoc inline-styled boxes */
131
+ .lab-callout { padding: 10px 14px; border-radius: 12px; font-size: 14px; line-height: 1.55; border: 1px solid var(--border, color-mix(in oklab, currentColor 12%, transparent)); background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 6%, transparent); }
132
+ .lab-callout[data-tone="result"] { border-color: color-mix(in oklab, var(--success, oklch(0.62 0.17 150)) 38%, transparent); background: color-mix(in oklab, var(--success, oklch(0.62 0.17 150)) 10%, transparent); }
133
+ .lab-callout-big { display: block; margin-top: 2px; font-size: 22px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--success, oklch(0.62 0.17 150)); }
134
+
135
+ /* goals — a collapsed disclosure, NOT an upfront wall of text */
136
+ .lab-goals { font-size: 13px; }
137
+ .lab-goals > summary { cursor: pointer; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted-foreground, color-mix(in oklab, currentColor 52%, transparent)); list-style: none; user-select: none; }
138
+ .lab-goals > summary::-webkit-details-marker { display: none; }
139
+ .lab-goals > summary::before { content: "▸ "; }
140
+ .lab-goals[open] > summary::before { content: "▾ "; }
141
+ .lab-goals ul { margin: 6px 0 0; padding-left: 18px; }
142
+ .lab-goals li { margin: 2px 0; color: var(--foreground, currentColor); }
143
+
144
+ /* ── Play-gate for hand-driven sim labs (press-to-start + off-screen pause) ──── */
145
+ .lab-playwrap { position: relative; }
146
+ /* one small play/pause toggle, top-right — never covers the figure */
147
+ .lab-play-toggle { position: absolute; top: 10px; right: 10px; z-index: 2; display: inline-flex; align-items: center; gap: 6px; min-width: 34px; height: 32px; padding: 0 12px; border-radius: 999px; border: 1px solid var(--border, color-mix(in oklab, currentColor 22%, transparent)); background: color-mix(in oklab, var(--background, #fff) 88%, transparent); color: var(--foreground, currentColor); cursor: pointer; font-size: 13px; font-weight: 700; box-shadow: 0 1px 4px rgba(0, 0, 0, .14); transition: filter .12s, transform .1s; }
148
+ .lab-play-toggle:hover { filter: brightness(1.05); }
149
+ .lab-play-toggle:active { transform: translateY(1px); }
150
+ .lab-play-toggle[data-playing="false"] { background: var(--primary, oklch(0.59 0.22 261)); color: #fff; border-color: transparent; }
151
+
152
+ /* ── In-lab stepper (teach one idea at a time) ──────────────────────────────── */
153
+ .lab-step-caption { margin: 0 0 14px; font-size: 17px; line-height: 1.5; font-weight: 600; color: var(--foreground, currentColor); max-width: 62ch; }
154
+ .lab-stepnav { display: flex; align-items: center; gap: 14px; }
155
+ .lab-btn-ghost { background: transparent; color: var(--foreground, currentColor); border: 1.5px solid var(--border, color-mix(in oklab, currentColor 24%, transparent)); }
156
+ .lab-btn-ghost:hover:not(:disabled) { filter: none; background: var(--muted, color-mix(in oklab, currentColor 7%, transparent)); }
157
+ .lab-dots { display: inline-flex; gap: 7px; }
158
+ .lab-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--border, color-mix(in oklab, currentColor 22%, transparent)); transition: background .2s; }
159
+ .lab-dot[data-on="true"] { background: var(--primary, oklch(0.59 0.22 261)); }
160
+
161
+ /* ── Language labs ───────────────────────────────────────────────────────────
162
+ Part-of-speech colours (Montessori-inspired, overridable). Tuned dark enough
163
+ for white tile text in both light + dark themes. Plus the .lang-* DOM kit. */
164
+ :root {
165
+ --lang-pos-noun: oklch(0.50 0.13 264);
166
+ --lang-pos-verb: oklch(0.53 0.20 25);
167
+ --lang-pos-article: oklch(0.52 0.13 150);
168
+ --lang-pos-adjective: oklch(0.55 0.13 60);
169
+ --lang-pos-preposition: oklch(0.52 0.13 235);
170
+ --lang-pos-pronoun: oklch(0.52 0.18 300);
171
+ --lang-pos-conjunction: oklch(0.55 0.18 350);
172
+ --lang-pos-adverb: oklch(0.52 0.12 195);
173
+ --lang-pos-other: oklch(0.50 0.02 260);
174
+ }
175
+
176
+ .lang-lab { position: relative; }
177
+ .lang-title { font-weight: 600; margin: 0 0 2px; color: var(--foreground, currentColor); }
178
+ .lang-hint { font-size: 13px; opacity: .72; margin: 0 0 10px; }
179
+ .lang-prompt { font-size: 19px; font-weight: 600; margin: 0 0 12px; color: var(--foreground, currentColor); }
180
+
181
+ /* POS-coloured word tile */
182
+ .lang-tile { display: inline-flex; flex-direction: column; align-items: center; gap: 1px; padding: 8px 14px; border: 0; border-radius: 12px; background: var(--pos, var(--lang-pos-other)); color: #fff; font-weight: 700; font-size: 16px; line-height: 1.15; cursor: pointer; box-shadow: 0 1px 2px rgba(0,0,0,.18); transition: transform .1s, filter .12s, box-shadow .12s; }
183
+ .lang-tile:hover { filter: brightness(1.08); }
184
+ .lang-tile:active { transform: translateY(1px); }
185
+ .lang-tile:focus-visible { outline: 2px solid var(--ring, var(--primary, oklch(0.59 0.22 261))); outline-offset: 2px; }
186
+ .lang-tile[data-sel="true"] { box-shadow: 0 0 0 3px color-mix(in oklab, var(--pos) 55%, transparent); }
187
+ .lang-tile[data-dim="true"] { opacity: .4; }
188
+ .lang-tile-text { font-size: 16px; }
189
+ .lang-tile-gloss { font-size: 11px; font-weight: 600; opacity: .82; }
190
+
191
+ /* the line being built + the bank */
192
+ .lang-line { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; min-height: 56px; padding: 12px; border-radius: 14px; border: 2px dashed var(--border, color-mix(in oklab, currentColor 28%, transparent)); background: var(--muted, color-mix(in oklab, currentColor 5%, transparent)); transition: border-color .15s, background .15s; }
193
+ .lang-line[data-state="ok"] { border-style: solid; border-color: var(--success, oklch(0.62 0.17 150)); background: color-mix(in oklab, var(--success, oklch(0.62 0.17 150)) 10%, transparent); }
194
+ .lang-line[data-state="no"] { border-color: var(--destructive, oklch(0.58 0.22 25)); }
195
+ .lang-line-empty { font-size: 13px; opacity: .55; }
196
+ .lang-bank { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
197
+
198
+ /* speaker button */
199
+ .lang-speak { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; margin-inline-start: 2px; border: 0; border-radius: 999px; background: color-mix(in oklab, currentColor 12%, transparent); color: inherit; font-size: 13px; cursor: pointer; transition: background .12s; }
200
+ .lang-speak:hover { background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 22%, transparent); }
201
+
202
+ /* matching grid */
203
+ .lang-match { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 28px; max-width: 520px; }
204
+ .lang-col { display: flex; flex-direction: column; gap: 8px; }
205
+ .lang-match-row { position: relative; display: flex; align-items: center; }
206
+ .lang-match-row .lang-match-cell { flex: 1; padding-right: 38px; }
207
+ .lang-match-row .lang-speak { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); margin: 0; }
208
+ .lang-match-cell { display: flex; align-items: center; justify-content: center; gap: 6px; position: relative; padding: 12px 14px; border: 1.5px solid var(--border, color-mix(in oklab, currentColor 28%, transparent)); border-radius: 12px; background: var(--card, var(--background, transparent)); color: var(--foreground, inherit); font-size: 15px; font-weight: 600; cursor: pointer; transition: border-color .12s, background .12s, transform .1s; }
209
+ .lang-match-cell:hover:not(:disabled) { border-color: var(--primary, oklch(0.59 0.22 261)); }
210
+ .lang-match-cell[data-state="sel"] { border-color: var(--primary, oklch(0.59 0.22 261)); background: color-mix(in oklab, var(--primary, oklch(0.59 0.22 261)) 12%, transparent); }
211
+ .lang-match-cell[data-state="ok"] { border-color: var(--success, oklch(0.62 0.17 150)); background: color-mix(in oklab, var(--success, oklch(0.62 0.17 150)) 14%, transparent); cursor: default; }
212
+ .lang-match-cell[data-state="no"] { border-color: var(--destructive, oklch(0.58 0.22 25)); background: color-mix(in oklab, var(--destructive, oklch(0.58 0.22 25)) 12%, transparent); animation: lang-shake .42s; }
213
+ .lang-match-cell:disabled { cursor: default; }
214
+ .lang-cell-sub { font-size: 11px; opacity: .6; font-weight: 500; }
215
+ .lang-cell-icon { font-size: 36px; line-height: 1; }
216
+ @keyframes lang-shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
217
+
218
+ /* river current — wave streaks drift downstream; period (28px) == dash period so the loop is seamless */
219
+ .lab-river-wave { animation-name: stage-river-drift; animation-timing-function: linear; animation-iteration-count: infinite; will-change: transform; }
220
+ @keyframes stage-river-drift { from { transform: translateX(0); } to { transform: translateX(28px); } }
221
+ @media (prefers-reduced-motion: reduce) { .lab-river-wave { animation: none; } }
222
+
223
+ /* boolean-circuit — a live wire (carrying a 1) shows current flowing source→device */
224
+ .lc-wire-live { stroke-dasharray: 7 9; animation: lc-flow .55s linear infinite; }
225
+ @keyframes lc-flow { to { stroke-dashoffset: -16; } }
226
+ @media (prefers-reduced-motion: reduce) { .lc-wire-live { animation: none; stroke-dasharray: none; } }
227
+
228
+ /* annotation kit — a Spotlight ring pulses outward to draw the eye */
229
+ .lab-pulse { animation: lab-pulse 1.5s ease-out infinite; }
230
+ @keyframes lab-pulse { 0% { transform: scale(.55); opacity: .75; } 100% { transform: scale(1.9); opacity: 0; } }
231
+ @media (prefers-reduced-motion: reduce) { .lab-pulse { animation: none; } }
232
+
233
+ /* choice-based grammar labs (ArticleLens, Agreement) */
234
+ .lang-sentence { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 22px; font-weight: 600; color: var(--foreground, currentColor); margin: 6px 0 16px; }
235
+ .lang-blank { display: inline-flex; align-items: center; justify-content: center; min-width: 52px; padding: 2px 12px; border-radius: 10px; border: 2px dashed var(--border, color-mix(in oklab, currentColor 30%, transparent)); background: var(--muted, color-mix(in oklab, currentColor 5%, transparent)); font-weight: 800; }
236
+ .lang-blank[data-state="ok"] { border-style: solid; border-color: var(--success, oklch(0.62 0.17 150)); color: var(--success, oklch(0.62 0.17 150)); background: color-mix(in oklab, var(--success, oklch(0.62 0.17 150)) 12%, transparent); }
237
+ .lang-blank[data-state="no"] { border-style: solid; border-color: var(--destructive, oklch(0.58 0.22 25)); color: var(--destructive, oklch(0.58 0.22 25)); }
238
+ .lang-noun, .lang-subject { font-weight: 700; }
239
+ .lang-subject[data-ok="true"] { color: var(--lang-pos-pronoun); }
240
+ .lang-link { color: var(--success, oklch(0.62 0.17 150)); font-weight: 800; }
241
+ .lang-choices { display: flex; flex-wrap: wrap; gap: 10px; }
242
+ .lang-choice { padding: 10px 20px; border-radius: 12px; border: 1.5px solid var(--border, color-mix(in oklab, currentColor 28%, transparent)); background: var(--card, var(--background, transparent)); color: var(--foreground, inherit); font-size: 17px; font-weight: 700; cursor: pointer; transition: border-color .12s, background .12s, transform .1s; }
243
+ .lang-choice:hover:not(:disabled) { border-color: var(--primary, oklch(0.59 0.22 261)); }
244
+ .lang-choice[data-state="ok"] { border-color: var(--success, oklch(0.62 0.17 150)); background: color-mix(in oklab, var(--success, oklch(0.62 0.17 150)) 16%, transparent); }
245
+ .lang-choice[data-state="no"] { border-color: var(--destructive, oklch(0.58 0.22 25)); background: color-mix(in oklab, var(--destructive, oklch(0.58 0.22 25)) 12%, transparent); animation: lang-shake .42s; }
246
+ .lang-choice:disabled:not([data-state="ok"]) { opacity: .5; cursor: default; }
247
+ .lang-why { font-size: 14px; font-weight: 600; margin: 12px 0 0; }
248
+ .lang-why[data-state="ok"] { color: var(--success, oklch(0.62 0.17 150)); }
249
+ .lang-why[data-state="no"] { color: var(--muted-foreground, color-mix(in oklab, currentColor 55%, transparent)); }
250
+
251
+ /* transform lab: read-only source row + arrow */
252
+ .lang-from { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; opacity: .85; }
253
+ .lang-from .lang-tile { filter: saturate(.7); cursor: default; }
254
+ .lang-arrow { font-size: 22px; font-weight: 800; color: var(--muted-foreground, color-mix(in oklab, currentColor 55%, transparent)); margin: 4px 0; text-align: center; width: 100%; }
255
+
256
+ /* preposition scene — emoji figure positioned vs a landmark (data-driven) */
257
+ .lang-scene { display: flex; justify-content: center; padding: 4px 0 10px; }
258
+ .lang-prepscene { position: relative; width: 240px; height: 172px; overflow: hidden; border-radius: 12px; border: 1px solid var(--border, color-mix(in oklab, currentColor 18%, transparent)); background: color-mix(in oklab, currentColor 3%, transparent); }
259
+ .lang-preplandmark { position: absolute; left: 50%; top: 56%; transform: translate(-50%, -50%); font-size: 62px; line-height: 1; }
260
+ .lang-prepfig { position: absolute; font-size: 38px; line-height: 1; filter: drop-shadow(0 1px 1.5px rgba(0,0,0,0.3)); }
261
+
262
+ /* vector types reference grid */
263
+ .lang-typegrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
264
+ .lang-typecard { border: 1px solid var(--border, color-mix(in oklab, currentColor 18%, transparent)); border-radius: 12px; padding: 6px 8px 10px; background: var(--card, transparent); min-width: 0; }
265
+ .lang-typecard svg { width: 100%; height: auto; max-width: 100%; }
266
+ .lang-typename { font-weight: 700; font-size: 14px; margin: 4px 0 0; color: var(--foreground, currentColor); }
267
+ .lang-typecap { font-size: 12px; opacity: .72; margin: 1px 0 0; }