six-degrees 0.4.11 โ†’ 0.5.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 (375) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +9 -9
  4. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  5. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  6. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  12. package/.next/standalone/.next/server/app/_not-found.rsc +12 -12
  13. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  14. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +11 -11
  15. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/api/admin-delete/route.js +1 -1
  17. package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/api/admin-update/route.js +1 -1
  19. package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/api/bridges/route.js +1 -1
  21. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/bulk-import/route.js +1 -1
  23. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +1 -1
  25. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/company-scores/route.js +1 -1
  27. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/connections/route.js +1 -1
  29. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/delete-cluster/route.js +1 -1
  36. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/ingest/route.js +1 -1
  38. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/network/route.js +1 -1
  40. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/notifications/route.js +1 -1
  42. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/outreach/route.js +1 -1
  44. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/api/queue/route.js +1 -1
  46. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/api/scraper/route.js +3 -2
  48. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/api/settings/route.js +1 -1
  50. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +1 -1
  52. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +1 -1
  54. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/setup-profile/route.js +1 -1
  56. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/social/route.js +3 -3
  60. package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/api/unlock/route.js +1 -1
  62. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/api/update-images/route.js +1 -1
  65. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/api/users/route.js +1 -1
  67. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/import.html +1 -1
  72. package/.next/standalone/.next/server/app/import.rsc +14 -14
  73. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +14 -14
  74. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +1 -1
  75. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +13 -13
  76. package/.next/standalone/.next/server/app/index.html +1 -1
  77. package/.next/standalone/.next/server/app/index.rsc +14 -14
  78. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  79. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  80. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  81. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  83. package/.next/standalone/.next/server/app/launch.html +2 -2
  84. package/.next/standalone/.next/server/app/launch.rsc +14 -14
  85. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +14 -14
  86. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +1 -1
  87. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +13 -13
  88. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  90. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  91. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  92. package/.next/standalone/.next/server/app/paths.html +1 -1
  93. package/.next/standalone/.next/server/app/paths.rsc +14 -14
  94. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +14 -14
  95. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +1 -1
  96. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +13 -13
  97. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  99. package/.next/standalone/.next/server/app/profile.html +1 -1
  100. package/.next/standalone/.next/server/app/profile.rsc +14 -14
  101. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +14 -14
  102. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +1 -1
  103. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +13 -13
  104. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  105. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  106. package/.next/standalone/.next/server/app/queue.html +1 -1
  107. package/.next/standalone/.next/server/app/queue.rsc +14 -14
  108. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +14 -14
  109. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +1 -1
  110. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +13 -13
  111. package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
  113. package/.next/standalone/.next/server/app/scores.html +1 -1
  114. package/.next/standalone/.next/server/app/scores.rsc +14 -14
  115. package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +14 -14
  116. package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +1 -1
  117. package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +13 -13
  118. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  119. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  120. package/.next/standalone/.next/server/app/settings.html +1 -1
  121. package/.next/standalone/.next/server/app/settings.rsc +14 -14
  122. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  123. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  124. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +13 -13
  125. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  126. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  127. package/.next/standalone/.next/server/app/setup.html +1 -1
  128. package/.next/standalone/.next/server/app/setup.rsc +14 -14
  129. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +14 -14
  130. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +1 -1
  131. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +13 -13
  132. package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
  133. package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
  134. package/.next/standalone/.next/server/app/social.html +1 -1
  135. package/.next/standalone/.next/server/app/social.rsc +14 -14
  136. package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +14 -14
  137. package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +1 -1
  138. package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +13 -13
  139. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0bat8nx._.js โ†’ [root-of-the-server]__13dx4sd._.js} +2 -2
  140. package/.next/standalone/.next/server/chunks/[root-of-the-server]__15wc9e-._.js +3 -0
  141. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +1 -1
  142. package/.next/standalone/.next/server/chunks/[root-of-the-server]__20rwfdw._.js +8 -0
  143. package/.next/standalone/.next/server/chunks/_072jl0y._.js +1 -1
  144. package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
  145. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
  146. package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
  147. package/.next/standalone/.next/server/chunks/lib_0851sk0._.js +8 -0
  148. package/.next/standalone/.next/server/chunks/lib_1q7p2ro._.js +8 -0
  149. package/.next/standalone/.next/server/chunks/lib_1r6l86l._.js +8 -0
  150. package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +8 -8
  151. package/.next/standalone/.next/server/chunks/lib_rpc_04s8mzr.js +3 -0
  152. package/.next/standalone/.next/server/chunks/lib_rpc_053z7as.js +3 -0
  153. package/.next/standalone/.next/server/chunks/lib_rpc_0b_-2te.js +3 -0
  154. package/.next/standalone/.next/server/chunks/lib_rpc_0dhbxdm.js +3 -0
  155. package/.next/standalone/.next/server/chunks/lib_rpc_0dxlk31.js +3 -0
  156. package/.next/standalone/.next/server/chunks/lib_rpc_0f8b-qc.js +3 -0
  157. package/.next/standalone/.next/server/chunks/lib_rpc_0pzie7_.js +3 -0
  158. package/.next/standalone/.next/server/chunks/lib_rpc_0r76fq_.js +3 -0
  159. package/.next/standalone/.next/server/chunks/lib_rpc_0ut7pjp.js +3 -0
  160. package/.next/standalone/.next/server/chunks/lib_rpc_15zyqaz.js +3 -0
  161. package/.next/standalone/.next/server/chunks/lib_rpc_18zpjtq.js +3 -0
  162. package/.next/standalone/.next/server/chunks/lib_rpc_1a8xkiz.js +3 -0
  163. package/.next/standalone/.next/server/chunks/lib_rpc_1e_55xo.js +3 -0
  164. package/.next/standalone/.next/server/chunks/lib_rpc_1oxfd1_.js +3 -0
  165. package/.next/standalone/.next/server/chunks/lib_rpc_1s0lod0.js +3 -0
  166. package/.next/standalone/.next/server/chunks/lib_scoring_1-e4ur0.js +1 -1
  167. package/.next/standalone/.next/server/chunks/ssr/_01kacen._.js +3 -0
  168. package/.next/standalone/.next/server/chunks/ssr/_03l7vge._.js +3 -0
  169. package/.next/standalone/.next/server/chunks/ssr/{_1ap1tu_._.js โ†’ _0gtv9jb._.js} +2 -2
  170. package/.next/standalone/.next/server/chunks/ssr/_0jdkqgi._.js +3 -0
  171. package/.next/standalone/.next/server/chunks/ssr/_0xi-fbs._.js +3 -0
  172. package/.next/standalone/.next/server/chunks/ssr/_0xmwmfv._.js +3 -0
  173. package/.next/standalone/.next/server/chunks/ssr/_1-b9hj7._.js +9 -0
  174. package/.next/standalone/.next/server/chunks/ssr/_112ewem._.js +3 -0
  175. package/.next/standalone/.next/server/chunks/ssr/_16ab63q._.js +3 -0
  176. package/.next/standalone/.next/server/chunks/ssr/_1fxm0-s._.js +3 -0
  177. package/.next/standalone/.next/server/chunks/ssr/_1ra1d3r._.js +9 -0
  178. package/.next/standalone/.next/server/chunks/ssr/app_141w189._.js +3 -0
  179. package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
  180. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +22 -10
  181. package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +2 -2
  182. package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
  183. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +6 -5
  184. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
  185. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +19 -3
  186. package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +1 -2
  187. package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.js +1 -1
  188. package/.next/standalone/.next/server/chunks/ssr/lib_13rapwj._.js +3 -0
  189. package/.next/standalone/.next/server/chunks/ssr/lib_galaxy-lab_108_lu-.js +1 -1
  190. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  191. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  192. package/.next/standalone/.next/server/pages/404.html +1 -1
  193. package/.next/standalone/.next/server/pages/500.html +1 -1
  194. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  195. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  196. package/.next/standalone/.next/static/chunks/03bziijw5srol.js +1 -0
  197. package/.next/standalone/.next/static/chunks/0bgq8wmopl_ig.js +7 -0
  198. package/.next/standalone/.next/static/chunks/0ezus6p2eb-vg.js +1 -0
  199. package/.next/standalone/.next/static/chunks/0g_fy2034bp0x.js +34 -0
  200. package/.next/standalone/.next/static/chunks/0q5dru4q6gxl5.js +22 -0
  201. package/.next/standalone/.next/static/chunks/0w-byiwb2zax8.js +2 -0
  202. package/.next/standalone/.next/static/chunks/1g7jcovdejc9-.js +1 -0
  203. package/.next/standalone/.next/static/chunks/1i51yylxdzht1.js +1 -0
  204. package/.next/standalone/.next/static/chunks/1zf8swaasjf1e.js +43 -0
  205. package/.next/standalone/.next/static/chunks/2rqtpccruavf2.js +1 -0
  206. package/.next/standalone/.next/static/chunks/2wgz9ietkqqe6.js +1 -0
  207. package/.next/standalone/.next/static/chunks/30x3oq_st7a5r.js +1 -0
  208. package/.next/standalone/.next/static/chunks/355ryio1b7sm1.js +1 -0
  209. package/.next/standalone/.next/static/chunks/3ap5hgma7n0o7.js +1 -0
  210. package/.next/standalone/.next/static/chunks/3fci6qi39-1n5.js +1 -0
  211. package/.next/standalone/.next/static/chunks/{24tvdun1cb3g1.js โ†’ 3sowbvbaj1s6n.js} +1 -1
  212. package/.next/standalone/CHANGELOG.md +187 -0
  213. package/.next/standalone/app/api/ingest/route.js +40 -1
  214. package/.next/standalone/app/api/scraper/route.js +7 -1
  215. package/.next/standalone/app/api/settings/sector-preview/route.js +2 -1
  216. package/.next/standalone/app/components/AppTabs.js +59 -0
  217. package/.next/standalone/app/components/ChainView.js +303 -89
  218. package/.next/standalone/app/components/CirclePanel.js +162 -0
  219. package/.next/standalone/app/components/CompanyScores.js +2 -2
  220. package/.next/standalone/app/components/FieldStep.js +4 -4
  221. package/.next/standalone/app/components/FilterPanel.js +121 -183
  222. package/.next/standalone/app/components/ForceGraph.js +41 -3
  223. package/.next/standalone/app/components/GalaxyLab.js +26 -31
  224. package/.next/standalone/app/components/LegacyScoresCard.js +2 -2
  225. package/.next/standalone/app/components/MapControls.js +154 -0
  226. package/.next/standalone/app/components/NoteDetail.js +118 -0
  227. package/.next/standalone/app/components/PathsAnalyzer.js +147 -110
  228. package/.next/standalone/app/components/PeopleMap.js +308 -0
  229. package/.next/standalone/app/components/ScanRadar.js +129 -0
  230. package/.next/standalone/app/components/ScanStatusBar.js +71 -27
  231. package/.next/standalone/app/components/SeparationView.js +626 -118
  232. package/.next/standalone/app/components/Sidebar.js +28 -2
  233. package/.next/standalone/app/components/settings/NetworkHealthSection.js +1 -1
  234. package/.next/standalone/app/components/settings/SectorSection.js +2 -2
  235. package/.next/standalone/app/components/settings/TierSection.js +1 -1
  236. package/.next/standalone/app/components/settings/TitleSection.js +149 -0
  237. package/.next/standalone/app/components/views.js +15 -14
  238. package/.next/standalone/app/page.js +89 -156
  239. package/.next/standalone/app/paths/page.js +39 -27
  240. package/.next/standalone/app/profile/page.js +33 -5
  241. package/.next/standalone/app/queue/page.js +56 -34
  242. package/.next/standalone/app/scores/page.js +16 -66
  243. package/.next/standalone/app/settings/page.js +27 -13
  244. package/.next/standalone/app/setup/page.js +298 -205
  245. package/.next/standalone/app/social/SocialHub.js +374 -0
  246. package/.next/standalone/app/social/page.js +10 -362
  247. package/.next/standalone/lib/chain-layout.js +105 -35
  248. package/.next/standalone/lib/degrees.js +0 -6
  249. package/.next/standalone/lib/dot-rings.js +25 -0
  250. package/.next/standalone/lib/galaxy-lab.js +65 -6
  251. package/.next/standalone/lib/ingest.js +2 -0
  252. package/.next/standalone/lib/island.js +40 -0
  253. package/.next/standalone/lib/linkedin-limits.js +6 -2
  254. package/.next/standalone/lib/map-heat.js +20 -0
  255. package/.next/standalone/lib/network-health.js +1 -1
  256. package/.next/standalone/lib/notifications.js +121 -0
  257. package/.next/standalone/lib/people-map.js +82 -0
  258. package/.next/standalone/lib/rarity.js +45 -3
  259. package/.next/standalone/lib/reach.js +7 -6
  260. package/.next/standalone/lib/rpc.js +15 -4
  261. package/.next/standalone/lib/scan-pace.js +46 -0
  262. package/.next/standalone/lib/scoring.js +39 -8
  263. package/.next/standalone/lib/scraper-client.js +19 -6
  264. package/.next/standalone/lib/sector-focus.js +4 -4
  265. package/.next/standalone/lib/separation.js +137 -10
  266. package/.next/standalone/lib/settings-effects.js +20 -11
  267. package/.next/standalone/lib/settings.js +3 -0
  268. package/.next/standalone/lib/tier-grid.js +99 -0
  269. package/.next/standalone/lib/title-ranking.js +83 -0
  270. package/.next/standalone/package-lock.json +2 -2
  271. package/.next/standalone/package.json +1 -1
  272. package/.next/standalone/scripts/scrape.py +51 -13
  273. package/.next/static/chunks/03bziijw5srol.js +1 -0
  274. package/.next/static/chunks/0bgq8wmopl_ig.js +7 -0
  275. package/.next/static/chunks/0ezus6p2eb-vg.js +1 -0
  276. package/.next/static/chunks/0g_fy2034bp0x.js +34 -0
  277. package/.next/static/chunks/0q5dru4q6gxl5.js +22 -0
  278. package/.next/static/chunks/0w-byiwb2zax8.js +2 -0
  279. package/.next/static/chunks/1g7jcovdejc9-.js +1 -0
  280. package/.next/static/chunks/1i51yylxdzht1.js +1 -0
  281. package/.next/static/chunks/1zf8swaasjf1e.js +43 -0
  282. package/.next/static/chunks/2rqtpccruavf2.js +1 -0
  283. package/.next/static/chunks/2wgz9ietkqqe6.js +1 -0
  284. package/.next/static/chunks/30x3oq_st7a5r.js +1 -0
  285. package/.next/static/chunks/355ryio1b7sm1.js +1 -0
  286. package/.next/static/chunks/3ap5hgma7n0o7.js +1 -0
  287. package/.next/static/chunks/3fci6qi39-1n5.js +1 -0
  288. package/.next/static/chunks/{24tvdun1cb3g1.js โ†’ 3sowbvbaj1s6n.js} +1 -1
  289. package/CHANGELOG.md +187 -0
  290. package/lib/chain-layout.js +105 -35
  291. package/lib/degrees.js +0 -6
  292. package/lib/dot-rings.js +25 -0
  293. package/lib/galaxy-lab.js +65 -6
  294. package/lib/ingest.js +2 -0
  295. package/lib/island.js +40 -0
  296. package/lib/linkedin-limits.js +6 -2
  297. package/lib/map-heat.js +20 -0
  298. package/lib/network-health.js +1 -1
  299. package/lib/notifications.js +121 -0
  300. package/lib/people-map.js +82 -0
  301. package/lib/rarity.js +45 -3
  302. package/lib/reach.js +7 -6
  303. package/lib/rpc.js +15 -4
  304. package/lib/scan-pace.js +46 -0
  305. package/lib/scoring.js +39 -8
  306. package/lib/scraper-client.js +19 -6
  307. package/lib/sector-focus.js +4 -4
  308. package/lib/separation.js +137 -10
  309. package/lib/settings-effects.js +20 -11
  310. package/lib/settings.js +3 -0
  311. package/lib/tier-grid.js +99 -0
  312. package/lib/title-ranking.js +83 -0
  313. package/package.json +1 -1
  314. package/scripts/scrape.py +51 -13
  315. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17hjtzl._.js +0 -8
  316. package/.next/standalone/.next/server/chunks/[root-of-the-server]__20tmem7._.js +0 -3
  317. package/.next/standalone/.next/server/chunks/lib_rpc_03i8xef.js +0 -3
  318. package/.next/standalone/.next/server/chunks/lib_rpc_05gt5ya.js +0 -3
  319. package/.next/standalone/.next/server/chunks/lib_rpc_08fc3rp.js +0 -3
  320. package/.next/standalone/.next/server/chunks/lib_rpc_08r2t_q.js +0 -3
  321. package/.next/standalone/.next/server/chunks/lib_rpc_0btpv1t.js +0 -3
  322. package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +0 -8
  323. package/.next/standalone/.next/server/chunks/lib_rpc_0cm2ev3.js +0 -3
  324. package/.next/standalone/.next/server/chunks/lib_rpc_0iovswz.js +0 -3
  325. package/.next/standalone/.next/server/chunks/lib_rpc_0is8flp.js +0 -3
  326. package/.next/standalone/.next/server/chunks/lib_rpc_0v8ajtd.js +0 -3
  327. package/.next/standalone/.next/server/chunks/lib_rpc_0xgmvvt.js +0 -3
  328. package/.next/standalone/.next/server/chunks/lib_rpc_144mzbf.js +0 -3
  329. package/.next/standalone/.next/server/chunks/lib_rpc_1bggi0n.js +0 -3
  330. package/.next/standalone/.next/server/chunks/lib_rpc_1dkcu9f.js +0 -3
  331. package/.next/standalone/.next/server/chunks/lib_rpc_1o0jb6w.js +0 -3
  332. package/.next/standalone/.next/server/chunks/ssr/_0-85h6g._.js +0 -3
  333. package/.next/standalone/.next/server/chunks/ssr/_08cfj2b._.js +0 -3
  334. package/.next/standalone/.next/server/chunks/ssr/_0c_y09g._.js +0 -3
  335. package/.next/standalone/.next/server/chunks/ssr/_0j4-lc3._.js +0 -3
  336. package/.next/standalone/.next/server/chunks/ssr/_0l8cxmo._.js +0 -3
  337. package/.next/standalone/.next/server/chunks/ssr/_0xkur4p._.js +0 -3
  338. package/.next/standalone/.next/server/chunks/ssr/_14iv_zy._.js +0 -3
  339. package/.next/standalone/.next/server/chunks/ssr/_15x6q32._.js +0 -3
  340. package/.next/standalone/.next/server/chunks/ssr/_212xw8q._.js +0 -3
  341. package/.next/standalone/.next/server/chunks/ssr/app_components_19c2d9c._.js +0 -3
  342. package/.next/standalone/.next/server/chunks/ssr/app_scores_page_09wepvv.js +0 -3
  343. package/.next/standalone/.next/static/chunks/0a5iadnmt9u9k.js +0 -1
  344. package/.next/standalone/.next/static/chunks/15sjx07xhpn6p.js +0 -1
  345. package/.next/standalone/.next/static/chunks/160wjb73ddwqd.js +0 -6
  346. package/.next/standalone/.next/static/chunks/1a74dky22dxd6.js +0 -1
  347. package/.next/standalone/.next/static/chunks/1c_n0973t07l0.js +0 -2
  348. package/.next/standalone/.next/static/chunks/1e1n0kkz-psdb.js +0 -1
  349. package/.next/standalone/.next/static/chunks/236f0jtp68j_h.js +0 -1
  350. package/.next/standalone/.next/static/chunks/297e1z34yi--z.js +0 -1
  351. package/.next/standalone/.next/static/chunks/2_ak6qjxb6oa5.js +0 -1
  352. package/.next/standalone/.next/static/chunks/2kfhc58df2xyo.js +0 -1
  353. package/.next/standalone/.next/static/chunks/39hr8d-b2ibtw.js +0 -31
  354. package/.next/standalone/.next/static/chunks/3ui4d-uqkqj5d.js +0 -2
  355. package/.next/standalone/.next/static/chunks/3zw8bv7-mc4n6.js +0 -33
  356. package/.next/standalone/app/components/OrbitGraph.js +0 -737
  357. package/.next/static/chunks/0a5iadnmt9u9k.js +0 -1
  358. package/.next/static/chunks/15sjx07xhpn6p.js +0 -1
  359. package/.next/static/chunks/160wjb73ddwqd.js +0 -6
  360. package/.next/static/chunks/1a74dky22dxd6.js +0 -1
  361. package/.next/static/chunks/1c_n0973t07l0.js +0 -2
  362. package/.next/static/chunks/1e1n0kkz-psdb.js +0 -1
  363. package/.next/static/chunks/236f0jtp68j_h.js +0 -1
  364. package/.next/static/chunks/297e1z34yi--z.js +0 -1
  365. package/.next/static/chunks/2_ak6qjxb6oa5.js +0 -1
  366. package/.next/static/chunks/2kfhc58df2xyo.js +0 -1
  367. package/.next/static/chunks/39hr8d-b2ibtw.js +0 -31
  368. package/.next/static/chunks/3ui4d-uqkqj5d.js +0 -2
  369. package/.next/static/chunks/3zw8bv7-mc4n6.js +0 -33
  370. /package/.next/standalone/.next/static/{jqE2D3zWqSGz5su948Azf โ†’ I-cj79yE2IZ8taX2dZGp3}/_buildManifest.js +0 -0
  371. /package/.next/standalone/.next/static/{jqE2D3zWqSGz5su948Azf โ†’ I-cj79yE2IZ8taX2dZGp3}/_clientMiddlewareManifest.js +0 -0
  372. /package/.next/standalone/.next/static/{jqE2D3zWqSGz5su948Azf โ†’ I-cj79yE2IZ8taX2dZGp3}/_ssgManifest.js +0 -0
  373. /package/.next/static/{jqE2D3zWqSGz5su948Azf โ†’ I-cj79yE2IZ8taX2dZGp3}/_buildManifest.js +0 -0
  374. /package/.next/static/{jqE2D3zWqSGz5su948Azf โ†’ I-cj79yE2IZ8taX2dZGp3}/_clientMiddlewareManifest.js +0 -0
  375. /package/.next/static/{jqE2D3zWqSGz5su948Azf โ†’ I-cj79yE2IZ8taX2dZGp3}/_ssgManifest.js +0 -0
