synthos 0.7.1 → 0.8.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 (263) hide show
  1. package/README.md +215 -65
  2. package/default-pages/application.json +1 -0
  3. package/default-pages/json_tools.json +1 -1
  4. package/default-pages/oregon_trail.html +321 -0
  5. package/default-pages/oregon_trail.json +12 -0
  6. package/default-pages/sidebar_page.json +1 -0
  7. package/default-pages/solar_explorer.html +10 -18
  8. package/default-pages/solar_explorer.json +2 -2
  9. package/default-pages/two-panel_page.json +1 -0
  10. package/default-pages/us_map.html +192 -0
  11. package/default-pages/us_map.json +12 -0
  12. package/default-pages/us_map_1850.html +325 -0
  13. package/default-pages/us_map_1850.json +12 -0
  14. package/default-pages/western_cities_1850.html +526 -0
  15. package/default-pages/western_cities_1850.json +12 -0
  16. package/default-themes/{nebula-dawn.css → nebula-dawn.v2.css} +24 -0
  17. package/default-themes/{nebula-dusk.css → nebula-dusk.v2.css} +24 -0
  18. package/dist/agents/a2a/a2aProvider.d.ts +3 -0
  19. package/dist/agents/a2a/a2aProvider.d.ts.map +1 -0
  20. package/dist/agents/a2a/a2aProvider.js +126 -0
  21. package/dist/agents/a2a/a2aProvider.js.map +1 -0
  22. package/dist/agents/discovery.d.ts +30 -0
  23. package/dist/agents/discovery.d.ts.map +1 -0
  24. package/dist/agents/discovery.js +52 -0
  25. package/dist/agents/discovery.js.map +1 -0
  26. package/dist/agents/index.d.ts +7 -0
  27. package/dist/agents/index.d.ts.map +1 -0
  28. package/dist/agents/index.js +19 -0
  29. package/dist/agents/index.js.map +1 -0
  30. package/dist/agents/openclaw/gatewayManager.d.ts +113 -0
  31. package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -0
  32. package/dist/agents/openclaw/gatewayManager.js +470 -0
  33. package/dist/agents/openclaw/gatewayManager.js.map +1 -0
  34. package/dist/agents/openclaw/openclawProvider.d.ts +3 -0
  35. package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -0
  36. package/dist/agents/openclaw/openclawProvider.js +239 -0
  37. package/dist/agents/openclaw/openclawProvider.js.map +1 -0
  38. package/dist/agents/openclaw/sshTunnelManager.d.ts +23 -0
  39. package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -0
  40. package/dist/agents/openclaw/sshTunnelManager.js +340 -0
  41. package/dist/agents/openclaw/sshTunnelManager.js.map +1 -0
  42. package/dist/agents/types.d.ts +64 -0
  43. package/dist/agents/types.d.ts.map +1 -0
  44. package/dist/agents/types.js +6 -0
  45. package/dist/agents/types.js.map +1 -0
  46. package/dist/connectors/airtable/connector.json +27 -0
  47. package/dist/connectors/alpha-vantage/connector.json +26 -0
  48. package/dist/connectors/brave-search/connector.json +26 -0
  49. package/dist/connectors/cloudinary/connector.json +27 -0
  50. package/dist/connectors/deepl/connector.json +28 -0
  51. package/dist/connectors/elevenlabs/connector.json +30 -0
  52. package/dist/connectors/giphy/connector.json +27 -0
  53. package/dist/connectors/github/connector.json +29 -0
  54. package/dist/connectors/huggingface/connector.json +27 -0
  55. package/dist/connectors/imgur/connector.json +29 -0
  56. package/dist/connectors/index.d.ts +1 -1
  57. package/dist/connectors/index.d.ts.map +1 -1
  58. package/dist/connectors/instagram/connector.json +43 -0
  59. package/dist/connectors/jira/connector.json +28 -0
  60. package/dist/connectors/mapbox/connector.json +26 -0
  61. package/dist/connectors/nasa/connector.json +27 -0
  62. package/dist/connectors/newsapi/connector.json +27 -0
  63. package/dist/connectors/notion/connector.json +28 -0
  64. package/dist/connectors/open-exchange-rates/connector.json +27 -0
  65. package/dist/connectors/openweathermap/connector.json +26 -0
  66. package/dist/connectors/pexels/connector.json +27 -0
  67. package/dist/connectors/registry.d.ts.map +1 -1
  68. package/dist/connectors/registry.js +42 -96
  69. package/dist/connectors/registry.js.map +1 -1
  70. package/dist/connectors/resend/connector.json +29 -0
  71. package/dist/connectors/rss2json/connector.json +27 -0
  72. package/dist/connectors/sendgrid/connector.json +27 -0
  73. package/dist/connectors/spoonacular/connector.json +28 -0
  74. package/dist/connectors/stability-ai/connector.json +27 -0
  75. package/dist/connectors/twilio/connector.json +28 -0
  76. package/dist/connectors/types.d.ts +23 -0
  77. package/dist/connectors/types.d.ts.map +1 -1
  78. package/dist/connectors/unsplash/connector.json +27 -0
  79. package/dist/connectors/wolfram-alpha/connector.json +26 -0
  80. package/dist/connectors/youtube-data/connector.json +30 -0
  81. package/dist/files.d.ts +1 -0
  82. package/dist/files.d.ts.map +1 -1
  83. package/dist/files.js +16 -1
  84. package/dist/files.js.map +1 -1
  85. package/dist/init.d.ts.map +1 -1
  86. package/dist/init.js +28 -0
  87. package/dist/init.js.map +1 -1
  88. package/dist/migrations.d.ts +3 -2
  89. package/dist/migrations.d.ts.map +1 -1
  90. package/dist/migrations.js +122 -138
  91. package/dist/migrations.js.map +1 -1
  92. package/dist/models/anthropic.d.ts +22 -0
  93. package/dist/models/anthropic.d.ts.map +1 -0
  94. package/dist/models/anthropic.js +76 -0
  95. package/dist/models/anthropic.js.map +1 -0
  96. package/dist/models/chainOfThought.d.ts +12 -0
  97. package/dist/models/chainOfThought.d.ts.map +1 -0
  98. package/dist/models/chainOfThought.js +45 -0
  99. package/dist/models/chainOfThought.js.map +1 -0
  100. package/dist/models/fireworksai.d.ts +30 -0
  101. package/dist/models/fireworksai.d.ts.map +1 -0
  102. package/dist/models/fireworksai.js +133 -0
  103. package/dist/models/fireworksai.js.map +1 -0
  104. package/dist/models/index.d.ts +7 -1
  105. package/dist/models/index.d.ts.map +1 -1
  106. package/dist/models/index.js +19 -1
  107. package/dist/models/index.js.map +1 -1
  108. package/dist/models/logCompletePrompt.d.ts +3 -0
  109. package/dist/models/logCompletePrompt.d.ts.map +1 -0
  110. package/dist/models/logCompletePrompt.js +23 -0
  111. package/dist/models/logCompletePrompt.js.map +1 -0
  112. package/dist/models/openai.d.ts +24 -0
  113. package/dist/models/openai.d.ts.map +1 -0
  114. package/dist/models/openai.js +80 -0
  115. package/dist/models/openai.js.map +1 -0
  116. package/dist/models/providers.d.ts +1 -0
  117. package/dist/models/providers.d.ts.map +1 -1
  118. package/dist/models/providers.js +12 -4
  119. package/dist/models/providers.js.map +1 -1
  120. package/dist/models/types.d.ts +34 -2
  121. package/dist/models/types.d.ts.map +1 -1
  122. package/dist/models/types.js +16 -0
  123. package/dist/models/types.js.map +1 -1
  124. package/dist/models/utils.d.ts +6 -0
  125. package/dist/models/utils.d.ts.map +1 -0
  126. package/dist/models/utils.js +21 -0
  127. package/dist/models/utils.js.map +1 -0
  128. package/dist/scripts.d.ts +2 -1
  129. package/dist/scripts.d.ts.map +1 -1
  130. package/dist/scripts.js +4 -3
  131. package/dist/scripts.js.map +1 -1
  132. package/dist/service/createCompletePrompt.d.ts +1 -1
  133. package/dist/service/createCompletePrompt.d.ts.map +1 -1
  134. package/dist/service/createCompletePrompt.js +9 -6
  135. package/dist/service/createCompletePrompt.js.map +1 -1
  136. package/dist/service/generateImage.d.ts +1 -1
  137. package/dist/service/generateImage.d.ts.map +1 -1
  138. package/dist/service/generateImage.js +3 -3
  139. package/dist/service/generateImage.js.map +1 -1
  140. package/dist/service/server.d.ts.map +1 -1
  141. package/dist/service/server.js +3 -0
  142. package/dist/service/server.js.map +1 -1
  143. package/dist/service/transformPage.d.ts +4 -2
  144. package/dist/service/transformPage.d.ts.map +1 -1
  145. package/dist/service/transformPage.js +74 -6
  146. package/dist/service/transformPage.js.map +1 -1
  147. package/dist/service/useAgentRoutes.d.ts +4 -0
  148. package/dist/service/useAgentRoutes.d.ts.map +1 -0
  149. package/dist/service/useAgentRoutes.js +389 -0
  150. package/dist/service/useAgentRoutes.js.map +1 -0
  151. package/dist/service/useApiRoutes.d.ts.map +1 -1
  152. package/dist/service/useApiRoutes.js +157 -16
  153. package/dist/service/useApiRoutes.js.map +1 -1
  154. package/dist/service/useConnectorRoutes.d.ts.map +1 -1
  155. package/dist/service/useConnectorRoutes.js +14 -3
  156. package/dist/service/useConnectorRoutes.js.map +1 -1
  157. package/dist/service/useGatewayRoutes.d.ts +4 -0
  158. package/dist/service/useGatewayRoutes.d.ts.map +1 -0
  159. package/dist/service/useGatewayRoutes.js +168 -0
  160. package/dist/service/useGatewayRoutes.js.map +1 -0
  161. package/dist/service/usePageRoutes.d.ts.map +1 -1
  162. package/dist/service/usePageRoutes.js +16 -5
  163. package/dist/service/usePageRoutes.js.map +1 -1
  164. package/dist/settings.d.ts +2 -1
  165. package/dist/settings.d.ts.map +1 -1
  166. package/dist/settings.js +4 -8
  167. package/dist/settings.js.map +1 -1
  168. package/dist/themes.d.ts +14 -0
  169. package/dist/themes.d.ts.map +1 -1
  170. package/dist/themes.js +86 -13
  171. package/dist/themes.js.map +1 -1
  172. package/package.json +10 -5
  173. package/page-scripts/helpers-v2.js +222 -0
  174. package/page-scripts/page-v2.js +656 -0
  175. package/required-pages/builder.html +1 -27
  176. package/required-pages/pages.html +745 -22
  177. package/required-pages/settings.html +819 -21
  178. package/required-pages/synthos_apis.html +56 -1
  179. package/src/agents/a2a/a2aProvider.ts +110 -0
  180. package/src/agents/discovery.ts +74 -0
  181. package/src/agents/index.ts +6 -0
  182. package/src/agents/openclaw/gatewayManager.ts +559 -0
  183. package/src/agents/openclaw/openclawProvider.ts +261 -0
  184. package/src/agents/openclaw/sshTunnelManager.ts +385 -0
  185. package/src/agents/types.ts +82 -0
  186. package/src/connectors/airtable/connector.json +27 -0
  187. package/src/connectors/alpha-vantage/connector.json +26 -0
  188. package/src/connectors/brave-search/connector.json +26 -0
  189. package/src/connectors/cloudinary/connector.json +27 -0
  190. package/src/connectors/deepl/connector.json +28 -0
  191. package/src/connectors/elevenlabs/connector.json +30 -0
  192. package/src/connectors/giphy/connector.json +27 -0
  193. package/src/connectors/github/connector.json +29 -0
  194. package/src/connectors/huggingface/connector.json +27 -0
  195. package/src/connectors/imgur/connector.json +29 -0
  196. package/src/connectors/index.ts +2 -0
  197. package/src/connectors/instagram/connector.json +43 -0
  198. package/src/connectors/jira/connector.json +28 -0
  199. package/src/connectors/mapbox/connector.json +26 -0
  200. package/src/connectors/nasa/connector.json +27 -0
  201. package/src/connectors/newsapi/connector.json +27 -0
  202. package/src/connectors/notion/connector.json +28 -0
  203. package/src/connectors/open-exchange-rates/connector.json +27 -0
  204. package/src/connectors/openweathermap/connector.json +26 -0
  205. package/src/connectors/pexels/connector.json +27 -0
  206. package/src/connectors/registry.ts +21 -97
  207. package/src/connectors/resend/connector.json +29 -0
  208. package/src/connectors/rss2json/connector.json +27 -0
  209. package/src/connectors/sendgrid/connector.json +27 -0
  210. package/src/connectors/spoonacular/connector.json +28 -0
  211. package/src/connectors/stability-ai/connector.json +27 -0
  212. package/src/connectors/twilio/connector.json +28 -0
  213. package/src/connectors/types.ts +25 -0
  214. package/src/connectors/unsplash/connector.json +27 -0
  215. package/src/connectors/wolfram-alpha/connector.json +26 -0
  216. package/src/connectors/youtube-data/connector.json +30 -0
  217. package/src/files.ts +14 -0
  218. package/src/init.ts +27 -0
  219. package/src/migrations.ts +121 -138
  220. package/src/models/anthropic.ts +89 -0
  221. package/src/models/chainOfThought.ts +56 -0
  222. package/src/models/fireworksai.ts +136 -0
  223. package/src/models/index.ts +7 -1
  224. package/src/models/logCompletePrompt.ts +25 -0
  225. package/src/models/openai.ts +90 -0
  226. package/src/models/providers.ts +12 -3
  227. package/src/models/types.ts +67 -2
  228. package/src/models/utils.ts +16 -0
  229. package/src/scripts.ts +2 -2
  230. package/src/service/createCompletePrompt.ts +3 -1
  231. package/src/service/generateImage.ts +2 -2
  232. package/src/service/server.ts +4 -0
  233. package/src/service/transformPage.ts +81 -8
  234. package/src/service/useAgentRoutes.ts +423 -0
  235. package/src/service/useApiRoutes.ts +173 -18
  236. package/src/service/useConnectorRoutes.ts +14 -3
  237. package/src/service/usePageRoutes.ts +20 -6
  238. package/src/settings.ts +6 -10
  239. package/src/themes.ts +84 -12
  240. package/tests/README.md +12 -0
  241. package/tests/anthropic.spec.ts +84 -0
  242. package/tests/chainOfThought.spec.ts +108 -0
  243. package/tests/ensureScripts.spec.ts +82 -0
  244. package/tests/files.spec.ts +233 -0
  245. package/tests/fireworksai.spec.ts +92 -0
  246. package/tests/logCompletePrompt.spec.ts +74 -0
  247. package/tests/migrations.spec.ts +169 -0
  248. package/tests/openai.spec.ts +71 -0
  249. package/tests/pages.spec.ts +328 -0
  250. package/tests/providers.spec.ts +144 -0
  251. package/tests/scripts.spec.ts +209 -0
  252. package/tests/transformPage.spec.ts +931 -0
  253. package/tests/types.spec.ts +23 -0
  254. package/default-pages/app_builder.json +0 -1
  255. package/default-pages/sidebar_builder.json +0 -1
  256. package/default-pages/two-panel_builder.json +0 -1
  257. package/images/home.png +0 -0
  258. package/images/page-management.png +0 -0
  259. package/images/settings.png +0 -0
  260. package/images/synthos-square.png +0 -0
  261. /package/default-pages/{app_builder.html → application.html} +0 -0
  262. /package/default-pages/{sidebar_builder.html → sidebar_page.html} +0 -0
  263. /package/default-pages/{two-panel_builder.html → two-panel_page.html} +0 -0
