six-degrees 0.6.0 β†’ 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 (609) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +4 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +42 -14
  5. package/.next/standalone/.next/routes-manifest.json +24 -0
  6. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
  12. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.rsc +26 -18
  16. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +26 -18
  17. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +25 -16
  18. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  19. package/.next/standalone/.next/server/app/api/admin-delete/route.js +2 -2
  20. package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/admin-update/route.js +2 -2
  22. package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/bridges/route.js +2 -2
  24. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/bulk-import/route.js +2 -2
  26. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +3 -3
  28. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/company-scores/route.js +3 -3
  30. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/connections/route.js +2 -2
  32. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/data/backup/route/app-paths-manifest.json +3 -0
  34. package/.next/standalone/.next/server/app/api/data/backup/route/build-manifest.json +12 -0
  35. package/.next/standalone/.next/server/app/api/data/backup/route/server-reference-manifest.json +4 -0
  36. package/.next/standalone/.next/server/app/api/data/backup/route.js +7 -0
  37. package/.next/standalone/.next/server/app/api/data/backup/route.js.map +5 -0
  38. package/.next/standalone/.next/server/app/api/data/backup/route.js.nft.json +1 -0
  39. package/.next/standalone/.next/server/app/api/data/backup/route_client-reference-manifest.js +3 -0
  40. package/.next/standalone/.next/server/app/api/data/csv/route/app-paths-manifest.json +3 -0
  41. package/.next/standalone/.next/server/app/api/data/csv/route/build-manifest.json +12 -0
  42. package/.next/standalone/.next/server/app/api/data/csv/route/server-reference-manifest.json +4 -0
  43. package/.next/standalone/.next/server/app/api/data/csv/route.js +8 -0
  44. package/.next/standalone/.next/server/app/api/data/csv/route.js.map +5 -0
  45. package/.next/standalone/.next/server/app/api/data/csv/route.js.nft.json +1 -0
  46. package/.next/standalone/.next/server/app/api/data/csv/route_client-reference-manifest.js +3 -0
  47. package/.next/standalone/.next/server/app/api/data/export/route.js +1 -1
  48. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/api/data/import/route.js +1 -1
  50. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/data/restart/route.js +1 -1
  52. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/data/restore/route/app-paths-manifest.json +3 -0
  54. package/.next/standalone/.next/server/app/api/data/restore/route/build-manifest.json +12 -0
  55. package/.next/standalone/.next/server/app/api/data/restore/route/server-reference-manifest.json +4 -0
  56. package/.next/standalone/.next/server/app/api/data/restore/route.js +7 -0
  57. package/.next/standalone/.next/server/app/api/data/restore/route.js.map +5 -0
  58. package/.next/standalone/.next/server/app/api/data/restore/route.js.nft.json +1 -0
  59. package/.next/standalone/.next/server/app/api/data/restore/route_client-reference-manifest.js +3 -0
  60. package/.next/standalone/.next/server/app/api/data/reveal/route.js +1 -1
  61. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/api/data/route.js +1 -1
  63. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/api/delete-cluster/route.js +2 -2
  65. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/api/ingest/route.js +2 -2
  67. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/api/network/route.js +2 -2
  69. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/api/notifications/route.js +2 -2
  71. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  72. package/.next/standalone/.next/server/app/api/outreach/route.js +3 -3
  73. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/api/queue/route.js +2 -2
  75. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/api/scraper/route.js +5 -3
  77. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/api/settings/route.js +3 -3
  79. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +3 -3
  81. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +3 -3
  83. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/api/setup-profile/route.js +2 -2
  85. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  86. package/.next/standalone/.next/server/app/api/social/crm/route.js +1 -1
  87. package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -1
  88. package/.next/standalone/.next/server/app/api/social/messages/route.js +1 -1
  89. package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/social/route.js +2 -2
  91. package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/api/unlock/route.js +2 -2
  93. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/update-images/route.js +2 -2
  96. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  97. package/.next/standalone/.next/server/app/api/users/route.js +2 -2
  98. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/avatars/[file]/route.js +1 -1
  100. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  101. package/.next/standalone/.next/server/app/import/page.js +1 -1
  102. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  104. package/.next/standalone/.next/server/app/import.html +1 -1
  105. package/.next/standalone/.next/server/app/import.rsc +32 -24
  106. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +32 -24
  107. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
  108. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +23 -18
  109. package/.next/standalone/.next/server/app/index.html +1 -1
  110. package/.next/standalone/.next/server/app/index.rsc +29 -22
  111. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +20 -15
  112. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +29 -22
  113. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  114. package/.next/standalone/.next/server/app/insights/page/app-paths-manifest.json +3 -0
  115. package/.next/standalone/.next/server/app/insights/page/build-manifest.json +20 -0
  116. package/.next/standalone/.next/server/app/insights/page/next-font-manifest.json +11 -0
  117. package/.next/standalone/.next/server/app/insights/page/react-loadable-manifest.json +1 -0
  118. package/.next/standalone/.next/server/app/insights/page/server-reference-manifest.json +4 -0
  119. package/.next/standalone/.next/server/app/insights/page.js +13 -0
  120. package/.next/standalone/.next/server/app/insights/page.js.map +5 -0
  121. package/.next/standalone/.next/server/app/insights/page.js.nft.json +1 -0
  122. package/.next/standalone/.next/server/app/insights/page_client-reference-manifest.js +3 -0
  123. package/.next/standalone/.next/server/app/insights.html +1 -0
  124. package/.next/standalone/.next/server/app/insights.meta +26 -0
  125. package/.next/standalone/.next/server/app/insights.rsc +35 -0
  126. package/.next/standalone/.next/server/app/insights.segments/_full.segment.rsc +35 -0
  127. package/.next/standalone/.next/server/app/insights.segments/_tree.segment.rsc +4 -0
  128. package/.next/standalone/.next/server/app/insights.segments/insights/__PAGE__.segment.rsc +33 -0
  129. package/.next/standalone/.next/server/app/launch/page.js +1 -1
  130. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  131. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  132. package/.next/standalone/.next/server/app/launch.html +2 -2
  133. package/.next/standalone/.next/server/app/launch.rsc +32 -24
  134. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +32 -24
  135. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
  136. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +23 -18
  137. package/.next/standalone/.next/server/app/page.js +1 -1
  138. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  139. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  140. package/.next/standalone/.next/server/app/paths/page.js +1 -1
  141. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  142. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  143. package/.next/standalone/.next/server/app/paths.html +1 -1
  144. package/.next/standalone/.next/server/app/paths.rsc +32 -24
  145. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +32 -24
  146. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
  147. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +21 -18
  148. package/.next/standalone/.next/server/app/profile/page.js +1 -1
  149. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  151. package/.next/standalone/.next/server/app/profile.html +1 -1
  152. package/.next/standalone/.next/server/app/profile.rsc +32 -24
  153. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +32 -24
  154. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
  155. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +23 -18
  156. package/.next/standalone/.next/server/app/queue/page.js +1 -1
  157. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  158. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  159. package/.next/standalone/.next/server/app/queue.html +1 -1
  160. package/.next/standalone/.next/server/app/queue.rsc +32 -24
  161. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +32 -24
  162. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
  163. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +21 -18
  164. package/.next/standalone/.next/server/app/scores/page.js +1 -1
  165. package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
  166. package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
  167. package/.next/standalone/.next/server/app/scores.html +1 -1
  168. package/.next/standalone/.next/server/app/scores.rsc +32 -24
  169. package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +32 -24
  170. package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
  171. package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +23 -18
  172. package/.next/standalone/.next/server/app/settings/page.js +1 -1
  173. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  174. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  175. package/.next/standalone/.next/server/app/settings.html +1 -1
  176. package/.next/standalone/.next/server/app/settings.rsc +32 -24
  177. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +32 -24
  178. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  179. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +20 -18
  180. package/.next/standalone/.next/server/app/setup/page.js +1 -1
  181. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  183. package/.next/standalone/.next/server/app/setup.html +1 -1
  184. package/.next/standalone/.next/server/app/setup.rsc +32 -24
  185. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +32 -24
  186. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  187. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +21 -18
  188. package/.next/standalone/.next/server/app/social/page.js +1 -1
  189. package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
  190. package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
  191. package/.next/standalone/.next/server/app/social.html +1 -1
  192. package/.next/standalone/.next/server/app/social.rsc +32 -24
  193. package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +32 -24
  194. package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
  195. package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +23 -18
  196. package/.next/standalone/.next/server/app-paths-manifest.json +4 -0
  197. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00la_y0._.js +1 -1
  198. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05_3-22._.js +1 -1
  199. package/.next/standalone/.next/server/chunks/[root-of-the-server]__066rab1._.js +7 -0
  200. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07t47cm._.js +1 -1
  201. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cj5jqc._.js +1 -1
  202. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e0fei3._.js +1 -1
  203. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fooke1._.js +7 -0
  204. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljnyho._.js +1 -1
  205. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o5-tcg._.js +1 -1
  206. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qrnous._.js +1 -1
  207. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__15wc9e-._.js β†’ [root-of-the-server]__0r-0t-9._.js} +2 -2
  208. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ra6xyg._.js +15 -0
  209. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__20rwfdw._.js β†’ [root-of-the-server]__0rcpjad._.js} +6 -3
  210. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +1 -1
  211. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t6y79e._.js +7 -0
  212. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wmexuc._.js +1 -1
  213. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0x29muh._.js +7 -0
  214. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xu34sz._.js +1 -1
  215. package/.next/standalone/.next/server/chunks/[root-of-the-server]__133knx1._.js +1 -1
  216. package/.next/standalone/.next/server/chunks/[root-of-the-server]__15-17hl._.js +1 -1
  217. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19b7mig._.js +1 -1
  218. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a_6x37._.js +8 -0
  219. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1an_8pa._.js +7 -0
  220. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bbcwub._.js +1 -1
  221. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ducpz2._.js +3 -0
  222. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1eris29._.js +1 -1
  223. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1gjo_cq._.js +1 -1
  224. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qcm08_._.js +1 -1
  225. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tir0vc._.js +1 -1
  226. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1w25q0m._.js +1 -1
  227. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xhyinn._.js +3 -0
  228. package/.next/standalone/.next/server/chunks/_072jl0y._.js +1 -1
  229. package/.next/standalone/.next/server/chunks/_0lw8_i0._.js +1 -1
  230. package/.next/standalone/.next/server/chunks/_0sqqpzb._.js +3 -0
  231. package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
  232. package/.next/standalone/.next/server/chunks/_1fn30_l._.js +1 -1
  233. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
  234. package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
  235. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_backup_route_actions_0zoj04p.js +3 -0
  236. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_csv_route_actions_0l6m7lg.js +3 -0
  237. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_restore_route_actions_0-b05bv.js +3 -0
  238. package/.next/standalone/.next/server/chunks/lib_02iz_9q._.js +4 -0
  239. package/.next/standalone/.next/server/chunks/lib_05agvk3._.js +4 -0
  240. package/.next/standalone/.next/server/chunks/lib_0v84u66._.js +4 -0
  241. package/.next/standalone/.next/server/chunks/lib_db-client_0_dch35.js +174 -0
  242. package/.next/standalone/.next/server/chunks/lib_linkedin-export_12imqxg.js +1 -1
  243. package/.next/standalone/.next/server/chunks/lib_rpc_00nndai.js +3 -0
  244. package/.next/standalone/.next/server/chunks/lib_rpc_03ibb-x.js +3 -0
  245. package/.next/standalone/.next/server/chunks/lib_rpc_03ri3ji.js +3 -0
  246. package/.next/standalone/.next/server/chunks/lib_rpc_078ce48.js +3 -0
  247. package/.next/standalone/.next/server/chunks/lib_rpc_0a69mgr.js +3 -0
  248. package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +7 -0
  249. package/.next/standalone/.next/server/chunks/lib_rpc_0cej3t8.js +3 -0
  250. package/.next/standalone/.next/server/chunks/lib_rpc_0cmh4g6.js +3 -0
  251. package/.next/standalone/.next/server/chunks/lib_rpc_0nx2_pc.js +3 -0
  252. package/.next/standalone/.next/server/chunks/lib_rpc_0r79-w1.js +3 -0
  253. package/.next/standalone/.next/server/chunks/lib_rpc_0t552z6.js +3 -0
  254. package/.next/standalone/.next/server/chunks/lib_rpc_0yx8ynd.js +3 -0
  255. package/.next/standalone/.next/server/chunks/lib_rpc_12p-o9-.js +3 -0
  256. package/.next/standalone/.next/server/chunks/lib_rpc_1466dnb.js +3 -0
  257. package/.next/standalone/.next/server/chunks/lib_rpc_1sryxv6.js +3 -0
  258. package/.next/standalone/.next/server/chunks/lib_rpc_1trn-x5.js +3 -0
  259. package/.next/standalone/.next/server/chunks/lib_rpc_1ygu_mv.js +3 -0
  260. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egamyq._.js +3 -0
  261. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qd8pzm._.js +3 -0
  262. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0qdeuyo._.js β†’ [root-of-the-server]__1-012q1._.js} +2 -2
  263. package/.next/standalone/.next/server/chunks/ssr/_04am_h8._.js +3 -0
  264. package/.next/standalone/.next/server/chunks/ssr/_06rgzfh._.js +3 -0
  265. package/.next/standalone/.next/server/chunks/ssr/_07zb7lu._.js +3 -0
  266. package/.next/standalone/.next/server/chunks/ssr/_0_79idq._.js +3 -0
  267. package/.next/standalone/.next/server/chunks/ssr/_0gds903._.js +3 -0
  268. package/.next/standalone/.next/server/chunks/ssr/_0hb-dhy._.js +3 -0
  269. package/.next/standalone/.next/server/chunks/ssr/_0klqt9z._.js +3 -0
  270. package/.next/standalone/.next/server/chunks/ssr/_14jak5s._.js +7 -0
  271. package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +3 -0
  272. package/.next/standalone/.next/server/chunks/ssr/_1cj2yog._.js +3 -0
  273. package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +2 -2
  274. package/.next/standalone/.next/server/chunks/ssr/_1hdqw0-._.js +7 -0
  275. package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +2 -2
  276. package/.next/standalone/.next/server/chunks/ssr/_1r62six._.js +7 -0
  277. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_insights_page_actions_0-0tf75.js +3 -0
  278. package/.next/standalone/.next/server/chunks/ssr/app_141w189._.js +1 -1
  279. package/.next/standalone/.next/server/chunks/ssr/app_components_0uuff77._.js +25 -2
  280. package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +25 -2
  281. package/.next/standalone/.next/server/chunks/ssr/app_components_CompanyScores_1g0mytz.js +1 -1
  282. package/.next/standalone/.next/server/chunks/ssr/app_components_settings_SectorPicker_1c-29qw.js +1 -1
  283. package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
  284. package/.next/standalone/.next/server/chunks/ssr/app_import_page_1fmu6_l.js +1 -1
  285. package/.next/standalone/.next/server/chunks/ssr/app_insights_page_1d_chja.js +3 -0
  286. package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +1 -1
  287. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +26 -14
  288. package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +2 -2
  289. package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
  290. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +11 -11
  291. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
  292. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +12 -13
  293. package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +1 -1
  294. package/.next/standalone/.next/server/chunks/ssr/{lib_1c4ieuw._.js β†’ lib_csv_1ttiu_h.js} +2 -2
  295. package/.next/standalone/.next/server/chunks/ssr/lib_galaxy-lab_108_lu-.js +1 -1
  296. package/.next/standalone/.next/server/chunks/ssr/lib_separation_1305zsx.js +3 -0
  297. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0pco7a6._.js +1 -1
  298. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  299. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  300. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  301. package/.next/standalone/.next/server/next-font-manifest.json +4 -0
  302. package/.next/standalone/.next/server/pages/404.html +1 -1
  303. package/.next/standalone/.next/server/pages/500.html +1 -1
  304. package/.next/standalone/.next/server/prefetch-hints.json +14 -0
  305. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  306. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  307. package/.next/standalone/.next/static/chunks/02wnf8dkxegxg.js +34 -0
  308. package/.next/standalone/.next/static/chunks/03-_esd2x_yk6.js +1 -0
  309. package/.next/standalone/.next/static/chunks/03-demj2iy-0p.js +44 -0
  310. package/.next/standalone/.next/static/chunks/0838_s6w-i_ik.js +1 -0
  311. package/.next/standalone/.next/static/chunks/0_1r-3csplxnj.js +1 -0
  312. package/.next/standalone/.next/static/chunks/0ka4prpk3w9wn.js +34 -0
  313. package/.next/standalone/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
  314. package/.next/standalone/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
  315. package/.next/standalone/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
  316. package/.next/standalone/.next/static/chunks/112mv-com-mqa.js +21 -0
  317. package/.next/standalone/.next/static/chunks/1bkt_hhjzvbh8.js +1 -0
  318. package/.next/standalone/.next/static/chunks/1cmphb3kh2ers.css +3 -0
  319. package/.next/standalone/.next/static/chunks/1d8yv3k_atka7.js +1 -0
  320. package/.next/standalone/.next/static/chunks/{0ws7zy0w57ufi.js β†’ 1eyajb9ntzlrl.js} +1 -1
  321. package/.next/standalone/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
  322. package/.next/standalone/.next/static/chunks/23hc51oa4vkhc.js +5 -0
  323. package/.next/standalone/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
  324. package/.next/standalone/.next/static/chunks/2q9i7pcxcnph1.js +7 -0
  325. package/.next/standalone/.next/static/chunks/2w-y83mjlpnse.js +1 -0
  326. package/.next/standalone/.next/static/chunks/2ws1xf293j-tm.js +5 -0
  327. package/.next/standalone/.next/static/chunks/2z1-q0_vunbql.js +2 -0
  328. package/.next/standalone/.next/static/chunks/34g73qhayuevu.js +1 -0
  329. package/.next/standalone/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
  330. package/.next/standalone/.next/static/chunks/3opgg1efrx8q6.js +1 -0
  331. package/.next/standalone/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
  332. package/.next/standalone/.next/static/chunks/3y40z6of3r9py.js +1 -0
  333. package/.next/standalone/.next/static/chunks/403dpflln8ah5.js +1 -0
  334. package/.next/standalone/.next/static/chunks/43pg2sursiypz.js +1 -0
  335. package/.next/standalone/CHANGELOG.md +203 -0
  336. package/.next/standalone/README.md +96 -50
  337. package/.next/standalone/SECURITY.md +25 -11
  338. package/.next/standalone/app/api/data/backup/route.js +25 -0
  339. package/.next/standalone/app/api/data/csv/route.js +74 -0
  340. package/.next/standalone/app/api/data/export/route.js +1 -1
  341. package/.next/standalone/app/api/data/restore/route.js +48 -0
  342. package/.next/standalone/app/api/data/reveal/route.js +19 -6
  343. package/.next/standalone/app/api/data/route.js +15 -4
  344. package/.next/standalone/app/api/ingest/route.js +1 -1
  345. package/.next/standalone/app/api/outreach/route.js +13 -73
  346. package/.next/standalone/app/api/queue/route.js +1 -1
  347. package/.next/standalone/app/api/scraper/route.js +217 -36
  348. package/.next/standalone/app/api/social/crm/route.js +2 -1
  349. package/.next/standalone/app/components/AppHeader.js +41 -21
  350. package/.next/standalone/app/components/AppTabs.js +12 -8
  351. package/.next/standalone/app/components/AutoConnect.js +286 -0
  352. package/.next/standalone/app/components/AutoScanButton.js +2 -2
  353. package/.next/standalone/app/components/Avatar.js +1 -1
  354. package/.next/standalone/app/components/ChainView.js +258 -113
  355. package/.next/standalone/app/components/CirclePanel.js +16 -16
  356. package/.next/standalone/app/components/ClusterSpinner.js +64 -0
  357. package/.next/standalone/app/components/CompanyScores.js +20 -20
  358. package/.next/standalone/app/components/EmptyState.js +39 -18
  359. package/.next/standalone/app/components/FieldStep.js +15 -13
  360. package/.next/standalone/app/components/FilterPanel.js +25 -18
  361. package/.next/standalone/app/components/ForceGraph.js +49 -14
  362. package/.next/standalone/app/components/GalaxyLab.js +33 -33
  363. package/.next/standalone/app/components/GridView.js +18 -18
  364. package/.next/standalone/app/components/LegacyScoresCard.js +10 -11
  365. package/.next/standalone/app/components/LinkedInLimits.js +57 -27
  366. package/.next/standalone/app/components/LiquidGlass.js +99 -0
  367. package/.next/standalone/app/components/ListView.js +20 -20
  368. package/.next/standalone/app/components/MapControls.js +5 -5
  369. package/.next/standalone/app/components/MappingProgress.js +16 -16
  370. package/.next/standalone/app/components/NoteDetail.js +13 -13
  371. package/.next/standalone/app/components/OnboardingGate.js +4 -4
  372. package/.next/standalone/app/components/OutlinkQuest.js +56 -35
  373. package/.next/standalone/app/components/PathsAnalyzer.js +37 -36
  374. package/.next/standalone/app/components/PeopleMap.js +21 -21
  375. package/.next/standalone/app/components/RingsView.js +11 -11
  376. package/.next/standalone/app/components/ScanRadar.js +84 -39
  377. package/.next/standalone/app/components/ScanStatusBar.js +40 -21
  378. package/.next/standalone/app/components/ScanTrail.js +21 -8
  379. package/.next/standalone/app/components/SeparationView.js +172 -124
  380. package/.next/standalone/app/components/Sidebar.js +308 -199
  381. package/.next/standalone/app/components/StaleServerBanner.js +4 -4
  382. package/.next/standalone/app/components/TheirCircle.js +26 -26
  383. package/.next/standalone/app/components/ThemeDefs.js +42 -0
  384. package/.next/standalone/app/components/ThemeLoader.js +20 -1
  385. package/.next/standalone/app/components/UpdatePanel.js +22 -22
  386. package/.next/standalone/app/components/UserProvider.js +22 -15
  387. package/.next/standalone/app/components/insights/Boards.js +275 -0
  388. package/.next/standalone/app/components/insights/PeopleView.js +266 -0
  389. package/.next/standalone/app/components/insights/Rail.js +156 -0
  390. package/.next/standalone/app/components/insights/Report.js +382 -0
  391. package/.next/standalone/app/components/insights/parts.js +239 -0
  392. package/.next/standalone/app/components/settings/AppearanceSection.js +47 -24
  393. package/.next/standalone/app/components/settings/DataSection.js +276 -109
  394. package/.next/standalone/app/components/settings/NetworkHealthSection.js +13 -13
  395. package/.next/standalone/app/components/settings/SectorPicker.js +12 -12
  396. package/.next/standalone/app/components/settings/SectorSection.js +13 -14
  397. package/.next/standalone/app/components/settings/TierSection.js +9 -9
  398. package/.next/standalone/app/components/settings/TitleSection.js +11 -11
  399. package/.next/standalone/app/components/settings/UsageSection.js +360 -0
  400. package/.next/standalone/app/components/ui.js +8 -8
  401. package/.next/standalone/app/globals.css +161 -5
  402. package/.next/standalone/app/import/page.js +94 -38
  403. package/.next/standalone/app/insights/page.js +220 -0
  404. package/.next/standalone/app/launch/page.js +5 -5
  405. package/.next/standalone/app/layout.js +6 -2
  406. package/.next/standalone/app/page.js +53 -53
  407. package/.next/standalone/app/paths/page.js +63 -63
  408. package/.next/standalone/app/profile/page.js +58 -58
  409. package/.next/standalone/app/queue/page.js +84 -72
  410. package/.next/standalone/app/scores/page.js +2 -2
  411. package/.next/standalone/app/settings/page.js +16 -13
  412. package/.next/standalone/app/setup/page.js +236 -133
  413. package/.next/standalone/app/social/Crm.js +63 -62
  414. package/.next/standalone/app/social/SocialHub.js +22 -22
  415. package/.next/standalone/app/social/Thread.js +7 -7
  416. package/.next/standalone/app/social/page.js +2 -2
  417. package/.next/standalone/lib/auto-connect.js +145 -0
  418. package/.next/standalone/lib/backups.js +458 -0
  419. package/.next/standalone/lib/chain-layout.js +32 -0
  420. package/.next/standalone/lib/companies.js +1 -1
  421. package/.next/standalone/lib/csv-store.js +131 -0
  422. package/.next/standalone/lib/csv.js +137 -39
  423. package/.next/standalone/lib/data-folder.js +19 -3
  424. package/.next/standalone/lib/data-import.js +5 -2
  425. package/.next/standalone/lib/db-client.js +78 -20
  426. package/.next/standalone/lib/demo.js +5 -4
  427. package/.next/standalone/lib/galaxy-export.js +9 -2
  428. package/.next/standalone/lib/galaxy-lab.js +19 -5
  429. package/.next/standalone/lib/galaxy-layouts.js +43 -0
  430. package/.next/standalone/lib/gate.js +10 -4
  431. package/.next/standalone/lib/in-progress.js +46 -0
  432. package/.next/standalone/lib/ingest.js +1 -1
  433. package/.next/standalone/lib/insights-board.js +613 -0
  434. package/.next/standalone/lib/linkedin-limits.js +240 -14
  435. package/.next/standalone/lib/liquid-glass.js +59 -0
  436. package/.next/standalone/lib/notifications.js +13 -0
  437. package/.next/standalone/lib/requests-client.js +10 -0
  438. package/.next/standalone/lib/requests.js +124 -0
  439. package/.next/standalone/lib/scan-pace.js +11 -0
  440. package/.next/standalone/lib/scan-progress.js +20 -0
  441. package/.next/standalone/lib/scan-risk.js +44 -0
  442. package/.next/standalone/lib/scan-state.js +1 -0
  443. package/.next/standalone/lib/scanner-setup.js +97 -15
  444. package/.next/standalone/lib/scraper-client.js +35 -8
  445. package/.next/standalone/lib/search-risk.js +7 -3
  446. package/.next/standalone/lib/settings-client.js +5 -3
  447. package/.next/standalone/lib/settings.js +13 -0
  448. package/.next/standalone/lib/social-store.js +3 -2
  449. package/.next/standalone/lib/synced-setting.js +46 -0
  450. package/.next/standalone/lib/theme-store.js +42 -10
  451. package/.next/standalone/lib/themes.js +111 -21
  452. package/.next/standalone/lib/usage.js +200 -0
  453. package/.next/standalone/package-lock.json +2 -2
  454. package/.next/standalone/package.json +1 -1
  455. package/.next/standalone/scripts/scrape.py +595 -11
  456. package/.next/static/chunks/02wnf8dkxegxg.js +34 -0
  457. package/.next/static/chunks/03-_esd2x_yk6.js +1 -0
  458. package/.next/static/chunks/03-demj2iy-0p.js +44 -0
  459. package/.next/static/chunks/0838_s6w-i_ik.js +1 -0
  460. package/.next/static/chunks/0_1r-3csplxnj.js +1 -0
  461. package/.next/static/chunks/0ka4prpk3w9wn.js +34 -0
  462. package/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
  463. package/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
  464. package/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
  465. package/.next/static/chunks/112mv-com-mqa.js +21 -0
  466. package/.next/static/chunks/1bkt_hhjzvbh8.js +1 -0
  467. package/.next/static/chunks/1cmphb3kh2ers.css +3 -0
  468. package/.next/static/chunks/1d8yv3k_atka7.js +1 -0
  469. package/.next/static/chunks/{0ws7zy0w57ufi.js β†’ 1eyajb9ntzlrl.js} +1 -1
  470. package/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
  471. package/.next/static/chunks/23hc51oa4vkhc.js +5 -0
  472. package/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
  473. package/.next/static/chunks/2q9i7pcxcnph1.js +7 -0
  474. package/.next/static/chunks/2w-y83mjlpnse.js +1 -0
  475. package/.next/static/chunks/2ws1xf293j-tm.js +5 -0
  476. package/.next/static/chunks/2z1-q0_vunbql.js +2 -0
  477. package/.next/static/chunks/34g73qhayuevu.js +1 -0
  478. package/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
  479. package/.next/static/chunks/3opgg1efrx8q6.js +1 -0
  480. package/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
  481. package/.next/static/chunks/3y40z6of3r9py.js +1 -0
  482. package/.next/static/chunks/403dpflln8ah5.js +1 -0
  483. package/.next/static/chunks/43pg2sursiypz.js +1 -0
  484. package/CHANGELOG.md +203 -0
  485. package/README.md +96 -50
  486. package/SECURITY.md +25 -11
  487. package/lib/auto-connect.js +145 -0
  488. package/lib/backups.js +458 -0
  489. package/lib/chain-layout.js +32 -0
  490. package/lib/companies.js +1 -1
  491. package/lib/csv-store.js +131 -0
  492. package/lib/csv.js +137 -39
  493. package/lib/data-folder.js +19 -3
  494. package/lib/data-import.js +5 -2
  495. package/lib/db-client.js +78 -20
  496. package/lib/demo.js +5 -4
  497. package/lib/galaxy-export.js +9 -2
  498. package/lib/galaxy-lab.js +19 -5
  499. package/lib/galaxy-layouts.js +43 -0
  500. package/lib/gate.js +10 -4
  501. package/lib/in-progress.js +46 -0
  502. package/lib/ingest.js +1 -1
  503. package/lib/insights-board.js +613 -0
  504. package/lib/linkedin-limits.js +240 -14
  505. package/lib/liquid-glass.js +59 -0
  506. package/lib/notifications.js +13 -0
  507. package/lib/requests-client.js +10 -0
  508. package/lib/requests.js +124 -0
  509. package/lib/scan-pace.js +11 -0
  510. package/lib/scan-progress.js +20 -0
  511. package/lib/scan-risk.js +44 -0
  512. package/lib/scan-state.js +1 -0
  513. package/lib/scanner-setup.js +97 -15
  514. package/lib/scraper-client.js +35 -8
  515. package/lib/search-risk.js +7 -3
  516. package/lib/settings-client.js +5 -3
  517. package/lib/settings.js +13 -0
  518. package/lib/social-store.js +3 -2
  519. package/lib/synced-setting.js +46 -0
  520. package/lib/theme-store.js +42 -10
  521. package/lib/themes.js +111 -21
  522. package/lib/usage.js +200 -0
  523. package/package.json +1 -1
  524. package/scripts/scrape.py +595 -11
  525. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-rnla2._.js +0 -3
  526. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13dx4sd._.js +0 -8
  527. package/.next/standalone/.next/server/chunks/[root-of-the-server]__14ou7j5._.js +0 -3
  528. package/.next/standalone/.next/server/chunks/[root-of-the-server]__16iu0hv._.js +0 -3
  529. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +0 -3
  530. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rphsdk._.js +0 -3
  531. package/.next/standalone/.next/server/chunks/_02twlca._.js +0 -10
  532. package/.next/standalone/.next/server/chunks/lib_0851sk0._.js +0 -8
  533. package/.next/standalone/.next/server/chunks/lib_1q7p2ro._.js +0 -8
  534. package/.next/standalone/.next/server/chunks/lib_1r6l86l._.js +0 -8
  535. package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +0 -174
  536. package/.next/standalone/.next/server/chunks/lib_rpc_04s8mzr.js +0 -3
  537. package/.next/standalone/.next/server/chunks/lib_rpc_053z7as.js +0 -3
  538. package/.next/standalone/.next/server/chunks/lib_rpc_0b_-2te.js +0 -3
  539. package/.next/standalone/.next/server/chunks/lib_rpc_0dhbxdm.js +0 -3
  540. package/.next/standalone/.next/server/chunks/lib_rpc_0dxlk31.js +0 -3
  541. package/.next/standalone/.next/server/chunks/lib_rpc_0f8b-qc.js +0 -3
  542. package/.next/standalone/.next/server/chunks/lib_rpc_0pzie7_.js +0 -3
  543. package/.next/standalone/.next/server/chunks/lib_rpc_0r76fq_.js +0 -3
  544. package/.next/standalone/.next/server/chunks/lib_rpc_0ut7pjp.js +0 -3
  545. package/.next/standalone/.next/server/chunks/lib_rpc_15zyqaz.js +0 -3
  546. package/.next/standalone/.next/server/chunks/lib_rpc_18zpjtq.js +0 -3
  547. package/.next/standalone/.next/server/chunks/lib_rpc_1a8xkiz.js +0 -3
  548. package/.next/standalone/.next/server/chunks/lib_rpc_1e_55xo.js +0 -3
  549. package/.next/standalone/.next/server/chunks/lib_rpc_1oxfd1_.js +0 -3
  550. package/.next/standalone/.next/server/chunks/lib_rpc_1s0lod0.js +0 -3
  551. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08oxiqh._.js +0 -3
  552. package/.next/standalone/.next/server/chunks/ssr/_03l7vge._.js +0 -3
  553. package/.next/standalone/.next/server/chunks/ssr/_08g31gm._.js +0 -3
  554. package/.next/standalone/.next/server/chunks/ssr/_0gk_ofx._.js +0 -3
  555. package/.next/standalone/.next/server/chunks/ssr/_0nwsf93._.js +0 -3
  556. package/.next/standalone/.next/server/chunks/ssr/_0vho1lb._.js +0 -3
  557. package/.next/standalone/.next/server/chunks/ssr/_1-658fq._.js +0 -3
  558. package/.next/standalone/.next/server/chunks/ssr/_1bc46kz._.js +0 -3
  559. package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +0 -3
  560. package/.next/standalone/.next/server/chunks/ssr/_2105jz8._.js +0 -3
  561. package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +0 -3
  562. package/.next/standalone/.next/static/chunks/02pq76u7y4v9-.js +0 -22
  563. package/.next/standalone/.next/static/chunks/0cmq0exd4d0h9.js +0 -1
  564. package/.next/standalone/.next/static/chunks/0i02yxppzds1o.js +0 -1
  565. package/.next/standalone/.next/static/chunks/0m_p4k-q2qh--.js +0 -1
  566. package/.next/standalone/.next/static/chunks/0oyslj62jkubd.js +0 -1
  567. package/.next/standalone/.next/static/chunks/0vo-l8hxneba6.css +0 -3
  568. package/.next/standalone/.next/static/chunks/0yh8z2tbrc5i_.js +0 -1
  569. package/.next/standalone/.next/static/chunks/17-rhp8sg4m1b.js +0 -44
  570. package/.next/standalone/.next/static/chunks/172e10mi-tpo_.js +0 -34
  571. package/.next/standalone/.next/static/chunks/1ei5vbe2uw6fl.js +0 -1
  572. package/.next/standalone/.next/static/chunks/1f7_pl_wq7lh3.js +0 -11
  573. package/.next/standalone/.next/static/chunks/1jzbe7zdx9vbj.js +0 -2
  574. package/.next/standalone/.next/static/chunks/1m3017gp790pw.js +0 -45
  575. package/.next/standalone/.next/static/chunks/1t20e8u0st7ep.js +0 -1
  576. package/.next/standalone/.next/static/chunks/2-ch9rm27eril.js +0 -11
  577. package/.next/standalone/.next/static/chunks/2ldv-v3s9yaif.js +0 -1
  578. package/.next/standalone/.next/static/chunks/3bp284gjf7dyq.js +0 -1
  579. package/.next/standalone/.next/static/chunks/3k1f6clbn3gj3.js +0 -7
  580. package/.next/standalone/.next/static/chunks/3l4t8je6iguzc.js +0 -1
  581. package/.next/standalone/.next/static/chunks/3tplzuc9jk-tl.js +0 -1
  582. package/.next/standalone/.next/static/chunks/42m0bqr8pbovz.js +0 -11
  583. package/.next/static/chunks/02pq76u7y4v9-.js +0 -22
  584. package/.next/static/chunks/0cmq0exd4d0h9.js +0 -1
  585. package/.next/static/chunks/0i02yxppzds1o.js +0 -1
  586. package/.next/static/chunks/0m_p4k-q2qh--.js +0 -1
  587. package/.next/static/chunks/0oyslj62jkubd.js +0 -1
  588. package/.next/static/chunks/0vo-l8hxneba6.css +0 -3
  589. package/.next/static/chunks/0yh8z2tbrc5i_.js +0 -1
  590. package/.next/static/chunks/17-rhp8sg4m1b.js +0 -44
  591. package/.next/static/chunks/172e10mi-tpo_.js +0 -34
  592. package/.next/static/chunks/1ei5vbe2uw6fl.js +0 -1
  593. package/.next/static/chunks/1f7_pl_wq7lh3.js +0 -11
  594. package/.next/static/chunks/1jzbe7zdx9vbj.js +0 -2
  595. package/.next/static/chunks/1m3017gp790pw.js +0 -45
  596. package/.next/static/chunks/1t20e8u0st7ep.js +0 -1
  597. package/.next/static/chunks/2-ch9rm27eril.js +0 -11
  598. package/.next/static/chunks/2ldv-v3s9yaif.js +0 -1
  599. package/.next/static/chunks/3bp284gjf7dyq.js +0 -1
  600. package/.next/static/chunks/3k1f6clbn3gj3.js +0 -7
  601. package/.next/static/chunks/3l4t8je6iguzc.js +0 -1
  602. package/.next/static/chunks/3tplzuc9jk-tl.js +0 -1
  603. package/.next/static/chunks/42m0bqr8pbovz.js +0 -11
  604. /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT β†’ 3NCyJyAPDCEYsYTwF1Ieu}/_buildManifest.js +0 -0
  605. /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT β†’ 3NCyJyAPDCEYsYTwF1Ieu}/_clientMiddlewareManifest.js +0 -0
  606. /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT β†’ 3NCyJyAPDCEYsYTwF1Ieu}/_ssgManifest.js +0 -0
  607. /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT β†’ 3NCyJyAPDCEYsYTwF1Ieu}/_buildManifest.js +0 -0
  608. /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT β†’ 3NCyJyAPDCEYsYTwF1Ieu}/_clientMiddlewareManifest.js +0 -0
  609. /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT β†’ 3NCyJyAPDCEYsYTwF1Ieu}/_ssgManifest.js +0 -0
