eduevidence 5.2.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 (312) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +506 -0
  3. package/README.zh-CN.md +434 -0
  4. package/SKILL.md +195 -0
  5. package/bin/eduevidence.js +127 -0
  6. package/domains/education/manifest.json +183 -0
  7. package/domains/education/outcome_taxonomy.json +127 -0
  8. package/domains/manifest.json +26 -0
  9. package/domains/policy/frame.schema.json +234 -0
  10. package/domains/policy/manifest.json +10 -0
  11. package/domains/policy/methodology_checklist.json +109 -0
  12. package/domains/policy/outcome_taxonomy.json +53 -0
  13. package/domains/policy/references/causal-identification.md +45 -0
  14. package/domains/policy/references/cost-evidence.md +44 -0
  15. package/domains/policy/references/equity.md +42 -0
  16. package/domains/policy/references/evidence-hierarchy.md +41 -0
  17. package/domains/policy/references/implementation-evidence.md +47 -0
  18. package/eduevidence_cli.py +26 -0
  19. package/engine/__init__.py +11 -0
  20. package/engine/__pycache__/__init__.cpython-312.pyc +0 -0
  21. package/engine/__pycache__/analysis.cpython-312.pyc +0 -0
  22. package/engine/__pycache__/bias.cpython-312.pyc +0 -0
  23. package/engine/__pycache__/briefs.cpython-312.pyc +0 -0
  24. package/engine/__pycache__/capabilities.cpython-312.pyc +0 -0
  25. package/engine/__pycache__/citation_check.cpython-312.pyc +0 -0
  26. package/engine/__pycache__/contracts.cpython-312.pyc +0 -0
  27. package/engine/__pycache__/datasets.cpython-312.pyc +0 -0
  28. package/engine/__pycache__/events.cpython-312.pyc +0 -0
  29. package/engine/__pycache__/evidence_graph.cpython-312.pyc +0 -0
  30. package/engine/__pycache__/evidence_review.cpython-312.pyc +0 -0
  31. package/engine/__pycache__/evidencecore.cpython-312.pyc +0 -0
  32. package/engine/__pycache__/gap_lens.cpython-312.pyc +0 -0
  33. package/engine/__pycache__/gaps.cpython-312.pyc +0 -0
  34. package/engine/__pycache__/graph_store.cpython-312.pyc +0 -0
  35. package/engine/__pycache__/graph_validate.cpython-312.pyc +0 -0
  36. package/engine/__pycache__/ids.cpython-312.pyc +0 -0
  37. package/engine/__pycache__/library.cpython-312.pyc +0 -0
  38. package/engine/__pycache__/library_builtin.cpython-312.pyc +0 -0
  39. package/engine/__pycache__/living.cpython-312.pyc +0 -0
  40. package/engine/__pycache__/log.cpython-312.pyc +0 -0
  41. package/engine/__pycache__/meta_analysis.cpython-312.pyc +0 -0
  42. package/engine/__pycache__/meta_synthesis.cpython-312.pyc +0 -0
  43. package/engine/__pycache__/migration.cpython-312.pyc +0 -0
  44. package/engine/__pycache__/mode_router.cpython-312.pyc +0 -0
  45. package/engine/__pycache__/paths.cpython-312.pyc +0 -0
  46. package/engine/__pycache__/pilot.cpython-312.pyc +0 -0
  47. package/engine/__pycache__/planner.cpython-312.pyc +0 -0
  48. package/engine/__pycache__/project.cpython-312.pyc +0 -0
  49. package/engine/__pycache__/projections.cpython-312.pyc +0 -0
  50. package/engine/__pycache__/robustness.cpython-312.pyc +0 -0
  51. package/engine/__pycache__/run.cpython-312.pyc +0 -0
  52. package/engine/__pycache__/semantics.cpython-312.pyc +0 -0
  53. package/engine/__pycache__/study_design.cpython-312.pyc +0 -0
  54. package/engine/__pycache__/synthesis.cpython-312.pyc +0 -0
  55. package/engine/__pycache__/tribunal.cpython-312.pyc +0 -0
  56. package/engine/__pycache__/update.cpython-312.pyc +0 -0
  57. package/engine/__pycache__/versions.cpython-312.pyc +0 -0
  58. package/engine/analysis.py +308 -0
  59. package/engine/bias.py +178 -0
  60. package/engine/briefs.py +106 -0
  61. package/engine/capabilities.py +99 -0
  62. package/engine/citation_check.py +192 -0
  63. package/engine/contracts.py +117 -0
  64. package/engine/datasets.py +165 -0
  65. package/engine/events.py +67 -0
  66. package/engine/evidence_graph.py +571 -0
  67. package/engine/evidence_review.py +88 -0
  68. package/engine/evidencecore.py +182 -0
  69. package/engine/gap_lens.py +132 -0
  70. package/engine/gaps.py +169 -0
  71. package/engine/graph_store.py +335 -0
  72. package/engine/graph_validate.py +87 -0
  73. package/engine/ids.py +77 -0
  74. package/engine/library.py +268 -0
  75. package/engine/library_builtin.py +301 -0
  76. package/engine/living.py +671 -0
  77. package/engine/log.py +39 -0
  78. package/engine/meta_analysis.py +333 -0
  79. package/engine/meta_synthesis.py +111 -0
  80. package/engine/migration.py +397 -0
  81. package/engine/mode_router.py +72 -0
  82. package/engine/paths.py +15 -0
  83. package/engine/pilot.py +368 -0
  84. package/engine/planner.py +126 -0
  85. package/engine/project.py +118 -0
  86. package/engine/projections.py +240 -0
  87. package/engine/robustness.py +109 -0
  88. package/engine/run.py +85 -0
  89. package/engine/semantics.py +135 -0
  90. package/engine/study_design.py +87 -0
  91. package/engine/synthesis.py +187 -0
  92. package/engine/tribunal.py +408 -0
  93. package/engine/update.py +113 -0
  94. package/engine/versions.py +12 -0
  95. package/install.sh +510 -0
  96. package/integrations/__init__.py +1 -0
  97. package/integrations/__pycache__/__init__.cpython-312.pyc +0 -0
  98. package/integrations/__pycache__/agent_mcp.cpython-312.pyc +0 -0
  99. package/integrations/__pycache__/smart_web_fetch.cpython-312.pyc +0 -0
  100. package/integrations/agent_mcp.py +856 -0
  101. package/integrations/smart_web_fetch.py +59 -0
  102. package/package.json +50 -0
  103. package/pyproject.toml +55 -0
  104. package/references/applicability-policy.md +88 -0
  105. package/references/education-framing.md +132 -0
  106. package/references/effect_size_formulas.md +35 -0
  107. package/references/evaluation-design.md +111 -0
  108. package/references/evidence-quality.md +79 -0
  109. package/references/grade_framework.md +29 -0
  110. package/references/intervention-design.md +98 -0
  111. package/references/methodology-audit.md +103 -0
  112. package/references/outcome-taxonomy.md +106 -0
  113. package/references/retrieval-protocol.md +142 -0
  114. package/references/skeptic-protocol.md +93 -0
  115. package/references/social_science_pitfalls.md +48 -0
  116. package/references/source-validity.md +140 -0
  117. package/references/tribunal-policy.md +112 -0
  118. package/references/wwc_standards.md +29 -0
  119. package/retrieval/__init__.py +1 -0
  120. package/retrieval/__pycache__/__init__.cpython-312.pyc +0 -0
  121. package/retrieval/__pycache__/corpus_store.cpython-312.pyc +0 -0
  122. package/retrieval/__pycache__/dedupe.cpython-312.pyc +0 -0
  123. package/retrieval/__pycache__/failures.cpython-312.pyc +0 -0
  124. package/retrieval/__pycache__/fetch.cpython-312.pyc +0 -0
  125. package/retrieval/__pycache__/search.cpython-312.pyc +0 -0
  126. package/retrieval/__pycache__/source.cpython-312.pyc +0 -0
  127. package/retrieval/__pycache__/validate.cpython-312.pyc +0 -0
  128. package/retrieval/corpus_store.py +181 -0
  129. package/retrieval/dedupe.py +127 -0
  130. package/retrieval/failures.py +90 -0
  131. package/retrieval/fetch.py +435 -0
  132. package/retrieval/search.py +493 -0
  133. package/retrieval/source.py +160 -0
  134. package/retrieval/validate.py +257 -0
  135. package/schemas/agent-mcp-approval.schema.json +57 -0
  136. package/schemas/chart-spec.schema.json +88 -0
  137. package/schemas/cross-model-review.schema.json +28 -0
  138. package/schemas/education-frame.schema.json +106 -0
  139. package/schemas/evaluation.schema.json +35 -0
  140. package/schemas/evidence.schema.json +81 -0
  141. package/schemas/fetch-result.schema.json +119 -0
  142. package/schemas/intervention.schema.json +46 -0
  143. package/schemas/methodology.schema.json +102 -0
  144. package/schemas/report-result.schema.json +381 -0
  145. package/schemas/report-spec.schema.json +130 -0
  146. package/schemas/source.schema.json +311 -0
  147. package/schemas/v2/analysis-plan.schema.json +28 -0
  148. package/schemas/v2/analysis-run.schema.json +33 -0
  149. package/schemas/v2/claim.schema.json +26 -0
  150. package/schemas/v2/dataset-asset.schema.json +40 -0
  151. package/schemas/v2/decision-snapshot.schema.json +53 -0
  152. package/schemas/v2/evidence-link.schema.json +38 -0
  153. package/schemas/v2/finding.schema.json +47 -0
  154. package/schemas/v2/graph-revision.schema.json +30 -0
  155. package/schemas/v2/knowledge-gap.schema.json +40 -0
  156. package/schemas/v2/methodology-audit.schema.json +30 -0
  157. package/schemas/v2/outcome.schema.json +18 -0
  158. package/schemas/v2/project.schema.json +31 -0
  159. package/schemas/v2/research-intent.schema.json +24 -0
  160. package/schemas/v2/run.schema.json +43 -0
  161. package/schemas/v2/source.schema.json +24 -0
  162. package/schemas/v2/study-design.schema.json +67 -0
  163. package/schemas/v2/study.schema.json +37 -0
  164. package/schemas/v3/pilot-outcome.schema.json +132 -0
  165. package/schemas/v3/run-manifest.schema.json +193 -0
  166. package/schemas/v3/synthesis.schema.json +86 -0
  167. package/schemas/v4/drift-report.schema.json +66 -0
  168. package/schemas/v4/evidence-library.schema.json +42 -0
  169. package/schemas/v4/living-subscription.schema.json +55 -0
  170. package/schemas/v4/meta-analysis.schema.json +152 -0
  171. package/schemas/verdict.schema.json +56 -0
  172. package/scripts/__init__.py +0 -0
  173. package/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
  174. package/scripts/__pycache__/benchmark.cpython-312.pyc +0 -0
  175. package/scripts/__pycache__/benchmark_evaluator.cpython-312.pyc +0 -0
  176. package/scripts/__pycache__/benchmark_judge.cpython-312.pyc +0 -0
  177. package/scripts/__pycache__/benchmark_routing.cpython-312.pyc +0 -0
  178. package/scripts/__pycache__/benchmark_v2.cpython-312.pyc +0 -0
  179. package/scripts/__pycache__/benchmark_v3.cpython-312.pyc +0 -0
  180. package/scripts/__pycache__/build_result.cpython-312.pyc +0 -0
  181. package/scripts/__pycache__/claim_audit.cpython-312.pyc +0 -0
  182. package/scripts/__pycache__/complexity_gate.cpython-312.pyc +0 -0
  183. package/scripts/__pycache__/compute_confidence.cpython-312.pyc +0 -0
  184. package/scripts/__pycache__/dashboard_server.cpython-312.pyc +0 -0
  185. package/scripts/__pycache__/did_regression.cpython-312.pyc +0 -0
  186. package/scripts/__pycache__/effect_calculator.cpython-312.pyc +0 -0
  187. package/scripts/__pycache__/evidence_matrix.cpython-312.pyc +0 -0
  188. package/scripts/__pycache__/evidence_score.cpython-312.pyc +0 -0
  189. package/scripts/__pycache__/evidence_semantics.cpython-312.pyc +0 -0
  190. package/scripts/__pycache__/fetch_benchmark.cpython-312.pyc +0 -0
  191. package/scripts/__pycache__/lint_report_layout.cpython-312.pyc +0 -0
  192. package/scripts/__pycache__/orchestrator.cpython-312.pyc +0 -0
  193. package/scripts/__pycache__/pre_verdict_gate.cpython-312.pyc +0 -0
  194. package/scripts/__pycache__/recompute_demo_quality.cpython-312.pyc +0 -0
  195. package/scripts/__pycache__/render_report.cpython-312.pyc +0 -0
  196. package/scripts/__pycache__/render_report_html.cpython-312.pyc +0 -0
  197. package/scripts/__pycache__/run_workspace.cpython-312.pyc +0 -0
  198. package/scripts/__pycache__/skill_lint.cpython-312.pyc +0 -0
  199. package/scripts/__pycache__/startup_probe.cpython-312.pyc +0 -0
  200. package/scripts/__pycache__/sync_killer_demo_report.cpython-312.pyc +0 -0
  201. package/scripts/__pycache__/test_adversarial_empirical.cpython-312-pytest-9.0.2.pyc +0 -0
  202. package/scripts/__pycache__/test_adversarial_empirical.cpython-312-pytest-9.1.1.pyc +0 -0
  203. package/scripts/__pycache__/validate_schema.cpython-312.pyc +0 -0
  204. package/scripts/audit_dois.py +292 -0
  205. package/scripts/bake_pack.sh +37 -0
  206. package/scripts/benchmark.py +183 -0
  207. package/scripts/benchmark_evaluator.py +371 -0
  208. package/scripts/benchmark_judge.py +535 -0
  209. package/scripts/benchmark_routing.py +120 -0
  210. package/scripts/benchmark_v2.py +304 -0
  211. package/scripts/benchmark_v3.py +552 -0
  212. package/scripts/build_esl_artifacts.py +1921 -0
  213. package/scripts/build_evidence_library.py +307 -0
  214. package/scripts/build_killer_demo.py +295 -0
  215. package/scripts/build_result.py +311 -0
  216. package/scripts/check_version_consistency.py +96 -0
  217. package/scripts/citation_check.py +123 -0
  218. package/scripts/claim_audit.py +157 -0
  219. package/scripts/complexity_gate.py +180 -0
  220. package/scripts/compute_confidence.py +176 -0
  221. package/scripts/dashboard_server.py +536 -0
  222. package/scripts/did_regression.py +315 -0
  223. package/scripts/effect_calculator.py +99 -0
  224. package/scripts/enrich_projects_human_and_lieflat.py +315 -0
  225. package/scripts/evidence_matrix.py +129 -0
  226. package/scripts/evidence_score.py +234 -0
  227. package/scripts/evidence_semantics.py +87 -0
  228. package/scripts/fetch_benchmark.py +177 -0
  229. package/scripts/generate_metrics.py +99 -0
  230. package/scripts/generate_new_projects.py +686 -0
  231. package/scripts/generate_promo.py +192 -0
  232. package/scripts/lint_report_layout.py +182 -0
  233. package/scripts/orchestrator.py +1456 -0
  234. package/scripts/pre_verdict_gate.py +513 -0
  235. package/scripts/quickstart.py +121 -0
  236. package/scripts/rebake_all_5themes.py +88 -0
  237. package/scripts/recompute_demo_quality.py +205 -0
  238. package/scripts/render_report.py +270 -0
  239. package/scripts/render_report_html.py +356 -0
  240. package/scripts/retraction_watch.py +110 -0
  241. package/scripts/run_workspace.py +337 -0
  242. package/scripts/serve_web.py +54 -0
  243. package/scripts/skill_lint.py +150 -0
  244. package/scripts/startup_probe.py +265 -0
  245. package/scripts/sync_killer_demo_report.py +270 -0
  246. package/scripts/test_adversarial_empirical.py +541 -0
  247. package/scripts/validate_schema.py +256 -0
  248. package/skill/agents/education-planner.md +80 -0
  249. package/skill/agents/evaluation-designer.md +74 -0
  250. package/skill/agents/evidence-analyst.md +106 -0
  251. package/skill/agents/evidence-judge.md +111 -0
  252. package/skill/agents/evidence-retriever.md +80 -0
  253. package/skill/agents/intervention-designer.md +82 -0
  254. package/skill/agents/method-reviewer.md +104 -0
  255. package/skill/agents/skeptic.md +89 -0
  256. package/skill/sub-skills/aihot-trend-analysis/SKILL.md +31 -0
  257. package/skill/sub-skills/contradiction-analysis/SKILL.md +17 -0
  258. package/skill/sub-skills/data-analysis/SKILL.md +23 -0
  259. package/skill/sub-skills/ethics-review/SKILL.md +25 -0
  260. package/skill/sub-skills/evidence-extraction/SKILL.md +19 -0
  261. package/skill/sub-skills/evidence-review/SKILL.md +18 -0
  262. package/skill/sub-skills/gap-analysis/SKILL.md +25 -0
  263. package/skill/sub-skills/literature-review/SKILL.md +21 -0
  264. package/skill/sub-skills/methodology-audit/SKILL.md +20 -0
  265. package/skill/sub-skills/report-generation/SKILL.md +51 -0
  266. package/skill/sub-skills/research-planning/SKILL.md +21 -0
  267. package/skill/sub-skills/study-design/SKILL.md +16 -0
  268. package/skill/task-briefs/adjudicate.md +17 -0
  269. package/skill/task-briefs/audit.md +15 -0
  270. package/skill/task-briefs/challenge.md +15 -0
  271. package/skill/task-briefs/evaluate.md +13 -0
  272. package/skill/task-briefs/extract.md +16 -0
  273. package/skill/task-briefs/frame.md +17 -0
  274. package/skill/task-briefs/intervene.md +14 -0
  275. package/skill/task-briefs/present.md +16 -0
  276. package/skill/task-briefs/retrieve.md +15 -0
  277. package/visualization/eduevidence-report/assets/base.css +337 -0
  278. package/visualization/eduevidence-report/motion/motion.css +157 -0
  279. package/visualization/eduevidence-report/motion/motion.js +107 -0
  280. package/visualization/eduevidence-report/references/bilingual-style.md +7 -0
  281. package/visualization/eduevidence-report/references/component-catalog.md +145 -0
  282. package/visualization/eduevidence-report/references/evidence-expansion.md +65 -0
  283. package/visualization/eduevidence-report/references/full-report-outline.md +86 -0
  284. package/visualization/eduevidence-report/references/layout-constraints.md +63 -0
  285. package/visualization/eduevidence-report/references/lieflat-composition.md +79 -0
  286. package/visualization/eduevidence-report/references/motion-system.md +31 -0
  287. package/visualization/eduevidence-report/schemas/adapter-envelope.schema.json +22 -0
  288. package/visualization/eduevidence-report/schemas/visual-layout.schema.json +87 -0
  289. package/visualization/eduevidence-report/scripts/__pycache__/adapter_contract.cpython-312.pyc +0 -0
  290. package/visualization/eduevidence-report/scripts/__pycache__/build_artifact_manifest.cpython-312.pyc +0 -0
  291. package/visualization/eduevidence-report/scripts/__pycache__/build_charts.cpython-312.pyc +0 -0
  292. package/visualization/eduevidence-report/scripts/__pycache__/build_figures.cpython-312.pyc +0 -0
  293. package/visualization/eduevidence-report/scripts/__pycache__/build_infographics.cpython-312.pyc +0 -0
  294. package/visualization/eduevidence-report/scripts/__pycache__/build_report.cpython-312.pyc +0 -0
  295. package/visualization/eduevidence-report/scripts/__pycache__/charts_data.cpython-312.pyc +0 -0
  296. package/visualization/eduevidence-report/scripts/__pycache__/lieflat_engine.cpython-312.pyc +0 -0
  297. package/visualization/eduevidence-report/scripts/__pycache__/zh_labels.cpython-312.pyc +0 -0
  298. package/visualization/eduevidence-report/scripts/adapter_contract.py +72 -0
  299. package/visualization/eduevidence-report/scripts/build_artifact_manifest.py +70 -0
  300. package/visualization/eduevidence-report/scripts/build_charts.py +283 -0
  301. package/visualization/eduevidence-report/scripts/build_figures.py +515 -0
  302. package/visualization/eduevidence-report/scripts/build_infographics.py +268 -0
  303. package/visualization/eduevidence-report/scripts/build_report.py +3211 -0
  304. package/visualization/eduevidence-report/scripts/charts_data.py +617 -0
  305. package/visualization/eduevidence-report/scripts/check_mobile_layout.js +220 -0
  306. package/visualization/eduevidence-report/scripts/lieflat_engine.py +852 -0
  307. package/visualization/eduevidence-report/scripts/zh_labels.py +245 -0
  308. package/visualization/eduevidence-report/themes/academic.css +94 -0
  309. package/visualization/eduevidence-report/themes/claude.css +96 -0
  310. package/visualization/eduevidence-report/themes/datalab-dark.css +147 -0
  311. package/visualization/eduevidence-report/themes/datalab.css +151 -0
  312. package/visualization/eduevidence-report/themes/presentation.css +140 -0