@@ -1,13 +1,16 @@
1
1
  'use client';
2
2
 
3
- // The Galaxy's physics lab (experimental), in the Filter panel: Obsidian-style
4
- // sliders for the forces that lay the Galaxy out, and a replay of your network
5
- // growing by the date you connected. Everything moves the Galaxy in place;
6
- // lib/galaxy-lab.js holds the settings and the clock.
3
+ // The Galaxy's physics, the main thing in Network Circle's Filters panel
4
+ // (Blake, 2026-10-02: "having the physics tab being the main function"):
5
+ // Obsidian-style sliders for the forces that lay the Galaxy out, and a replay
6
+ // of your network growing by the date you connected. Everything moves the
7
+ // Galaxy in place; lib/galaxy-lab.js holds the settings and the clock. It began
8
+ // as an experimental box with its own on switch; now it is always on, and sits
9
+ // flush in the panel.
7
10
 
8
11
  import { useState, useSyncExternalStore } from 'react';
9
12
  import {
10
- LAB_DEFAULTS, CLUSTERS, labNow, setLab, watchLab,
13
+ LAB_DEFAULTS, CLUSTERS, ORBIT, layoutOf, labNow, setLab, watchLab,
11
14
  clockNow, setClock, watchClock, play, pause, stopReplay,
12
15
  layoutsNow, watchLayouts, saveLayout, applyLayout, forgetLayout, milestones,
13
16
  } from '../../lib/galaxy-lab';
@@ -95,29 +98,16 @@ export default function GalaxyLab() {
95
98
  try { await job(); } catch (e) { setNote(e.message || 'That didnโ€™t work.'); } finally { setBusy(null); done(); }
96
99
  };
97
100
  const canReplay = clock.min != null && clock.max != null && clock.max > clock.min;
98
- const preset = FORCES.every((f) => lab[f.key] === LAB_DEFAULTS[f.key]) ? 'rings'
99
- : Object.entries(CLUSTERS).every(([k, v]) => lab[k] === v) ? 'clusters' : null;
101
+ const preset = layoutOf(lab);
100
102
 
101
103
  return (
102
- <div style={{ marginBottom: 18, padding: '10px 10px 8px', borderRadius: 8, border: '1px solid rgba(212,175,55,0.25)', background: 'rgba(212,175,55,0.04)' }}>
103
- <label style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
104
- <input
105
- type="checkbox" checked={lab.on}
106
- onChange={(e) => { if (!e.target.checked) { stopReplay(); setClock({ find: '' }); } setLab({ on: e.target.checked }); }}
107
- style={{ accentColor: '#D4AF37' }}
108
- />
109
- <span style={{ fontSize: 11.5, fontWeight: 700, color: '#e6d7a0' }}>Physics lab</span>
110
- <span style={{ fontSize: 9, fontWeight: 700, color: '#D4AF37', border: '1px solid rgba(212,175,55,0.4)', borderRadius: 4, padding: '0 4px' }}>EXPERIMENTAL</span>
111
- </label>
112
- {!lab.on && (
113
- <div style={{ ...small, marginTop: 6 }}>
114
- Sliders for the forces that lay the Galaxy out, colours by company or warmth, find, a branch that lights
115
- up on hover, and a replay of your network growing that you can save as a video.
116
- </div>
117
- )}
104
+ <div style={{ marginBottom: 18, borderTop: '1px solid rgba(255,255,255,0.06)', paddingTop: 12 }}>
105
+ <div style={{ fontSize: 13.5, fontWeight: 700, color: '#dde' }}>Physics</div>
106
+ <div style={{ ...small, marginTop: 3 }}>The forces that lay the Galaxy out. Everything here moves it in place.</div>
107
+
108
+ <div style={heading}>Names</div>
109
+ <Choice value={lab.labels} options={[[true, 'On'], [false, 'Off']]} onPick={(v) => setLab({ labels: v })} />
118
110
 
119
- {lab.on && (
120
- <>
121
111
  <div style={heading}>Find</div>
122
112
  <input
123
113
  type="search" value={clock.find} placeholder="A name, company or role"
@@ -137,13 +127,15 @@ export default function GalaxyLab() {
137
127
  <div style={heading}>Layout</div>
138
128
  <Choice
139
129
  value={preset}
140
- options={[['rings', 'Rings'], ['clusters', 'Clusters']]}
141
- onPick={(v) => setLab(v === 'rings' ? { ...Object.fromEntries(FORCES.map((f) => [f.key, LAB_DEFAULTS[f.key]])), sizeBy: 'power' } : CLUSTERS)}
130
+ options={[['rings', 'Rings'], ['orbit', 'Orbit'], ['clusters', 'Clusters']]}
131
+ onPick={(v) => setLab(v === 'rings' ? { ...Object.fromEntries(FORCES.map((f) => [f.key, LAB_DEFAULTS[f.key]])), sizeBy: 'power' } : v === 'orbit' ? ORBIT : CLUSTERS)}
142
132
  />
143
133
  <div style={{ ...small, marginBottom: 6 }}>
144
134
  {preset === 'clusters'
145
135
  ? 'No rings: each connection pulls their circle round them, and a dot grows with everyone behind it.'
146
- : 'Drag a dot to see what it pulls with it. Try Rings at 0 and Pull up.'}
136
+ : preset === 'orbit'
137
+ ? 'Each tier on its own orbit, S nearest you, with each connectionโ€™s circle tucked in behind them. Drag a bridge and its circle follows.'
138
+ : 'Drag a dot to see what it pulls with it. Try Rings at 0 and Pull up.'}
147
139
  </div>
148
140
 
149
141
  <div style={heading}>Forces</div>
@@ -156,9 +148,14 @@ export default function GalaxyLab() {
156
148
  <div style={{ fontSize: 11, color: '#aab', marginBottom: 4 }}>Colour by</div>
157
149
  <Choice
158
150
  value={lab.colourBy}
159
- options={[['tier', 'Tier'], ['degree', 'Degree'], ['company', 'Company'], ['warmth', 'Warmth']]}
151
+ options={[['tier', 'Tier'], ['heat', 'Heat'], ['degree', 'Degree'], ['company', 'Company'], ['warmth', 'Warmth']]}
160
152
  onPick={(v) => setLab({ colourBy: v })}
161
153
  />
154
+ {lab.colourBy === 'heat' && (
155
+ <div style={{ ...small, marginTop: -4, marginBottom: 8 }}>
156
+ Power as a thermal map: the higher someone&rsquo;s score among the people showing, the hotter, and the hottest glow. Where the glow pools, powerful people cluster.
157
+ </div>
158
+ )}
162
159
  {lab.colourBy === 'warmth' && clock.social === null && (
163
160
  <div style={{ ...small, marginTop: -4, marginBottom: 8 }}>
164
161
  Warmth comes from the Social tab: import your LinkedIn export there first. Until then it&rsquo;s by tier.
@@ -271,8 +268,6 @@ export default function GalaxyLab() {
271
268
  marginTop: 10, width: '100%', padding: '6px 10px', borderRadius: 6, fontSize: 11, cursor: 'pointer',
272
269
  border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(255,255,255,0.04)', color: '#aaa',
273
270
  }}>Reset to today&rsquo;s layout</button>
274
- </>
275
- )}
276
271
  </div>
277
272
  );
278
273
  }
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- // The Scores tab: the one-time offer to keep the curated list's old scores as
3
+ // Settings โ†’ Scores: the one-time offer to keep the curated list's old scores as
4
4
  // your own, after the list was made neutral (lib/legacy-offer.js decides who
5
- // sees it and what "keep" writes). It sits at the top of the Scores tab until
5
+ // sees it and what "keep" writes). It sits at the top of the company scores until
6
6
  // it's answered, then never shows again. Not while a CSV import or the sample
7
7
  // is on screen: those aren't scored on the server, so the offer isn't theirs.
8
8
 
@@ -0,0 +1,154 @@
1
+ 'use client';
2
+
3
+ // Paths' two maps (companies and people) read the way Network Circle does
4
+ // (Blake, 2026-10-02: "the paths should have the same filter as network circle
5
+ // even with phyics as well if they want to enable them and change color heat
6
+ // mapping"): colour by sector or by heat, and physics you can switch on, then
7
+ // drag bubbles and move the forces. Off, the layout is computed once and stays
8
+ // still, as it always has.
9
+
10
+ import { useEffect, useRef, useState } from 'react';
11
+ import { forceCollide, forceLink, forceManyBody, forceSimulation, forceX, forceY } from 'd3';
12
+ import { heatColour } from '../../lib/galaxy-lab';
13
+ import { Seg, panelHeading } from './PathsAnalyzer';
14
+
15
+ export const PHYSICS_OFF = Object.freeze({ live: false, spread: 1, pull: 1, links: 1 });
16
+
17
+ const hint = { fontSize: 10.5, color: '#667', lineHeight: 1.45, marginTop: 6 };
18
+ const SLIDERS = [
19
+ { key: 'spread', label: 'Spread', min: 0.2, max: 4, step: 0.05, tip: 'How hard bubbles push each other apart.' },
20
+ { key: 'pull', label: 'Pull to their group', min: 0, max: 4, step: 0.05, tip: 'How hard each bubble keeps to its sector. At 0 they find their own shape.' },
21
+ { key: 'links', label: 'Pull along lines', min: 0, max: 6, step: 0.05, tip: 'How hard two bubbles joined by a line pull together.' },
22
+ ];
23
+
24
+ /** The panel's Colour and Physics sections. */
25
+ export function MapLook({ colourBy, onColourBy, physics, onPhysics, heatHint }) {
26
+ return (
27
+ <>
28
+ <div style={panelHeading}>Colour</div>
29
+ <Seg value={colourBy} onChange={onColourBy} options={[['sector', 'Sector'], ['heat', 'Heat']]} />
30
+ {colourBy === 'heat' && <div style={hint}>{heatHint}</div>}
31
+
32
+ <div style={panelHeading}>Physics</div>
33
+ <Seg value={physics.live ? 'on' : 'off'} onChange={(v) => onPhysics({ ...physics, live: v === 'on' })} options={[['off', 'Still'], ['on', 'Live']]} />
34
+ {physics.live ? (
35
+ <div style={{ marginTop: 8 }}>
36
+ {SLIDERS.map((s) => (
37
+ <label key={s.key} title={s.tip} style={{ display: 'block', marginBottom: 6 }}>
38
+ <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: '#aab' }}>
39
+ <span>{s.label}</span>
40
+ <span style={{ color: physics[s.key] === PHYSICS_OFF[s.key] ? '#556' : '#cfe6f7', fontVariantNumeric: 'tabular-nums' }}>{physics[s.key].toFixed(2)}ร—</span>
41
+ </div>
42
+ <input type="range" min={s.min} max={s.max} step={s.step} value={physics[s.key]}
43
+ onChange={(e) => onPhysics({ ...physics, [s.key]: Number(e.target.value) })}
44
+ style={{ width: '100%', accentColor: '#3498DB' }} />
45
+ </label>
46
+ ))}
47
+ <div style={hint}>Drag a bubble and the ones joined to it follow. Click still opens it.</div>
48
+ <button type="button" onClick={() => onPhysics({ ...PHYSICS_OFF, live: true })} style={{
49
+ marginTop: 6, padding: '4px 10px', borderRadius: 6, fontSize: 10.5, cursor: 'pointer',
50
+ border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(255,255,255,0.04)', color: '#aab',
51
+ }}>Reset the forces</button>
52
+ </div>
53
+ ) : (
54
+ <div style={hint}>Live lets the bubbles move: drag them, and change the forces that lay the map out.</div>
55
+ )}
56
+ </>
57
+ );
58
+ }
59
+
60
+ /**
61
+ * The map's layout, moving: a simulation on the layout's own nodes (each with
62
+ * `ax`, `ay`, where its group sits) and lines (each with `k`, its pull), the
63
+ * same forces the still layout settled under, redrawn once a frame while it moves.
64
+ * Returns `drag(event, node)` for a bubble's pointer-down, and `clicked()`,
65
+ * false right after a drag so letting go doesn't open the bubble.
66
+ */
67
+ export function useLivePhysics(layout, physics) {
68
+ const [, setFrame] = useState(0);
69
+ const sim = useRef(null);
70
+ const moved = useRef(false);
71
+ useEffect(() => {
72
+ if (!physics.live || !layout.nodes.length) return undefined;
73
+ let raf = 0;
74
+ const s = forceSimulation(layout.nodes)
75
+ .force('x', forceX((d) => d.ax).strength(0.12 * physics.pull))
76
+ .force('y', forceY((d) => d.ay).strength(0.12 * physics.pull))
77
+ .force('collide', forceCollide((d) => d.r + 3).iterations(2))
78
+ .force('charge', forceManyBody().strength(-25 * physics.spread))
79
+ // Each line's own pull from the still layout (`k`), so at 1ร— nothing moves until you drag.
80
+ .force('link', forceLink(layout.edges).id((d) => d.id)
81
+ .strength((e) => (e.k ?? 0.1) * physics.links).distance(60 * Math.sqrt(physics.spread)))
82
+ .alpha(0.15)
83
+ .on('tick', () => {
84
+ if (!raf) raf = requestAnimationFrame(() => { raf = 0; setFrame((f) => f + 1); });
85
+ });
86
+ sim.current = s;
87
+ return () => { s.stop(); cancelAnimationFrame(raf); sim.current = null; };
88
+ }, [layout, physics.live, physics.spread, physics.pull, physics.links]);
89
+
90
+ const drag = (ev, node) => {
91
+ const s = sim.current;
92
+ if (!s) return;
93
+ const svg = ev.currentTarget.ownerSVGElement;
94
+ const ctm = svg?.getScreenCTM();
95
+ if (!ctm) return;
96
+ const inv = ctm.inverse();
97
+ const at = (e) => {
98
+ const pt = svg.createSVGPoint();
99
+ pt.x = e.clientX; pt.y = e.clientY;
100
+ return pt.matrixTransform(inv);
101
+ };
102
+ const start = { x: ev.clientX, y: ev.clientY };
103
+ moved.current = false;
104
+ const move = (e) => {
105
+ if (Math.hypot(e.clientX - start.x, e.clientY - start.y) > 3) moved.current = true;
106
+ const p = at(e);
107
+ node.fx = p.x; node.fy = p.y;
108
+ };
109
+ const up = () => {
110
+ node.fx = null; node.fy = null;
111
+ s.alphaTarget(0);
112
+ window.removeEventListener('pointermove', move);
113
+ window.removeEventListener('pointerup', up);
114
+ };
115
+ const p = at(ev);
116
+ node.fx = p.x; node.fy = p.y;
117
+ // Gently: the spacing between bubbles isn't scaled by the heat, the pulls are,
118
+ // so a calm drag keeps them from piling up while they follow.
119
+ s.alphaTarget(0.08).restart();
120
+ window.addEventListener('pointermove', move);
121
+ window.addEventListener('pointerup', up);
122
+ };
123
+ const clicked = () => {
124
+ if (!moved.current) return true;
125
+ moved.current = false;
126
+ return false;
127
+ };
128
+ return { drag: physics.live ? drag : null, clicked };
129
+ }
130
+
131
+ /** Radial glows for Heat, one per step of the ramp; `id` keeps two maps' apart. */
132
+ export function HeatDefs({ id }) {
133
+ return (
134
+ <defs>
135
+ {[0, 1, 2, 3, 4, 5].map((k) => (
136
+ <radialGradient key={k} id={`${id}-${k}`}>
137
+ <stop offset="0" stopColor={heatColour(k / 5)} stopOpacity={0.16 + 0.07 * k} />
138
+ <stop offset="1" stopColor={heatColour(k / 5)} stopOpacity={0} />
139
+ </radialGradient>
140
+ ))}
141
+ </defs>
142
+ );
143
+ }
144
+
145
+ /** The glow behind the hotter bubbles, screen-blended so it pools where they cluster. */
146
+ export function HeatGlow({ id, nodes, heat }) {
147
+ return (
148
+ <g style={{ mixBlendMode: 'screen', pointerEvents: 'none' }}>
149
+ {nodes.filter((n) => heat(n) >= 0.5).map((n) => (
150
+ <circle key={n.id} cx={n.x} cy={n.y} r={n.r * 1.9 + 18} fill={`url(#${id}-${Math.round(heat(n) * 5)})`} />
151
+ ))}
152
+ </g>
153
+ );
154
+ }
@@ -0,0 +1,118 @@
1
+ 'use client';
2
+
3
+ // A notification, opened in the right panel (Blake, 2026-10-02: "if it is
4
+ // [clicked] then it should take over the right panel and show a more detailed
5
+ // version of the notifications telling you what person added back from who and
6
+ // that they are a value person if the score is s"). Who it's about comes from
7
+ // lib/notifications.js noteSubject; everything shown is on file already.
8
+
9
+ import Avatar from './Avatar';
10
+ import { noteSubject } from '../../lib/notifications';
11
+
12
+ const TIER = { S: '#FFD700', A: '#9B59B6', B: '#3498DB', C: '#95A5A6', D: '#BDC3C7' };
13
+ const VALUE = {
14
+ S: 'S-tier: one of the most valuable people in your network to know.',
15
+ A: 'A-tier: a strong person to know.',
16
+ };
17
+ const ago = (when) => {
18
+ const t = new Date(String(when || '').replace(' ', 'T') + (String(when || '').includes('Z') ? '' : 'Z')).getTime();
19
+ if (!Number.isFinite(t)) return '';
20
+ const m = Math.round((Date.now() - t) / 60000);
21
+ if (m < 1) return 'just now';
22
+ if (m < 60) return `${m} min ago`;
23
+ const h = Math.round(m / 60);
24
+ if (h < 24) return `${h} h ago`;
25
+ return new Date(t).toLocaleDateString();
26
+ };
27
+ const btn = {
28
+ padding: '8px 12px', borderRadius: 8, fontSize: 12, fontWeight: 700, cursor: 'pointer', textAlign: 'left',
29
+ border: '1px solid rgba(255,255,255,0.12)', background: 'rgba(255,255,255,0.05)', color: '#ddd',
30
+ };
31
+
32
+ export default function NoteDetail({ note, connections = [], degree2 = [], onBack, onSelect, onOpenCircle, onShowInSeparation }) {
33
+ const { person, via, people } = noteSubject(note, connections, degree2);
34
+ const tier = person?.tier;
35
+ const score = Number.parseFloat(person?.power_score);
36
+ const prestige = Number(person?.company_prestige_score);
37
+ const addedBack = ['added_back', 'request_accepted', 'connection_accepted'].includes(note?.type);
38
+ const hasCircle = person && degree2.some((r) => r.source_connection_id === person.id);
39
+
40
+ return (
41
+ <div>
42
+ <button type="button" onClick={onBack} style={{ background: 'none', border: 'none', color: '#aaa', cursor: 'pointer', fontSize: 12, padding: 0, marginBottom: 12 }}>
43
+ โ† Back
44
+ </button>
45
+ <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
46
+ <span style={{ fontSize: 22 }}>{note?.icon || '๐Ÿ“Œ'}</span>
47
+ <div style={{ minWidth: 0 }}>
48
+ <div style={{ fontSize: 15, fontWeight: 800, color: '#fff', lineHeight: 1.35 }}>{note?.title}</div>
49
+ <div style={{ fontSize: 11, color: '#777', marginTop: 3 }}>{ago(note?.created_at)}</div>
50
+ </div>
51
+ </div>
52
+
53
+ {person && (
54
+ <div style={{ marginTop: 16, padding: 14, borderRadius: 12, border: `1px solid ${(TIER[tier] || '#555')}55`, background: `${TIER[tier] || '#555'}10` }}>
55
+ <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
56
+ <Avatar person={person} size={44} />
57
+ <div style={{ minWidth: 0 }}>
58
+ <div style={{ fontSize: 15, fontWeight: 800 }}>{person.name}</div>
59
+ <div style={{ fontSize: 11.5, color: '#aab', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{person.headline || person.company || ''}</div>
60
+ <div style={{ fontSize: 11.5, fontWeight: 800, color: TIER[tier] || '#aaa', marginTop: 2 }}>
61
+ {tier ? `${tier}-tier` : 'Not scored yet'}{Number.isFinite(score) ? ` ยท ${score.toFixed(1)}` : ''}
62
+ </div>
63
+ </div>
64
+ </div>
65
+ {addedBack && (
66
+ <div style={{ marginTop: 12, fontSize: 12.5, color: '#ddd', lineHeight: 1.5 }}>
67
+ <b>{person.name.split(' ')[0]}</b> added you back
68
+ {via ? <>. You met through <b style={{ color: TIER[via.tier] || '#fff' }}>{via.name}</b>.</> : '.'}
69
+ </div>
70
+ )}
71
+ {!addedBack && via && (
72
+ <div style={{ marginTop: 12, fontSize: 12.5, color: '#ddd' }}>
73
+ {person.degree === 2 ? 'In the circle of ' : 'You met through '}<b>{via.name}</b>.
74
+ </div>
75
+ )}
76
+ {VALUE[tier] && <div style={{ marginTop: 8, fontSize: 12.5, fontWeight: 700, color: TIER[tier] }}>{VALUE[tier]}</div>}
77
+ {prestige >= 8 && (
78
+ <div style={{ marginTop: 6, fontSize: 12, color: '#cfd3e6' }}>Works at a top company{person.company ? `, ${person.company}` : ''} (its score: {prestige}).</div>
79
+ )}
80
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginTop: 14 }}>
81
+ <button type="button" style={btn} onClick={() => onSelect?.(person)}>Open {person.name.split(' ')[0]}โ€™s card โ†’</button>
82
+ {(hasCircle || person.degree === 1) && onOpenCircle && (
83
+ <button type="button" style={btn} onClick={() => onOpenCircle(person.id)}>
84
+ {hasCircle ? `Open ${person.name.split(' ')[0]}โ€™s circle in Bridge Chains โ†’` : `${person.name.split(' ')[0]}โ€™s circle: not scanned yet`}
85
+ </button>
86
+ )}
87
+ {person.degree === 2 && onShowInSeparation && (
88
+ <button type="button" style={btn} onClick={() => onShowInSeparation({ query: person.name })}>Show in Separation โ†’</button>
89
+ )}
90
+ </div>
91
+ </div>
92
+ )}
93
+
94
+ {people.length > 1 && (
95
+ <div style={{ marginTop: 16 }}>
96
+ <div style={{ fontSize: 10, fontWeight: 800, letterSpacing: 1, color: '#6b7090', textTransform: 'uppercase', marginBottom: 8 }}>Who</div>
97
+ {people.slice(0, 12).map((p) => (
98
+ <button key={p.id} type="button" onClick={() => onSelect?.(p)} style={{ ...btn, display: 'flex', gap: 10, alignItems: 'center', width: '100%', marginBottom: 6, fontWeight: 600 }}>
99
+ <Avatar person={p} size={26} />
100
+ <span style={{ minWidth: 0, flex: 1 }}>
101
+ <span style={{ display: 'block', color: '#fff' }}>{p.name}</span>
102
+ <span style={{ display: 'block', fontSize: 10.5, color: '#8a8fa8', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.company || p.headline || ''}</span>
103
+ </span>
104
+ <span style={{ fontSize: 11, fontWeight: 800, color: TIER[p.tier] || '#aaa' }}>{p.tier}</span>
105
+ </button>
106
+ ))}
107
+ </div>
108
+ )}
109
+
110
+ {note?.message && (
111
+ <div style={{ marginTop: 14, fontSize: 12, color: '#999', lineHeight: 1.55 }}>{note.message}</div>
112
+ )}
113
+ {!person && !people.length && (
114
+ <div style={{ marginTop: 10, fontSize: 11.5, color: '#667' }}>Nothing more on file about this one.</div>
115
+ )}
116
+ </div>
117
+ );
118
+ }