@@ -1,8 +1,9 @@
1
1
  'use client';
2
2
 
3
- import { useState, useEffect, useMemo, useCallback } from 'react';
3
+ import { useState, useEffect, useMemo, useCallback, useSyncExternalStore } from 'react';
4
4
  import Link from 'next/link';
5
- import { beginScrape, scraperStatus, notReadyMessage, resumePoint, scansCircleOf, isCircleScan, busyReason } from '../../lib/scraper-client';
5
+ import { beginScrape, scraperStatus, notReadyMessage, resumePoint, scansCircleOf, isCircleScan, busyReason, watchScanner, scannerNow } from '../../lib/scraper-client';
6
+ import { scanBoxTitle, stoppedLine } from '../../lib/in-progress';
6
7
  import useScanner from './useScanner';
7
8
  import useRequests from './useRequests';
8
9
  import TheirCircle from './TheirCircle';
@@ -17,6 +18,7 @@ import Avatar from './Avatar';
17
18
  import NoteDetail from './NoteDetail';
18
19
  import CirclePanel from './CirclePanel';
19
20
  import { localPhoto } from '../../lib/photos';
21
+ import ConnectChoice, { secondaryLook } from './AutoConnect';
20
22
 
21
23
  export default function Sidebar({ selected, stats, tierColors, connections, degree2 = [], mode, collapsed, filter, pending = [], onToggle, onSelect, onSwitchMode, onFocusNode, onMarkSent, onUndoPending, scanNotes, csvSource = null, onOpenCircle, onShowInSeparation, note = null, onCloseNote, circle = null }) {
22
24
  const isDegreesMode = mode === 'degrees';
@@ -54,6 +56,12 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
54
56
  // Separation, the circle and the Outlink queue at once (lib/requests-client.js).
55
57
  const requests = useRequests();
56
58
  const isRequested = useCallback((row) => hasRequest(row, requests), [requests]);
59
+ // Where Resume would carry on with the person open, asked once for the whole
60
+ // card: the line by their name and the scan box below both show it. Only for
61
+ // whoever gets a scan box (the same test as below). Above the early returns,
62
+ // so the hook order never changes.
63
+ const scansHere = Boolean(selected) && canScan && (selected.degree === 1 || selected.outreach_status === 'accepted');
64
+ const { resume, scanning: scanningThem } = useResume(scansHere ? selected : null);
57
65
 
58
66
  // A notification someone clicked takes the panel over until they go back (app/components/NoteDetail.js).
59
67
  if (note) {
@@ -82,12 +90,12 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
82
90
  onClick={() => onSelect && onSelect(null)}
83
91
  style={{
84
92
  display: 'flex', alignItems: 'center', gap: 6, background: 'none', border: 'none',
85
- color: '#888', fontSize: 12, cursor: 'pointer', padding: '0 0 10px', fontWeight: 600,
93
+ color: 'var(--sd-fg-3, #888)', fontSize: 12, cursor: 'pointer', padding: '0 0 10px', fontWeight: 600,
86
94
  }}
87
95
  >
88
96
  <span style={{ fontSize: 16 }}>&larr;</span> Back to list
89
97
  </button>
90
- <div style={{ fontSize: 10, color: '#888', marginBottom: 8, letterSpacing: 1, textTransform: 'uppercase' }}>
98
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 8, letterSpacing: 1, textTransform: 'uppercase' }}>
91
99
  {selected.degree === 2 ? 'Degree 2 Connection' : 'Degree 1 Connection'}
92
100
  </div>
93
101
  <div style={{ display: 'flex', gap: 6, marginBottom: 8, flexWrap: 'wrap' }}>
@@ -108,7 +116,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
108
116
  fontSize: 11.5, color: '#8fb8d6', lineHeight: 1.5,
109
117
  }}>
110
118
  {selected.degree === 1 ? 'You met them through ' : 'Reachable through '}
111
- <b style={{ color: '#cfe6f7' }}>{selected.unlocked_from_name}</b>
119
+ <b style={{ color: 'var(--sd-fg-1, #cfe6f7)' }}>{selected.unlocked_from_name}</b>
112
120
  </div>
113
121
  )}
114
122
 
@@ -136,13 +144,13 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
136
144
  background: tierColors[selected.tier] || '#555',
137
145
  display: localPhoto(selected.profile_image_url) ? 'none' : 'flex',
138
146
  alignItems: 'center', justifyContent: 'center',
139
- fontSize: 20, fontWeight: 700, color: selected.tier === 'S' ? '#000' : '#fff',
147
+ fontSize: 20, fontWeight: 700, color: selected.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
140
148
  }}>
141
149
  {selected.name?.charAt(0)}
142
150
  </div>
143
151
  <div style={{ minWidth: 0 }}>
144
152
  <h2 style={{ fontSize: 18, fontWeight: 700, margin: 0 }}>{selected.name}</h2>
145
- <p style={{ color: '#aaa', fontSize: 11, margin: '3px 0 0', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{selected.headline?.substring(0, 60)}</p>
153
+ <p style={{ color: 'var(--sd-fg-3, #aaa)', fontSize: 11, margin: '3px 0 0', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{selected.headline?.substring(0, 60)}</p>
146
154
  {selected.profile_url && (
147
155
  <a href={selected.profile_url} target="_blank" rel="noopener noreferrer" style={{ fontSize: 10, color: '#0077B5', textDecoration: 'none', fontWeight: 600 }}>
148
156
  View on LinkedIn
@@ -151,6 +159,9 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
151
159
  </div>
152
160
  </div>
153
161
 
162
+ {/* Their scan stopped partway: said by their name, where it's seen without scrolling. */}
163
+ {scansHere && resume && <StoppedPartway resume={resume} scanning={scanningThem} />}
164
+
154
165
  {/* Their circle, out to six degrees: who they know, who you added from
155
166
  it, and who those people know (TheirCircle.js). Your connections only:
156
167
  a 2nd-degree person's circle isn't yours to scan until they accept. */}
@@ -166,22 +177,22 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
166
177
  if (!i) return null;
167
178
  const first = selected.name?.split(' ')[0] || 'them';
168
179
  const twin = i.twin && connections.find((c) => c.id === i.twin.id);
169
- const row = { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, padding: '7px 0', borderTop: '1px solid rgba(255,255,255,0.05)' };
170
- const label = { fontSize: 10.5, color: '#8b9a9a', minWidth: 92 };
171
- const act = { background: 'none', border: 'none', padding: 0, color: '#3498DB', cursor: 'pointer', fontSize: 11.5, whiteSpace: 'nowrap' };
180
+ const row = { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, padding: '7px 0', borderTop: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.05)' };
181
+ const label = { fontSize: 10.5, color: 'var(--sd-fg-3, #8b9a9a)', minWidth: 92 };
182
+ const act = { background: 'none', border: 'none', padding: 0, color: 'var(--sd-blue, #3498DB)', cursor: 'pointer', fontSize: 11.5, whiteSpace: 'nowrap' };
172
183
  const scanned = i.bars == null ? 'Not scanned yet' : i.bars === 5 ? 'Their whole list' : `About ${i.bars * 20}% of their list`;
173
184
  return (
174
185
  <div style={{ border: '1px solid rgba(52,152,219,0.25)', borderRadius: 8, marginBottom: 16, background: 'rgba(52,152,219,0.04)' }}>
175
186
  <button onClick={() => setShowInsights((v) => !v)} aria-expanded={showInsights}
176
- style={{ width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '9px 12px', background: 'none', border: 'none', cursor: 'pointer', color: '#cfe6f7' }}>
187
+ style={{ width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '9px 12px', background: 'none', border: 'none', cursor: 'pointer', color: 'var(--sd-fg-1, #cfe6f7)' }}>
177
188
  <span style={{ fontSize: 11, fontWeight: 700, letterSpacing: 1 }}>INSIGHTS</span>
178
- <span style={{ fontSize: 11, color: '#8b9a9a' }}>
189
+ <span style={{ fontSize: 11, color: 'var(--sd-fg-3, #8b9a9a)' }}>
179
190
  {!showInsights && i.circle > 0 && `${i.circle.toLocaleString()} in their circle${i.only ? ` Β· ${i.only.toLocaleString()} only through ${first}` : ''} `}
180
191
  {showInsights ? 'β–²' : 'β–Ό'}
181
192
  </span>
182
193
  </button>
183
194
  {showInsights && (
184
- <div style={{ padding: '0 12px 8px', fontSize: 12, color: '#ccc' }}>
195
+ <div style={{ padding: '0 12px 8px', fontSize: 12, color: 'var(--sd-fg-2, #ccc)' }}>
185
196
  <div style={row}>
186
197
  <span style={label}>Their circle</span>
187
198
  <span style={{ flex: 1 }}>{i.circle ? `${i.circle.toLocaleString()} people` : 'None scanned yet'}</span>
@@ -190,7 +201,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
190
201
  <div style={row}>
191
202
  <span style={label}>Only through {first}</span>
192
203
  <span style={{ flex: 1 }}>
193
- {i.circle ? <><b style={{ color: '#00ff88' }}>{i.only.toLocaleString()}</b> ({Math.round(i.onlyShare * 100)}%): none of your other connections reach them</> : 'β€”'}
204
+ {i.circle ? <><b style={{ color: 'var(--sd-green, #00ff88)' }}>{i.only.toLocaleString()}</b> ({Math.round(i.onlyShare * 100)}%): none of your other connections reach them</> : '-'}
194
205
  </span>
195
206
  {i.only > 0 && onShowInSeparation && (
196
207
  <button style={act} onClick={() => onShowInSeparation({ query: selected.name, rarity: 'only' })}>Show them β†’</button>
@@ -199,18 +210,18 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
199
210
  <div style={row}>
200
211
  <span style={label}>Closest overlap</span>
201
212
  <span style={{ flex: 1 }}>
202
- {twin ? <>Opens the same doors as <b style={{ color: '#fff' }}>{twin.name}</b> ({Math.round(i.twin.share * 100)}%, {i.twin.shared.toLocaleString()} people)</> : 'No one opens the same doors'}
213
+ {twin ? <>Opens the same doors as <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{twin.name}</b> ({Math.round(i.twin.share * 100)}%, {i.twin.shared.toLocaleString()} people)</> : 'No one opens the same doors'}
203
214
  </span>
204
215
  {twin && <button style={act} onClick={() => onSelect?.(twin)}>Open β†’</button>}
205
216
  </div>
206
217
  <div style={row}>
207
218
  <span style={label}>Tier mix</span>
208
- <span style={{ flex: 1, display: 'flex', height: 8, borderRadius: 4, overflow: 'hidden', background: 'rgba(255,255,255,0.05)', alignSelf: 'center' }}>
219
+ <span style={{ flex: 1, display: 'flex', height: 8, borderRadius: 4, overflow: 'hidden', background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)', alignSelf: 'center' }}>
209
220
  {i.circle > 0 && ['S', 'A', 'B', 'C', 'D'].map((t) => i.mix[t] > 0 && (
210
221
  <span key={t} title={`${t}: ${i.mix[t]}`} style={{ width: `${(100 * i.mix[t]) / i.circle}%`, background: tierColors[t] }} />
211
222
  ))}
212
223
  </span>
213
- <span style={{ fontSize: 10.5, color: '#8b9a9a' }}>{i.circle ? `${i.mix.S} S Β· ${i.mix.A} A` : ''}</span>
224
+ <span style={{ fontSize: 10.5, color: 'var(--sd-fg-3, #8b9a9a)' }}>{i.circle ? `${i.mix.S} S Β· ${i.mix.A} A` : ''}</span>
214
225
  {i.mix.S > 0 && onShowInSeparation && (
215
226
  <button style={act} onClick={() => onShowInSeparation({ query: selected.name, tier: 'S' })}>S only β†’</button>
216
227
  )}
@@ -224,9 +235,15 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
224
235
  <div style={row}>
225
236
  <span style={label}>Scanned</span>
226
237
  <span style={{ flex: 1 }}>{scanned}</span>
227
- {i.bars !== 5 && canScan && (
238
+ {/* Stopped partway: carry on from that page, the line by their name's own
239
+ Resume. The Scan page's Scan one circle reads the list again from page 1,
240
+ which spends the searches already spent; that stays for anyone else. */}
241
+ {i.bars !== 5 && canScan && (scansHere && resume ? (
242
+ <button type="button" style={act} title={`Resume from page ${resume.nextPage}`}
243
+ onClick={() => resumeInScanBox(scanningThem)}>Resume β†’</button>
244
+ ) : (resume === null || i.bars == null || !scansHere) && (
228
245
  <a href={`/setup?scan=${encodeURIComponent(selected.id)}`} style={act}>{i.bars == null ? 'Scan β†’' : 'Finish β†’'}</a>
229
- )}
246
+ ))}
230
247
  </div>
231
248
  {(() => {
232
249
  const since = selected.connected_date ? new Date(selected.connected_date) : null;
@@ -257,11 +274,11 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
257
274
  background: 'rgba(0,255,136,0.08)', border: '1px solid rgba(0,255,136,0.3)',
258
275
  borderRadius: 8, padding: 12, marginBottom: 16,
259
276
  }}>
260
- <div style={{ fontSize: 10, color: '#00ff88', fontWeight: 700, marginBottom: 4, letterSpacing: 1 }}>CATALYST NODE</div>
261
- <div style={{ fontSize: 12, color: '#ccc' }}>
277
+ <div style={{ fontSize: 10, color: 'var(--sd-green, #00ff88)', fontWeight: 700, marginBottom: 4, letterSpacing: 1 }}>CATALYST NODE</div>
278
+ <div style={{ fontSize: 12, color: 'var(--sd-fg-2, #ccc)' }}>
262
279
  This person&apos;s network power exceeds their own tier. They connect to{' '}
263
- <strong style={{ color: '#00ff88' }}>{selected.catalyst_score} S+A tier</strong>{' '}
264
- people β€” making them a high-value stepping stone to reach elite connections.
280
+ <strong style={{ color: 'var(--sd-green, #00ff88)' }}>{selected.catalyst_score} S+A tier</strong>{' '}
281
+ people, making them a high-value stepping stone to reach elite connections.
265
282
  </div>
266
283
  </div>
267
284
  )}
@@ -271,43 +288,43 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
271
288
  )}
272
289
 
273
290
  {/* === SCORE CARD === */}
274
- <div style={{ background: 'rgba(255,255,255,0.04)', borderRadius: 8, padding: 12, marginBottom: 16 }}>
291
+ <div style={{ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.04)', borderRadius: 8, padding: 12, marginBottom: 16 }}>
275
292
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 8 }}>
276
- <span style={{ fontSize: 11, color: '#888', fontWeight: 600, letterSpacing: 1, textTransform: 'uppercase' }}>Score</span>
293
+ <span style={{ fontSize: 11, color: 'var(--sd-fg-3, #888)', fontWeight: 600, letterSpacing: 1, textTransform: 'uppercase' }}>Score</span>
277
294
  <span style={{ fontSize: 28, fontWeight: 800, color: tierColors[selected.tier] || '#fff' }}>
278
295
  {parseFloat(selected.power_score).toFixed(1)}
279
296
  </span>
280
297
  </div>
281
298
  {/* Why: title Γ— company weight + bonuses (lib/scoring.js) */}
282
299
  {selected.score_why && (
283
- <div style={{ fontSize: 11, color: '#aab7b7', lineHeight: 1.5, marginBottom: 10 }}>{selected.score_why}</div>
300
+ <div style={{ fontSize: 11, color: 'var(--sd-fg-2, #aab7b7)', lineHeight: 1.5, marginBottom: 10 }}>{selected.score_why}</div>
284
301
  )}
285
302
  {/* Job Power bar */}
286
303
  <div style={{ marginBottom: 6 }}>
287
- <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: '#888', marginBottom: 2 }}>
304
+ <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 2 }}>
288
305
  <span>Title</span><span>{selected.seniority_score || 0}/10</span>
289
306
  </div>
290
- <div style={{ height: 4, background: 'rgba(255,255,255,0.08)', borderRadius: 2 }}>
307
+ <div style={{ height: 4, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.08)', borderRadius: 2 }}>
291
308
  <div style={{ height: '100%', width: `${(selected.seniority_score || 0) * 10}%`, background: tierColors[selected.tier] || '#FFD700', borderRadius: 2 }} />
292
309
  </div>
293
310
  </div>
294
311
  {/* Status Power bar */}
295
312
  <div style={{ marginBottom: selected.circle_power > 0 ? 6 : 0 }}>
296
- <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: '#888', marginBottom: 2 }}>
313
+ <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 2 }}>
297
314
  <span>Company</span><span>{selected.company_prestige_score || 0}/10</span>
298
315
  </div>
299
- <div style={{ height: 4, background: 'rgba(255,255,255,0.08)', borderRadius: 2 }}>
316
+ <div style={{ height: 4, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.08)', borderRadius: 2 }}>
300
317
  <div style={{ height: '100%', width: `${(selected.company_prestige_score || 0) * 10}%`, background: '#3498DB', borderRadius: 2 }} />
301
318
  </div>
302
319
  </div>
303
320
  {/* Circle Power bar β€” only shows for bridges with clusters */}
304
321
  {selected.circle_power > 0 && (
305
322
  <div>
306
- <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: '#888', marginBottom: 2 }}>
323
+ <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 2 }}>
307
324
  <span>Circle Power</span>
308
- <span style={{ color: '#FF6B35' }}>{selected.circle_s_count || 0}S Β· {selected.circle_a_count || 0}A</span>
325
+ <span style={{ color: 'var(--sd-orange, #FF6B35)' }}>{selected.circle_s_count || 0}S Β· {selected.circle_a_count || 0}A</span>
309
326
  </div>
310
- <div style={{ height: 4, background: 'rgba(255,255,255,0.08)', borderRadius: 2 }}>
327
+ <div style={{ height: 4, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.08)', borderRadius: 2 }}>
311
328
  <div style={{ height: '100%', width: `${Math.min(parseFloat(selected.circle_power) / 70 * 100, 100)}%`, background: '#FF6B35', borderRadius: 2 }} />
312
329
  </div>
313
330
  </div>
@@ -316,10 +333,10 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
316
333
 
317
334
  {/* === WHY THIS MATTERS === */}
318
335
  <div style={{ marginBottom: 16 }}>
319
- <div style={{ fontSize: 10, fontWeight: 700, color: '#FFD700', letterSpacing: 1, marginBottom: 6, textTransform: 'uppercase' }}>
336
+ <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--sd-gold, #FFD700)', letterSpacing: 1, marginBottom: 6, textTransform: 'uppercase' }}>
320
337
  Why This Matters
321
338
  </div>
322
- <div style={{ display: 'flex', flexDirection: 'column', gap: 4, fontSize: 11, color: '#ccc' }}>
339
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4, fontSize: 11, color: 'var(--sd-fg-2, #ccc)' }}>
323
340
  {generateInsights(selected, userProfile, connections, degree2, routes).map((insight, idx) => (
324
341
  <div key={idx} style={{ display: 'flex', gap: 6, alignItems: 'flex-start' }}>
325
342
  <span style={{ color: insight.color || '#888', fontSize: 13, lineHeight: 1 }}>{insight.icon}</span>
@@ -331,13 +348,13 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
331
348
 
332
349
  {selected.company && (
333
350
  <div style={{ marginBottom: 8 }}>
334
- <div style={{ color: '#666', fontSize: 10 }}>Company</div>
351
+ <div style={{ color: 'var(--sd-fg-4, #666)', fontSize: 10 }}>Company</div>
335
352
  <div style={{ fontWeight: 600, fontSize: 12 }}>{selected.company}</div>
336
353
  </div>
337
354
  )}
338
355
  {selected.role && (
339
356
  <div style={{ marginBottom: 12 }}>
340
- <div style={{ color: '#666', fontSize: 10 }}>Role</div>
357
+ <div style={{ color: 'var(--sd-fg-4, #666)', fontSize: 10 }}>Role</div>
341
358
  <div style={{ fontSize: 12 }}>{selected.role}</div>
342
359
  </div>
343
360
  )}
@@ -349,12 +366,12 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
349
366
  const topPeople = [...bridgeConnections].sort((a, b) => (parseFloat(b.power_score) || 0) - (parseFloat(a.power_score) || 0)).slice(0, 8);
350
367
  return (
351
368
  <div style={{ marginBottom: 16 }}>
352
- <div style={{ fontSize: 10, fontWeight: 700, color: '#FF6B35', letterSpacing: 1, marginBottom: 8, textTransform: 'uppercase' }}>
353
- Cluster Overview β€” {bridgeConnections.length} connections
369
+ <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--sd-orange, #FF6B35)', letterSpacing: 1, marginBottom: 8, textTransform: 'uppercase' }}>
370
+ Cluster Overview Β· {bridgeConnections.length} connections
354
371
  </div>
355
372
  <div style={{ display: 'flex', gap: 6, marginBottom: 8, fontSize: 10 }}>
356
- {sTier.length > 0 && <span style={{ color: '#FFD700', fontWeight: 600 }}>{sTier.length} S-tier</span>}
357
- {aTier.length > 0 && <span style={{ color: '#9B59B6', fontWeight: 600 }}>{aTier.length} A-tier</span>}
373
+ {sTier.length > 0 && <span style={{ color: 'var(--sd-gold, #FFD700)', fontWeight: 600 }}>{sTier.length} S-tier</span>}
374
+ {aTier.length > 0 && <span style={{ color: 'var(--sd-purple, #9B59B6)', fontWeight: 600 }}>{aTier.length} A-tier</span>}
358
375
  </div>
359
376
  {/* Outlink Bridge button */}
360
377
  <a href={`/queue?bridge=${selected.id}&groupBy=bridge`} style={{
@@ -364,7 +381,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
364
381
  }}>
365
382
  Outlink Bridge β†’ Add {bridgeConnections.filter(m => m.tier === 'S' || m.tier === 'A' || m.tier === 'B').length} People
366
383
  </a>
367
- <div style={{ fontSize: 10, color: '#888', marginBottom: 8 }}>Most valuable in this cluster:</div>
384
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 8 }}>Most valuable in this cluster:</div>
368
385
  <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
369
386
  {topPeople.map(m => (
370
387
  <div key={m.id}
@@ -372,10 +389,10 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
372
389
  style={{
373
390
  display: 'flex', alignItems: 'center', gap: 6, padding: '4px 6px',
374
391
  borderRadius: 4, cursor: 'pointer', borderLeft: `2px solid ${tierColors[m.tier] || '#555'}`,
375
- background: 'rgba(255,255,255,0.03)',
392
+ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.03)',
376
393
  }}
377
- onMouseEnter={e => e.currentTarget.style.background = 'rgba(255,255,255,0.08)'}
378
- onMouseLeave={e => e.currentTarget.style.background = 'rgba(255,255,255,0.03)'}
394
+ onMouseEnter={e => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.08)'}
395
+ onMouseLeave={e => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.03)'}
379
396
  >
380
397
  {localPhoto(m.profile_image_url) ? (
381
398
  <img src={localPhoto(m.profile_image_url)} alt="" style={{
@@ -385,12 +402,12 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
385
402
  ) : null}
386
403
  <div style={{
387
404
  width: 22, height: 22, borderRadius: '50%', flexShrink: 0, fontSize: 9, fontWeight: 700,
388
- background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : '#fff',
405
+ background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
389
406
  display: localPhoto(m.profile_image_url) ? 'none' : 'flex', alignItems: 'center', justifyContent: 'center',
390
407
  }}>{m.name?.charAt(0)}</div>
391
408
  <div style={{ flex: 1, minWidth: 0 }}>
392
409
  <div style={{ fontSize: 10, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.name}</div>
393
- <div style={{ fontSize: 8, color: '#666', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.headline?.substring(0, 40)}</div>
410
+ <div style={{ fontSize: 8, color: 'var(--sd-fg-4, #666)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.headline?.substring(0, 40)}</div>
394
411
  </div>
395
412
  <span style={{ fontSize: 9, color: tierColors[m.tier], fontWeight: 600, flexShrink: 0 }}>{parseFloat(m.power_score).toFixed(1)}</span>
396
413
  </div>
@@ -402,7 +419,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
402
419
 
403
420
  {isBridge && bridgeConnections.length > 0 && (
404
421
  <div style={{ marginTop: 16 }}>
405
- <div style={{ fontSize: 12, fontWeight: 600, color: '#FF6B35', marginBottom: 8 }}>
422
+ <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--sd-orange, #FF6B35)', marginBottom: 8 }}>
406
423
  Gateway to {bridgeConnections.length} degree-2 connections:
407
424
  </div>
408
425
  {bridgeConnections.sort((a, b) => (parseFloat(b.power_score) || 0) - (parseFloat(a.power_score) || 0)).slice(0, 10).map(c => (
@@ -411,8 +428,8 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
411
428
  borderLeft: '3px solid #FF6B35', marginBottom: 4, fontSize: 12,
412
429
  }}>
413
430
  <div style={{ fontWeight: 600 }}>{c.name}</div>
414
- <div style={{ color: '#888', fontSize: 11 }}>{c.role}{c.company ? ` @ ${c.company}` : ''}</div>
415
- <div style={{ color: '#FF6B35', fontSize: 10 }}>Score: {parseFloat(c.power_score).toFixed(1)}</div>
431
+ <div style={{ color: 'var(--sd-fg-3, #888)', fontSize: 11 }}>{c.role}{c.company ? ` @ ${c.company}` : ''}</div>
432
+ <div style={{ color: 'var(--sd-orange, #FF6B35)', fontSize: 10 }}>Score: {parseFloat(c.power_score).toFixed(1)}</div>
416
433
  </div>
417
434
  ))}
418
435
  </div>
@@ -441,20 +458,20 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
441
458
  background: 'rgba(255,215,0,0.06)', border: `1px ${asked ? 'dashed' : 'solid'} rgba(255,215,0,${asked ? 0.45 : 0.25})`,
442
459
  borderRadius: 10, padding: 16, marginTop: 16, textAlign: 'center',
443
460
  }}>
444
- <div style={{ fontSize: 10, color: '#FFD700', fontWeight: 700, letterSpacing: 1, marginBottom: 6 }}>
461
+ <div style={{ fontSize: 10, color: 'var(--sd-gold, #FFD700)', fontWeight: 700, letterSpacing: 1, marginBottom: 6 }}>
445
462
  {asked ? 'REQUEST SENT' : 'LOCKED PATH'}
446
463
  </div>
447
- <div style={{ fontSize: 13, color: '#ccc', marginBottom: 12 }}>
464
+ <div style={{ fontSize: 13, color: 'var(--sd-fg-2, #ccc)', marginBottom: 12 }}>
448
465
  {asked
449
466
  ? `Waiting for ${selected.name} to accept. The next scan of your own connections notices when they do.`
450
467
  : `Connect with ${selected.name} to unlock their network and extend your six degrees.`
451
468
  }
452
469
  </div>
453
470
  <div style={{
454
- width: '100%', height: 60, background: 'rgba(255,255,255,0.03)',
455
- borderRadius: 8, border: '1px dashed rgba(255,255,255,0.1)',
471
+ width: '100%', height: 60, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.03)',
472
+ borderRadius: 8, border: '1px dashed rgba(var(--sd-ink, 255, 255, 255), 0.1)',
456
473
  display: 'flex', alignItems: 'center', justifyContent: 'center',
457
- fontSize: 11, color: '#444', marginBottom: 12,
474
+ fontSize: 11, color: 'var(--sd-fg-5, #444)', marginBottom: 12,
458
475
  }}>
459
476
  {asked ? '[ Cluster Pending... ]' : '[ Hidden Network ]'}
460
477
  </div>
@@ -462,27 +479,33 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
462
479
  <button
463
480
  onClick={() => { undoRequest(selected).catch(() => {}); }}
464
481
  style={{
465
- background: 'none', border: 'none', color: '#888', fontSize: 11, fontWeight: 600, cursor: 'pointer',
482
+ background: 'none', border: 'none', color: 'var(--sd-fg-3, #888)', fontSize: 11, fontWeight: 600, cursor: 'pointer',
466
483
  }}
467
484
  >
468
485
  Didn&apos;t send it? Undo
469
486
  </button>
470
487
  ) : (
471
- <a href={selected.profile_url} target="_blank" rel="noopener noreferrer"
472
- style={{
473
- display: 'block', padding: '10px 16px',
474
- background: 'linear-gradient(135deg, #FFD700, #FF6B35)',
475
- color: '#000', borderRadius: 8, textDecoration: 'none',
476
- fontWeight: 700, fontSize: 13,
477
- }}
478
- onClick={() => {
479
- // Opens their profile to connect, and marks the request
480
- // sent, through the bridge whose circle you found them in.
481
- markRequested(selected, { bridgeId: selected.source_connection_id }).catch(() => {});
482
- }}
483
- >
484
- Connect to Unlock Path
485
- </a>
488
+ // Auto first, the better pick; Connect beside it as an outline
489
+ // (AutoConnect.js; Blake, 2026-10-03). Your own network only.
490
+ <ConnectChoice person={selected} canAuto={canScan} size="card" connect={(second) => (
491
+ <a href={selected.profile_url} target="_blank" rel="noopener noreferrer"
492
+ title={second ? 'Opens their LinkedIn profile, to connect yourself' : undefined}
493
+ style={second ? { ...secondaryLook('card'), flex: 1 } : {
494
+ display: 'block', padding: '10px 16px',
495
+ background: 'linear-gradient(135deg, #FFD700, #FF6B35)',
496
+ color: '#000', borderRadius: 8, textDecoration: 'none',
497
+ fontWeight: 700, fontSize: 13,
498
+ }}
499
+ onClick={() => {
500
+ // Opens their profile to connect, and marks the request
501
+ // sent, through the bridge whose circle you found them in.
502
+ markRequested(selected, { bridgeId: selected.source_connection_id }).catch(() => {});
503
+ }}
504
+ >
505
+ {/* Beside Auto there's room for one word (a 320 px panel). */}
506
+ {second ? 'Connect' : 'Connect to Unlock Path'}
507
+ </a>
508
+ )} />
486
509
  )}
487
510
  </div>
488
511
  );
@@ -491,7 +514,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
491
514
  {/* Create Cluster β€” for D1 connections OR accepted D2 (promoted, ready to bridge for D3) */}
492
515
  {(selected.degree === 1 || selected.outreach_status === 'accepted') && (
493
516
  canScan
494
- ? <CreateClusterCard key={selected.id} selected={selected} degree2={degree2} />
517
+ ? <CreateClusterCard key={selected.id} selected={selected} degree2={degree2} resume={resume} />
495
518
  : <ScansNeedYourNetwork csvSource={csvSource} style={{ marginTop: 16 }} />
496
519
  )}
497
520
 
@@ -525,13 +548,13 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
525
548
  onClick={onToggle}
526
549
  style={{
527
550
  display: 'flex', alignItems: 'center', gap: 6, background: 'none', border: 'none',
528
- color: '#888', fontSize: 12, cursor: 'pointer', padding: '0 0 10px', fontWeight: 600,
551
+ color: 'var(--sd-fg-3, #888)', fontSize: 12, cursor: 'pointer', padding: '0 0 10px', fontWeight: 600,
529
552
  }}
530
553
  >
531
554
  <span style={{ fontSize: 16 }}>&larr;</span> Close
532
555
  </button>
533
- <h3 style={{ fontSize: 16, fontWeight: 700, marginTop: 0, color: '#FF6B35' }}>Degrees</h3>
534
- <p style={{ fontSize: 12, color: '#888', marginBottom: 12 }}>
556
+ <h3 style={{ fontSize: 16, fontWeight: 700, marginTop: 0, color: 'var(--sd-orange, #FF6B35)' }}>Degrees</h3>
557
+ <p style={{ fontSize: 12, color: 'var(--sd-fg-3, #888)', marginBottom: 12 }}>
535
558
  Your bridge connections and who they unlock.
536
559
  </p>
537
560
 
@@ -556,8 +579,8 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
556
579
  onChange={e => setSearchQuery(e.target.value)}
557
580
  style={{
558
581
  width: '100%', padding: '8px 12px', borderRadius: 8, fontSize: 12,
559
- border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(255,255,255,0.05)',
560
- color: '#fff', outline: 'none', boxSizing: 'border-box',
582
+ border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)', background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)',
583
+ color: 'var(--sd-fg-1, #fff)', outline: 'none', boxSizing: 'border-box',
561
584
  }}
562
585
  />
563
586
  {searchQuery.length >= 2 && (() => {
@@ -575,7 +598,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
575
598
  return (
576
599
  <div style={{
577
600
  position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 50,
578
- background: 'color-mix(in srgb, var(--sd-bg) 97%, transparent)', border: '1px solid rgba(255,255,255,0.1)',
601
+ background: 'color-mix(in srgb, var(--sd-bg) 97%, transparent)', border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)',
579
602
  borderRadius: 8, overflow: 'hidden', maxHeight: 200, overflowY: 'auto',
580
603
  boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
581
604
  }}>
@@ -586,9 +609,9 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
586
609
  if (onFocusNode && m._matchType === 'bridge') onFocusNode(m.id);
587
610
  }} style={{
588
611
  padding: '8px 12px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 8,
589
- borderBottom: '1px solid rgba(255,255,255,0.05)',
612
+ borderBottom: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.05)',
590
613
  }}
591
- onMouseEnter={e => e.currentTarget.style.background = 'rgba(255,255,255,0.06)'}
614
+ onMouseEnter={e => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.06)'}
592
615
  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
593
616
  >
594
617
  {localPhoto(m.profile_image_url) ? (
@@ -598,7 +621,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
598
621
  )}
599
622
  <div style={{ flex: 1, minWidth: 0 }}>
600
623
  <div style={{ fontSize: 11, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.name}</div>
601
- <div style={{ fontSize: 8, color: '#666' }}>{m._matchType === 'bridge' ? 'Bridge' : 'Degree-2'}</div>
624
+ <div style={{ fontSize: 8, color: 'var(--sd-fg-4, #666)' }}>{m._matchType === 'bridge' ? 'Bridge' : 'Degree-2'}</div>
602
625
  </div>
603
626
  <span style={{ fontSize: 9, fontWeight: 700, color: tierColors[m.tier] }}>{m.tier}</span>
604
627
  </div>
@@ -611,10 +634,10 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
611
634
  {/* Pending Requests View */}
612
635
  {filter === 'pending' && pending.length > 0 && (
613
636
  <>
614
- <h4 style={{ fontSize: 13, fontWeight: 600, color: '#FF6B35', marginBottom: 8 }}>
637
+ <h4 style={{ fontSize: 13, fontWeight: 600, color: 'var(--sd-orange, #FF6B35)', marginBottom: 8 }}>
615
638
  ⏳ Pending Requests ({pending.length})
616
639
  </h4>
617
- <p style={{ fontSize: 10, color: '#666', marginBottom: 10, lineHeight: 1.4 }}>
640
+ <p style={{ fontSize: 10, color: 'var(--sd-fg-4, #666)', marginBottom: 10, lineHeight: 1.4 }}>
618
641
  Friend requests you&apos;ve sent. When accepted, their cluster unlocks for bridging.
619
642
  </p>
620
643
  <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
@@ -635,7 +658,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
635
658
  ) : (
636
659
  <div style={{
637
660
  width: 32, height: 32, borderRadius: '50%', flexShrink: 0, fontSize: 12, fontWeight: 700,
638
- background: tierColors[p.tier] || '#555', color: p.tier === 'S' ? '#000' : '#fff',
661
+ background: tierColors[p.tier] || '#555', color: p.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
639
662
  display: 'flex', alignItems: 'center', justifyContent: 'center',
640
663
  }}>{p.name?.charAt(0)}</div>
641
664
  )}
@@ -645,11 +668,11 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
645
668
  <div style={{ fontSize: 11, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
646
669
  {p.name}
647
670
  </div>
648
- <div style={{ fontSize: 8, color: '#888', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
671
+ <div style={{ fontSize: 8, color: 'var(--sd-fg-3, #888)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
649
672
  {p.headline?.substring(0, 40)}
650
673
  </div>
651
674
  {bridge && (
652
- <div style={{ fontSize: 8, color: '#FF6B35', marginTop: 1 }}>
675
+ <div style={{ fontSize: 8, color: 'var(--sd-orange, #FF6B35)', marginTop: 1 }}>
653
676
  via {bridge.name?.split(' ')[0]}
654
677
  </div>
655
678
  )}
@@ -660,7 +683,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
660
683
  <div style={{ fontSize: 9, fontWeight: 800, color: tierColors[p.tier] || '#888' }}>
661
684
  {p.tier}
662
685
  </div>
663
- <div style={{ fontSize: 8, color: '#666' }}>
686
+ <div style={{ fontSize: 8, color: 'var(--sd-fg-4, #666)' }}>
664
687
  {parseFloat(p.power_score || 0).toFixed(1)}
665
688
  </div>
666
689
  </div>
@@ -670,7 +693,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
670
693
  onClick={() => onUndoPending && onUndoPending(p)}
671
694
  title="Remove from pending"
672
695
  style={{
673
- background: 'none', border: 'none', color: '#555', cursor: 'pointer',
696
+ background: 'none', border: 'none', color: 'var(--sd-fg-5, #555)', cursor: 'pointer',
674
697
  fontSize: 12, padding: 2, flexShrink: 0,
675
698
  }}
676
699
  >βœ•</button>
@@ -683,7 +706,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
683
706
 
684
707
  {/* Clusters View (hidden when viewing pending) */}
685
708
  {filter !== 'pending' && (<>
686
- <h4 style={{ fontSize: 13, fontWeight: 600, color: '#FF6B35', marginBottom: 8 }}>Most Valuable Clusters</h4>
709
+ <h4 style={{ fontSize: 13, fontWeight: 600, color: 'var(--sd-orange, #FF6B35)', marginBottom: 8 }}>Most Valuable Clusters</h4>
687
710
  <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
688
711
  {(() => {
689
712
  const clusterStats = Object.entries(bridgeMap).map(([bridgeId, members]) => {
@@ -757,8 +780,8 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
757
780
  onClick={onToggle}
758
781
  style={{
759
782
  display: 'flex', alignItems: 'center', gap: 6,
760
- background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)',
761
- borderRadius: 6, color: '#aaa', fontSize: 12, cursor: 'pointer',
783
+ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.06)', border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)',
784
+ borderRadius: 6, color: 'var(--sd-fg-3, #aaa)', fontSize: 12, cursor: 'pointer',
762
785
  padding: '6px 12px', marginBottom: 12, fontWeight: 600,
763
786
  }}
764
787
  >
@@ -783,14 +806,14 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
783
806
  onChange={(e) => setSearchQuery(e.target.value)}
784
807
  style={{
785
808
  width: '100%', padding: '8px 12px', borderRadius: 8, boxSizing: 'border-box',
786
- border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(0,0,0,0.3)',
787
- color: '#fff', fontSize: 12, outline: 'none',
809
+ border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)', background: 'rgba(var(--sd-shade, 0, 0, 0), 0.3)',
810
+ color: 'var(--sd-fg-1, #fff)', fontSize: 12, outline: 'none',
788
811
  }}
789
812
  />
790
813
  {searchResults.length > 0 && (
791
814
  <div style={{
792
815
  position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 10,
793
- background: 'color-mix(in srgb, var(--sd-bg) 97%, transparent)', border: '1px solid rgba(255,255,255,0.1)',
816
+ background: 'color-mix(in srgb, var(--sd-bg) 97%, transparent)', border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.1)',
794
817
  borderRadius: 8, marginTop: 4, overflow: 'hidden',
795
818
  boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
796
819
  }}>
@@ -804,9 +827,9 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
804
827
  }}
805
828
  style={{
806
829
  display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px',
807
- cursor: 'pointer', borderBottom: '1px solid rgba(255,255,255,0.04)',
830
+ cursor: 'pointer', borderBottom: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.04)',
808
831
  }}
809
- onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.08)'}
832
+ onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.08)'}
810
833
  onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
811
834
  >
812
835
  {localPhoto(c.profile_image_url) ? (
@@ -817,13 +840,13 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
817
840
  ) : (
818
841
  <div style={{
819
842
  width: 24, height: 24, borderRadius: '50%', flexShrink: 0, fontSize: 10, fontWeight: 700,
820
- background: tierColors[c.tier] || '#555', color: c.tier === 'S' ? '#000' : '#fff',
843
+ background: tierColors[c.tier] || '#555', color: c.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
821
844
  display: 'flex', alignItems: 'center', justifyContent: 'center',
822
845
  }}>{c.name?.charAt(0)}</div>
823
846
  )}
824
847
  <div style={{ flex: 1, minWidth: 0 }}>
825
848
  <div style={{ fontSize: 12, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.name}</div>
826
- <div style={{ fontSize: 9, color: '#666' }}>{c.headline?.substring(0, 35)}</div>
849
+ <div style={{ fontSize: 9, color: 'var(--sd-fg-4, #666)' }}>{c.headline?.substring(0, 35)}</div>
827
850
  </div>
828
851
  <span style={{ fontSize: 10, color: tierColors[c.tier], fontWeight: 700 }}>{c.tier}</span>
829
852
  </div>
@@ -832,7 +855,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
832
855
  )}
833
856
  </div>
834
857
 
835
- <h4 style={{ fontSize: 13, fontWeight: 600, color: '#FFD700', marginBottom: 8 }}>
858
+ <h4 style={{ fontSize: 13, fontWeight: 600, color: 'var(--sd-gold, #FFD700)', marginBottom: 8 }}>
836
859
  Power Rankings ({allRanked.length})
837
860
  </h4>
838
861
  <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
@@ -850,7 +873,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
850
873
  if (showHeader) tierRankCounter[c.tier] = 0;
851
874
  tierRankCounter[c.tier] = (tierRankCounter[c.tier] || 0) + 1;
852
875
  const tierRank = tierRankCounter[c.tier];
853
- const tierNames = { S: 'S-Tier β€” Elite', A: 'A-Tier β€” High Value', B: 'B-Tier β€” Notable', C: 'C-Tier β€” Standard', D: 'D-Tier β€” Entry' };
876
+ const tierNames = { S: 'S-Tier Β· Elite', A: 'A-Tier Β· High Value', B: 'B-Tier Β· Notable', C: 'C-Tier Β· Standard', D: 'D-Tier Β· Entry' };
854
877
  return (
855
878
  <div key={c.id}>
856
879
  {showHeader && (
@@ -869,16 +892,16 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
869
892
  <div
870
893
  onClick={() => { onSelect && onSelect(c); onFocusNode && onFocusNode(c.id); }}
871
894
  style={{
872
- padding: '6px 8px', background: 'rgba(255,255,255,0.03)', borderRadius: 6,
895
+ padding: '6px 8px', background: 'rgba(var(--sd-ink, 255, 255, 255), 0.03)', borderRadius: 6,
873
896
  borderLeft: `3px solid ${tierColors[c.tier] || '#555'}`,
874
897
  cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 8,
875
898
  transition: 'background 0.15s',
876
899
  }}
877
- onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.1)'}
878
- onMouseLeave={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.03)'}
900
+ onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.1)'}
901
+ onMouseLeave={(e) => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.03)'}
879
902
  >
880
903
  {/* Rank number β€” per tier */}
881
- <span style={{ color: '#555', fontSize: 10, fontWeight: 600, minWidth: 22, textAlign: 'right' }}>
904
+ <span style={{ color: 'var(--sd-fg-5, #555)', fontSize: 10, fontWeight: 600, minWidth: 22, textAlign: 'right' }}>
882
905
  #{tierRank}
883
906
  </span>
884
907
  {/* Profile photo or initial */}
@@ -896,7 +919,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
896
919
  background: tierColors[c.tier] || '#555',
897
920
  display: localPhoto(c.profile_image_url) ? 'none' : 'flex',
898
921
  alignItems: 'center', justifyContent: 'center',
899
- fontSize: 12, fontWeight: 700, color: c.tier === 'S' ? '#000' : '#fff',
922
+ fontSize: 12, fontWeight: 700, color: c.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
900
923
  }}>
901
924
  {c.name?.charAt(0)}
902
925
  </div>
@@ -905,7 +928,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
905
928
  <div style={{ fontWeight: 600, fontSize: 11, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
906
929
  {c.name}
907
930
  </div>
908
- <div style={{ fontSize: 9, color: '#666', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
931
+ <div style={{ fontSize: 9, color: 'var(--sd-fg-4, #666)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
909
932
  {c.headline?.substring(0, 45)}
910
933
  </div>
911
934
  </div>
@@ -914,7 +937,7 @@ export default function Sidebar({ selected, stats, tierColors, connections, degr
914
937
  <div style={{ fontSize: 10, fontWeight: 700, color: tierColors[c.tier] || '#555' }}>
915
938
  {parseFloat(c.power_score).toFixed(1)}
916
939
  </div>
917
- <div style={{ fontSize: 8, color: '#555' }}>{c.tier}</div>
940
+ <div style={{ fontSize: 8, color: 'var(--sd-fg-5, #555)' }}>{c.tier}</div>
918
941
  </div>
919
942
  </div>
920
943
  </div>
@@ -939,7 +962,7 @@ function SidebarWrapper({ children, collapsed, onToggle }) {
939
962
  display: 'flex', alignItems: 'center', flexDirection: 'row-reverse', gap: 0,
940
963
  height: 36, borderRadius: 18,
941
964
  background: 'rgba(255,215,0,0.15)', border: '2px solid rgba(255,215,0,0.5)',
942
- color: '#FFD700', fontWeight: 700,
965
+ color: 'var(--sd-gold, #FFD700)', fontWeight: 700,
943
966
  boxShadow: '0 0 12px rgba(255,215,0,0.3)',
944
967
  backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
945
968
  overflow: 'hidden', transition: 'width 0.25s ease',
@@ -960,13 +983,13 @@ function SidebarWrapper({ children, collapsed, onToggle }) {
960
983
  position: 'fixed', top: 0, right: 0, bottom: 0, zIndex: 100,
961
984
  width: '100vw', pointerEvents: 'auto',
962
985
  } : { flexShrink: 0, height: '100%' }}>
963
- {isMobile && <div onClick={onToggle} style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.5)' }} />}
964
- <div style={{
986
+ {isMobile && <div onClick={onToggle} style={{ position: 'absolute', inset: 0, background: 'rgba(var(--sd-shade, 0, 0, 0), 0.5)' }} />}
987
+ <div data-glass-panel={isMobile ? undefined : 'side'} style={{
965
988
  width: isMobile ? '80vw' : 320, minWidth: isMobile ? 0 : 320, maxWidth: isMobile ? 300 : 320, height: '100%',
966
989
  borderLeft: '1px solid rgba(255,215,0,0.12)',
967
990
  padding: isMobile ? '12px 10px' : '16px 16px',
968
991
  overflowY: 'auto', overflowX: 'hidden',
969
- background: isMobile ? 'rgba(15,12,5,0.98)' : 'var(--sd-panel)', fontSize: 13,
992
+ background: isMobile ? 'var(--sd-surface, rgba(15,12,5,0.98))' : 'var(--sd-panel)', fontSize: 13,
970
993
  backdropFilter: 'var(--sd-panel-blur)', WebkitBackdropFilter: 'var(--sd-panel-blur)',
971
994
  boxShadow: 'inset 0 0 60px rgba(255,215,0,0.03), -4px 0 24px rgba(0,0,0,0.3)',
972
995
  marginLeft: isMobile ? 'auto' : 0,
@@ -979,15 +1002,15 @@ function SidebarWrapper({ children, collapsed, onToggle }) {
979
1002
 
980
1003
  function StatBox({ label, value }) {
981
1004
  return (
982
- <div style={{ background: 'rgba(255,255,255,0.05)', padding: '10px 12px', borderRadius: 8 }}>
983
- <div style={{ fontSize: 10, color: '#888', marginBottom: 2 }}>{label}</div>
1005
+ <div style={{ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)', padding: '10px 12px', borderRadius: 8 }}>
1006
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginBottom: 2 }}>{label}</div>
984
1007
  <div style={{ fontSize: 18, fontWeight: 700 }}>{value}</div>
985
1008
  </div>
986
1009
  );
987
1010
  }
988
1011
 
989
1012
  function Arrow() {
990
- return <span style={{ color: '#555', fontSize: 16 }}>&rarr;</span>;
1013
+ return <span style={{ color: 'var(--sd-fg-5, #555)', fontSize: 16 }}>&rarr;</span>;
991
1014
  }
992
1015
 
993
1016
  const CANT_NAME_TITLE = 'This route came from a scanned list whose connection record doesn’t match anyone in '
@@ -1009,15 +1032,15 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
1009
1032
  background: 'rgba(255,107,53,0.1)', border: '1px solid rgba(255,107,53,0.3)',
1010
1033
  borderRadius: 8, padding: 12, marginBottom: 16,
1011
1034
  }}>
1012
- <div style={{ fontSize: 10, color: '#FF6B35', fontWeight: 600, marginBottom: 8 }}>
1035
+ <div style={{ fontSize: 10, color: 'var(--sd-orange, #FF6B35)', fontWeight: 600, marginBottom: 8 }}>
1013
1036
  PATH TO THIS PERSON{n > 1 ? ` Β· ${n} WAYS IN` : ''}
1014
1037
  </div>
1015
1038
  <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
1016
1039
  {shown.map((r, i) => {
1017
1040
  if (!r.bridge) {
1018
1041
  return (
1019
- <div key={`unnamed-${r.id}`} title={CANT_NAME_TITLE} style={{ ...line, color: '#888', fontStyle: 'italic' }}>
1020
- <span style={{ fontWeight: 700, fontStyle: 'normal', color: '#fff' }}>You</span>
1042
+ <div key={`unnamed-${r.id}`} title={CANT_NAME_TITLE} style={{ ...line, color: 'var(--sd-fg-3, #888)', fontStyle: 'italic' }}>
1043
+ <span style={{ fontWeight: 700, fontStyle: 'normal', color: 'var(--sd-fg-1, #fff)' }}>You</span>
1021
1044
  <Arrow />
1022
1045
  <span>a connection we can&rsquo;t name</span>
1023
1046
  <Arrow />
@@ -1045,17 +1068,17 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
1045
1068
  {b.name}
1046
1069
  </button>
1047
1070
  <Arrow />
1048
- <span style={{ color: '#FF6B35', fontWeight: 600 }}>{selected.name}</span>
1071
+ <span style={{ color: 'var(--sd-orange, #FF6B35)', fontWeight: 600 }}>{selected.name}</span>
1049
1072
  {/* Not "strongest": the app knows nothing about how well they
1050
1073
  know each other, only how this connection scores. */}
1051
1074
  {i === 0 && n > 1 && (
1052
1075
  <span style={{
1053
- fontSize: 9, fontWeight: 700, color: '#FF6B35', padding: '1px 6px', borderRadius: 8,
1076
+ fontSize: 9, fontWeight: 700, color: 'var(--sd-orange, #FF6B35)', padding: '1px 6px', borderRadius: 8,
1054
1077
  background: 'rgba(255,107,53,0.15)', whiteSpace: 'nowrap',
1055
1078
  }}>top-scored bridge</span>
1056
1079
  )}
1057
1080
  </div>
1058
- {about && <div style={{ fontSize: 11, color: '#888', marginTop: 3 }}>{about}</div>}
1081
+ {about && <div style={{ fontSize: 11, color: 'var(--sd-fg-3, #888)', marginTop: 3 }}>{about}</div>}
1059
1082
  </div>
1060
1083
  );
1061
1084
  })}
@@ -1065,7 +1088,7 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
1065
1088
  onClick={() => setShowAll((v) => !v)}
1066
1089
  style={{
1067
1090
  marginTop: 10, padding: '4px 10px', borderRadius: 6, cursor: 'pointer', fontSize: 11, fontWeight: 600,
1068
- border: '1px solid rgba(255,107,53,0.35)', background: 'transparent', color: '#FF6B35',
1091
+ border: '1px solid rgba(255,107,53,0.35)', background: 'transparent', color: 'var(--sd-orange, #FF6B35)',
1069
1092
  }}
1070
1093
  >
1071
1094
  {showAll ? 'Show fewer' : `Show all ${n}`}
@@ -1075,6 +1098,87 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
1075
1098
  );
1076
1099
  }
1077
1100
 
1101
+ const noWatch = () => () => {};
1102
+
1103
+ /**
1104
+ * Where Resume would carry on with this person ({ nextPage, pagesRead, legacy };
1105
+ * null when there is nothing to carry on with; undefined until known), and
1106
+ * whether their circle is being scanned right now. One question to the server
1107
+ * for the whole card (GET /api/scraper?resume=<id>), asked again whenever a
1108
+ * scan ends, since every read moves it. Only those two facts are taken from the
1109
+ * scanner, never its whole answer: that changes every time a running scan's log
1110
+ * grows, and this panel would redraw with it.
1111
+ */
1112
+ function useResume(person) {
1113
+ const id = person?.id ?? null;
1114
+ const subscribe = id ? watchScanner : noWatch;
1115
+ const lastEnded = useSyncExternalStore(subscribe, () => scannerNow().finished[0]?.startedAt ?? null, () => null);
1116
+ const scanning = useSyncExternalStore(subscribe, () => {
1117
+ const now = scannerNow();
1118
+ return Boolean(now.running && person && scansCircleOf(now, person));
1119
+ }, () => false);
1120
+ const [got, setGot] = useState({ id: null, resume: undefined });
1121
+ useEffect(() => {
1122
+ if (!id) return undefined;
1123
+ let live = true;
1124
+ resumePoint(id).then((r) => { if (live) setGot({ id, resume: r }); }, () => { if (live) setGot({ id, resume: null }); });
1125
+ return () => { live = false; };
1126
+ }, [id, lastEnded]);
1127
+ // Another person's answer never shows on this one's card while theirs is asked.
1128
+ return { resume: id && got.id === id ? got.resume : undefined, scanning: Boolean(id) && scanning };
1129
+ }
1130
+
1131
+ /**
1132
+ * Resume, from anywhere on the card: bring the scan box into view and press its
1133
+ * own Resume, so the same checks run and the scan's log or any problem shows
1134
+ * where it's seen. While their scan runs (or Resume is greyed out) it only
1135
+ * brings the box into view, which says why.
1136
+ */
1137
+ function resumeInScanBox(scanning = false) {
1138
+ const box = document.getElementById('scan-box');
1139
+ if (!box) return;
1140
+ box.scrollIntoView({ behavior: 'smooth', block: 'center' });
1141
+ box.animate?.([{ boxShadow: '0 0 0 3px rgba(255,215,0,0.75)' }, { boxShadow: '0 0 0 0 rgba(255,215,0,0)' }], { duration: 1600 });
1142
+ if (!scanning) box.querySelector('button[data-resume]:not([disabled])')?.click();
1143
+ }
1144
+
1145
+ /**
1146
+ * The line by their name when the read of their list stopped partway (Blake,
1147
+ * 2026-10-03: "if someone was scanned but not finished it needs to show that in
1148
+ * their profile card"). The scan box is far down the card, so this says it where
1149
+ * it's seen, and Resume here presses the box's own Resume: the same checks, and
1150
+ * the box, brought into view, is where the scan's log and any problem show.
1151
+ * While their scan runs it says so, and only takes you to the box.
1152
+ */
1153
+ function StoppedPartway({ resume, scanning }) {
1154
+ const gold = 'var(--sd-gold, #FFD700)';
1155
+ return (
1156
+ <button type="button" onClick={() => resumeInScanBox(scanning)}
1157
+ aria-label={scanning ? 'Scanning their circle now: go to the scan' : `${stoppedLine(resume)}. Resume from page ${resume.nextPage}`}
1158
+ style={{
1159
+ display: 'flex', alignItems: 'center', gap: 9, width: '100%', boxSizing: 'border-box', margin: '-6px 0 16px',
1160
+ padding: '8px 11px', borderRadius: 8, cursor: 'pointer', textAlign: 'left', font: 'inherit',
1161
+ background: 'rgba(255,215,0,0.07)', border: '1px solid rgba(255,215,0,0.32)', color: 'var(--sd-fg-2, #ddd)',
1162
+ }}>
1163
+ {/* A pause sign while stopped; a pulsing dot while it runs. */}
1164
+ {scanning ? (
1165
+ // ScanLog's keyframes: the box below shows its log while their scan runs.
1166
+ <span aria-hidden="true" className="scanlog-dot" style={{ width: 8, height: 8, borderRadius: '50%', background: gold, flexShrink: 0, animation: 'scanlogPulse 1s ease-in-out infinite' }} />
1167
+ ) : (
1168
+ <span aria-hidden="true" style={{ display: 'flex', gap: 2, flexShrink: 0 }}>
1169
+ <span style={{ width: 3, height: 10, borderRadius: 1, background: gold }} />
1170
+ <span style={{ width: 3, height: 10, borderRadius: 1, background: gold }} />
1171
+ </span>
1172
+ )}
1173
+ <span style={{ flex: 1, minWidth: 0, fontSize: 11.5, lineHeight: 1.35 }}>
1174
+ <b style={{ color: gold }}>{scanning ? 'Scanning their circle now' : `${stoppedLine(resume)}.`}</b>
1175
+ {!scanning && <span style={{ color: 'var(--sd-fg-3, #999)' }}> Their list isn&apos;t finished.</span>}
1176
+ </span>
1177
+ <span style={{ fontSize: 11.5, fontWeight: 800, color: gold, whiteSpace: 'nowrap' }}>{scanning ? 'See it ↓' : 'Resume ↓'}</span>
1178
+ </button>
1179
+ );
1180
+ }
1181
+
1078
1182
  // Scan one person's circle, or carry on with it.
1079
1183
  //
1080
1184
  // LinkedIn lists someone else's connections in its own order, with no dates,
@@ -1085,11 +1189,18 @@ function PathBox({ routes, selected, tierColors, onSelect }) {
1085
1189
  // Whether a scan is running comes from the scanner (useScanner), not from this
1086
1190
  // card: close the card mid-scan and open it again and the scan is still here,
1087
1191
  // and every other card greys its buttons out until it ends.
1088
- function CreateClusterCard({ selected, degree2 }) {
1192
+ //
1193
+ // `resume` is where Resume carries on (useResume, asked once for the card),
1194
+ // null when there is nothing to resume, undefined until it's known. A read that
1195
+ // stopped partway is the first thing the box says: SCAN IN PROGRESS, in gold,
1196
+ // with Resume as the main button (Blake, 2026-10-03: "if someone was scanned but
1197
+ // not finished it needs to show that in their profile card ... showing resume
1198
+ // scanner in that actual card"). It used to sit under CLUSTER ACTIVE, which
1199
+ // reads as done.
1200
+ function CreateClusterCard({ selected, degree2, resume }) {
1089
1201
  const scan = useScanner();
1090
1202
  const [checking, setChecking] = useState(false);
1091
1203
  const [problem, setProblem] = useState(null); // why a scan didn't start: { text, offline }
1092
- const [resume, setResume] = useState(undefined); // where Resume carries on; null: nothing to resume
1093
1204
  const clusterCount = degree2?.filter(d => d.source_connection_id === selected.id).length || 0;
1094
1205
  const hasCluster = clusterCount > 0;
1095
1206
 
@@ -1097,14 +1208,6 @@ function CreateClusterCard({ selected, degree2 }) {
1097
1208
  const busy = scan.running && !mine ? busyReason(scan) : null;
1098
1209
  const last = scan.finished.find((j) => scansCircleOf(j, selected));
1099
1210
 
1100
- // Every read moves where Resume would carry on, so ask again whenever one ends.
1101
- const lastEnded = scan.finished[0]?.startedAt ?? null;
1102
- useEffect(() => {
1103
- let live = true;
1104
- resumePoint(selected.id).then((r) => { if (live) setResume(r); }, () => { if (live) setResume(null); });
1105
- return () => { live = false; };
1106
- }, [selected.id, lastEnded]);
1107
-
1108
1211
  async function start(action) {
1109
1212
  setProblem(null);
1110
1213
  setChecking(true);
@@ -1122,27 +1225,32 @@ function CreateClusterCard({ selected, degree2 }) {
1122
1225
  }
1123
1226
 
1124
1227
  const read = hasCluster || Boolean(resume);
1125
- const accent = hasCluster ? '#00ff88' : '#9B59B6';
1228
+ // Gold while a read is stopped partway, green once a circle is in, purple before.
1229
+ const accent = resume ? '#FFD700' : hasCluster ? '#00ff88' : '#9B59B6';
1230
+ // Gold words vanish on a light look; the theme's own gold reads on either.
1231
+ const ink = resume ? 'var(--sd-gold, #FFD700)' : accent;
1126
1232
  const off = Boolean(busy) || checking;
1127
1233
  const button = (primary) => ({
1128
1234
  flex: 1, padding: '11px 8px', borderRadius: 8, fontWeight: 700, fontSize: primary ? 13 : 12,
1129
1235
  cursor: off ? 'not-allowed' : 'pointer', opacity: off ? 0.45 : 1,
1130
1236
  ...(primary
1131
1237
  ? { border: 'none', background: 'linear-gradient(135deg, #9B59B6, #3498DB)', color: '#fff' }
1132
- : { border: `1px solid ${accent}55`, background: `${accent}14`, color: accent }),
1238
+ : { border: `1px solid ${accent}55`, background: `${accent}14`, color: ink }),
1133
1239
  });
1134
1240
 
1135
1241
  return (
1136
1242
  <div id="scan-box" style={{
1137
- background: hasCluster ? 'rgba(0,255,136,0.06)' : 'rgba(155,89,182,0.08)',
1138
- border: `1px solid ${hasCluster ? 'rgba(0,255,136,0.2)' : 'rgba(155,89,182,0.3)'}`,
1243
+ background: resume ? 'rgba(255,215,0,0.06)' : hasCluster ? 'rgba(0,255,136,0.06)' : 'rgba(155,89,182,0.08)',
1244
+ border: `1px solid ${resume ? 'rgba(255,215,0,0.32)' : hasCluster ? 'rgba(0,255,136,0.2)' : 'rgba(155,89,182,0.3)'}`,
1139
1245
  borderRadius: 10, padding: 16, marginTop: 16,
1140
1246
  }}>
1141
- <div style={{ fontSize: 10, color: accent, fontWeight: 700, letterSpacing: 1, marginBottom: 4, textAlign: 'center' }}>
1142
- {hasCluster ? 'CLUSTER ACTIVE' : 'CREATE CLUSTER'}
1247
+ <div style={{ fontSize: 10, color: ink, fontWeight: 700, letterSpacing: 1, marginBottom: 4, textAlign: 'center' }}>
1248
+ {scanBoxTitle({ resume, hasCluster })}
1143
1249
  </div>
1144
- <div style={{ fontSize: 12, color: '#aaa', marginBottom: 12, textAlign: 'center' }}>
1145
- {hasCluster
1250
+ <div style={{ fontSize: 12, color: 'var(--sd-fg-3, #aaa)', marginBottom: 12, textAlign: 'center' }}>
1251
+ {resume
1252
+ ? (hasCluster ? `${clusterCount} connections mapped so far` : 'Their list is only partly read')
1253
+ : hasCluster
1146
1254
  ? `${clusterCount} connections mapped in Six Degrees`
1147
1255
  : <>Scan {selected.name}&apos;s connections to map their network</>}
1148
1256
  </div>
@@ -1151,15 +1259,15 @@ function CreateClusterCard({ selected, degree2 }) {
1151
1259
  <ScanLog title={scan.pending ? 'Starting…' : `Scanning ${selected.name}’s circle…`} log={scan.log} />
1152
1260
  ) : problem?.offline ? (
1153
1261
  <>
1154
- <div style={{ padding: '10px', borderRadius: 8, background: 'rgba(255,80,80,0.1)', border: '1px solid rgba(255,80,80,0.3)', color: '#ff5050', fontSize: 12, marginBottom: 8, textAlign: 'center' }}>
1262
+ <div style={{ padding: '10px', borderRadius: 8, background: 'rgba(255,80,80,0.1)', border: '1px solid rgba(255,80,80,0.3)', color: 'var(--sd-red, #ff5050)', fontSize: 12, marginBottom: 8, textAlign: 'center' }}>
1155
1263
  Scanner offline
1156
1264
  </div>
1157
- <div style={{ fontSize: 10, color: '#888', textAlign: 'center', marginBottom: 8 }}>
1265
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', textAlign: 'center', marginBottom: 8 }}>
1158
1266
  {problem.text} Open the <strong>Scan</strong> page to finish setting the scanner up.
1159
1267
  </div>
1160
1268
  <button onClick={() => setProblem(null)} style={{
1161
1269
  width: '100%', padding: '10px', borderRadius: 8, border: 'none', cursor: 'pointer',
1162
- background: 'rgba(255,255,255,0.1)', color: '#aaa', fontWeight: 600, fontSize: 12,
1270
+ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.1)', color: 'var(--sd-fg-3, #aaa)', fontWeight: 600, fontSize: 12,
1163
1271
  }}>
1164
1272
  Retry
1165
1273
  </button>
@@ -1169,7 +1277,8 @@ function CreateClusterCard({ selected, degree2 }) {
1169
1277
  {last && <LastRead job={last} />}
1170
1278
  <div style={{ display: 'flex', gap: 8 }}>
1171
1279
  {resume && (
1172
- <button onClick={() => start('resume')} disabled={off} style={button(true)}>
1280
+ // data-resume: the line by their name presses this one (StoppedPartway).
1281
+ <button data-resume onClick={() => start('resume')} disabled={off} style={button(true)}>
1173
1282
  Resume from page {resume.nextPage}
1174
1283
  </button>
1175
1284
  )}
@@ -1178,19 +1287,19 @@ function CreateClusterCard({ selected, degree2 }) {
1178
1287
  </button>
1179
1288
  </div>
1180
1289
  {resume && (
1181
- <div style={{ fontSize: 10, color: '#888', marginTop: 8, lineHeight: 1.45, textAlign: 'center' }}>
1290
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginTop: 8, lineHeight: 1.45, textAlign: 'center' }}>
1182
1291
  Read to page {resume.pagesRead} so far. Resume carries on from page {resume.nextPage}. LinkedIn
1183
1292
  lists their connections in its own order, not by date, so Rescan reads them all again from page 1.
1184
1293
  </div>
1185
1294
  )}
1186
1295
  {hasCluster && resume === null && (
1187
- <div style={{ fontSize: 10, color: '#888', marginTop: 8, lineHeight: 1.45, textAlign: 'center' }}>
1296
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', marginTop: 8, lineHeight: 1.45, textAlign: 'center' }}>
1188
1297
  Their whole list has been read. LinkedIn doesn&apos;t date other people&apos;s connections, so a
1189
1298
  rescan reads it all again to find anyone new.
1190
1299
  </div>
1191
1300
  )}
1192
1301
  {busy && (
1193
- <div style={{ fontSize: 10, color: '#bbb', marginTop: 8, textAlign: 'center' }}>
1302
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-2, #bbb)', marginTop: 8, textAlign: 'center' }}>
1194
1303
  {busy}. One scan at a time: this one can start when it finishes.
1195
1304
  </div>
1196
1305
  )}
@@ -1203,18 +1312,18 @@ function CreateClusterCard({ selected, degree2 }) {
1203
1312
  );
1204
1313
  }
1205
1314
 
1206
- // In place of the Scan buttons while the sample or a CSV import is open. Both
1207
- // live in this window only, so a scan could only fail: the scanner looks the
1208
- // person up in the database, and says "Bridge '…' not found in database".
1315
+ // In place of the Scan buttons while the sample or a CSV import is open.
1316
+ // Neither is in the database, so a scan could only fail: the scanner looks the
1317
+ // person up there, and says "Bridge '…' not found in database".
1209
1318
  function ScansNeedYourNetwork({ csvSource, style }) {
1210
1319
  return (
1211
1320
  <div style={{
1212
- padding: '10px 12px', borderRadius: 8, fontSize: 11, color: '#999', lineHeight: 1.5, textAlign: 'center',
1213
- background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.08)', ...style,
1321
+ padding: '10px 12px', borderRadius: 8, fontSize: 11, color: 'var(--sd-fg-3, #999)', lineHeight: 1.5, textAlign: 'center',
1322
+ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.03)', border: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.08)', ...style,
1214
1323
  }}>
1215
1324
  {csvSource === 'sample'
1216
1325
  ? 'Scanning needs your own network: everyone in the sample is invented.'
1217
- : 'Scanning needs your own network: a CSV import lives only in this window. Close it (Γ— at the top) and open Scan.'}
1326
+ : 'Scanning needs your own network, not a CSV import. Remove the import (Γ— at the top) and open Scan.'}
1218
1327
  </div>
1219
1328
  );
1220
1329
  }
@@ -1229,9 +1338,9 @@ function ScanLog({ title, log, small = false }) {
1229
1338
  {/* Its own keyframes: the 'pulse' this named was never defined anywhere, so the dot sat still. */}
1230
1339
  <style>{'@keyframes scanlogPulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.7); } } @media (prefers-reduced-motion: reduce) { .scanlog-dot { animation: none !important; } }'}</style>
1231
1340
  <div className="scanlog-dot" style={{ width: small ? 6 : 8, height: small ? 6 : 8, borderRadius: '50%', background: '#9B59B6', animation: 'scanlogPulse 1s ease-in-out infinite' }} />
1232
- <span style={{ fontSize: 11, fontWeight: 600, color: '#9B59B6' }}>{title}</span>
1341
+ <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--sd-purple, #9B59B6)' }}>{title}</span>
1233
1342
  </div>
1234
- <div style={{ fontFamily: 'monospace', fontSize: small ? 9 : 10, color: '#888', maxHeight: small ? 80 : 100, overflow: 'auto' }}>
1343
+ <div style={{ fontFamily: 'monospace', fontSize: small ? 9 : 10, color: 'var(--sd-fg-3, #888)', maxHeight: small ? 80 : 100, overflow: 'auto' }}>
1235
1344
  {log.slice(-40).map((l, i) => <div key={i}>{l}</div>)}
1236
1345
  </div>
1237
1346
  </div>
@@ -1247,7 +1356,7 @@ function LastRead({ job, who = null }) {
1247
1356
  padding: '8px 10px', borderRadius: 8, marginBottom: 10, fontSize: 11, textAlign: 'center', lineHeight: 1.4,
1248
1357
  background: ok ? 'rgba(0,255,136,0.08)' : 'rgba(255,80,80,0.08)',
1249
1358
  border: `1px solid ${ok ? 'rgba(0,255,136,0.25)' : 'rgba(255,80,80,0.25)'}`,
1250
- color: ok ? '#00ff88' : '#ff8080',
1359
+ color: ok ? 'var(--sd-green, #00ff88)' : '#ff8080',
1251
1360
  }}>
1252
1361
  {ok
1253
1362
  ? `${who ? `${who}’s circle` : 'The scan'} finished. What it found is on the map.`
@@ -1261,7 +1370,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
1261
1370
 
1262
1371
  return (
1263
1372
  <div style={{
1264
- background: 'rgba(255,255,255,0.05)', borderRadius: 6,
1373
+ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)', borderRadius: 6,
1265
1374
  borderLeft: `3px solid ${tierColors[cs.bridge.tier] || '#FF6B35'}`,
1266
1375
  overflow: 'hidden',
1267
1376
  }}>
@@ -1280,34 +1389,34 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
1280
1389
  ) : (
1281
1390
  <div style={{
1282
1391
  width: 28, height: 28, borderRadius: '50%', flexShrink: 0, fontSize: 11, fontWeight: 700,
1283
- background: tierColors[cs.bridge.tier] || '#555', color: cs.bridge.tier === 'S' ? '#000' : '#fff',
1392
+ background: tierColors[cs.bridge.tier] || '#555', color: cs.bridge.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
1284
1393
  display: 'flex', alignItems: 'center', justifyContent: 'center',
1285
1394
  }}>{cs.bridge.name?.charAt(0)}</div>
1286
1395
  )}
1287
1396
  <div>
1288
1397
  <div style={{ fontWeight: 600, fontSize: 12 }}>
1289
- <span style={{ color: '#555', marginRight: 4 }}>#{rank}</span>{cs.bridge.name}
1398
+ <span style={{ color: 'var(--sd-fg-5, #555)', marginRight: 4 }}>#{rank}</span>{cs.bridge.name}
1290
1399
  </div>
1291
- <div style={{ fontSize: 9, color: '#666' }}>{cs.bridge.headline?.substring(0, 40)}</div>
1400
+ <div style={{ fontSize: 9, color: 'var(--sd-fg-4, #666)' }}>{cs.bridge.headline?.substring(0, 40)}</div>
1292
1401
  </div>
1293
1402
  </div>
1294
1403
  <span style={{
1295
1404
  fontSize: 10, fontWeight: 700, padding: '2px 6px', borderRadius: 4,
1296
- background: tierColors[cs.bridge.tier], color: cs.bridge.tier === 'S' ? '#000' : '#fff',
1405
+ background: tierColors[cs.bridge.tier], color: cs.bridge.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
1297
1406
  }}>{cs.bridge.tier}</span>
1298
1407
  </div>
1299
1408
  <div style={{ display: 'flex', gap: 6, marginTop: 6, fontSize: 10 }}>
1300
- {cs.sCount > 0 && <span style={{ color: '#FFD700', fontWeight: 600 }}>{cs.sCount}S{cs.sAvgPower > 0 ? ` (${cs.sAvgPower.toFixed(1)})` : ''}</span>}
1301
- {cs.aCount > 0 && <span style={{ color: '#9B59B6', fontWeight: 600 }}>{cs.aCount}A</span>}
1302
- {cs.bCount > 0 && <span style={{ color: '#3498DB' }}>{cs.bCount}B</span>}
1409
+ {cs.sCount > 0 && <span style={{ color: 'var(--sd-gold, #FFD700)', fontWeight: 600 }}>{cs.sCount}S{cs.sAvgPower > 0 ? ` (${cs.sAvgPower.toFixed(1)})` : ''}</span>}
1410
+ {cs.aCount > 0 && <span style={{ color: 'var(--sd-purple, #9B59B6)', fontWeight: 600 }}>{cs.aCount}A</span>}
1411
+ {cs.bCount > 0 && <span style={{ color: 'var(--sd-blue, #3498DB)' }}>{cs.bCount}B</span>}
1303
1412
  {cs.risingCount > 0 && <span style={{ color: '#2ECC71' }}>{cs.risingCount} rising</span>}
1304
- <span style={{ color: '#555' }}>{cs.members} total</span>
1413
+ <span style={{ color: 'var(--sd-fg-5, #555)' }}>{cs.members} total</span>
1305
1414
  </div>
1306
1415
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 4, fontSize: 10 }}>
1307
- <span style={{ color: '#666' }}>
1416
+ <span style={{ color: 'var(--sd-fg-4, #666)' }}>
1308
1417
  Elite: {(cs.elitePct * 100).toFixed(0)}% Β· Avg: {cs.avgPower.toFixed(1)}
1309
1418
  </span>
1310
- <span style={{ color: '#FF6B35', fontWeight: 700 }}>
1419
+ <span style={{ color: 'var(--sd-orange, #FF6B35)', fontWeight: 700 }}>
1311
1420
  {cs.clusterValue.toFixed(1)}
1312
1421
  </span>
1313
1422
  </div>
@@ -1326,13 +1435,13 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
1326
1435
  ) : (
1327
1436
  <div key={m.id} style={{
1328
1437
  width: 22, height: 22, borderRadius: '50%', fontSize: 9, fontWeight: 700,
1329
- background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : '#fff',
1438
+ background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
1330
1439
  display: 'flex', alignItems: 'center', justifyContent: 'center',
1331
1440
  }} title={m.name}>{m.name?.charAt(0)}</div>
1332
1441
  )
1333
1442
  ))}
1334
1443
  {(cs.sCount + cs.aCount) > 4 && (
1335
- <span style={{ fontSize: 9, color: '#666' }}>+{cs.sCount + cs.aCount - 4} more</span>
1444
+ <span style={{ fontSize: 9, color: 'var(--sd-fg-4, #666)' }}>+{cs.sCount + cs.aCount - 4} more</span>
1336
1445
  )}
1337
1446
  </div>
1338
1447
  )}
@@ -1341,7 +1450,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
1341
1450
  <button
1342
1451
  onClick={() => setExpanded(!expanded)}
1343
1452
  style={{
1344
- marginTop: 6, background: 'none', border: 'none', color: '#888',
1453
+ marginTop: 6, background: 'none', border: 'none', color: 'var(--sd-fg-3, #888)',
1345
1454
  fontSize: 10, cursor: 'pointer', padding: 0, display: 'flex', alignItems: 'center', gap: 4,
1346
1455
  }}
1347
1456
  >
@@ -1353,7 +1462,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
1353
1462
  {/* Expanded member list */}
1354
1463
  {expanded && (
1355
1464
  <div style={{
1356
- borderTop: '1px solid rgba(255,255,255,0.06)',
1465
+ borderTop: '1px solid rgba(var(--sd-ink, 255, 255, 255), 0.06)',
1357
1466
  padding: '6px 10px 10px', maxHeight: 250, overflowY: 'auto',
1358
1467
  }}>
1359
1468
  {cs.topMembers.map(m => (
@@ -1364,7 +1473,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
1364
1473
  display: 'flex', alignItems: 'center', gap: 6, padding: '4px 2px',
1365
1474
  cursor: 'pointer', borderRadius: 4,
1366
1475
  }}
1367
- onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.06)'}
1476
+ onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(var(--sd-ink, 255, 255, 255), 0.06)'}
1368
1477
  onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
1369
1478
  >
1370
1479
  {localPhoto(m.profile_image_url) ? (
@@ -1375,7 +1484,7 @@ function ClusterCard({ cs, rank, tierColors, onSelect }) {
1375
1484
  ) : null}
1376
1485
  <div style={{
1377
1486
  width: 20, height: 20, borderRadius: '50%', flexShrink: 0, fontSize: 8, fontWeight: 700,
1378
- background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : '#fff',
1487
+ background: tierColors[m.tier] || '#555', color: m.tier === 'S' ? '#000' : 'var(--sd-fg-1, #fff)',
1379
1488
  display: localPhoto(m.profile_image_url) ? 'none' : 'flex',
1380
1489
  alignItems: 'center', justifyContent: 'center',
1381
1490
  }}>{m.name?.charAt(0)}</div>
@@ -1405,13 +1514,13 @@ function generateInsights(person, user, allConnections, degree2, routes = []) {
1405
1514
 
1406
1515
  // 1. Title leverage
1407
1516
  if (role.match(/ceo|chief|founder|president|chairman/i)) {
1408
- insights.push({ icon: 'πŸ‘‘', text: `${person.role} β€” C-suite executive, highest leverage contact`, color: '#FFD700' });
1517
+ insights.push({ icon: 'πŸ‘‘', text: `${person.role}: C-suite executive, highest leverage contact`, color: 'var(--sd-gold, #FFD700)' });
1409
1518
  } else if (role.match(/vp|vice president|svp|evp|managing director/i)) {
1410
- insights.push({ icon: '⚑', text: `${person.role} β€” VP-level, strong decision-making authority`, color: '#FFD700' });
1519
+ insights.push({ icon: '⚑', text: `${person.role}: VP-level, strong decision-making authority`, color: 'var(--sd-gold, #FFD700)' });
1411
1520
  } else if (role.match(/director|head of|senior director/i)) {
1412
- insights.push({ icon: '🎯', text: `${person.role} β€” Senior leadership, controls team/budget`, color: '#FF6B35' });
1521
+ insights.push({ icon: '🎯', text: `${person.role}: Senior leadership, controls team/budget`, color: 'var(--sd-orange, #FF6B35)' });
1413
1522
  } else if (role.match(/manager|lead|principal/i)) {
1414
- insights.push({ icon: 'πŸ“Š', text: `${person.role} β€” Mid-senior, operational influence`, color: '#3498DB' });
1523
+ insights.push({ icon: 'πŸ“Š', text: `${person.role}: Mid-senior, operational influence`, color: 'var(--sd-blue, #3498DB)' });
1415
1524
  }
1416
1525
 
1417
1526
  // 2–3. A top company now, and one before, by the model's own company scores
@@ -1421,28 +1530,28 @@ function generateInsights(person, user, allConnections, degree2, routes = []) {
1421
1530
  // headline, so "Metadata Analyst" read as Meta and an ex-Googler as at Google.
1422
1531
  const { now, before } = topCompanies(person);
1423
1532
  if (now) {
1424
- insights.push({ icon: '🏒', text: `At ${now.name} (${now.score}/10) β€” top-tier company network access`, color: '#9B59B6' });
1533
+ insights.push({ icon: '🏒', text: `At ${now.name} (${now.score}/10): top-tier company network access`, color: 'var(--sd-purple, #9B59B6)' });
1425
1534
  }
1426
1535
  if (before) {
1427
- insights.push({ icon: 'πŸ“œ', text: `Former ${before.name} (${before.score}/10) β€” carries network from previous role`, color: '#95A5A6' });
1536
+ insights.push({ icon: 'πŸ“œ', text: `Former ${before.name} (${before.score}/10): carries network from previous role`, color: 'var(--sd-fg-3, #95A5A6)' });
1428
1537
  }
1429
1538
 
1430
1539
  // 4. Sector overlap with user
1431
1540
  const matchingSectors = userSectors.filter(s => headline.includes(s) || company.includes(s));
1432
1541
  if (matchingSectors.length > 0) {
1433
- insights.push({ icon: 'πŸ”—', text: `Shared sector: ${matchingSectors.join(', ')} β€” direct industry relevance to you`, color: '#2ECC71' });
1542
+ insights.push({ icon: 'πŸ”—', text: `Shared sector: ${matchingSectors.join(', ')}: direct industry relevance to you`, color: '#2ECC71' });
1434
1543
  }
1435
1544
 
1436
1545
  // 5. Bridge / gateway value
1437
1546
  const bridgeCount = degree2.filter(d => d.source_connection_id === person.id).length;
1438
1547
  if (bridgeCount > 0) {
1439
1548
  const bridgeSCount = degree2.filter(d => d.source_connection_id === person.id && d.tier === 'S').length;
1440
- insights.push({ icon: '🌐', text: `Gateway to ${bridgeCount} degree-2 connections${bridgeSCount > 0 ? ` (${bridgeSCount} S-tier)` : ''}`, color: '#FF6B35' });
1549
+ insights.push({ icon: '🌐', text: `Gateway to ${bridgeCount} degree-2 connections${bridgeSCount > 0 ? ` (${bridgeSCount} S-tier)` : ''}`, color: 'var(--sd-orange, #FF6B35)' });
1441
1550
  }
1442
1551
 
1443
1552
  // 6. Catalyst
1444
1553
  if (person.is_catalyst) {
1445
- insights.push({ icon: '⚑', text: `Catalyst β€” network power exceeds personal tier, high stepping-stone value`, color: '#00ff88' });
1554
+ insights.push({ icon: '⚑', text: `Catalyst: network power exceeds personal tier, high stepping-stone value`, color: 'var(--sd-green, #00ff88)' });
1446
1555
  }
1447
1556
 
1448
1557
  // 7. Every way in (degree 2). Built from the merged routes, so it can never
@@ -1452,8 +1561,8 @@ function generateInsights(person, user, allConnections, degree2, routes = []) {
1452
1561
  const named = routes.filter(r => r.bridge);
1453
1562
  if (routes.length === 1) {
1454
1563
  insights.push(named.length
1455
- ? { icon: '🀝', text: `Reachable via ${named[0].bridge.name} (${named[0].bridge.tier}-tier)`, color: '#3498DB' }
1456
- : { icon: '🀝', text: 'Reachable through a connection we can’t name', color: '#888' });
1564
+ ? { icon: '🀝', text: `Reachable via ${named[0].bridge.name} (${named[0].bridge.tier}-tier)`, color: 'var(--sd-blue, #3498DB)' }
1565
+ : { icon: '🀝', text: 'Reachable through a connection we can’t name', color: 'var(--sd-fg-3, #888)' });
1457
1566
  } else {
1458
1567
  const firstName = (n) => String(n || '').trim().split(/\s+/)[0];
1459
1568
  const names = named.slice(0, 2).map(r => `${firstName(r.bridge.name)} (${r.bridge.tier})`);
@@ -1461,13 +1570,13 @@ function generateInsights(person, user, allConnections, degree2, routes = []) {
1461
1570
  const via = names.length === 0 ? 'connections we can’t name'
1462
1571
  : more > 0 ? `${names.join(', ')} and ${more} more`
1463
1572
  : names.join(' and ');
1464
- insights.push({ icon: '🀝', text: `Reachable ${routes.length} ways β€” via ${via}`, color: '#3498DB' });
1573
+ insights.push({ icon: '🀝', text: `Reachable ${routes.length} ways, via ${via}`, color: 'var(--sd-blue, #3498DB)' });
1465
1574
  }
1466
1575
  }
1467
1576
 
1468
1577
  // Fallback if no insights generated
1469
1578
  if (insights.length === 0) {
1470
- insights.push({ icon: 'πŸ“Œ', text: `${person.tier}-tier connection with ${parseFloat(person.power_score).toFixed(1)} power score`, color: '#888' });
1579
+ insights.push({ icon: 'πŸ“Œ', text: `${person.tier}-tier connection with ${parseFloat(person.power_score).toFixed(1)} power score`, color: 'var(--sd-fg-3, #888)' });
1471
1580
  }
1472
1581
 
1473
1582
  return insights.slice(0, 5); // Max 5 insights
@@ -1510,10 +1619,10 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
1510
1619
  background: 'rgba(0,255,136,0.05)', border: '1px solid rgba(0,255,136,0.2)',
1511
1620
  borderRadius: 10, padding: 14, marginBottom: 16,
1512
1621
  }}>
1513
- <div style={{ fontSize: 12, fontWeight: 800, color: '#00ff88', marginBottom: 4 }}>
1622
+ <div style={{ fontSize: 12, fontWeight: 800, color: 'var(--sd-green, #00ff88)', marginBottom: 4 }}>
1514
1623
  Ready to scan ({ready.length})
1515
1624
  </div>
1516
- <div style={{ fontSize: 10.5, color: '#999', lineHeight: 1.5, marginBottom: 10 }}>
1625
+ <div style={{ fontSize: 10.5, color: 'var(--sd-fg-3, #999)', lineHeight: 1.5, marginBottom: 10 }}>
1517
1626
  People you added through a circle whose own circle isn&apos;t scanned yet. Scanning one
1518
1627
  brings in who they know: 3rd degree, through the circle you found them in.
1519
1628
  </div>
@@ -1525,7 +1634,7 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
1525
1634
  ) : last && <LastRead job={last} who={last.target?.name} />}
1526
1635
 
1527
1636
  {ready.length === 0 ? (
1528
- <div style={{ fontSize: 11, color: '#aaa', lineHeight: 1.5 }}>
1637
+ <div style={{ fontSize: 11, color: 'var(--sd-fg-3, #aaa)', lineHeight: 1.5 }}>
1529
1638
  Nobody yet. When someone you asked from a circle accepts, ↻ <b>Check for new</b> brings
1530
1639
  them into your connections, and they show here.
1531
1640
  </div>
@@ -1539,20 +1648,20 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
1539
1648
  aria-label={`Scan ${p.name}’s circle: opens the Scan page to confirm`}
1540
1649
  style={{
1541
1650
  display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px', borderRadius: 8,
1542
- textDecoration: 'none', color: '#fff',
1543
- background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(0,255,136,0.18)',
1651
+ textDecoration: 'none', color: 'var(--sd-fg-1, #fff)',
1652
+ background: 'rgba(var(--sd-ink, 255, 255, 255), 0.04)', border: '1px solid rgba(0,255,136,0.18)',
1544
1653
  }}>
1545
1654
  <span style={{ width: 8, height: 8, borderRadius: '50%', flexShrink: 0, background: tierColors[p.tier] || '#888', boxShadow: '0 0 0 2px rgba(0,255,136,0.45)' }} />
1546
1655
  <span style={{ flex: 1, minWidth: 0 }}>
1547
1656
  <span style={{ fontSize: 12, fontWeight: 700 }}>{p.name}</span>
1548
1657
  <span style={{ fontSize: 10, color: tierColors[p.tier] || '#888', fontWeight: 700, marginLeft: 6 }}>{p.tier}</span>
1549
1658
  {from && (
1550
- <span style={{ display: 'block', fontSize: 10, color: '#888', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
1659
+ <span style={{ display: 'block', fontSize: 10, color: 'var(--sd-fg-3, #888)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
1551
1660
  was in {first(from)}&apos;s circle
1552
1661
  </span>
1553
1662
  )}
1554
1663
  </span>
1555
- <span style={{ fontSize: 10.5, fontWeight: 700, color: '#00ff88', whiteSpace: 'nowrap' }}>
1664
+ <span style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--sd-green, #00ff88)', whiteSpace: 'nowrap' }}>
1556
1665
  {now ? 'Scanning…' : 'Scan… β†’'}
1557
1666
  </span>
1558
1667
  </Link>
@@ -1560,7 +1669,7 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
1560
1669
  })}
1561
1670
  {ready.length > 5 && (
1562
1671
  <button type="button" onClick={() => setAll((v) => !v)} style={{
1563
- background: 'none', border: 'none', color: '#888', fontSize: 10.5, fontWeight: 600, cursor: 'pointer', padding: '2px 0', textAlign: 'left',
1672
+ background: 'none', border: 'none', color: 'var(--sd-fg-3, #888)', fontSize: 10.5, fontWeight: 600, cursor: 'pointer', padding: '2px 0', textAlign: 'left',
1564
1673
  }}>
1565
1674
  {all ? 'Show fewer' : `Show all ${ready.length}`}
1566
1675
  </button>
@@ -1569,7 +1678,7 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
1569
1678
  )}
1570
1679
 
1571
1680
  {ready.length > 0 && (
1572
- <div style={{ fontSize: 10, color: '#888', lineHeight: 1.5, marginTop: 8 }}>
1681
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-3, #888)', lineHeight: 1.5, marginTop: 8 }}>
1573
1682
  Each scan: {cost.profileViews} profile view, then one LinkedIn search for every page of their
1574
1683
  list, up to {cost.searches} pages (about {cost.minutes} min for a whole list). Nothing starts
1575
1684
  until you confirm it on the Scan page.
@@ -1577,10 +1686,10 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
1577
1686
  )}
1578
1687
 
1579
1688
  {hidden.length > 0 && (
1580
- <div style={{ marginTop: 10, fontSize: 10.5, color: '#777', lineHeight: 1.6 }}>
1689
+ <div style={{ marginTop: 10, fontSize: 10.5, color: 'var(--sd-fg-4, #777)', lineHeight: 1.6 }}>
1581
1690
  {hidden.slice(0, 3).map((p) => (
1582
1691
  <div key={p.id} style={{ opacity: 0.7 }}>
1583
- <span aria-hidden="true">πŸ”’</span> {p.name} <span style={{ color: '#666' }}>Β· their list is hidden</span>
1692
+ <span aria-hidden="true">πŸ”’</span> {p.name} <span style={{ color: 'var(--sd-fg-4, #666)' }}>Β· their list is hidden</span>
1584
1693
  </div>
1585
1694
  ))}
1586
1695
  {hidden.length > 3 && <div style={{ opacity: 0.7 }}>πŸ”’ and {hidden.length - 3} more with hidden lists</div>}
@@ -1588,13 +1697,13 @@ function ReadyToScan({ connections, degree2, scanNotes, tierColors }) {
1588
1697
  )}
1589
1698
 
1590
1699
  {others > 0 && (
1591
- <div style={{ fontSize: 10.5, color: '#888', lineHeight: 1.5, marginTop: 10 }}>
1700
+ <div style={{ fontSize: 10.5, color: 'var(--sd-fg-3, #888)', lineHeight: 1.5, marginTop: 10 }}>
1592
1701
  {others.toLocaleString('en-US')} of your other connections aren&apos;t scanned yet.{' '}
1593
- <Link href="/setup" style={{ color: '#3498DB', textDecoration: 'none' }}>Map them in batches on the Scan page β†’</Link>
1702
+ <Link href="/setup" style={{ color: 'var(--sd-blue, #3498DB)', textDecoration: 'none' }}>Map them in batches on the Scan page β†’</Link>
1594
1703
  </div>
1595
1704
  )}
1596
1705
  {busy && (
1597
- <div style={{ fontSize: 10, color: '#bbb', marginTop: 8 }}>
1706
+ <div style={{ fontSize: 10, color: 'var(--sd-fg-2, #bbb)', marginTop: 8 }}>
1598
1707
  {busy}. One scan at a time.
1599
1708
  </div>
1600
1709
  )}