@@ -0,0 +1,157 @@
1
+ /* EduEvidence Motion Template
2
+ Motion explains hierarchy only. It never changes evidence meaning or numeric state. */
3
+
4
+ .motion-ready [data-animate] {
5
+ opacity:0;
6
+ transform:translateY(10px);
7
+ transition:opacity .52s cubic-bezier(.22,.61,.36,1),
8
+ transform .52s cubic-bezier(.22,.61,.36,1);
9
+ transition-delay:var(--motion-delay,0ms);
10
+ }
11
+ .motion-ready [data-animate].is-visible { opacity:1; transform:none; }
12
+
13
+ .motion-ready .quality-meter i,
14
+ .motion-ready .balance-track i {
15
+ transform:scaleX(0);
16
+ transform-origin:left center;
17
+ transition:transform .72s cubic-bezier(.22,.61,.36,1) var(--motion-delay,0ms);
18
+ }
19
+ .motion-ready .quality-meter.is-visible i,
20
+ .motion-ready .balance-track.is-visible i { transform:scaleX(1); }
21
+
22
+ .motion-ready .flow-arrow {
23
+ opacity:.18;
24
+ transform:translateX(-4px);
25
+ transition:opacity .36s ease, transform .36s ease;
26
+ transition-delay:var(--motion-delay,0ms);
27
+ }
28
+ .motion-ready .flow-arrow.is-visible { opacity:1; transform:none; }
29
+
30
+ .motion-ready .detail-expander[open] .detail-body {
31
+ animation:eduevidenceDetailReveal .24s cubic-bezier(.22,.61,.36,1) both;
32
+ }
33
+ @keyframes eduevidenceDetailReveal {
34
+ from { opacity:0; transform:translateY(-4px); }
35
+ to { opacity:1; transform:none; }
36
+ }
37
+
38
+ .motion-ready .report-page:not([hidden]) {
39
+ animation:eduevidencePageReveal .24s cubic-bezier(.22,.61,.36,1) both;
40
+ }
41
+ @keyframes eduevidencePageReveal {
42
+ from { opacity:0; transform:translateY(4px); }
43
+ to { opacity:1; transform:none; }
44
+ }
45
+
46
+ .motion-ready .full-report-toc a {
47
+ transition:color .18s ease, background-color .18s ease,
48
+ border-color .18s ease, box-shadow .18s ease;
49
+ }
50
+
51
+ /* ────────────────────────────────────────────────────────────────────────
52
+ data-lieflat gallery reveal — aligned with the Lieflat mono-tokens spec:
53
+ lf-pop scale 0→1, cubic-bezier(.2,.7,.3,1.3), 500ms (quarticOut family)
54
+ lf-fade 900ms ease
55
+ lf-draw dasharray 1, 1s cubic-bezier(.4,0,.2,1)
56
+ --motion-delay inline variable carries the per-element stagger
57
+ (dot matrices 8–15ms, bars 80–130ms — set by the renderer).
58
+ Gated by .js-lf (added by motion.js only when JS runs and motion is not
59
+ reduced): without JS everything stays visible — static-first, never broken.
60
+ .is-live on the [data-lieflat] card starts the one-shot reveal; removing
61
+ and re-adding it replays (click-to-replay, timers cleared by motion.js).
62
+ ──────────────────────────────────────────────────────────────────────── */
63
+ .js-lf [data-lieflat] .lf-pop,
64
+ .js-lf [data-lieflat] .lf-fade,
65
+ .js-lf [data-lieflat] .lf-draw { opacity:0; }
66
+ .js-lf [data-lieflat] .lf-draw { stroke-dasharray:1; stroke-dashoffset:1; }
67
+
68
+ .js-lf [data-lieflat].is-live .lf-pop {
69
+ opacity:1;
70
+ transform-box:fill-box;
71
+ transform-origin:center;
72
+ animation:eduevidenceLfPop .5s cubic-bezier(.2,.7,.3,1.3) both;
73
+ animation-delay:var(--motion-delay,0ms);
74
+ }
75
+ .js-lf [data-lieflat].is-live .lf-fade {
76
+ opacity:1;
77
+ animation:eduevidenceLfFade .9s ease both;
78
+ animation-delay:var(--motion-delay,0ms);
79
+ }
80
+ .js-lf [data-lieflat].is-live .lf-draw {
81
+ animation:eduevidenceLfDraw 1s cubic-bezier(.4,0,.2,1) both;
82
+ animation-delay:var(--motion-delay,0ms);
83
+ }
84
+ @keyframes eduevidenceLfPop {
85
+ from { transform:scale(0); opacity:0; }
86
+ to { transform:none; opacity:1; }
87
+ }
88
+ @keyframes eduevidenceLfFade {
89
+ from { opacity:0; }
90
+ to { opacity:1; }
91
+ }
92
+ @keyframes eduevidenceLfDraw {
93
+ to { stroke-dashoffset:0; }
94
+ }
95
+
96
+ .js-lf [data-lieflat] { cursor:pointer; }
97
+
98
+ @media (hover:hover) {
99
+ .motion-ready .tribunal-card:hover,
100
+ .motion-ready .trace-chain-card:hover,
101
+ .motion-ready .outcome-group:hover,
102
+ .motion-ready .action-node:hover,
103
+ .motion-ready .method-audit-item:hover {
104
+ transform:translateY(-2px);
105
+ }
106
+ .motion-ready .evidence-matrix tbody tr:hover .dir {
107
+ transform:translateY(-1px);
108
+ filter:saturate(1.08);
109
+ }
110
+ }
111
+
112
+ @media (prefers-reduced-motion:reduce) {
113
+ .motion-ready [data-animate],
114
+ .motion-ready .quality-meter i,
115
+ .motion-ready .balance-track i,
116
+ .motion-ready .flow-arrow,
117
+ .motion-ready .dir,
118
+ .motion-ready .detail-body,
119
+ .motion-ready .report-page,
120
+ .motion-ready .full-report-toc a {
121
+ opacity:1 !important;
122
+ transform:none !important;
123
+ transition:none !important;
124
+ animation:none !important;
125
+ }
126
+ .js-lf [data-lieflat] .lf-pop,
127
+ .js-lf [data-lieflat] .lf-fade {
128
+ opacity:1 !important;
129
+ transform:none !important;
130
+ animation:none !important;
131
+ }
132
+ .js-lf [data-lieflat] .lf-draw {
133
+ opacity:1 !important;
134
+ animation:none !important;
135
+ stroke-dasharray:none !important;
136
+ stroke-dashoffset:0 !important;
137
+ }
138
+ html { scroll-behavior:auto; }
139
+ }
140
+
141
+ @media print {
142
+ [data-animate], .quality-meter i, .balance-track i, .flow-arrow {
143
+ opacity:1 !important;
144
+ transform:none !important;
145
+ transition:none !important;
146
+ animation:none !important;
147
+ }
148
+ [data-lieflat] .lf-pop,
149
+ [data-lieflat] .lf-fade,
150
+ [data-lieflat] .lf-draw {
151
+ opacity:1 !important;
152
+ transform:none !important;
153
+ animation:none !important;
154
+ stroke-dasharray:none !important;
155
+ stroke-dashoffset:0 !important;
156
+ }
157
+ }
@@ -0,0 +1,107 @@
1
+ /* EduEvidence Motion Template — one-shot progressive enhancement.
2
+ The [data-lieflat] gallery block implements the Lieflat mono-tokens
3
+ obsReveal contract: reveal once when scrolled into view (threshold .3),
4
+ click to replay (per-id timers cleared first so animations never stack),
5
+ prefers-reduced-motion downgrade, and static-visible without JS. */
6
+ (function () {
7
+ 'use strict';
8
+ var root = document.documentElement;
9
+ var reduceMotion = !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches);
10
+ window.__EDUEVIDENCE_REDUCE_MOTION__ = reduceMotion;
11
+ if (reduceMotion) return;
12
+
13
+ root.classList.add('motion-ready');
14
+ root.classList.add('js-lf');
15
+ var groups = [
16
+ ['.decision-hero', 0], ['.hero-insight', 70], ['.brief-block', 55],
17
+ ['.outcome-group', 70], ['.tribunal-card', 75], ['.method-audit-item', 45],
18
+ ['.trace-chain-card', 70], ['.action-node', 60], ['.flow-arrow', 60],
19
+ ['.phase', 60], ['.full-chapter', 35], ['.brief-source', 40]
20
+ ];
21
+ groups.forEach(function (entry) {
22
+ document.querySelectorAll(entry[0]).forEach(function (el, index) {
23
+ el.setAttribute('data-animate', '');
24
+ el.style.setProperty('--motion-delay', Math.min(index * entry[1], 320) + 'ms');
25
+ });
26
+ });
27
+ document.querySelectorAll('.quality-meter,.balance-track').forEach(function (el, index) {
28
+ el.style.setProperty('--motion-delay', Math.min((index % 8) * 35, 210) + 'ms');
29
+ });
30
+
31
+ var animated = document.querySelectorAll('[data-animate],.quality-meter,.balance-track,.flow-arrow');
32
+ if (!('IntersectionObserver' in window)) {
33
+ animated.forEach(function (el) { el.classList.add('is-visible'); });
34
+ } else {
35
+ var observer = new IntersectionObserver(function (entries, obs) {
36
+ entries.forEach(function (entry) {
37
+ if (!entry.isIntersecting) return;
38
+ entry.target.classList.add('is-visible');
39
+ obs.unobserve(entry.target);
40
+ });
41
+ }, {threshold:.12, rootMargin:'0px 0px -6% 0px'});
42
+ animated.forEach(function (el) { observer.observe(el); });
43
+ }
44
+
45
+ // ---- data-lieflat gallery: reveal on scroll, click to replay ----
46
+ // Per-container timers (mirrors mono-tokens `keep`): every scheduled
47
+ // replay step is registered under the container id and cleared before the
48
+ // next replay so staggered animations never stack on rapid clicking.
49
+ var lfTimers = {};
50
+ var lfBoxes = Array.prototype.slice.call(document.querySelectorAll('[data-lieflat]'));
51
+ lfBoxes.forEach(function (box, index) {
52
+ var base = (box.dataset.chartId || 'figure');
53
+ var safe = 'lf-' + index + '-' + (window.CSS && CSS.escape ? CSS.escape(base) : base.replace(/[^a-zA-Z0-9_-]/g, '-'));
54
+ box.dataset.lfId = safe;
55
+ if (!box.hasAttribute('aria-label')) {
56
+ box.setAttribute('aria-label', 'Lieflat chart — click to replay the reveal animation');
57
+ }
58
+ });
59
+
60
+ function clearLfTimers(id) {
61
+ (lfTimers[id] || []).forEach(function (t) { if (t) clearTimeout(t); });
62
+ lfTimers[id] = [];
63
+ }
64
+
65
+ // Entrance choreography: cards revealed shortly after load (already in the
66
+ // viewport) get a short visual stagger so the draw-in is actually seen —
67
+ // without this, the load-time reveal finishes before the user looks and the
68
+ // charts appear static until clicked. Scrolled-in and click reveals play
69
+ // immediately.
70
+ var bootTime = Date.now();
71
+ function revealDelay(box, index) {
72
+ var fresh = Date.now() - bootTime < 1500;
73
+ if (!fresh) return 40;
74
+ return 140 + ((index % 6) * 130);
75
+ }
76
+
77
+ function replayLieflat(box, delay) {
78
+ var id = box.dataset.lfId;
79
+ delay = (delay === undefined ? 40 : delay);
80
+ clearLfTimers(id);
81
+ box.classList.remove('is-live');
82
+ // force reflow so the re-added class restarts the CSS animations
83
+ void box.offsetWidth;
84
+ var tid = setTimeout(function () {
85
+ box.classList.add('is-live');
86
+ lfTimers[id] = lfTimers[id].filter(function (t) { return t !== tid; });
87
+ }, delay);
88
+ lfTimers[id].push(tid);
89
+ }
90
+
91
+ if (!('IntersectionObserver' in window)) {
92
+ lfBoxes.forEach(function (box) { box.classList.add('is-live'); });
93
+ } else {
94
+ var lfObserver = new IntersectionObserver(function (entries, obs) {
95
+ entries.forEach(function (entry) {
96
+ if (!entry.isIntersecting) return;
97
+ var index = lfBoxes.indexOf(entry.target);
98
+ replayLieflat(entry.target, revealDelay(entry.target, index));
99
+ obs.unobserve(entry.target);
100
+ });
101
+ }, {threshold:.3});
102
+ lfBoxes.forEach(function (box) { lfObserver.observe(box); });
103
+ }
104
+ lfBoxes.forEach(function (box, index) {
105
+ box.addEventListener('click', function () { replayLieflat(box, 0); });
106
+ });
107
+ })();
@@ -0,0 +1,7 @@
1
+ # Bilingual Rendering Style
2
+
3
+ Chinese mode translates stable UI labels, section titles, methodology keys, flow labels and enumerations. It does not rewrite freeform research claims or evidence prose in the renderer.
4
+
5
+ Allowed to remain in English in Chinese mode: AI, RCT, DOI, Evidence ID, Claim ID, Source ID, and original paper titles. Original titles should be explicitly labeled `原文标题`.
6
+
7
+ If `result.zh.json` lacks a localized freeform field, preserve the source text and mark it as original text rather than silently generating a new translation.
@@ -0,0 +1,145 @@
1
+ # HTML Component Catalog(结果层冻结组件)
2
+
3
+ > LLM 可以规划章节和选择已有组件,但不能自由编写影响证据语义的 DOM / chart 逻辑。组件固定,章节组合动态。
4
+
5
+ ## 1. Shell / 导航
6
+
7
+ | 组件 | 职责 |
8
+ |---|---|
9
+ | `ReportShell` | 单文件离线报告外壳 |
10
+ | `GeneratedThemeMarker` | 显示生成时选择的五种视觉系统之一 |
11
+ | `LanguageSwitcher` | 中文 / English 切换 |
12
+ | `PageSwitcher` | Visual Brief / Full Report 一级分页 |
13
+ | `FullReportReader` | 左 TOC + 右完整报告阅读器 |
14
+ | `CollapsibleTOC` | 读取动态 5–7 章 outline;sticky / active / collapse |
15
+ | `FullChapter` | AI 规划后的章节容器,只组合语义模块,不修改研究数据 |
16
+
17
+ ## 2. 决策 / 摘要
18
+
19
+ | 组件 | 职责 |
20
+ |---|---|
21
+ | `DecisionHero` | Decision / Confidence / strongest claim / uncertainty / risk / action |
22
+ | `ConfidenceBadge` | High / Moderate / Low / Insufficient |
23
+ | `VisualBriefBlock` | 摘要页高价值模块容器;不是完整报告章节 |
24
+ | `KeySourceCards` | 摘要页只显示少量关键来源 |
25
+
26
+ ## 3. Outcome / Visualization
27
+
28
+ | 组件 | 引擎 | 职责 |
29
+ |---|---|---|
30
+ | `OutcomeSeparation` | HTML/CSS | Task / Learning / Retention / Transfer / Risk 构念分离 |
31
+ | `EvidenceBalance` | SVG/ECharts | 基于 `effect_direction` 的正向/负向/零效应比较;只有 Gate 通过才渲染 |
32
+ | `LieflatGalleryCard` | 内联 SVG(charts_data + lieflat_engine) | AI 组合的数据驱动 Lieflat 图卡:结论式标题 + 副标题(图例 `·` 分隔)+ 主题化 SVG + 全大写来源行 + 可选图注;`data-lieflat` / `data-visual` 属性供 motion 与测试定位 |
33
+ | `LieflatSuppressed` | HTML | 数据不足时列出被抑制图型与原因(镜像 Meaningful Visualization Gate) |
34
+ | `InteractiveChart` | ECharts | 有信息增益的交互分析图 |
35
+ | `AcademicFigure` | Academic Figures | 出版级静态图(outcome-comparison / benchmark / forest,保持主题无关) |
36
+ | `InfographicBlock` | SVG / AntV | 流程、干预、评价等语义图 |
37
+ | `VisualizationSuppressed` | HTML | 数据不足时解释为什么不画图 |
38
+
39
+ Lieflat 图卡只渲染 `resolve_visual_layout` 校验通过的 `visual_layout` 条目;每个条目经注册表(`references/lieflat-composition.md`)提取器出数,未注册 type 显式报错。完整性门 `lieflat_data_bound` 逐值核对数值溯源。
40
+
41
+ ## 4. Evidence / progressive disclosure
42
+
43
+ | 组件 | 职责 |
44
+ |---|---|
45
+ | `EvidenceMatrix` | 6 列主视图:Evidence ID / Outcome / Effect / Quality / Claim / Source |
46
+ | `EvidenceRow` | 单条 Evidence 摘要 |
47
+ | `ExpandableEvidence` | 展开 study/sample/design/intervention/comparison/effect/quality/source 等完整字段 |
48
+ | `QualityMeter` | 仅表达已有 quality_score |
49
+ | `SafeSourceLink` | 只允许 http / https 可点击 URL |
50
+
51
+ Outcome/Matrix 的主方向使用 `effect_direction`。`relation_to_claim` 只作为次级 Claim relation 显示。
52
+
53
+ ## 5. Adjudication / methodology / trace
54
+
55
+ | 组件 | 职责 |
56
+ |---|---|
57
+ | `TribunalView` | Supported / Uncertain / Contradicted / Missing Evidence |
58
+ | `ExpandableTribunalClaim` | 长裁决文本和 Evidence IDs 渐进展开 |
59
+ | `MethodologyPanel` | compact status surface |
60
+ | `ExpandableMethodology` | 展开每项 methodology note |
61
+ | `ConflictCard` | 去重后的冲突/异质性解释 |
62
+ | `ClaimTrace` | Claim → Evidence → Outcome → Effect → Quality → Source |
63
+
64
+ ## 6. Applicability / intervention / evaluation
65
+
66
+ | 组件 | 职责 |
67
+ |---|---|
68
+ | `ApplicabilityCard` | Suitable / not suitable / conditions / boundary |
69
+ | `EvidenceToAction` | Evidence → Applicability → Decision → Guardrails → Stop → Evaluation |
70
+ | `InterventionTimeline` | 教学试点阶段 |
71
+ | `EvaluationFlow` | Baseline → Post → Retention → Transfer |
72
+ | `StopConditionBlock` | 失败/停止条件 |
73
+
74
+ ## 7. Sources / provenance
75
+
76
+ | 组件 | 职责 |
77
+ |---|---|
78
+ | `SourceList` | Source ID / original title / year / authority / location |
79
+ | `ExpandableSource` | canonical URL / source location / fetch metadata |
80
+ | `ProvenancePanel` | 只显示真实存在的 fetch metadata;空 fetch 不生成空表 |
81
+ | `Footnote` | 模式 / 版本 / integrity 状态 |
82
+
83
+ ## 8. Motion Template
84
+
85
+ | 组件 | 职责 |
86
+ |---|---|
87
+ | `MotionTemplate` | 统一 section/stagger/bar/trace/flow/detail/page/toc 动画 |
88
+ | `ChartReveal` | `data-lieflat` 图卡的 mono-tokens reveal:滚入视野(threshold .3)播一次 + 点击重播(timer 清理)+ reduced-motion 降级 + 无 JS 静态可见 |
89
+
90
+ 动画由 `motion/motion.css` + `motion/motion.js` 固化。五种主题不得创建不同的科学/数据动画逻辑,`chart-reveal` 为固定模板角色(见 `references/motion-system.md`)。
91
+
92
+ ## 9. Dynamic Report Planner
93
+
94
+ AI 不创建新组件,而是把固定语义模块组合成 5–7 个章节:
95
+
96
+ ```text
97
+ decision · scope · retrieval · outcomes · evidence · quality
98
+ conflicts · trace · applicability · intervention · evaluation · sources
99
+ ```
100
+
101
+ 规则:
102
+
103
+ 1. 第一章包含 `decision`。
104
+ 2. 最后一章包含 `sources`。
105
+ 3. 全部模块覆盖且每个恰好一次。
106
+ 4. AI 可以自由命名章节和合并中间模块。
107
+ 5. Invalid outline → safe six-chapter fallback。
108
+
109
+ 章节之外的**图表计划**由 AI 写入 `visual_layout`(每图一个独立结论、≤6 张、形状不重复),渲染器只执行注册表校验通过的条目;数值一律由提取器从 `result.json` 出数(`references/lieflat-composition.md`)。
110
+
111
+ ## 10. 五种主题共用组件,不共用排版
112
+
113
+ 同一组件在五种主题中可以改变:
114
+
115
+ - 宽度和列布局。
116
+ - 卡片/横线/面板策略。
117
+ - TOC 外观。
118
+ - Brief 模块网格。
119
+ - 表格密度。
120
+ - 标题尺度和章节节奏。
121
+
122
+ 不能改变:
123
+
124
+ - Evidence / Claim / Verdict / Confidence。
125
+ - `effect_direction`。
126
+ - 数据数量。
127
+ - 页面功能与 Evidence 展开能力。
128
+ - Meaningful Visualization Gate。
129
+
130
+ **排版守则(硬性,见 `references/layout-constraints.md`)**:主题规则特殊性高于基座断点——
131
+ 凡 ≥2 列含 px 最小值的 `grid-template-columns`,主题必须自带 `@media (max-width:980px)` 覆写;
132
+ 轨道用 `minmax(0,1fr)` 或 `minmax(min(Npx,100%),1fr)`,禁止裸 `1fr` 与固定 px 最小值 auto-fit。
133
+ 改动后跑 `scripts/lint_report_layout.py`(静态 + 浏览器级 390/768/1280 × brief/full)。
134
+
135
+ ## 11. 自检
136
+
137
+ - [ ] 同一 result 生成五种主题,数据与章节内容覆盖完全一致。
138
+ - [ ] 五种主题的首屏、Brief 排版、TOC、正文宽度、章节 surface 明显不同。
139
+ - [ ] Visual Brief / Full Report 都可切换。
140
+ - [ ] 5–7 章 TOC 自动读取 outline。
141
+ - [ ] 无 JS 时核心研究内容仍存在于 HTML。
142
+ - [ ] 打印只输出完整报告并暴露 detail 内容。
143
+ - [ ] Outcome visual 使用 `effect_direction`,不是 Claim support。
144
+ - [ ] `lint_report_layout.py` PASS:五主题静态不变量 + 浏览器级(390/768/1280 × brief/full)无溢出、reveal 生效。
145
+ - [ ] 手机(390px)与平板(768px)实测:无横向滚动、无裁切、图表完整、点击重播动画正常。
@@ -0,0 +1,65 @@
1
+ # Evidence Expansion Contract
2
+
3
+ Evidence is progressive disclosure, not a flat wall of prose.
4
+
5
+ ## Compact matrix
6
+
7
+ Default columns:
8
+
9
+ ```text
10
+ Evidence ID | Outcome | Effect | Quality | Claim | Source
11
+ ```
12
+
13
+ `Effect` is derived from `evidence.effect_direction` (`positive / negative / null`). `relation_to_claim` is shown only as a secondary relationship note.
14
+
15
+ ## Full expansion
16
+
17
+ When present, expose:
18
+
19
+ ```text
20
+ study_id
21
+ sample_id
22
+ title
23
+ year
24
+ study_type
25
+ education_level
26
+ population
27
+ sample_size
28
+ intervention
29
+ comparison
30
+ outcome_measure
31
+ claim
32
+ effect
33
+ effect_direction
34
+ relation_to_claim
35
+ duration
36
+ method
37
+ strengths
38
+ limitations
39
+ confounders
40
+ quality_dimensions
41
+ quality_score
42
+ evidence_level
43
+ directness
44
+ applicability
45
+ confidence
46
+ status
47
+ extensions.claim_id
48
+ source_id
49
+ source_location
50
+ canonical_url
51
+ ```
52
+
53
+ Missing fields are omitted. The renderer must not manufacture placeholders that could be mistaken for research data.
54
+
55
+ ## Long text
56
+
57
+ Brief surfaces show an exact prefix excerpt. Clicking the native `<details>` control reveals the complete original string. The renderer may normalize whitespace but may not paraphrase, strengthen, weaken or translate the claim to create a shorter version.
58
+
59
+ ## Source safety
60
+
61
+ Only `http` / `https` locations become links. Other source locations remain plain text.
62
+
63
+ ## Print
64
+
65
+ Print mode exposes detail content and hides interactive summaries so scientific information is not lost in PDF/print export.
@@ -0,0 +1,86 @@
1
+ # Full Report Outline
2
+
3
+ EduEvidence HTML contains two top-level views in one offline file:
4
+
5
+ 1. **Visual Brief** — default, scan-first, preserves the visual summary experience.
6
+ 2. **Full Report** — audit-first, desktop uses a collapsible sticky TOC and continuous report body.
7
+
8
+ ## Dynamic 5–7 chapter rule
9
+
10
+ The Full Report is **not** a frozen 12-chapter document. An upstream AI should organize the research into **5–7 chapters** based on the actual evidence story.
11
+
12
+ The renderer works with semantic modules rather than fixed chapters:
13
+
14
+ ```text
15
+ decision
16
+ scope
17
+ retrieval
18
+ outcomes
19
+ evidence
20
+ quality
21
+ conflicts
22
+ trace
23
+ applicability
24
+ intervention
25
+ evaluation
26
+ sources
27
+ ```
28
+
29
+ The AI may merge and reorder middle modules and write research-specific chapter titles. Examples:
30
+
31
+ - `retrieval + quality` → “证据从哪里来,以及它们有多可信”
32
+ - `outcomes + evidence` → “效率提升背后的学习结果分化”
33
+ - `conflicts + trace` → “为什么证据冲突,以及哪些主张仍可成立”
34
+ - `applicability + intervention` → “从适用边界到有护栏试点”
35
+
36
+ Constraints:
37
+
38
+ - 5–7 chapters total.
39
+ - First chapter contains `decision`.
40
+ - Last chapter contains `sources`.
41
+ - Every semantic module appears exactly once.
42
+ - No evidence, contradiction, methodology audit or source provenance may be dropped by chapter merging.
43
+ - If an AI outline is invalid, the renderer falls back to a safe six-chapter grouping.
44
+
45
+ ## Optional `report_outline`
46
+
47
+ ```json
48
+ {
49
+ "report_outline": {
50
+ "chapters": [
51
+ {
52
+ "key": "decision",
53
+ "title_zh": "结论与研究边界",
54
+ "title_en": "Decision and Research Boundary",
55
+ "lead_zh": "先明确可以得出什么结论,再解释为什么。",
56
+ "lead_en": "State what can be concluded before explaining why.",
57
+ "modules": ["decision", "scope"]
58
+ }
59
+ ]
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Visual insertion rules
65
+
66
+ A chapter may include a chart or semantic visual only when it adds information beyond adjacent text/table. Sparse states such as `1 support / 0 contradict / 0 neutral` stay as badges/text. Every meaningful visual must have an interpretation caption explaining what the reader should take from it.
67
+
68
+ Outcome visuals must encode `effect_direction` (`positive / negative / null`), not `relation_to_claim`. Evidence can support a claim that an intervention caused a harmful outcome; therefore `support` is not equivalent to a positive effect.
69
+
70
+ **Lieflat gallery insertion** goes through the registry (`references/lieflat-composition.md`): the AI writes `visual_layout` entries (type + catalog ref + bilingual copy + source + params), and the renderer draws each entry from its extractor bundle only. Unregistered types are rejected, insufficient data suppresses the chart with a recorded reason, and a missing/invalid layout falls back to the deterministic safe combination (forest_plot + dot_cascade + bubble_almanac + tick_rows).
71
+
72
+ ## Progressive disclosure
73
+
74
+ Evidence, methodology audit items, tribunal claims and sources default to compact summaries and expose full traceable detail through accessible native `<details>/<summary>` controls. Print mode must not lose the hidden evidence content.
75
+
76
+ ## Five themes, one content contract
77
+
78
+ The same Visual Brief / Full Report structure, dynamic outline and evidence content are rendered through five clearly differentiated layout templates:
79
+
80
+ - Claude Research [Light] — calm research reader.
81
+ - Academic Paper [Light] — journal/paper layout.
82
+ - DataLab [Light] — light analytical workbench.
83
+ - DataLab [Dark] — dark analytical workbench with the same information architecture.
84
+ - Presentation / Judge [Dark] — review/presentation layout.
85
+
86
+ Theme differences may include header composition, Brief grid, TOC appearance, body width, chapter surfaces, table density and data breakout width. Themes may not change evidence semantics or chapter content coverage.
@@ -0,0 +1,63 @@
1
+ # Layout Constraints — 五主题报告排版守则(移动端 + 桌面)
2
+
3
+ EduEvidence 的五套烘焙主题(claude / academic / datalab / datalab-dark / presentation)
4
+ 共用同一内容契约,但各自拥有排版策略。主题是实现层的自由舞台,**但不能破坏阅读**:
5
+ 任何加入/修改主题 CSS 或渲染器内联样式的人,都必须遵守以下不变量,并在改动后跑
6
+
7
+ ```bash
8
+ python3 scripts/lint_report_layout.py --html-dir examples/ai-coding-assistant-50/reports-5themes
9
+ ```
10
+
11
+ 静态审计 + 浏览器级实测(390 / 768 / 1280 px × Visual Brief / Full Report)全部通过才能合入。
12
+
13
+ ## 1. 为什么会有这套守则(历史教训)
14
+
15
+ - `:root[data-theme="X"] .selector` 特异性是 0,2,0,**压过**基座 `@media (max-width:980px)` 的 0,1,0 断点。
16
+ 之前五套主题的桌面 `full-report-layout { grid-template-columns:210px minmax(0,1fr) }` 在手机上
17
+ 把内容列挤到 ~104px(390 视口下横向裁切);`repeat(auto-fit,minmax(240px,1fr))` 的内在尺寸
18
+ 爆炸让 768px 平板的第二列结果直接消失在视口外(shell scrollWidth 1025 > 768)。
19
+ - 修复范式 = 基座断点提供安全网 + **每个主题在自己的 @media ≤980 内重新声明响应式覆写**。
20
+
21
+ ## 2. 硬性不变量(static lint 会逐条检查)
22
+
23
+ 1. **移动端轨道收缩安全**
24
+ - 网格列一律 `minmax(0, 1fr)`(绝不允许裸 `1fr`,它按内容 min-content 定宽)。
25
+ - `repeat(auto-fit, minmax(Npx, 1fr))` 一律写成 `repeat(auto-fit, minmax(min(Npx,100%), 1fr))`,
26
+ 让最小值随容器收缩,杜绝内在尺寸爆炸。
27
+ 2. **主题必须自带移动端覆写**
28
+ - 主题里任何 ≥2 列、含 px 最小值的 `grid-template-columns`(如 full-report-layout、
29
+ report-page-brief、hero-insights、tribunal-grid、brief-source-grid、outcome-groups……)
30
+ 都必须在**同一主题文件**的 `@media (max-width:980px)` 内提供等效单列/收缩覆写——
31
+ 基座断点压不过主题特异性。
32
+ - 媒体查询外出现裸 `grid-template-columns:1fr` 直接违规。
33
+ 3. **基座安全网必须存在**(build_report.py 内联样式):`html,body` 的 `overflow-x:hidden`;
34
+ @media 980 的 `minmax(0,1fr)`;@media 720 的网格 item `min-width:0` 清单与
35
+ `.outcome-groups` / `.evidence-detail-grid,.source-detail-grid` 收缩覆写。
36
+ 4. **表格与长文本**:任何数据表外包 `.table-wrap { overflow-x:auto }`(滚动而不是撑破页面);
37
+ `.source-detail-grid dd` / `.claim-cell` 等长文本位点 `overflow-wrap:anywhere`。
38
+
39
+ ## 3. 浏览器级门(check_mobile_layout.js)
40
+
41
+ 无依赖 Node 脚本(Node ≥21,CDP 驱动 headless Chrome),对每个报告在
42
+ 390 / 768 / 1280 × brief / full 检查:
43
+
44
+ - `documentElement.scrollWidth > innerWidth` → 页面级横向溢出;
45
+ - 可见 `.report-shell` 的 `scrollWidth > clientWidth` → 内容被裁切;
46
+ - 逃逸视口且不在滚动容器/`<svg>` 内的元素 → 真溢出(表内/横向操作条内滚动是合法的);
47
+ - 画廊卡片:滚入后必须全部拿到 `is-live`(reveal 契约:滚入播放 + 点击重播)。
48
+
49
+ 无 Chrome/Node 的环境跳过浏览器级阶段(pytest 用 `skipif` 处理)。
50
+
51
+ ## 4. 移动端体验红线
52
+
53
+ - 390px:单列全内容可读;控件(lang/视图切换)不挤压标题;图表 `width:100%` 自适应。
54
+ - 768px(平板):两列工作台可优雅回退单列,不出现半列被裁。
55
+ - `prefers-reduced-motion` / 打印:图表静态完整可见(motion.css 已覆盖 `data-lieflat`)。
56
+ - 新滚动容器(`overflow-x:auto`)只是"容器内滚动",不得让 `.report-shell` 自身出现横向滚动条。
57
+
58
+ ## 5. 验收清单(改动后必跑)
59
+
60
+ - [ ] `python3 scripts/lint_report_layout.py --html-dir <报告目录>` → PASS
61
+ - [ ] `python3 scripts/rebake_all_5themes.py` 重烘焙无回归
62
+ - [ ] `python3 -m pytest tests/test_report_layout_mobile.py -q` 全绿
63
+ - [ ] 手机实机(或 Chrome 设备模拟)打开 15 份报告:无横向滚动、图表完整、点击可重播动画