@@ -0,0 +1,526 @@
1
+ <!DOCTYPE html><html lang="en"><head>
2
+ <meta charset="UTF-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4
+ <title>SynthOS</title>
5
+ <script id="theme-info" src="/api/theme-info.js" data-locked="true"></script>
6
+ <link id="theme-css" rel="stylesheet" href="/api/theme.css" data-locked="true">
7
+ <style>.idle-container{position:absolute;width:100%;height:100%;pointer-events:none;opacity:1;transition:opacity 1s ease-out}.idle-container.hidden{opacity:0}.breathing-orb{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:80px;height:80px;border-radius:50%;background:radial-gradient(circle,rgba(102,126,234,.15) 0,transparent 70%);animation:4s ease-in-out infinite breathe}.breathing-orb::before{content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:8px;height:8px;border-radius:50%;background:rgba(183,148,246,.6);box-shadow:0 0 20px rgba(183,148,246,.4);animation:4s ease-in-out infinite core-pulse}@keyframes breathe{0%,100%{width:80px;height:80px;opacity:.3}50%{width:120px;height:120px;opacity:.6}}@keyframes core-pulse{0%,100%{opacity:.4;box-shadow:0 0 20px rgba(183,148,246,.3)}50%{opacity:.8;box-shadow:0 0 30px rgba(183,148,246,.5)}}.orbit-ring{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:200px;height:200px;border:1px solid rgba(102,126,234,.1);border-radius:50%;animation:20s linear infinite orbit-rotate}.orbit-ring::after{content:'';position:absolute;top:-3px;left:50%;transform:translateX(-50%);width:6px;height:6px;background:rgba(240,147,251,.5);border-radius:50%;box-shadow:0 0 10px rgba(240,147,251,.3)}@keyframes orbit-rotate{from{transform:translate(-50%,-50%) rotate(0)}to{transform:translate(-50%,-50%) rotate(360deg)}}</style>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"></script>
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/14.1.1/marked.min.js"></script>
10
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.1.0/mermaid.min.js"></script>
11
+ <script id="page-info" src="/api/page-info.js?page=builder"></script>
12
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js" id="topojson-lib"></script><style id="us-map-styles">#us-map-container{width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:hidden}#us-map-header{min-height:var(--header-min-height);padding:var(--header-padding-vertical) var(--header-padding-horizontal);line-height:var(--header-line-height);display:flex;align-items:center;justify-content:center;box-sizing:border-box;font-size:1.25rem;font-weight:600;color:var(--text-primary);width:100%;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0;position:relative}#us-map-svg-wrap{flex:1;width:100%;display:flex;align-items:center;justify-content:center;box-sizing:border-box;position:relative}#us-map-svg-wrap svg{width:100%;height:100%;position:absolute;top:0;left:0;cursor:grab}#us-map-svg-wrap svg:active{cursor:grabbing}.region-path{cursor:pointer;transition:filter .2s ease;stroke-linejoin:round}.region-path:hover{filter:brightness(1.25)}.region-state{fill:rgba(46,125,50,0.5);stroke:#1b5e20;stroke-width:1.2}.region-oregon{fill:rgba(230,81,0,0.45);stroke:#bf360c;stroke-width:1.5}.region-minnesota{fill:rgba(255,152,0,0.45);stroke:#e65100;stroke-width:1.5}.region-utah{fill:rgba(255,111,0,0.4);stroke:#bf360c;stroke-width:1.5}.region-newmexico{fill:rgba(239,108,0,0.45);stroke:#bf360c;stroke-width:1.5}.region-unorganized{fill:rgba(141,110,99,0.4);stroke:#4e342e;stroke-width:1.5}.region-indian{fill:rgba(121,85,72,0.45);stroke:#3e2723;stroke-width:1.5}.light-mode .region-state{fill:rgba(46,125,50,0.5);stroke:#1b5e20}.light-mode .region-oregon{fill:rgba(230,81,0,0.45);stroke:#bf360c}.light-mode .region-minnesota{fill:rgba(255,152,0,0.45);stroke:#e65100}.light-mode .region-utah{fill:rgba(255,111,0,0.4);stroke:#bf360c}.light-mode .region-newmexico{fill:rgba(239,108,0,0.45);stroke:#bf360c}.light-mode .region-unorganized{fill:rgba(141,110,99,0.4);stroke:#4e342e}.light-mode .region-indian{fill:rgba(121,85,72,0.45);stroke:#3e2723}#map-tooltip{position:absolute;pointer-events:none;background:var(--bg-tertiary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:6px;padding:6px 12px;font-size:0.85rem;font-weight:500;box-shadow:0 2px 8px rgba(0,0,0,0.12);opacity:0;transition:opacity .15s ease;z-index:10;white-space:nowrap}#hist-legend{position:absolute;bottom:16px;left:16px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;padding:10px 14px;font-size:0.75rem;color:var(--text-primary);z-index:5;box-shadow:0 2px 8px rgba(0,0,0,0.1)}#hist-legend .legend-item{display:flex;align-items:center;gap:8px;margin-bottom:4px}#hist-legend .legend-item:last-child{margin-bottom:0}#hist-legend .legend-swatch{width:14px;height:14px;border-radius:3px;flex-shrink:0}#zoom-controls{position:absolute;top:16px;right:16px;display:flex;flex-direction:column;gap:4px;z-index:5}#zoom-controls button{width:36px;height:36px;border:1px solid var(--border-color);border-radius:6px;background:var(--bg-tertiary);color:var(--text-primary);font-size:1.2rem;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 6px rgba(0,0,0,0.1);transition:background .15s ease}#zoom-controls button:hover{background:var(--bg-secondary)}</style><style id="detail-card-styles">.city-marker{cursor:pointer}.city-marker .marker-glow{fill:var(--accent-primary);opacity:0.15;transition:opacity .2s ease}.city-marker .marker-dot{fill:var(--accent-primary);transition:r .2s ease}.city-marker .marker-hit{fill:transparent;cursor:pointer}.city-marker:hover .marker-glow{opacity:0.35}.city-marker:hover .marker-dot{r:3.5}.city-marker .marker-label{font-size:8px;font-weight:600;fill:var(--text-primary);text-anchor:middle;pointer-events:none;paint-order:stroke;stroke:var(--bg-primary);stroke-width:2.5px;stroke-linecap:round;stroke-linejoin:round}#detail-card{position:absolute;top:16px;right:16px;width:340px;max-height:calc(100% - 40px);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,0.15);z-index:20;opacity:0;transform:translateY(-10px) scale(0.97);pointer-events:none;transition:opacity .25s ease,transform .25s ease;overflow:hidden;display:flex;flex-direction:column}#detail-card.visible{opacity:1;transform:translateY(0) scale(1);pointer-events:auto}#detail-card .card-header{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 8px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}#detail-card .card-header h3{margin:0;font-size:0.95rem;font-weight:700;color:var(--text-primary);line-height:1.3}#detail-card .card-header .card-close{background:none;border:none;font-size:1.3rem;cursor:pointer;color:var(--text-secondary);padding:0 2px;line-height:1;border-radius:4px;transition:background .15s ease}#detail-card .card-header .card-close:hover{background:rgba(0,0,0,0.08)}#detail-card .card-subtitle{font-size:0.72rem;color:var(--text-secondary);margin:2px 0 0;font-weight:500}#detail-card .card-tabs{display:flex;border-bottom:1px solid var(--border-color);flex-shrink:0}#detail-card .card-tab{flex:1;padding:8px 10px;font-size:0.78rem;font-weight:600;text-align:center;cursor:pointer;border:none;background:none;color:var(--text-secondary);transition:all .15s ease;border-bottom:2px solid transparent;position:relative}#detail-card .card-tab:hover{color:var(--text-primary);background:rgba(0,0,0,0.03)}#detail-card .card-tab.active{color:var(--accent-primary);border-bottom-color:var(--accent-primary)}#detail-card .card-tab-icon{margin-right:4px}#detail-card .tab-content{flex:1;overflow:hidden;display:flex;flex-direction:column;min-height:0}#detail-card .tab-pane{display:none;flex:1;overflow-y:auto;flex-direction:column;min-height:0}#detail-card .tab-pane.active{display:flex}#detail-card .facts-pane{padding:12px 14px;overflow-y:auto}#detail-card .fact-row{display:flex;gap:8px;margin-bottom:8px;align-items:flex-start}#detail-card .fact-icon{font-size:1rem;flex-shrink:0;width:22px;text-align:center;margin-top:1px}#detail-card .fact-content{flex:1}#detail-card .fact-label{font-size:0.65rem;text-transform:uppercase;letter-spacing:0.5px;color:var(--text-secondary);font-weight:600;margin-bottom:1px}#detail-card .fact-value{font-size:0.8rem;color:var(--text-primary);line-height:1.4}#detail-card .card-divider{height:1px;background:var(--border-color);margin:4px 0 8px}#detail-card .card-description{font-size:0.78rem;color:var(--text-primary);line-height:1.5;margin-top:2px}#detail-card .chat-pane{flex-direction:column;min-height:0;flex:1}#detail-card .chat-messages-area{flex:1;overflow-y:auto;padding:10px 12px;display:flex;flex-direction:column;gap:8px;min-height:120px}#detail-card .chat-welcome{text-align:center;padding:16px 8px;color:var(--text-secondary);font-size:0.78rem;line-height:1.5}#detail-card .chat-welcome strong{color:var(--text-primary)}#detail-card .chat-bubble{max-width:92%;padding:8px 11px;border-radius:12px;font-size:0.78rem;line-height:1.45;word-wrap:break-word;animation:bubbleIn .2s ease}#detail-card .chat-bubble.user-bubble{align-self:flex-end;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;border-bottom-right-radius:4px}#detail-card .chat-bubble.ai-bubble{align-self:flex-start;background:var(--bg-secondary);color:var(--text-primary);border:1px solid var(--border-color);border-bottom-left-radius:4px}#detail-card .chat-bubble.ai-bubble.loading{opacity:0.7}#detail-card .typing-dots{display:inline-flex;gap:3px;padding:2px 0}#detail-card .typing-dots span{width:5px;height:5px;border-radius:50%;background:var(--text-secondary);animation:dotBounce .6s ease-in-out infinite}#detail-card .typing-dots span:nth-child(2){animation-delay:.15s}#detail-card .typing-dots span:nth-child(3){animation-delay:.3s}@keyframes dotBounce{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}@keyframes bubbleIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}#detail-card .chat-input-area{display:flex;gap:6px;padding:8px 10px;border-top:1px solid var(--border-color);background:var(--bg-tertiary);flex-shrink:0;border-radius:0 0 12px 12px}#detail-card .chat-input-field{flex:1;border:1px solid var(--border-color);border-radius:18px;padding:7px 12px;font-size:0.78rem;background:var(--bg-primary);color:var(--text-primary);outline:none;transition:border-color .15s ease;font-family:inherit}#detail-card .chat-input-field:focus{border-color:var(--accent-primary)}#detail-card .chat-input-field::placeholder{color:var(--text-secondary);opacity:0.7}#detail-card .chat-send-btn{width:32px;height:32px;border-radius:50%;border:none;background:linear-gradient(135deg,var(--accent-primary),var(--accent-secondary));color:#fff;font-size:0.9rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform .1s ease,opacity .15s ease;flex-shrink:0}#detail-card .chat-send-btn:hover{transform:scale(1.08)}#detail-card .chat-send-btn:disabled{opacity:0.4;cursor:not-allowed;transform:none}#detail-card .suggested-questions{display:flex;flex-wrap:wrap;gap:4px;padding:0 12px 8px}#detail-card .suggested-q{font-size:0.68rem;padding:4px 8px;border-radius:12px;border:1px solid var(--border-color);background:var(--bg-primary);color:var(--text-secondary);cursor:pointer;transition:all .15s ease;white-space:nowrap}#detail-card .suggested-q:hover{color:var(--accent-primary);border-color:var(--accent-primary)}#card-backdrop{display:none;position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.2);z-index:15}#card-backdrop.visible{display:block}</style></head>
13
+ <body>
14
+ <div class="chat-panel" data-locked="true">
15
+ <div class="chat-header" data-locked="true">SynthOS</div>
16
+ <div class="chat-messages" id="chatMessages" data-locked="true">
17
+ <div class="chat-message" id="defaultGreeting"><p><strong>SynthOS:</strong> Welcome! This is an interactive map of the United States circa the 1850s, showing how the country was politically organized after the Compromise of 1850. It's designed for interactive exploration — here are a few things you could try:
18
+ <ul style="margin-top:8px;margin-bottom:4px;padding-left:20px;">
19
+ <li><strong>Population density overlay</strong> — Visualize estimated population distribution across states and territories in the 1850s</li>
20
+ <li><strong>Railroad &amp; transportation routes</strong> — Map the major rail lines, trails, and waterways that connected the nation</li>
21
+ <li><strong>Climate &amp; geography zones</strong> — Overlay biomes, elevation, or average rainfall data onto the territorial boundaries</li>
22
+ <li><strong>Statehood timeline animation</strong> — Animate how territories became states over time from 1776 to 1860</li>
23
+ <li><strong>Resource &amp; agriculture map</strong> — Show where key crops, minerals, and natural resources were concentrated</li>
24
+ </ul>
25
+ Just tell me what you'd like to explore!</p></div>
26
+ <div class="chat-message"><p><strong>User:</strong> Add all of the major towns or cities out west in 1850 with a styled detail card that shows facts about each.</p></div><div class="chat-message"><p><strong>SynthOS:</strong> I've added <strong>18 major western cities and towns</strong> from the 1850s era to the map! Each one appears as a glowing marker dot with a label. Click any marker to open a detailed card with:</p><ul style="margin-top:8px;padding-left:20px;"><li><strong>📋 Facts tab</strong> — Population, founding date, economy, historical role, and more</li><li><strong>💬 Ask Me tab</strong> — Chat with an AI historian about that specific location</li><li><strong>Suggested questions</strong> — Quick-start prompts tailored to each city</li></ul><p style="margin-top:8px;">Cities include: <em>San Francisco, Sacramento, Salt Lake City, Santa Fe, Portland, Oregon City, Los Angeles, San Diego, Independence, Council Bluffs, St. Joseph, Monterey, Tucson, Olympia, Stockton, El Paso, Astoria,</em> and <em>San Jose</em>. Try zooming in to explore the western regions!</p></div></div>
27
+ <div class="link-group" data-locked="true">
28
+ <a href="#" id="saveLink" data-locked="true">Save</a>
29
+ <a href="/pages" id="pagesLink" data-locked="true">Pages</a>
30
+ <a href="#" id="resetLink" data-locked="true">Reset</a>
31
+ </div>
32
+ <form action="/" method="POST" id="chatForm" data-locked="true">
33
+ <input type="text" class="chat-input" id="chatInput" name="message" placeholder="Type a message..." data-locked="true">
34
+ <button type="submit" class="chat-submit" data-locked="true">Send</button>
35
+ </form>
36
+ </div>
37
+ <div class="viewer-panel full-viewer" id="viewerPanel"><div id="us-map-container"><div id="us-map-header">United States — Circa 1850</div><div id="us-map-svg-wrap"><div id="hist-legend"><div style="font-weight:600;margin-bottom:6px;">Circa 1850</div><div class="legend-item"><div class="legend-swatch" style="background:rgba(46,125,50,0.6);border:1px solid #1b5e20;"></div><span>States (31)</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(230,81,0,0.55);border:1px solid #bf360c;"></div><span>Oregon Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(255,152,0,0.55);border:1px solid #e65100;"></div><span>Minnesota Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(255,111,0,0.5);border:1px solid #bf360c;"></div><span>Utah Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(239,108,0,0.55);border:1px solid #bf360c;"></div><span>New Mexico Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(141,110,99,0.5);border:1px solid #4e342e;"></div><span>Unorganized Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(121,85,72,0.55);border:1px solid #3e2723;"></div><span>Indian Territory</span></div></div><div id="zoom-controls"><button id="zoom-in-btn" title="Zoom in">+</button><button id="zoom-out-btn" title="Zoom out">−</button><button id="zoom-reset-btn" title="Reset view" style="font-size:0.75rem;">⟲</button></div></div><div id="map-tooltip"></div><div id="detail-card"><div class="card-header"><div><h3 id="card-title"></h3><div class="card-subtitle" id="card-subtitle"></div></div><button class="card-close" id="card-close-btn" aria-label="Close">×</button></div><div class="card-tabs"><button class="card-tab active" data-tab="facts"><span class="card-tab-icon">📋</span>Facts</button><button class="card-tab" data-tab="chat"><span class="card-tab-icon">💬</span>Ask Me</button></div><div class="tab-content"><div class="tab-pane facts-pane active" id="facts-pane"><div id="card-body"></div></div><div class="tab-pane chat-pane" id="chat-pane"><div class="chat-messages-area" id="detail-chat-messages"></div><div class="suggested-questions" id="detail-suggested-q"></div><div class="chat-input-area"><input type="text" class="chat-input-field" id="detail-chat-input" placeholder="Ask me anything..." autocomplete="off"><button class="chat-send-btn" id="detail-chat-send" aria-label="Send">➤</button></div></div></div></div><div id="card-backdrop"></div></div><div id="loadingOverlay" class="loading-overlay"><div class="spinner"></div></div></div>
38
+ <div id="instructions" style="display: none;" data-locked="true"></div>
39
+ <div id="thoughts" style="display: none;" data-locked="true">User wants major western towns/cities circa 1850 plotted on the map with styled detail cards showing facts. I need to populate the MARKER_DATA array in the detail-card-script with historically accurate western cities from the 1850s era. Key western cities/towns: San Francisco, Sacramento, Salt Lake City, Portland, Oregon City, Santa Fe, Astoria, Los Angeles, San Diego, Monterey, Tucson, El Paso, Independence (MO - gateway), Council Bluffs, Fort Laramie, Sutter's Fort/Sacramento, Yerba Buena/San Francisco, Olympia, etc. I'll focus on the most significant ones. I also need to make sure the detail card positioning works well with the zoom controls. The detail card already has full styling and functionality from the existing CSS and script - I just need to populate MARKER_DATA. Let me also add some cities that were important jumping-off points. I'll update the detail-card-script to include rich MARKER_DATA.</div>
40
+ <script id="idle-animation">function hideIdleAnimation(){const idleContainer=document.getElementById("idleAnimation");idleContainer&&(idleContainer.classList.add("hidden"),setTimeout(()=>{idleContainer.style.display="none"},1e3))}function showIdleAnimation(){const idleContainer=document.getElementById("idleAnimation");idleContainer&&(idleContainer.style.display="block",setTimeout(()=>{idleContainer.classList.remove("hidden")},10))}</script>
41
+ <button class="chat-toggle" aria-label="Toggle chat panel">
42
+ <span class="chat-toggle-dots">
43
+ <span class="chat-toggle-dot"></span>
44
+ <span class="chat-toggle-dot"></span>
45
+ <span class="chat-toggle-dot"></span>
46
+ </span>
47
+ </button>
48
+
49
+
50
+ <script id="us-map-script">(function(){var FIPS_TO_NAME={1:'Alabama',2:'Alaska',4:'Arizona',5:'Arkansas',6:'California',8:'Colorado',9:'Connecticut',10:'Delaware',11:'District of Columbia',12:'Florida',13:'Georgia',15:'Hawaii',16:'Idaho',17:'Illinois',18:'Indiana',19:'Iowa',20:'Kansas',21:'Kentucky',22:'Louisiana',23:'Maine',24:'Maryland',25:'Massachusetts',26:'Michigan',27:'Minnesota',28:'Mississippi',29:'Missouri',30:'Montana',31:'Nebraska',32:'Nevada',33:'New Hampshire',34:'New Jersey',35:'New Mexico',36:'New York',37:'North Carolina',38:'North Dakota',39:'Ohio',40:'Oklahoma',41:'Oregon',42:'Pennsylvania',44:'Rhode Island',45:'South Carolina',46:'South Dakota',47:'Tennessee',48:'Texas',49:'Utah',50:'Vermont',51:'Virginia',53:'Washington',54:'West Virginia',55:'Wisconsin',56:'Wyoming'};
51
+ var STATES_1850=[9,10,13,24,25,33,34,36,37,42,44,45,51,50,21,47,39,22,18,28,17,1,23,29,5,26,12,48,19,55,6,54,11];
52
+ var OREGON_TERR=[41,53,16];
53
+ var MINNESOTA_TERR=[27];
54
+ var UTAH_TERR=[49,32];
55
+ var NEWMEXICO_TERR=[35,4];
56
+ var UNORGANIZED=[31,20,38,46,56,30,8];
57
+ var INDIAN_TERR=[40];
58
+ var TERRITORY_GROUPS=[{fips:OREGON_TERR,name:'Oregon Territory',cls:'region-oregon'},{fips:MINNESOTA_TERR,name:'Minnesota Territory',cls:'region-minnesota'},{fips:UTAH_TERR,name:'Utah Territory',cls:'region-utah'},{fips:NEWMEXICO_TERR,name:'New Mexico Territory',cls:'region-newmexico'},{fips:UNORGANIZED,name:'Unorganized Territory',cls:'region-unorganized'},{fips:INDIAN_TERR,name:'Indian Territory',cls:'region-indian'}];
59
+ function init(){var wrap=document.getElementById('us-map-svg-wrap');if(!wrap)return;var tooltip=document.getElementById('map-tooltip');wrap.querySelectorAll('svg').forEach(function(s){s.remove();});
60
+ var svg=d3.select(wrap).append('svg').attr('id','hist-map-svg').attr('viewBox','0 0 960 600').attr('preserveAspectRatio','xMidYMid meet').style('padding','0').style('box-sizing','border-box');
61
+ var g=svg.append('g').attr('id','map-zoom-group');
62
+ var zoom=d3.zoom().scaleExtent([1,12]).on('zoom',function(event){g.attr('transform',event.transform);});
63
+ svg.call(zoom);
64
+ svg.on('dblclick.zoom',null);
65
+ var projection=d3.geoAlbersUsa().scale(1280).translate([480,300]);var path=d3.geoPath().projection(projection);
66
+ d3.json('https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json').then(function(us){var statesGeo=us.objects.states;var allGeometries=statesGeo.geometries;
67
+ function geomsForFips(fipsList){return allGeometries.filter(function(g){return fipsList.indexOf(+g.id)!==-1;});}
68
+ var stateGeoms=geomsForFips(STATES_1850);stateGeoms.forEach(function(geom){var feature=topojson.feature(us,geom);g.append('path').datum(feature).attr('class','region-path region-state').attr('d',path).on('mousemove',function(event){var name=FIPS_TO_NAME[+geom.id]||'Unknown';tooltip.textContent=name+' (State)';tooltip.style.opacity='1';var rect=wrap.getBoundingClientRect();var x=event.clientX-rect.left+12;var y=event.clientY-rect.top-30;if(x+180>rect.width)x=x-200;if(y<0)y=event.clientY-rect.top+18;tooltip.style.left=x+'px';tooltip.style.top=y+'px';}).on('mouseleave',function(){tooltip.style.opacity='0';});});
69
+ TERRITORY_GROUPS.forEach(function(group){var geoms=geomsForFips(group.fips);if(geoms.length===0)return;var merged=topojson.merge(us,geoms);g.append('path').datum(merged).attr('class','region-path '+group.cls).attr('d',path).on('mousemove',function(event){tooltip.textContent=group.name;tooltip.style.opacity='1';var rect=wrap.getBoundingClientRect();var x=event.clientX-rect.left+12;var y=event.clientY-rect.top-30;if(x+180>rect.width)x=x-200;if(y<0)y=event.clientY-rect.top+18;tooltip.style.left=x+'px';tooltip.style.top=y+'px';}).on('mouseleave',function(){tooltip.style.opacity='0';});});
70
+ var stateGeoms2=geomsForFips(STATES_1850);g.append('path').datum(topojson.mesh(us,{type:'GeometryCollection',geometries:stateGeoms2},function(a,b){return a!==b&&STATES_1850.indexOf(+a.id)!==-1&&STATES_1850.indexOf(+b.id)!==-1;})).attr('fill','none').attr('stroke','rgba(27,94,32,0.4)').attr('stroke-width','0.5').attr('d',path).style('pointer-events','none');
71
+ }).catch(function(err){console.error('Failed to load US map data:',err);wrap.innerHTML='<p style="color:var(--text-secondary);text-align:center;">Failed to load map data. Please try again.</p>';});}
72
+ if(typeof topojson!=='undefined'){init();}else{var check=setInterval(function(){if(typeof topojson!=='undefined'){clearInterval(check);init();}},100);setTimeout(function(){clearInterval(check);},10000);}
73
+ })();</script><script id="zoom-controls-script">(function(){function waitForSvg(){var svg=d3.select('#hist-map-svg');if(svg.empty()){setTimeout(waitForSvg,200);return;}var zoomBehavior=null;svg.each(function(){var z=d3.zoomTransform(this);if(z)zoomBehavior=true;});var zoomHandler=d3.zoom().scaleExtent([1,12]).on('zoom',function(event){d3.select('#map-zoom-group').attr('transform',event.transform);});document.getElementById('zoom-in-btn').addEventListener('click',function(){svg.transition().duration(300).call(zoomHandler.scaleBy,1.5);});document.getElementById('zoom-out-btn').addEventListener('click',function(){svg.transition().duration(300).call(zoomHandler.scaleBy,1/1.5);});document.getElementById('zoom-reset-btn').addEventListener('click',function(){svg.transition().duration(400).call(zoomHandler.transform,d3.zoomIdentity);});svg.call(zoomHandler);}waitForSvg();})();</script><script id="detail-card-script">(function(){
74
+ var MARKER_DATA = [
75
+ {
76
+ name: 'San Francisco',
77
+ lat: 37.7749, lon: -122.4194,
78
+ subtitle: 'Boomtown of the Gold Rush',
79
+ description: 'San Francisco exploded from a tiny settlement called Yerba Buena into a roaring city of tens of thousands almost overnight after gold was discovered at Sutter\'s Mill in 1848. By 1850 it was the commercial capital of the Pacific Coast, with ships abandoned in the harbor as crews deserted for the goldfields.',
80
+ facts: [
81
+ { icon: '👥', label: 'Population (1850)', value: '~25,000 (up from ~200 in 1846)' },
82
+ { icon: '📅', label: 'Statehood', value: 'California admitted Sept 9, 1850' },
83
+ { icon: '⛏️', label: 'Gold Rush', value: 'Primary port of entry for 49ers' },
84
+ { icon: '🚢', label: 'Harbor', value: 'Hundreds of abandoned ships in the bay' },
85
+ { icon: '🏗️', label: 'Growth', value: '6 major fires between 1849–1851' }
86
+ ],
87
+ suggestedQuestions: ['What was daily life like during the Gold Rush?', 'How did the fires shape the city?', 'What happened to all the abandoned ships?']
88
+ },
89
+ {
90
+ name: 'Sacramento',
91
+ lat: 38.5816, lon: -121.4944,
92
+ subtitle: 'Gateway to the Goldfields',
93
+ description: 'Sacramento grew up around Sutter\'s Fort and became the main supply depot and jumping-off point for miners heading to the Sierra Nevada goldfields. It was incorporated as a city in 1850 and became the state capital in 1854.',
94
+ facts: [
95
+ { icon: '👥', label: 'Population (1850)', value: '~6,800' },
96
+ { icon: '⛏️', label: 'Role', value: 'Primary supply hub for gold miners' },
97
+ { icon: '🏰', label: 'Sutter\'s Fort', value: 'Founded 1839 by John Sutter' },
98
+ { icon: '🌊', label: 'Floods', value: 'Devastating floods in 1850 and 1852' },
99
+ { icon: '🛒', label: 'Economy', value: 'Merchants often wealthier than miners' }
100
+ ],
101
+ suggestedQuestions: ['Who was John Sutter?', 'How did supplies reach Sacramento?', 'What was the journey from Sacramento to the mines like?']
102
+ },
103
+ {
104
+ name: 'Salt Lake City',
105
+ lat: 40.7608, lon: -111.8910,
106
+ subtitle: 'Zion in the Desert — Mormon Settlement',
107
+ description: 'Founded in 1847 by Brigham Young and the Latter-day Saints, Salt Lake City was the center of the Utah Territory established by the Compromise of 1850. By 1850 it was a well-organized community of several thousand, with an ambitious irrigation system transforming the arid valley.',
108
+ facts: [
109
+ { icon: '👥', label: 'Population (1850)', value: '~6,000' },
110
+ { icon: '⛪', label: 'Founded', value: 'July 24, 1847 by Brigham Young' },
111
+ { icon: '🏛️', label: 'Territory', value: 'Utah Territory est. Sept 1850' },
112
+ { icon: '💧', label: 'Innovation', value: 'Pioneering irrigation agriculture' },
113
+ { icon: '🛤️', label: 'Trail Stop', value: 'Key resupply point on California Trail' }
114
+ ],
115
+ suggestedQuestions: ['Why did the Mormons settle here?', 'How did irrigation work in the desert?', 'What was the relationship with the federal government?']
116
+ },
117
+ {
118
+ name: 'Santa Fe',
119
+ lat: 35.6870, lon: -105.9378,
120
+ subtitle: 'Ancient Capital of the Southwest',
121
+ description: 'Santa Fe was one of the oldest European-founded cities in North America, serving as the capital of New Mexico since 1610. Captured by the U.S. during the Mexican-American War in 1846, it became the capital of the New Mexico Territory in 1850. The Santa Fe Trail connected it to Missouri.',
122
+ facts: [
123
+ { icon: '👥', label: 'Population (1850)', value: '~4,800' },
124
+ { icon: '📅', label: 'Founded', value: '1610 — over 240 years old by 1850' },
125
+ { icon: '🛤️', label: 'Santa Fe Trail', value: '~900 miles from Independence, MO' },
126
+ { icon: '🏛️', label: 'Territory', value: 'New Mexico Territory capital, 1850' },
127
+ { icon: '🏠', label: 'Architecture', value: 'Adobe buildings, Spanish colonial style' }
128
+ ],
129
+ suggestedQuestions: ['What was the Santa Fe Trail like?', 'How did U.S. annexation change the city?', 'What cultures mixed in Santa Fe?']
130
+ },
131
+ {
132
+ name: 'Portland',
133
+ lat: 45.5152, lon: -122.6784,
134
+ subtitle: 'The Clearing in Oregon Country',
135
+ description: 'Portland was founded in 1845 and incorporated in 1851. Situated at the confluence of the Willamette and Columbia rivers, it quickly became the principal port and trading center of the Oregon Territory, serving settlers arriving via the Oregon Trail.',
136
+ facts: [
137
+ { icon: '👥', label: 'Population (1850)', value: '~800' },
138
+ { icon: '📅', label: 'Founded', value: '1845 — named by coin toss' },
139
+ { icon: '🌲', label: 'Economy', value: 'Lumber, shipping, and trade' },
140
+ { icon: '🚢', label: 'Port', value: 'Deep-water access to Pacific via Columbia' },
141
+ { icon: '🛤️', label: 'Oregon Trail', value: 'Terminus for many overland emigrants' }
142
+ ],
143
+ suggestedQuestions: ['How was Portland named by a coin toss?', 'What was the Oregon Trail journey like?', 'How did Portland compete with Oregon City?']
144
+ },
145
+ {
146
+ name: 'Oregon City',
147
+ lat: 45.3573, lon: -122.6068,
148
+ subtitle: 'End of the Oregon Trail',
149
+ description: 'Oregon City was the first incorporated city west of the Rocky Mountains (1844) and served as the original capital of the Oregon Territory. Located at Willamette Falls, it was the official end of the Oregon Trail and a center of early government and industry.',
150
+ facts: [
151
+ { icon: '👥', label: 'Population (1850)', value: '~900' },
152
+ { icon: '📅', label: 'Incorporated', value: '1844 — first city west of Rockies' },
153
+ { icon: '🏛️', label: 'Capital', value: 'Oregon Territory capital 1848–1851' },
154
+ { icon: '🌊', label: 'Willamette Falls', value: 'Powered sawmills and flour mills' },
155
+ { icon: '📰', label: 'Newspaper', value: 'Oregon Spectator — first newspaper on Pacific Coast (1846)' }
156
+ ],
157
+ suggestedQuestions: ['What was it like arriving at the end of the Oregon Trail?', 'Why did the capital move away?', 'How important were the falls?']
158
+ },
159
+ {
160
+ name: 'Los Angeles',
161
+ lat: 34.0522, lon: -118.2437,
162
+ subtitle: 'A Quiet Pueblo Awakening',
163
+ description: 'In 1850, Los Angeles was a small but growing pueblo that had just been incorporated as a city when California achieved statehood. It was a rough frontier town known for cattle ranching, with a diverse population of Californios, Americans, and Native peoples.',
164
+ facts: [
165
+ { icon: '👥', label: 'Population (1850)', value: '~1,600' },
166
+ { icon: '📅', label: 'Founded', value: '1781 as a Spanish pueblo' },
167
+ { icon: '🐄', label: 'Economy', value: 'Cattle ranching and hide trade' },
168
+ { icon: '⚖️', label: 'Incorporated', value: 'April 4, 1850' },
169
+ { icon: '🌍', label: 'Culture', value: 'Mix of Californio, American, and Native peoples' }
170
+ ],
171
+ suggestedQuestions: ['What were the Californio ranchos like?', 'How rough was frontier Los Angeles?', 'How did the Gold Rush affect LA?']
172
+ },
173
+ {
174
+ name: 'San Diego',
175
+ lat: 32.7157, lon: -117.1611,
176
+ subtitle: 'California\'s Birthplace',
177
+ description: 'San Diego was the site of the first European settlement in California (Mission San Diego, 1769). By 1850 it was a small but strategic town near the Mexican border, serving as a military post and hoping to become a major port city.',
178
+ facts: [
179
+ { icon: '👥', label: 'Population (1850)', value: '~650' },
180
+ { icon: '📅', label: 'Mission Founded', value: '1769 — first in California' },
181
+ { icon: '🏰', label: 'Military', value: 'U.S. Army garrison established' },
182
+ { icon: '🌊', label: 'Harbor', value: 'Excellent natural deep-water port' },
183
+ { icon: '🇲🇽', label: 'Border', value: 'Near new U.S.–Mexico boundary' }
184
+ ],
185
+ suggestedQuestions: ['What was the mission system?', 'How did the Mexican-American War affect San Diego?', 'Why didn\'t San Diego grow as fast as San Francisco?']
186
+ },
187
+ {
188
+ name: 'Independence',
189
+ lat: 39.0911, lon: -94.4155,
190
+ subtitle: 'Jumping-Off Point for the West',
191
+ description: 'Independence, Missouri was the most famous "jumping-off" town for westward emigrants. It was the eastern terminus of the Santa Fe, Oregon, and California trails. Every spring, thousands of wagons gathered here before heading west across the plains.',
192
+ facts: [
193
+ { icon: '👥', label: 'Population (1850)', value: '~3,000' },
194
+ { icon: '🛤️', label: 'Trails', value: 'Start of Oregon, California & Santa Fe Trails' },
195
+ { icon: '🛒', label: 'Outfitting', value: 'Major supply center for wagon trains' },
196
+ { icon: '📅', label: 'Peak Years', value: '1843–1855 for overland emigration' },
197
+ { icon: '🐂', label: 'Wagon Trains', value: 'Thousands departed each spring' }
198
+ ],
199
+ suggestedQuestions: ['What supplies did emigrants need?', 'How long did the journey west take?', 'What was the competition between jumping-off towns?']
200
+ },
201
+ {
202
+ name: 'Council Bluffs',
203
+ lat: 41.2619, lon: -95.8608,
204
+ subtitle: 'Missouri River Crossing',
205
+ description: 'Council Bluffs (originally Kanesville) was a major outfitting point and Missouri River crossing for emigrants heading west, particularly Mormon pioneers. It competed with Independence and St. Joseph as a primary departure point for the overland trails.',
206
+ facts: [
207
+ { icon: '👥', label: 'Population (1850)', value: '~2,000' },
208
+ { icon: '🛤️', label: 'Role', value: 'Major Missouri River crossing point' },
209
+ { icon: '⛪', label: 'Mormon Trail', value: 'Key staging area for LDS emigrants' },
210
+ { icon: '🌊', label: 'River', value: 'Ferries carried wagons across the Missouri' },
211
+ { icon: '📛', label: 'Name', value: 'Called Kanesville until 1853' }
212
+ ],
213
+ suggestedQuestions: ['Why was the Missouri River crossing so important?', 'What was the Mormon Trail?', 'How did Council Bluffs develop?']
214
+ },
215
+ {
216
+ name: 'St. Joseph',
217
+ lat: 39.7687, lon: -94.8466,
218
+ subtitle: 'Rival Gateway to the West',
219
+ description: 'St. Joseph, Missouri was a booming frontier town and major rival to Independence as a jumping-off point for the western trails. Located further north on the Missouri River, it offered a shorter route west and became the eastern terminus of the Pony Express in 1860.',
220
+ facts: [
221
+ { icon: '👥', label: 'Population (1850)', value: '~3,400' },
222
+ { icon: '🛤️', label: 'Trails', value: 'Alternative start for Oregon & California Trails' },
223
+ { icon: '📈', label: 'Growth', value: 'Fastest-growing town in Missouri' },
224
+ { icon: '🏪', label: 'Commerce', value: 'Thriving outfitting and trade center' },
225
+ { icon: '📬', label: 'Future', value: 'Pony Express terminus (1860)' }
226
+ ],
227
+ suggestedQuestions: ['How did St. Joseph compete with Independence?', 'What made it a good jumping-off point?', 'What was commerce like here?']
228
+ },
229
+ {
230
+ name: 'Monterey',
231
+ lat: 36.6002, lon: -121.8947,
232
+ subtitle: 'Former Capital of Alta California',
233
+ description: 'Monterey served as the capital of Alta California under both Spain and Mexico. The U.S. flag was raised here in 1846 during the Mexican-American War. California\'s constitutional convention was held in Monterey\'s Colton Hall in 1849.',
234
+ facts: [
235
+ { icon: '👥', label: 'Population (1850)', value: '~1,100' },
236
+ { icon: '🏛️', label: 'Historic Role', value: 'Capital of Alta California' },
237
+ { icon: '📜', label: 'Constitution', value: 'CA Constitution drafted here, 1849' },
238
+ { icon: '🐋', label: 'Economy', value: 'Whaling, fishing, and trade' },
239
+ { icon: '🇺🇸', label: 'U.S. Capture', value: 'July 7, 1846 by Commodore Sloat' }
240
+ ],
241
+ suggestedQuestions: ['What happened at the constitutional convention?', 'Why did the capital move to Sacramento?', 'What was Monterey like under Mexican rule?']
242
+ },
243
+ {
244
+ name: 'Tucson',
245
+ lat: 32.2226, lon: -110.9747,
246
+ subtitle: 'Desert Presidio of the Southwest',
247
+ description: 'Tucson was an ancient settlement site with a Spanish presidio (fort) established in 1775. In 1850 it was part of Mexico — it wouldn\'t become U.S. territory until the Gadsden Purchase of 1854. It was a small but vital stop on southern routes to California.',
248
+ facts: [
249
+ { icon: '👥', label: 'Population (1850)', value: '~500' },
250
+ { icon: '🏰', label: 'Presidio', value: 'Spanish fort established 1775' },
251
+ { icon: '🇲🇽', label: 'Sovereignty', value: 'Still part of Mexico in 1850' },
252
+ { icon: '🌵', label: 'Geography', value: 'Sonoran Desert oasis' },
253
+ { icon: '🛤️', label: 'Routes', value: 'On southern emigrant trail to California' }
254
+ ],
255
+ suggestedQuestions: ['What was the Gadsden Purchase?', 'Who lived in Tucson in 1850?', 'What was the southern route to California?']
256
+ },
257
+ {
258
+ name: 'Olympia',
259
+ lat: 47.0379, lon: -122.9007,
260
+ subtitle: 'Settlement on Puget Sound',
261
+ description: 'Olympia was one of the earliest American settlements on Puget Sound, founded in 1846. It served as the customs house for the region and would become the capital of Washington Territory when it was split from Oregon Territory in 1853.',
262
+ facts: [
263
+ { icon: '👥', label: 'Population (1850)', value: '~300' },
264
+ { icon: '📅', label: 'Founded', value: '1846 by Edmund Sylvester & Levi Smith' },
265
+ { icon: '🏛️', label: 'Future Capital', value: 'Washington Territory capital (1853)' },
266
+ { icon: '🌲', label: 'Economy', value: 'Lumber and maritime trade' },
267
+ { icon: '🏔️', label: 'Setting', value: 'Southern tip of Puget Sound' }
268
+ ],
269
+ suggestedQuestions: ['What was life like on Puget Sound?', 'How did Oregon Territory govern this area?', 'What drew settlers to the Pacific Northwest?']
270
+ },
271
+ {
272
+ name: 'Stockton',
273
+ lat: 37.9577, lon: -121.2908,
274
+ subtitle: 'Supply Depot of the Southern Mines',
275
+ description: 'Founded in 1849 by Captain Charles Weber, Stockton was a critical supply center for the southern gold mining regions. Located on the San Joaquin River, it provided water access from San Francisco Bay to the interior goldfields.',
276
+ facts: [
277
+ { icon: '👥', label: 'Population (1850)', value: '~1,000' },
278
+ { icon: '📅', label: 'Founded', value: '1849 by Captain Charles Weber' },
279
+ { icon: '⛏️', label: 'Role', value: 'Supply hub for southern gold mines' },
280
+ { icon: '🚢', label: 'River Access', value: 'Steamboats from San Francisco Bay' },
281
+ { icon: '🏪', label: 'Commerce', value: 'Booming mercantile center' }
282
+ ],
283
+ suggestedQuestions: ['How did river transport work in the Gold Rush?', 'What were the southern mines?', 'Who was Captain Weber?']
284
+ },
285
+ {
286
+ name: 'El Paso',
287
+ lat: 31.7619, lon: -106.4850,
288
+ subtitle: 'The Pass of the North',
289
+ description: 'El Paso del Norte was a strategic crossing point on the Rio Grande. The American settlement on the north bank grew after the Mexican-American War. It was a key stop on the southern overland route to California and a military outpost on the new border.',
290
+ facts: [
291
+ { icon: '👥', label: 'Population (1850)', value: '~200 (U.S. side)' },
292
+ { icon: '🏰', label: 'Military', value: 'Fort Bliss established 1849' },
293
+ { icon: '🛤️', label: 'Routes', value: 'Southern Overland Trail to California' },
294
+ { icon: '🌊', label: 'Rio Grande', value: 'Major river crossing point' },
295
+ { icon: '🇲🇽', label: 'Border', value: 'New international boundary at the river' }
296
+ ],
297
+ suggestedQuestions: ['What was the southern route to California?', 'Why was Fort Bliss established?', 'What was life like on the border?']
298
+ },
299
+ {
300
+ name: 'Astoria',
301
+ lat: 46.1879, lon: -123.8313,
302
+ subtitle: 'Oldest American Settlement West of the Rockies',
303
+ description: 'Founded in 1811 as a fur trading post by John Jacob Astor\'s Pacific Fur Company, Astoria was the first permanent American settlement on the Pacific Coast. By 1850 it was a small but historic town at the mouth of the Columbia River.',
304
+ facts: [
305
+ { icon: '👥', label: 'Population (1850)', value: '~250' },
306
+ { icon: '📅', label: 'Founded', value: '1811 — oldest U.S. settlement on Pacific' },
307
+ { icon: '🦫', label: 'Fur Trade', value: 'Originally Pacific Fur Company post' },
308
+ { icon: '🌊', label: 'Location', value: 'Mouth of the Columbia River' },
309
+ { icon: '🐟', label: 'Economy', value: 'Fishing, timber, and river trade' }
310
+ ],
311
+ suggestedQuestions: ['What was the fur trade like?', 'Who was John Jacob Astor?', 'How dangerous was the Columbia River bar?']
312
+ },
313
+ {
314
+ name: 'San Jose',
315
+ lat: 37.3382, lon: -121.8863,
316
+ subtitle: 'First Capital of California',
317
+ description: 'San Jose was California\'s first state capital when it was admitted to the Union in 1850. Founded as a Spanish pueblo in 1777, it was one of the oldest settlements in California and served as a farming community supplying the Gold Rush miners.',
318
+ facts: [
319
+ { icon: '👥', label: 'Population (1850)', value: '~3,000' },
320
+ { icon: '🏛️', label: 'Capital', value: 'First California state capital (1850–51)' },
321
+ { icon: '📅', label: 'Founded', value: '1777 as Pueblo de San José' },
322
+ { icon: '🌾', label: 'Economy', value: 'Agriculture supplying gold miners' },
323
+ { icon: '🏠', label: 'Character', value: 'Mix of Californio and American settlers' }
324
+ ],
325
+ suggestedQuestions: ['Why was San Jose chosen as the first capital?', 'What crops were grown here?', 'What was the Californio culture like?']
326
+ }
327
+ ];
328
+
329
+ var currentItem = null;
330
+ var chatHistory = [];
331
+
332
+ function waitForMap(){
333
+ var g=document.getElementById('map-zoom-group');
334
+ if(!g||!g.querySelector('.region-path')){setTimeout(waitForMap,300);return;}
335
+ plotMarkers(g);
336
+ }
337
+
338
+ function plotMarkers(zoomGroup){
339
+ if(MARKER_DATA.length===0)return;
340
+ var projection=d3.geoAlbersUsa().scale(1280).translate([480,300]);
341
+ var g=d3.select(zoomGroup);
342
+ MARKER_DATA.forEach(function(item){
343
+ var pt=projection([item.lon,item.lat]);
344
+ if(!pt)return;
345
+ var marker=g.append('g').attr('class','city-marker').attr('transform','translate('+pt[0]+','+pt[1]+')');
346
+ marker.append('circle').attr('class','marker-glow').attr('r',8);
347
+ marker.append('circle').attr('class','marker-dot').attr('r',3);
348
+ marker.append('text').attr('class','marker-label').attr('y',-12).text(item.name);
349
+ marker.append('circle').attr('class','marker-hit').attr('r',14);
350
+ marker.on('click',function(event){event.stopPropagation();openCard(item);});
351
+ });
352
+ }
353
+
354
+ function openCard(item){
355
+ var card=document.getElementById('detail-card');
356
+ var backdrop=document.getElementById('card-backdrop');
357
+ if(!card)return;
358
+ document.getElementById('card-title').textContent=item.name;
359
+ document.getElementById('card-subtitle').textContent=item.subtitle||'';
360
+ var body=document.getElementById('card-body');
361
+ var html='';
362
+ if(item.facts&&item.facts.length){
363
+ item.facts.forEach(function(f){
364
+ html+='<div class="fact-row"><div class="fact-icon">'+f.icon+'</div><div class="fact-content"><div class="fact-label">'+f.label+'</div><div class="fact-value">'+f.value+'</div></div></div>';
365
+ });
366
+ }
367
+ if(item.description){
368
+ if(html)html+='<div class="card-divider"></div>';
369
+ html+='<div class="card-description">'+item.description+'</div>';
370
+ }
371
+ body.innerHTML=html||'<div class="card-description" style="color:var(--text-secondary);">No facts available.</div>';
372
+ if(!currentItem||currentItem.name!==item.name){
373
+ chatHistory=[];
374
+ var msgArea=document.getElementById('detail-chat-messages');
375
+ msgArea.innerHTML='<div class="chat-welcome">Select the <strong>Ask Me</strong> tab to ask questions about <strong>'+item.name+'</strong>.</div>';
376
+ }
377
+ currentItem=item;
378
+ updateSuggestedQuestions(item);
379
+ card.classList.add('visible');
380
+ if(backdrop)backdrop.classList.add('visible');
381
+ setActiveTab('facts');
382
+ }
383
+
384
+ function closeCard(){
385
+ var card=document.getElementById('detail-card');
386
+ var backdrop=document.getElementById('card-backdrop');
387
+ if(card)card.classList.remove('visible');
388
+ if(backdrop)backdrop.classList.remove('visible');
389
+ currentItem=null;
390
+ }
391
+
392
+ function setActiveTab(tabName){
393
+ document.querySelectorAll('#detail-card .card-tab').forEach(function(t){
394
+ t.classList.toggle('active',t.getAttribute('data-tab')===tabName);
395
+ });
396
+ document.querySelectorAll('#detail-card .tab-pane').forEach(function(p){
397
+ if(tabName==='facts')p.classList.toggle('active',p.id==='facts-pane');
398
+ else p.classList.toggle('active',p.id==='chat-pane');
399
+ });
400
+ if(tabName==='chat'){
401
+ var input=document.getElementById('detail-chat-input');
402
+ if(input)setTimeout(function(){input.focus();},100);
403
+ scrollChatToBottom();
404
+ }
405
+ }
406
+
407
+ function addChatBubble(text,isUser){
408
+ var area=document.getElementById('detail-chat-messages');
409
+ var welcome=area.querySelector('.chat-welcome');
410
+ if(welcome)welcome.remove();
411
+ var bubble=document.createElement('div');
412
+ bubble.className='chat-bubble '+(isUser?'user-bubble':'ai-bubble');
413
+ bubble.textContent=text;
414
+ area.appendChild(bubble);
415
+ scrollChatToBottom();
416
+ return bubble;
417
+ }
418
+
419
+ function addLoadingBubble(){
420
+ var area=document.getElementById('detail-chat-messages');
421
+ var bubble=document.createElement('div');
422
+ bubble.className='chat-bubble ai-bubble loading';
423
+ bubble.id='detail-loading-bubble';
424
+ bubble.innerHTML='<div class="typing-dots"><span></span><span></span><span></span></div>';
425
+ area.appendChild(bubble);
426
+ scrollChatToBottom();
427
+ return bubble;
428
+ }
429
+
430
+ function removeLoadingBubble(){
431
+ var el=document.getElementById('detail-loading-bubble');
432
+ if(el)el.remove();
433
+ }
434
+
435
+ function scrollChatToBottom(){
436
+ var area=document.getElementById('detail-chat-messages');
437
+ if(area)area.scrollTop=area.scrollHeight;
438
+ }
439
+
440
+ function updateSuggestedQuestions(item){
441
+ var container=document.getElementById('detail-suggested-q');
442
+ var questions=(item.suggestedQuestions&&item.suggestedQuestions.length)
443
+ ?item.suggestedQuestions
444
+ :['What was it like here?','Tell me more about this place.','Why was this important?'];
445
+ container.innerHTML='';
446
+ questions.forEach(function(q){
447
+ var btn=document.createElement('button');
448
+ btn.className='suggested-q';
449
+ btn.textContent=q;
450
+ btn.addEventListener('click',function(){sendChat(q);});
451
+ container.appendChild(btn);
452
+ });
453
+ }
454
+
455
+ function buildPrompt(userQuestion){
456
+ var parts=[];
457
+ parts.push('You are a knowledgeable historian specializing in the American West circa 1850. Answer questions about '+currentItem.name+' based on the provided context and your historical knowledge.');
458
+ parts.push('');
459
+ parts.push('Location: '+currentItem.name);
460
+ if(currentItem.subtitle)parts.push('Summary: '+currentItem.subtitle);
461
+ if(currentItem.description)parts.push('Description: '+currentItem.description);
462
+ if(currentItem.facts&&currentItem.facts.length){
463
+ parts.push('Key facts:');
464
+ currentItem.facts.forEach(function(f){parts.push('- '+f.label+': '+f.value);});
465
+ }
466
+ parts.push('');
467
+ parts.push('RULES:');
468
+ parts.push('- Keep answers concise (2-4 short paragraphs max)');
469
+ parts.push('- Be accurate and informative about the 1850s era');
470
+ parts.push('- If you do not know something, say so honestly');
471
+ parts.push('');
472
+ if(chatHistory.length>0){
473
+ parts.push('Recent conversation:');
474
+ var recent=chatHistory.slice(-10);
475
+ recent.forEach(function(turn){
476
+ parts.push((turn.role==='user'?'User: ':'Assistant: ')+turn.text);
477
+ });
478
+ parts.push('');
479
+ }
480
+ parts.push('User question: '+userQuestion);
481
+ return parts.join('\n');
482
+ }
483
+
484
+ async function sendChat(message){
485
+ if(!message||!message.trim()||!currentItem)return;
486
+ var input=document.getElementById('detail-chat-input');
487
+ var sendBtn=document.getElementById('detail-chat-send');
488
+ message=message.trim();
489
+ input.value='';
490
+ sendBtn.disabled=true;
491
+ setActiveTab('chat');
492
+ addChatBubble(message,true);
493
+ chatHistory.push({role:'user',text:message});
494
+ addLoadingBubble();
495
+ try{
496
+ var prompt=buildPrompt(message);
497
+ var result=await synthos.generate.completion({prompt:prompt,temperature:0.7});
498
+ removeLoadingBubble();
499
+ var answer=result.answer||'I wasn\'t able to generate a response. Please try again.';
500
+ addChatBubble(answer,false);
501
+ chatHistory.push({role:'assistant',text:answer});
502
+ if(chatHistory.length>20)chatHistory=chatHistory.slice(-20);
503
+ }catch(err){
504
+ removeLoadingBubble();
505
+ addChatBubble('Something went wrong. Please try again in a moment.',false);
506
+ console.error('Detail card chat error:',err);
507
+ }
508
+ sendBtn.disabled=false;
509
+ input.focus();
510
+ }
511
+
512
+ document.getElementById('card-close-btn').addEventListener('click',function(e){e.stopPropagation();closeCard();});
513
+ document.getElementById('card-backdrop').addEventListener('click',function(e){e.stopPropagation();closeCard();});
514
+ document.querySelectorAll('#detail-card .card-tab').forEach(function(tab){
515
+ tab.addEventListener('click',function(e){e.stopPropagation();setActiveTab(tab.getAttribute('data-tab'));});
516
+ });
517
+ document.getElementById('detail-chat-send').addEventListener('click',function(e){
518
+ e.stopPropagation();sendChat(document.getElementById('detail-chat-input').value);
519
+ });
520
+ document.getElementById('detail-chat-input').addEventListener('keydown',function(e){
521
+ if(e.key==='Enter'){e.preventDefault();e.stopPropagation();sendChat(this.value);}
522
+ });
523
+ document.getElementById('detail-chat-input').addEventListener('click',function(e){e.stopPropagation();});
524
+
525
+ waitForMap();
526
+ })();</script><script id="page-helpers" src="/api/page-helpers.js?v=2" data-locked="true"></script><script id="page-script" src="/api/page-script.js?v=2" data-locked="true"></script></body></html>
@@ -0,0 +1,12 @@
1
+ {
2
+ "title": "Western Cities 1850",
3
+ "categories": [
4
+ "Educational"
5
+ ],
6
+ "pinned": false,
7
+ "showInAll": false,
8
+ "createdDate": "2026-02-17T19:25:22.510Z",
9
+ "lastModified": "2026-02-17T19:25:22.510Z",
10
+ "pageVersion": 2,
11
+ "mode": "unlocked"
12
+ }
@@ -676,6 +676,30 @@ body.chat-collapsed .chat-toggle {
676
676
  font-style: italic;
677
677
  }
678
678
 
679
+ /* ---- Save Line ---- */
680
+ .save-line {
681
+ display: flex;
682
+ align-items: center;
683
+ gap: 10px;
684
+ margin: 8px 0 15px;
685
+ font-size: 11px;
686
+ color: var(--text-secondary);
687
+ opacity: 0.7;
688
+ }
689
+
690
+ .save-line::before,
691
+ .save-line::after {
692
+ content: '';
693
+ flex: 1;
694
+ height: 1px;
695
+ background: linear-gradient(90deg, transparent, var(--border-color), transparent);
696
+ }
697
+
698
+ .save-line-label {
699
+ white-space: nowrap;
700
+ letter-spacing: 0.5px;
701
+ }
702
+
679
703
  /* ---- Shared page rules ---- */
680
704
  #loadingOverlay { position: absolute; }
681
705
  .chat-submit:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }