stream_weaver 0.3.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 (381) hide show
  1. checksums.yaml +7 -0
  2. data/.beads/.gitignore +77 -0
  3. data/.beads/README.md +81 -0
  4. data/.beads/config.yaml +54 -0
  5. data/.beads/metadata.json +7 -0
  6. data/.rspec +3 -0
  7. data/AGENTS.md +91 -0
  8. data/CHANGELOG.md +294 -0
  9. data/CLAUDE.md +67 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +565 -0
  12. data/Rakefile +13 -0
  13. data/assets/streamweaver-hero.jpg +0 -0
  14. data/bench/baselines/ledger.rb +58 -0
  15. data/bench/baselines/warroom.rb +51 -0
  16. data/bench/fixtures/ledger.rb +76 -0
  17. data/bench/fixtures/warroom.rb +60 -0
  18. data/bench/results/6daf8b8.md +102 -0
  19. data/bench/results/c8d749b.md +102 -0
  20. data/bench/results/eb06ab9.md +102 -0
  21. data/bench/run.rb +151 -0
  22. data/bench/support.rb +84 -0
  23. data/copy_this/dto_run_sample_run_7631.html +220 -0
  24. data/docs/SERVICE_MODE.md +302 -0
  25. data/docs/architecture/how_streamweaver_works.md +772 -0
  26. data/docs/blog/2026-01-16-streamweaver-introduction.md +515 -0
  27. data/docs/bug-2026-08-31-canvas-bridge-socket-collision.md +83 -0
  28. data/docs/canvas-ipc-session-summary.md +127 -0
  29. data/docs/canvas-panel-workflow.md +172 -0
  30. data/docs/canvas-read.md +147 -0
  31. data/docs/canvas-roadmap.md +275 -0
  32. data/docs/case-studies/2026-09-03-didx-canvas-read-shelf.md +147 -0
  33. data/docs/claude-code-companion-skill-spec.md +567 -0
  34. data/docs/components_reference.md +1223 -0
  35. data/docs/crud-patterns.md +265 -0
  36. data/docs/endpoints.md +122 -0
  37. data/docs/for_llms.md +1 -0
  38. data/docs/form-patterns.md +165 -0
  39. data/docs/frontend-only.md +169 -0
  40. data/docs/html-artifact-audit.md +238 -0
  41. data/docs/ideas/2025-01-01-as-a-service.md +203 -0
  42. data/docs/ideas/2026-01-16-charm-tui-exploration.md +542 -0
  43. data/docs/ideas/2026-08-27-static-doc-shelf-export.md +153 -0
  44. data/docs/ideas/dhh-review-future-refactors.md +142 -0
  45. data/docs/opal-jamstack.md +47 -0
  46. data/docs/opal-npm-direction.md +184 -0
  47. data/docs/opal-spike-findings.md +194 -0
  48. data/docs/plans/2025-12-16-form-blocks-design.md +124 -0
  49. data/docs/plans/2025-12-30-examples-browser-design.md +152 -0
  50. data/docs/plans/2026-01-02-charts-design.md +288 -0
  51. data/docs/plans/2026-01-10-canvas-ipc-design.md +247 -0
  52. data/docs/plans/2026-01-19-cabinet-control-components.md +176 -0
  53. data/docs/plans/2026-01-26-gem-release-and-panel.md +140 -0
  54. data/docs/plans/canvas-claude-project-design.md +238 -0
  55. data/docs/plans/canvas-doc-location-and-discovery.md +32 -0
  56. data/docs/plans/org-doc-preview-surfaces.md +293 -0
  57. data/docs/plans/shadcn-polish-plan.md +417 -0
  58. data/docs/porting-artifacts.md +252 -0
  59. data/docs/reference/agent-skills-comparison.md +369 -0
  60. data/docs/reference/travel-state-prd.artifact.html +780 -0
  61. data/docs/research/2026-08-17-hotwire-alike-landscape.md +268 -0
  62. data/docs/research/2026-08-17-hotwire-concept-map.md +404 -0
  63. data/docs/research/2026-08-22-lazy-fragments-trigger-decision.md +246 -0
  64. data/docs/research/2026-08-22-learnhotwire-syllabus-coverage.md +239 -0
  65. data/docs/research/frontend-only-matrix.md +278 -0
  66. data/docs/research/streamweaver-way-spike-findings.md +529 -0
  67. data/docs/resource-dsl.md +342 -0
  68. data/docs/routing.md +302 -0
  69. data/docs/ruby-ui-comparison.md +319 -0
  70. data/docs/shared-dsl-fragments.md +356 -0
  71. data/docs/streamweaver-for-ai-agents.md +401 -0
  72. data/docs/streamweaver-frontend-vision.md +123 -0
  73. data/docs/streamweaver_canvas/glimmer_initial_final_layer.rb +77 -0
  74. data/docs/streamweaver_canvas/save_example.rb +9 -0
  75. data/docs/templates.md +213 -0
  76. data/docs/testing.md +155 -0
  77. data/docs/theming-hooks.md +281 -0
  78. data/docs/tutorials/the-streamweaver-way.md +882 -0
  79. data/docs/university/capability-inventory.md +137 -0
  80. data/docs/university/dependency-survey.md +114 -0
  81. data/docs/university/design-spec.md +217 -0
  82. data/docs/university/mockups/code-block-doc-theme-dark.png +0 -0
  83. data/docs/university/mockups/code-block-doc-theme-light.png +0 -0
  84. data/docs/university/mockups/course-list-dark.png +0 -0
  85. data/docs/university/mockups/course-list-light.png +0 -0
  86. data/docs/university/mockups/course_canvas_mockup.rb +741 -0
  87. data/docs/university/mockups/step-screen-dark.png +0 -0
  88. data/docs/university/mockups/step-screen-light.png +0 -0
  89. data/docs/university/roadmap.md +72 -0
  90. data/docs/university/send-to-coworker.md +77 -0
  91. data/docs/university/worker-session-mining.md +109 -0
  92. data/docs/visual/browser-rendering-spike.md +173 -0
  93. data/docs/visual/builder-visual-plan-analysis.md +378 -0
  94. data/docs/visual/sw-plan-format-exploration.md +511 -0
  95. data/docs/visual/sw-plan-rendering-deep-dive.md +453 -0
  96. data/docs/visual-skills/PROGRESS.md +60 -0
  97. data/docs/visual-skills/SESSION-CONTEXT.md +207 -0
  98. data/docs/visual-skills/analysis/components.md +317 -0
  99. data/docs/visual-skills/analysis/overlap.md +360 -0
  100. data/docs/visual-skills/analysis/pi-design-deck.md +1102 -0
  101. data/docs/visual-skills/analysis/streamweaver-inventory.md +93 -0
  102. data/docs/visual-skills/analysis/unified-specs.feature +1003 -0
  103. data/docs/visual-skills/analysis/visual-explainer.md +964 -0
  104. data/docs/visual-skills/blog/blog-series-outline.md +39 -0
  105. data/docs/visual-skills/blog/token-efficiency.md +73 -0
  106. data/docs/visual-skills/design/architecture.md +1725 -0
  107. data/docs/visual-skills/design/codex-review.md +340 -0
  108. data/docs/visual-skills/design/dhh-review.md +209 -0
  109. data/docs/visual-skills/design/evolution.md +100 -0
  110. data/docs/visual-skills/design/gemini-review.md +55 -0
  111. data/docs/visual-skills/design/review-synthesis.md +149 -0
  112. data/docs/visual-skills/implementation/STATE.md +22 -0
  113. data/docs/visual-skills/implementation/plan.md +347 -0
  114. data/docs/visual-skills/implementation/spike-findings.md +237 -0
  115. data/docs/visual-skills/implementation/tasks.md +702 -0
  116. data/docs/visual-skills/lessons-learned/process.md +145 -0
  117. data/examples/README.md +96 -0
  118. data/examples/advanced/all_components.rb +177 -0
  119. data/examples/advanced/examples_browser.rb +394 -0
  120. data/examples/advanced/teachables_browser.rb +261 -0
  121. data/examples/advanced/theme_tweaker.rb +366 -0
  122. data/examples/advanced/tutorial.rb +1528 -0
  123. data/examples/agentic/agentic_form.rb +30 -0
  124. data/examples/agentic/agentic_form_autoclose.rb +30 -0
  125. data/examples/agentic/cultivation_tracker.rb +69 -0
  126. data/examples/basic/hello_world.rb +22 -0
  127. data/examples/basic/opal_tabs_table.rb +44 -0
  128. data/examples/basic/todo_list.rb +39 -0
  129. data/examples/button_loading_test.rb +36 -0
  130. data/examples/canvas/mermaid_canvas_demo.sh +151 -0
  131. data/examples/charts/bar_chart_demo.rb +57 -0
  132. data/examples/charts/line_chart_demo.rb +73 -0
  133. data/examples/charts/pie_area_demo.rb +87 -0
  134. data/examples/charts/stacked_bar_chart_demo.rb +69 -0
  135. data/examples/claude_code/README.md +85 -0
  136. data/examples/claude_code/codebreaker/.claude/commands/infiltrate.md +632 -0
  137. data/examples/claude_code/codebreaker/.claude/settings.json +11 -0
  138. data/examples/claude_code/codebreaker/.claude/settings.local.json +17 -0
  139. data/examples/claude_code/codebreaker/.claude/skills/infiltrate.md +0 -0
  140. data/examples/claude_code/codebreaker/README.md +213 -0
  141. data/examples/claude_code/tutorial/.claude/commands/learn.md +453 -0
  142. data/examples/claude_code/tutorial/README.md +102 -0
  143. data/examples/claude_code/verification_flow/.claude/commands/verify.md +171 -0
  144. data/examples/claude_code/verification_flow/README.md +126 -0
  145. data/examples/components/annotated_code_demo.rb +54 -0
  146. data/examples/components/callout_demo.rb +33 -0
  147. data/examples/components/checkbox_group_demo.rb +46 -0
  148. data/examples/components/design_review.css +468 -0
  149. data/examples/components/design_review_demo.rb +44 -0
  150. data/examples/components/design_review_dsl.rb +300 -0
  151. data/examples/components/diff_block_demo.rb +112 -0
  152. data/examples/components/events_demo.rb +184 -0
  153. data/examples/components/form_demo.rb +62 -0
  154. data/examples/components/lesson_demo.rb +53 -0
  155. data/examples/components/markdown_demo.rb +110 -0
  156. data/examples/components/mermaid_demo.rb +166 -0
  157. data/examples/components/pareto_set.rb +64 -0
  158. data/examples/components/prd_demo.rb +21 -0
  159. data/examples/components/prd_dsl.rb +385 -0
  160. data/examples/components/quiz_demo.rb +47 -0
  161. data/examples/components/run_viewer_demo.rb +100 -0
  162. data/examples/components/score_and_collapsible_demo.rb +82 -0
  163. data/examples/components/select_stale_value_smoke_test.rb +39 -0
  164. data/examples/components/table_demo.rb +247 -0
  165. data/examples/components/timer_with_state_demo.rb +58 -0
  166. data/examples/components/todo_due_dates.rb +63 -0
  167. data/examples/components/uat_gaps_demo.rb +112 -0
  168. data/examples/dashboard/feed_simulator.rb +60 -0
  169. data/examples/dashboard/live_dashboard.rb +80 -0
  170. data/examples/dashboard_components.rb +108 -0
  171. data/examples/deferred_fragments_demo.rb +62 -0
  172. data/examples/generate_more_spike/README.md +63 -0
  173. data/examples/generate_more_spike/app.rb +441 -0
  174. data/examples/git_health.sh +401 -0
  175. data/examples/layout/layout_components_demo.rb +174 -0
  176. data/examples/layout/modal_demo.rb +215 -0
  177. data/examples/layout/navigation_demo.rb +227 -0
  178. data/examples/layout/route_tabs_demo.rb +52 -0
  179. data/examples/layout/routing_demo.rb +52 -0
  180. data/examples/layout/scroll_box_demo.rb +154 -0
  181. data/examples/lazy_fragments_demo.rb +151 -0
  182. data/examples/my_todos/README.md +29 -0
  183. data/examples/my_todos/my_todos.rb +312 -0
  184. data/examples/my_todos/store.rb +86 -0
  185. data/examples/opal/reactive_demo.rb +62 -0
  186. data/examples/opal/scenarios/s1_counter.rb +15 -0
  187. data/examples/opal/scenarios/s2_search_filter.rb +17 -0
  188. data/examples/opal/scenarios/s3_sibling_tabs.rb +25 -0
  189. data/examples/opal/scenarios/s4_shopping_cart.rb +34 -0
  190. data/examples/opal/scenarios/s5_watch.rb +39 -0
  191. data/examples/opal/scenarios/s6_on_start.rb +20 -0
  192. data/examples/opal/scenarios/s7_wizard.rb +33 -0
  193. data/examples/opal/scenarios/s8_loan_calculator.rb +21 -0
  194. data/examples/opal/scenarios/s9_dashboard.rb +27 -0
  195. data/examples/operations_dashboard_demo.rb +167 -0
  196. data/examples/panel_demo.sh +447 -0
  197. data/examples/parity/assets/tyrion_slice.css +86 -0
  198. data/examples/parity/rivet_people_slice.rb +182 -0
  199. data/examples/parity/tyrion_components.css +777 -0
  200. data/examples/parity/tyrion_warroom_components.rb +414 -0
  201. data/examples/parity/tyrion_warroom_slice.rb +549 -0
  202. data/examples/puma_dev/README.md +124 -0
  203. data/examples/puma_dev/config.ru +34 -0
  204. data/examples/puma_dev/standalone_app.rb +34 -0
  205. data/examples/scaffolding/blog.rb +49 -0
  206. data/examples/scaffolding/utf_lite.rb +105 -0
  207. data/examples/styling/feedback_demo.rb +229 -0
  208. data/examples/styling/style_showcase.rb +172 -0
  209. data/examples/styling/theme_demo.rb +508 -0
  210. data/examples/timer_health_checker.rb +111 -0
  211. data/examples/timer_showcase.rb +131 -0
  212. data/examples/tutorials/render_markdown.rb +112 -0
  213. data/examples/tutorials/streamweaver_way_tutorial.rb +44 -0
  214. data/examples/tutorials/tutorial_content.rb +1082 -0
  215. data/examples/visual_skills/design_deck_demo.rb +314 -0
  216. data/examples/visual_skills/explainer_demo.rb +499 -0
  217. data/exe/streamweaver +9 -0
  218. data/gsd/ROADMAP-1.0.md +167 -0
  219. data/gsd/STATE.md +13 -0
  220. data/gsd/research/market-positioning-research.md +139 -0
  221. data/gsd/research/production-patterns-research.md +270 -0
  222. data/gsd/research/repo-audit-1.0.md +274 -0
  223. data/lib/stream_weaver/action_token.rb +58 -0
  224. data/lib/stream_weaver/adapter/alpinejs.rb +8249 -0
  225. data/lib/stream_weaver/adapter/base.rb +591 -0
  226. data/lib/stream_weaver/adapter/opal.rb +334 -0
  227. data/lib/stream_weaver/adapter/static.rb +1118 -0
  228. data/lib/stream_weaver/admin.rb +176 -0
  229. data/lib/stream_weaver/app.rb +1821 -0
  230. data/lib/stream_weaver/assets/js/sw-copy.js +50 -0
  231. data/lib/stream_weaver/assets/js/sw-heredoc-rewrite.js +68 -0
  232. data/lib/stream_weaver/assets/js/sw-keyboard.js +165 -0
  233. data/lib/stream_weaver/assets/js/sw-mermaid-zoom.js +621 -0
  234. data/lib/stream_weaver/assets/js/sw-route-tabs.js +53 -0
  235. data/lib/stream_weaver/assets/js/sw-sidebar-toc.js +116 -0
  236. data/lib/stream_weaver/assets/js/sw-slide-nav.js +103 -0
  237. data/lib/stream_weaver/canvas/bridge.rb +239 -0
  238. data/lib/stream_weaver/canvas/bridge_server.rb +646 -0
  239. data/lib/stream_weaver/canvas/client.rb +298 -0
  240. data/lib/stream_weaver/canvas/doc_roots.rb +233 -0
  241. data/lib/stream_weaver/canvas/doc_store.rb +252 -0
  242. data/lib/stream_weaver/canvas/gist_publisher.rb +264 -0
  243. data/lib/stream_weaver/canvas/gist_save_handler.rb +89 -0
  244. data/lib/stream_weaver/canvas/gist_store.rb +135 -0
  245. data/lib/stream_weaver/canvas/helpers.rb +109 -0
  246. data/lib/stream_weaver/canvas/history.rb +90 -0
  247. data/lib/stream_weaver/canvas/protocol.rb +86 -0
  248. data/lib/stream_weaver/canvas/reader.rb +853 -0
  249. data/lib/stream_weaver/canvas/save_doc_widget.rb +457 -0
  250. data/lib/stream_weaver/canvas/scroll_top_hint.rb +21 -0
  251. data/lib/stream_weaver/canvas/session.rb +132 -0
  252. data/lib/stream_weaver/cli.rb +3235 -0
  253. data/lib/stream_weaver/component_assets.rb +70 -0
  254. data/lib/stream_weaver/component_registry.rb +67 -0
  255. data/lib/stream_weaver/component_renderer.rb +48 -0
  256. data/lib/stream_weaver/components/annotated_code.rb +53 -0
  257. data/lib/stream_weaver/components/api_endpoint.rb +42 -0
  258. data/lib/stream_weaver/components/callout.rb +59 -0
  259. data/lib/stream_weaver/components/chart.rb +84 -0
  260. data/lib/stream_weaver/components/code_block.rb +77 -0
  261. data/lib/stream_weaver/components/comparison.rb +39 -0
  262. data/lib/stream_weaver/components/decision.rb +38 -0
  263. data/lib/stream_weaver/components/deck/close_overlay.rb +84 -0
  264. data/lib/stream_weaver/components/deck/confirmation_bar.rb +60 -0
  265. data/lib/stream_weaver/components/deck/deck_option.rb +61 -0
  266. data/lib/stream_weaver/components/deck/deck_slide.rb +77 -0
  267. data/lib/stream_weaver/components/deck/deck_state.rb +469 -0
  268. data/lib/stream_weaver/components/deck/deck_summary.rb +73 -0
  269. data/lib/stream_weaver/components/deck/design_deck.rb +60 -0
  270. data/lib/stream_weaver/components/deck/generate_more_controls.rb +84 -0
  271. data/lib/stream_weaver/components/deck/model_selector.rb +84 -0
  272. data/lib/stream_weaver/components/deck/skeleton_placeholder.rb +36 -0
  273. data/lib/stream_weaver/components/diff_block.rb +125 -0
  274. data/lib/stream_weaver/components/doc_header.rb +57 -0
  275. data/lib/stream_weaver/components/image_block.rb +70 -0
  276. data/lib/stream_weaver/components/implementation_map.rb +33 -0
  277. data/lib/stream_weaver/components/keyboard_shortcuts.rb +94 -0
  278. data/lib/stream_weaver/components/kpi_dashboard.rb +78 -0
  279. data/lib/stream_weaver/components/mermaid.rb +79 -0
  280. data/lib/stream_weaver/components/pipeline.rb +63 -0
  281. data/lib/stream_weaver/components/sidebar_toc.rb +46 -0
  282. data/lib/stream_weaver/components/slide_container.rb +141 -0
  283. data/lib/stream_weaver/components/timeline_event.rb +58 -0
  284. data/lib/stream_weaver/components/wireframe.rb +29 -0
  285. data/lib/stream_weaver/components/wireframe_block.rb +34 -0
  286. data/lib/stream_weaver/components.rb +2711 -0
  287. data/lib/stream_weaver/css.rb +230 -0
  288. data/lib/stream_weaver/dev_fallback_overlay.rb +61 -0
  289. data/lib/stream_weaver/display_dsl.rb +1004 -0
  290. data/lib/stream_weaver/export/html_exporter.rb +478 -0
  291. data/lib/stream_weaver/feed.rb +34 -0
  292. data/lib/stream_weaver/feed_builder.rb +31 -0
  293. data/lib/stream_weaver/fonts.rb +33 -0
  294. data/lib/stream_weaver/interaction_runner.rb +487 -0
  295. data/lib/stream_weaver/iterm.rb +460 -0
  296. data/lib/stream_weaver/layout_registry.rb +92 -0
  297. data/lib/stream_weaver/opal/bridge.rb +52 -0
  298. data/lib/stream_weaver/opal/builder.rb +193 -0
  299. data/lib/stream_weaver/opal/env.rb +29 -0
  300. data/lib/stream_weaver/opal/reactive_state.rb +75 -0
  301. data/lib/stream_weaver/opal/regexp_anchor_patch.rb +62 -0
  302. data/lib/stream_weaver/opal/renderer.rb +77 -0
  303. data/lib/stream_weaver/opal/runtime.rb +250 -0
  304. data/lib/stream_weaver/opal/shell.rb +145 -0
  305. data/lib/stream_weaver/opal/string_bridge.rb +50 -0
  306. data/lib/stream_weaver/opal/stubs/diff.min.js +1 -0
  307. data/lib/stream_weaver/opal/stubs/digest.rb +15 -0
  308. data/lib/stream_weaver/opal/stubs/marked.umd.js +79 -0
  309. data/lib/stream_weaver/opal/stubs/md5.rb +3 -0
  310. data/lib/stream_weaver/opal/stubs/morphdom.min.js +775 -0
  311. data/lib/stream_weaver/opal/stubs/prism-tomorrow.min.css +1 -0
  312. data/lib/stream_weaver/opal/stubs/prism.min.js +1967 -0
  313. data/lib/stream_weaver/opal_entry.rb +136 -0
  314. data/lib/stream_weaver/org/inline.rb +95 -0
  315. data/lib/stream_weaver/org/reader.rb +561 -0
  316. data/lib/stream_weaver/org/recording_context.rb +86 -0
  317. data/lib/stream_weaver/org/source_splitter.rb +63 -0
  318. data/lib/stream_weaver/org/writer.rb +300 -0
  319. data/lib/stream_weaver/page_shell.rb +530 -0
  320. data/lib/stream_weaver/portfile.rb +79 -0
  321. data/lib/stream_weaver/pushable.rb +42 -0
  322. data/lib/stream_weaver/resource/default_views.rb +111 -0
  323. data/lib/stream_weaver/resource/field_input.rb +25 -0
  324. data/lib/stream_weaver/resource/state_keys.rb +16 -0
  325. data/lib/stream_weaver/resource/store.rb +18 -0
  326. data/lib/stream_weaver/resource.rb +104 -0
  327. data/lib/stream_weaver/server.rb +1471 -0
  328. data/lib/stream_weaver/service.rb +1240 -0
  329. data/lib/stream_weaver/service_client.rb +104 -0
  330. data/lib/stream_weaver/session_store.rb +186 -0
  331. data/lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md +66 -0
  332. data/lib/stream_weaver/skills/streamweaver-canvas-safe/examples/canvas-safe-showcase.rb +98 -0
  333. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/actions-and-buttons.md +47 -0
  334. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/charts-and-diagrams.md +38 -0
  335. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/deck.md +32 -0
  336. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/inputs-and-forms.md +65 -0
  337. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/tabs-and-navigation.md +53 -0
  338. data/lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md +298 -0
  339. data/lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md +130 -0
  340. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.css +468 -0
  341. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.rb +39 -0
  342. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example_dsl.rb +300 -0
  343. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example.rb +24 -0
  344. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb +385 -0
  345. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md +28 -0
  346. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/cleanup-and-panel.md +44 -0
  347. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/example-gallery.md +8 -0
  348. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/persistence.md +58 -0
  349. data/lib/stream_weaver/skills/streamweaver-way/SKILL.md +396 -0
  350. data/lib/stream_weaver/skills/visual-plan/SKILL.md +201 -0
  351. data/lib/stream_weaver/skills/visual-recap/SKILL.md +244 -0
  352. data/lib/stream_weaver/streamer.rb +63 -0
  353. data/lib/stream_weaver/templates/choices.rb +149 -0
  354. data/lib/stream_weaver/templates/code.rb +157 -0
  355. data/lib/stream_weaver/templates/confirm.rb +110 -0
  356. data/lib/stream_weaver/templates/diff.rb +195 -0
  357. data/lib/stream_weaver/templates/info.rb +142 -0
  358. data/lib/stream_weaver/templates/table.rb +169 -0
  359. data/lib/stream_weaver/templates/wizard.rb +271 -0
  360. data/lib/stream_weaver/theme/auto_mode.rb +116 -0
  361. data/lib/stream_weaver/theme/presets.rb +555 -0
  362. data/lib/stream_weaver/theme.rb +639 -0
  363. data/lib/stream_weaver/university/canvas.rb +924 -0
  364. data/lib/stream_weaver/university/course.rb +699 -0
  365. data/lib/stream_weaver/university/demos/counter.rb +33 -0
  366. data/lib/stream_weaver/university/demos/dashboard.rb +147 -0
  367. data/lib/stream_weaver/university/demos/decision_form.rb +143 -0
  368. data/lib/stream_weaver/university/demos.rb +50 -0
  369. data/lib/stream_weaver/university/listener.rb +467 -0
  370. data/lib/stream_weaver/university/progress.rb +201 -0
  371. data/lib/stream_weaver/university/runner.rb +138 -0
  372. data/lib/stream_weaver/university/scripts/growing_doc.rb +609 -0
  373. data/lib/stream_weaver/university/scripts/growing_doc_state.rb +91 -0
  374. data/lib/stream_weaver/utils.rb +31 -0
  375. data/lib/stream_weaver/version.rb +5 -0
  376. data/lib/stream_weaver/views/canvas/reader_layout.erb +800 -0
  377. data/lib/stream_weaver/views.rb +3940 -0
  378. data/lib/stream_weaver.rb +122 -0
  379. data/llms.txt +1269 -0
  380. data/sig/stream_weaver.rbs +4 -0
  381. metadata +598 -0
@@ -0,0 +1,777 @@
1
+ /* Tyrion War Room -- component-parity slice (stream_weaver-oeo proof)
2
+ *
3
+ * ONE stylesheet, targeting ONLY the sw- hook classes documented in
4
+ * docs/theming-hooks.md (now including sw-topbar and lane's icon:
5
+ * slot, both added by this same ticket) plus this slice's own tc-
6
+ * prefixed classes for the handful of elements with no dedicated
7
+ * component (git/error pills, war-table hero wrapper, story-detail page
8
+ * chrome -- see this file's companion .rb header comment for why those
9
+ * specific gaps exist). No specificity workaround anywhere -- every
10
+ * framework rule lives in @layer stream-weaver (stream_weaver-oeo
11
+ * commit 1), so a plain unlayered selector here always wins.
12
+ *
13
+ * Palette/type values re-derived by reading (READ-ONLY, never copied)
14
+ * ~/work/tyrion/web/public/shared.css's :root custom properties and
15
+ * .wr-board/.wr-col-header/.wr-card rules (translucency/photo-bg
16
+ * convergence pass, same ticket).
17
+ */
18
+
19
+ :root {
20
+ --tc-bg: #0D0A07;
21
+ --tc-surface: #1A1208;
22
+ --tc-border: #4A3520;
23
+ --tc-text: #F5E6C8;
24
+ --tc-text-dim: #D4B896;
25
+ --tc-text-muted: #9B7D5A;
26
+ --tc-text-faint: #6B5037;
27
+ --tc-amber: #F59E0B;
28
+ --tc-amber-dim: #D97706;
29
+ --tc-crimson: #DC2626;
30
+ --tc-emerald: #16A34A;
31
+ --tc-gold: #D97706;
32
+ --tc-gold-bright: #F59E0B;
33
+ --tc-parchment: #F0E4C0;
34
+ --tc-parchment-aged: #D9CDB0;
35
+ --tc-ink: #1A0E05;
36
+ --tc-ink-dim: #3D2410;
37
+ --tc-ink-muted: #6B4525;
38
+ --tc-ink-faint: #9B7550;
39
+ --tc-font-display: 'Cinzel', Georgia, serif;
40
+ --tc-font-serif: 'Lora', Georgia, serif;
41
+ --tc-font-mono: 'IBM Plex Mono', monospace;
42
+ --tc-sidebar-w: 240px;
43
+ --tc-topbar-h: 52px;
44
+ --tc-navbar-h: 40px;
45
+ }
46
+
47
+ html, body {
48
+ height: 100%;
49
+ overflow: hidden;
50
+ }
51
+
52
+ body.sw-chromeless {
53
+ padding: 0;
54
+ }
55
+
56
+ /* ===========================================================
57
+ Topbar (sw-topbar hooks, stream_weaver-oeo -- replaces the
58
+ design-parity-fights.md #6 hand-rolled tc-topbar div/phrase soup)
59
+ =========================================================== */
60
+ .sw-topbar {
61
+ height: var(--tc-topbar-h);
62
+ min-height: var(--tc-topbar-h);
63
+ padding: 0 16px;
64
+ background: var(--tc-surface);
65
+ border-bottom: 0;
66
+ gap: 8px;
67
+ /* Real .topbar carries the war-table photo too (re-derived from
68
+ ~/work/tyrion/web/public/shared.css, read-only) -- MAP_URL's
69
+ resolved value is appended by the .rb file as a small inline
70
+ override (env var unset: this gradient-only fallback stands). */
71
+ background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.48), rgba(13, 10, 7, 0.88));
72
+ background-size: cover;
73
+ background-position: center 35%;
74
+ }
75
+
76
+ .sw-topbar-icon {
77
+ width: 34px;
78
+ height: 34px;
79
+ }
80
+
81
+ .sw-topbar-wordmark {
82
+ font-family: var(--tc-font-display);
83
+ font-size: 22px;
84
+ font-weight: 700;
85
+ color: var(--tc-gold-bright);
86
+ letter-spacing: 0.1em;
87
+ }
88
+
89
+ .sw-topbar-breadcrumbs {
90
+ font-family: var(--tc-font-mono);
91
+ font-size: 13px;
92
+ color: var(--tc-text-muted);
93
+ }
94
+
95
+ .sw-topbar-separator {
96
+ color: var(--tc-text-faint);
97
+ }
98
+
99
+ .sw-topbar-crumb--active {
100
+ color: var(--tc-gold-bright);
101
+ font-weight: 500;
102
+ }
103
+
104
+ .tc-pill {
105
+ font-family: var(--tc-font-mono);
106
+ font-size: 11px;
107
+ padding: 3px 8px;
108
+ border-radius: 4px;
109
+ background: rgba(255, 255, 255, 0.06);
110
+ color: var(--tc-text-dim);
111
+ }
112
+
113
+ .tc-pill--amber {
114
+ background: rgba(245, 158, 11, 0.12);
115
+ color: var(--tc-amber);
116
+ }
117
+
118
+ /* navbar (real sw-navbar/sw-navbar-item hooks) */
119
+ .tc-navbar.sw-navbar {
120
+ height: var(--tc-navbar-h);
121
+ background: rgba(0, 0, 0, 0.42);
122
+ border-top: 1px solid rgba(107, 78, 42, 0.45);
123
+ border-bottom: 2px solid var(--tc-border);
124
+ padding: 0 8px;
125
+ margin-bottom: 0;
126
+ gap: 0;
127
+ }
128
+
129
+ .sw-navbar-item {
130
+ display: inline-flex;
131
+ align-items: center;
132
+ font-family: var(--tc-font-mono);
133
+ font-size: 13px;
134
+ color: var(--tc-text-muted);
135
+ padding: 8px 12px 7px;
136
+ text-decoration: none;
137
+ }
138
+
139
+ .sw-navbar-item-active {
140
+ color: var(--tc-gold-bright);
141
+ border-bottom: 2px solid var(--tc-gold-bright);
142
+ }
143
+
144
+ .sw-navbar-item__close {
145
+ order: -1;
146
+ margin: 0 6px 0 0;
147
+ opacity: 1;
148
+ font-weight: 400;
149
+ }
150
+
151
+ /* ===========================================================
152
+ Shell / Sidebar (sw-app-shell / sw-sidebar hooks)
153
+ =========================================================== */
154
+ .tc-shell.sw-app-shell {
155
+ height: calc(100% - var(--tc-topbar-h) - var(--tc-navbar-h));
156
+ }
157
+
158
+ .sw-app-shell-main {
159
+ overflow-y: auto;
160
+ background: var(--tc-bg);
161
+ }
162
+
163
+ .tc-sidebar.sw-sidebar {
164
+ background: var(--tc-surface);
165
+ border-right: 1px solid var(--tc-border);
166
+ overflow: hidden;
167
+ padding-bottom: 0;
168
+ }
169
+
170
+ .tc-sidebar-path {
171
+ padding: 8px 14px 0;
172
+ font-size: 11px;
173
+ color: var(--tc-text-faint);
174
+ font-family: var(--tc-font-mono);
175
+ }
176
+
177
+ /* The framework's own .sw-sidebar-section hook is card-styled
178
+ (background/border/radius, meant for a "Monica-style" facts box) --
179
+ insufficient for a bare section label like "Stories · warroom-
180
+ components" (white-band regression, stream_weaver-oeo review). Fix is
181
+ exactly what docs/theming-hooks.md's own worked example shows:
182
+ background: transparent, no border -- this hook is a plain CSS
183
+ utility, not a dedicated component, so there's nothing to change in
184
+ the framework itself. */
185
+ .sw-sidebar-section {
186
+ background: transparent;
187
+ border: none;
188
+ border-radius: 0;
189
+ padding: 12px 14px 4px;
190
+ font-size: 11px;
191
+ font-family: var(--tc-font-display);
192
+ font-weight: 500;
193
+ text-transform: uppercase;
194
+ letter-spacing: 0.14em;
195
+ color: var(--tc-text-dim);
196
+ white-space: nowrap;
197
+ overflow: hidden;
198
+ text-overflow: ellipsis;
199
+ }
200
+
201
+ .tc-story-row.sw-clickable {
202
+ display: flex;
203
+ align-items: center;
204
+ gap: 8px;
205
+ padding: 6px 10px 6px 12px;
206
+ margin: 2px 8px;
207
+ font-family: var(--tc-font-mono);
208
+ font-size: 15px;
209
+ color: var(--tc-ink-dim);
210
+ text-decoration: none;
211
+ border: 1px solid #B8A070;
212
+ border-radius: 3px;
213
+ background: var(--tc-parchment-aged);
214
+ min-width: 0;
215
+ }
216
+
217
+ .tc-story-row:hover {
218
+ background: #F5EDD8;
219
+ border-color: var(--tc-amber);
220
+ }
221
+
222
+ .tc-story-row--done .tc-story-icon {
223
+ color: var(--tc-emerald);
224
+ }
225
+
226
+ .tc-story-row--done {
227
+ opacity: 0.65;
228
+ }
229
+
230
+ .tc-story-name {
231
+ min-width: 0;
232
+ overflow: hidden;
233
+ text-overflow: ellipsis;
234
+ white-space: nowrap;
235
+ }
236
+
237
+ .tc-story-row--in_progress .tc-story-icon {
238
+ color: var(--tc-amber);
239
+ }
240
+
241
+ .tc-story-row--pending .tc-story-icon {
242
+ color: var(--tc-text-faint);
243
+ }
244
+
245
+ .tc-discoveries {
246
+ margin-top: auto;
247
+ border-top: 1px solid var(--tc-border);
248
+ padding: 10px 0 8px;
249
+ }
250
+
251
+ .tc-disc-row.sw-clickable {
252
+ display: flex;
253
+ align-items: center;
254
+ gap: 8px;
255
+ padding: 4px 14px;
256
+ text-decoration: none;
257
+ }
258
+
259
+ .tc-disc-pill {
260
+ font-family: var(--tc-font-mono);
261
+ font-size: 10px;
262
+ padding: 2px 6px;
263
+ border-radius: 3px;
264
+ color: var(--tc-ink);
265
+ }
266
+
267
+ .tc-disc-pill--spike {
268
+ background: #7C3AED;
269
+ color: #fff;
270
+ }
271
+
272
+ .tc-disc-pill--mark {
273
+ background: rgba(255, 255, 255, 0.08);
274
+ color: var(--tc-text-dim);
275
+ }
276
+
277
+ .tc-disc-label {
278
+ font-size: 12px;
279
+ color: var(--tc-text-muted);
280
+ }
281
+
282
+ /* ===========================================================
283
+ War table hero + board (sw-board / sw-board__lane / sw-board__card hooks)
284
+ =========================================================== */
285
+ .tc-board-hero {
286
+ position: relative;
287
+ height: 100%;
288
+ min-height: 0;
289
+ /* War-table photo goes here (MAP_URL, appended by the .rb file as a
290
+ small inline override -- see its header comment); unset MAP_URL
291
+ falls back to this gradient-only look. */
292
+ background:
293
+ radial-gradient(circle at 50% 52%, rgba(255, 180, 60, 0.08), transparent 32%),
294
+ linear-gradient(180deg, rgba(8, 10, 11, 0.55), rgba(8, 10, 11, 0.75)), var(--tc-bg);
295
+ padding: 0;
296
+ overflow: hidden;
297
+ }
298
+
299
+ .tc-dragon-zone {
300
+ position: absolute;
301
+ top: 88px;
302
+ bottom: 196px;
303
+ left: 50%;
304
+ width: 22%;
305
+ transform: translateX(-50%);
306
+ z-index: 1;
307
+ display: flex;
308
+ flex-direction: column;
309
+ align-items: center;
310
+ justify-content: center;
311
+ text-align: center;
312
+ color: #ead7ba;
313
+ padding: 24px 16px;
314
+ border-radius: 24px;
315
+ background:
316
+ radial-gradient(circle at 50% 48%, rgba(255, 80, 20, 0.28), rgba(0, 0, 0, 0) 26%),
317
+ radial-gradient(circle at 50% 45%, rgba(0, 0, 0, 0.62), rgba(0, 0, 0, 0.24) 55%, rgba(0, 0, 0, 0) 82%);
318
+ pointer-events: none;
319
+ }
320
+
321
+ .tc-dragon-zone::before {
322
+ content: "";
323
+ position: absolute;
324
+ inset: 8% 12%;
325
+ background: radial-gradient(circle at 50% 48%, rgba(255, 112, 54, 0.28), rgba(255, 80, 20, 0.08) 22%, transparent 50%);
326
+ filter: blur(14px);
327
+ }
328
+
329
+ .tc-dragon-glyph.tc-art-img {
330
+ width: 70px;
331
+ height: 70px;
332
+ margin: 0 auto 10px;
333
+ position: relative;
334
+ z-index: 2;
335
+ background-size: contain;
336
+ background-repeat: no-repeat;
337
+ background-position: center;
338
+ opacity: 0.82;
339
+ filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.5));
340
+ }
341
+
342
+ .tc-dragon-glyph.tc-art-glyph {
343
+ display: block;
344
+ font-size: 48px;
345
+ margin-bottom: 10px;
346
+ opacity: 0.82;
347
+ }
348
+
349
+ .tc-dragon-zone h3 {
350
+ font-family: var(--tc-font-display);
351
+ position: relative;
352
+ z-index: 2;
353
+ margin: 0 0 8px;
354
+ font-size: 22px;
355
+ letter-spacing: 0.04em;
356
+ color: #f0cdb4;
357
+ }
358
+
359
+ .tc-dragon-zone p {
360
+ position: relative;
361
+ z-index: 2;
362
+ color: var(--tc-text-dim);
363
+ margin: 0;
364
+ font-size: 13px;
365
+ line-height: 1.5;
366
+ }
367
+
368
+ /* Board frame: rounded/bordered/shadowed like the real .wr-board so the
369
+ photo doesn't bleed square corners past the war-table edge, gap: 0 +
370
+ each lane's own border-right (below) reproduces the real CSS's
371
+ edge-to-edge columns-with-rule-lines look instead of a gutter that
372
+ shows flat board-hero background between lanes. */
373
+ .sw-board {
374
+ position: relative;
375
+ z-index: 2;
376
+ gap: 0;
377
+ width: 100%;
378
+ height: 100%;
379
+ margin: 0;
380
+ align-items: stretch;
381
+ border-radius: 16px;
382
+ border: 1px solid rgba(215, 176, 102, 0.28);
383
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.45);
384
+ overflow: hidden;
385
+ }
386
+
387
+ .sw-board--pinned-headers {
388
+ overflow-x: hidden;
389
+ overflow-y: hidden;
390
+ }
391
+
392
+ .sw-board--pinned-headers .sw-board__lane {
393
+ max-height: 100%;
394
+ overflow-y: auto;
395
+ scrollbar-width: thin;
396
+ scrollbar-color: rgba(215, 176, 102, 0.2) transparent;
397
+ }
398
+
399
+ .sw-board::after {
400
+ content: "";
401
+ position: absolute;
402
+ inset: 0;
403
+ background:
404
+ radial-gradient(circle at 50% 52%, rgba(255, 180, 60, 0.07), transparent 22%),
405
+ linear-gradient(180deg, rgba(18, 18, 18, 0.06), rgba(3, 4, 5, 0.22));
406
+ pointer-events: none;
407
+ z-index: 1;
408
+ }
409
+
410
+ /* Lane containers stay transparent so the war-table photo shows through
411
+ uninterrupted -- only a soft vertical rule separates them (softer
412
+ than the framework default's solid 1px box border all around, per
413
+ stream_weaver-oeo review's "softer lane container borders" note). */
414
+ .sw-board__lane {
415
+ flex: 1 0 25%;
416
+ min-width: 0;
417
+ min-height: 100%;
418
+ position: relative;
419
+ z-index: 2;
420
+ background: transparent;
421
+ border: none;
422
+ border-right: 1px solid rgba(215, 176, 102, 0.18);
423
+ border-radius: 0;
424
+ }
425
+
426
+ .sw-board__lane:last-child {
427
+ border-right: none;
428
+ }
429
+
430
+ /* Muted, translucent parchment-gradient bands (re-derived from
431
+ ~/work/tyrion/web/public/shared.css's .wr-col-header/.active-hdr/
432
+ .dragons-hdr/.done-hdr, read-only) -- NOT the flat saturated
433
+ --tc-gold/--tc-crimson/--tc-emerald blocks this slice shipped with
434
+ originally (stream_weaver-oeo review finding). */
435
+ .sw-board__lane-header {
436
+ background: linear-gradient(180deg, rgba(236, 220, 184, 0.94), rgba(187, 164, 122, 0.92));
437
+ color: #2b2418;
438
+ height: 78px;
439
+ padding: 0 14px;
440
+ justify-content: center;
441
+ text-align: center;
442
+ border-bottom: 1px solid rgba(89, 70, 40, 0.3);
443
+ box-shadow: inset 0 -4px 18px rgba(64, 43, 14, 0.1);
444
+ z-index: 4;
445
+ }
446
+
447
+ .sw-board__lane-header--neutral {
448
+ background: linear-gradient(180deg, rgba(236, 220, 184, 0.94), rgba(187, 164, 122, 0.92));
449
+ color: #2b2418;
450
+ }
451
+
452
+ .sw-board__lane-header--warning {
453
+ background: linear-gradient(180deg, rgba(255, 220, 140, 0.95), rgba(210, 160, 60, 0.9));
454
+ color: #2b2418;
455
+ }
456
+
457
+ .sw-board__lane-header--error {
458
+ background: linear-gradient(180deg, rgba(200, 130, 120, 0.92), rgba(155, 70, 60, 0.88));
459
+ color: #2a0e0a;
460
+ }
461
+
462
+ .sw-board__lane-header--success {
463
+ background: linear-gradient(180deg, rgba(180, 210, 170, 0.93), rgba(130, 165, 110, 0.88));
464
+ color: #1a2e14;
465
+ }
466
+
467
+ .sw-board__lane-icon {
468
+ width: 22px;
469
+ height: 22px;
470
+ margin-right: 0;
471
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4));
472
+ }
473
+
474
+ .sw-board__lane-title {
475
+ font-family: var(--tc-font-display);
476
+ font-size: 15px;
477
+ font-weight: 700;
478
+ text-transform: uppercase;
479
+ letter-spacing: 0.06em;
480
+ line-height: 1.1;
481
+ text-align: center;
482
+ }
483
+
484
+ .sw-board__lane-subtitle {
485
+ font-size: 11px;
486
+ opacity: 0.7;
487
+ text-align: center;
488
+ margin-top: 2px;
489
+ }
490
+
491
+ .sw-board__lane-count {
492
+ position: absolute;
493
+ right: 16px;
494
+ top: 50%;
495
+ transform: translateY(-50%);
496
+ font-family: var(--tc-font-display);
497
+ font-size: 20px;
498
+ opacity: 1;
499
+ }
500
+
501
+ .sw-board__lane-body {
502
+ background: transparent;
503
+ padding: 14px;
504
+ gap: 0;
505
+ min-height: 60px;
506
+ }
507
+
508
+ /* Warm parchment cards floating on the map, translucent enough that the
509
+ photo still reads through the gaps between them (re-derived from the
510
+ real .wr-card, read-only). */
511
+ .sw-board__card {
512
+ position: relative;
513
+ background: linear-gradient(180deg, rgba(236, 220, 184, 0.97), rgba(209, 186, 141, 0.96));
514
+ color: var(--tc-ink);
515
+ border-radius: 12px;
516
+ padding: 14px 14px 12px;
517
+ border: 1px solid rgba(96, 73, 32, 0.35);
518
+ margin-bottom: 12px;
519
+ text-decoration: none;
520
+ display: block;
521
+ box-shadow: 0 12px 26px rgba(0, 0, 0, 0.22), inset 0 0 0 1px rgba(255, 255, 255, 0.18);
522
+ }
523
+
524
+ /* Decorative corner studs (re-derived from the real .wr-card::before/
525
+ ::after, read-only). */
526
+ .sw-board__card::before,
527
+ .sw-board__card::after {
528
+ content: "";
529
+ position: absolute;
530
+ width: 8px;
531
+ height: 8px;
532
+ top: 8px;
533
+ border-radius: 50%;
534
+ background: #92713c;
535
+ opacity: 0.6;
536
+ box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.35), 0 1px 2px rgba(0, 0, 0, 0.28);
537
+ }
538
+
539
+ .sw-board__card::before {
540
+ left: 10px;
541
+ }
542
+
543
+ .sw-board__card::after {
544
+ right: 10px;
545
+ }
546
+
547
+ .sw-board__card--error {
548
+ border-left: 3px solid var(--tc-crimson);
549
+ }
550
+
551
+ .tc-card--done {
552
+ background: linear-gradient(180deg, rgba(200, 190, 160, 0.88), rgba(175, 162, 128, 0.84));
553
+ opacity: 0.82;
554
+ }
555
+
556
+ .sw-board__card h4 {
557
+ font-family: var(--tc-font-serif);
558
+ font-size: 17px;
559
+ line-height: 1.25;
560
+ font-weight: 500;
561
+ margin: 0;
562
+ color: var(--tc-ink);
563
+ }
564
+
565
+ .tc-card-epic {
566
+ font-family: var(--tc-font-mono);
567
+ display: block;
568
+ font-size: 13px;
569
+ color: #564327;
570
+ margin-bottom: 6px;
571
+ }
572
+
573
+ .tc-card-ctx {
574
+ font-size: 12px;
575
+ color: #4a3318;
576
+ margin-top: 6px;
577
+ font-family: var(--tc-font-mono);
578
+ line-height: 1.4;
579
+ }
580
+
581
+ .sw-board__card .sw-badge {
582
+ display: inline-block;
583
+ margin-top: 10px;
584
+ padding: 3px 8px;
585
+ border: 1px solid rgba(88, 70, 41, 0.2);
586
+ border-radius: 6px;
587
+ background: rgba(113, 92, 58, 0.14);
588
+ color: #3e3222;
589
+ font-family: var(--tc-font-mono);
590
+ font-size: 11px;
591
+ line-height: 1.2;
592
+ }
593
+
594
+ .tc-card-done-meta {
595
+ font-size: 11px;
596
+ color: #166534;
597
+ }
598
+
599
+ .tc-card--stale {
600
+ opacity: 0.85;
601
+ }
602
+
603
+ .tc-stale-badge {
604
+ display: block;
605
+ font-size: 10px;
606
+ color: var(--tc-crimson);
607
+ margin-bottom: 4px;
608
+ }
609
+
610
+ /* ===========================================================
611
+ Story detail page (no dedicated component -- sw-card/sw-status-badge hooks)
612
+ =========================================================== */
613
+ .tc-story-page {
614
+ max-width: 760px;
615
+ margin: 0 auto;
616
+ padding: 24px;
617
+ }
618
+
619
+ .tc-back-link.sw-clickable {
620
+ display: inline-block;
621
+ font-size: 12px;
622
+ font-family: var(--tc-font-mono);
623
+ color: var(--tc-text-faint);
624
+ text-decoration: none;
625
+ margin-bottom: 12px;
626
+ }
627
+
628
+ .sw-card {
629
+ background: var(--tc-surface);
630
+ border: 1px solid var(--tc-border);
631
+ color: var(--tc-text-dim);
632
+ }
633
+
634
+ .tc-story-hero.sw-card {
635
+ background: linear-gradient(160deg, var(--tc-surface), var(--tc-bg));
636
+ }
637
+
638
+ .sw-card-header {
639
+ font-family: var(--tc-font-display);
640
+ font-size: 12px;
641
+ text-transform: uppercase;
642
+ letter-spacing: 0.08em;
643
+ color: var(--tc-text-faint);
644
+ padding: 12px 16px 4px;
645
+ }
646
+
647
+ .sw-card-body {
648
+ padding: 8px 16px 16px;
649
+ color: var(--tc-text-dim);
650
+ }
651
+
652
+ .tc-hero-status {
653
+ display: flex;
654
+ align-items: center;
655
+ gap: 10px;
656
+ }
657
+
658
+ .tc-hero-meta {
659
+ font-size: 12px;
660
+ color: var(--tc-text-muted);
661
+ }
662
+
663
+ .tc-hero-title {
664
+ font-family: var(--tc-font-display);
665
+ font-size: 26px;
666
+ color: var(--tc-text);
667
+ margin: 8px 0 0;
668
+ }
669
+
670
+ .tc-brief {
671
+ background: rgba(180, 140, 80, 0.08);
672
+ border-left: 3px solid rgba(180, 140, 80, 0.35);
673
+ border-radius: 0 6px 6px 0;
674
+ padding: 10px 14px;
675
+ margin-top: 14px;
676
+ }
677
+
678
+ .tc-brief-label {
679
+ font-size: 10px;
680
+ font-family: var(--tc-font-mono);
681
+ color: var(--tc-text-faint);
682
+ letter-spacing: 0.1em;
683
+ display: block;
684
+ margin-bottom: 6px;
685
+ }
686
+
687
+ .tc-brief-text {
688
+ font-family: var(--tc-font-serif);
689
+ font-size: 14px;
690
+ color: var(--tc-text-dim);
691
+ font-style: italic;
692
+ }
693
+
694
+ .tc-story-split {
695
+ display: grid;
696
+ grid-template-columns: 1fr 1fr;
697
+ gap: 16px;
698
+ }
699
+
700
+ .tc-crit-row {
701
+ display: flex;
702
+ align-items: center;
703
+ gap: 8px;
704
+ padding: 4px 0;
705
+ }
706
+
707
+ .tc-crit-check {
708
+ color: var(--tc-text-faint);
709
+ }
710
+
711
+ .tc-crit-row--met .tc-crit-check {
712
+ color: var(--tc-emerald);
713
+ }
714
+
715
+ .tc-note-entry {
716
+ padding: 6px 0;
717
+ border-bottom: 1px solid var(--tc-border);
718
+ }
719
+
720
+ .tc-note-meta {
721
+ display: block;
722
+ font-size: 11px;
723
+ color: var(--tc-text-faint);
724
+ font-family: var(--tc-font-mono);
725
+ }
726
+
727
+ .tc-note-body {
728
+ font-size: 13px;
729
+ color: var(--tc-text-dim);
730
+ }
731
+
732
+ .tc-resume-strip {
733
+ display: grid;
734
+ grid-template-columns: 1fr 1.4fr 1fr;
735
+ gap: 12px;
736
+ margin-top: 16px;
737
+ padding: 14px;
738
+ background: var(--tc-surface);
739
+ border-radius: 6px;
740
+ border: 1px solid var(--tc-border);
741
+ }
742
+
743
+ .tc-rs-panel {
744
+ display: flex;
745
+ flex-direction: column;
746
+ gap: 4px;
747
+ }
748
+
749
+ .tc-rs-panel--beacon {
750
+ flex-direction: row;
751
+ align-items: center;
752
+ gap: 10px;
753
+ }
754
+
755
+ .tc-lantern-glyph.tc-art-img {
756
+ width: 32px;
757
+ height: 32px;
758
+ background-size: contain;
759
+ background-repeat: no-repeat;
760
+ background-position: center;
761
+ }
762
+
763
+ .tc-lantern-glyph.tc-art-glyph {
764
+ font-size: 24px;
765
+ }
766
+
767
+ .tc-rs-label {
768
+ font-size: 10px;
769
+ font-family: var(--tc-font-mono);
770
+ color: var(--tc-text-faint);
771
+ letter-spacing: 0.08em;
772
+ }
773
+
774
+ .tc-rs-text {
775
+ font-size: 13px;
776
+ color: var(--tc-text-dim);
777
+ }