@highjumpdigitalsoftware/blog-kit 0.6.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 (397) hide show
  1. package/INTEGRATION.md +76 -0
  2. package/LICENSE +74 -0
  3. package/README.md +102 -0
  4. package/astro/AdPreview.astro +64 -0
  5. package/astro/AdPreviewPair.astro +10 -0
  6. package/astro/AuditFindings.astro +29 -0
  7. package/astro/AuditScores.astro +60 -0
  8. package/astro/AuthorCard.astro +32 -0
  9. package/astro/BeforeAfter.astro +26 -0
  10. package/astro/BlogBehaviors.astro +15 -0
  11. package/astro/CTABanner.astro +28 -0
  12. package/astro/CalloutBox.astro +28 -0
  13. package/astro/CaseStudyHero.astro +45 -0
  14. package/astro/ChannelMixBars.astro +33 -0
  15. package/astro/Checklist.astro +24 -0
  16. package/astro/ChecklistItem.astro +15 -0
  17. package/astro/CodeSnippet.astro +20 -0
  18. package/astro/ComparisonTable.astro +103 -0
  19. package/astro/Definition.astro +30 -0
  20. package/astro/DeliveryComparison.astro +40 -0
  21. package/astro/FAQList.astro +43 -0
  22. package/astro/FurtherReading.astro +34 -0
  23. package/astro/ImageFeature.astro +22 -0
  24. package/astro/Infographic.astro +12 -0
  25. package/astro/KeyMetric.astro +40 -0
  26. package/astro/KeywordTable.astro +69 -0
  27. package/astro/List.astro +46 -0
  28. package/astro/MetricHighlight.astro +77 -0
  29. package/astro/NewsletterCTA.astro +40 -0
  30. package/astro/NumberedCard.astro +6 -0
  31. package/astro/ProConBlock.astro +38 -0
  32. package/astro/ProseList.astro +46 -0
  33. package/astro/QuoteBlock.astro +72 -0
  34. package/astro/RegionCallout.astro +24 -0
  35. package/astro/RelatedPosts.astro +47 -0
  36. package/astro/ResultsStrip.astro +59 -0
  37. package/astro/ScoreBar.astro +19 -0
  38. package/astro/SerpPreview.astro +35 -0
  39. package/astro/ServicePromoCard.astro +21 -0
  40. package/astro/StatCard.astro +48 -0
  41. package/astro/StepBlock.astro +5 -0
  42. package/astro/TableOfContents.astro +12 -0
  43. package/astro/TimelineBlock.astro +30 -0
  44. package/astro/TipBox.astro +14 -0
  45. package/astro/TrafficChart.astro +61 -0
  46. package/astro/VerdictCard.astro +48 -0
  47. package/astro/blogkit/Article.astro +63 -0
  48. package/astro/blogkit/BlogIndex.astro +144 -0
  49. package/core/behaviors/code.js +78 -0
  50. package/core/behaviors/comparison.js +52 -0
  51. package/core/behaviors/delivery-comparison.js +52 -0
  52. package/core/behaviors/faq.js +61 -0
  53. package/core/behaviors/index.d.ts +3 -0
  54. package/core/behaviors/index.js +35 -0
  55. package/core/behaviors/keyword-table.js +52 -0
  56. package/core/behaviors/toc.js +130 -0
  57. package/core/css/base.css +146 -0
  58. package/core/css/components.css +2632 -0
  59. package/core/css/index-listing.css +207 -0
  60. package/core/css/index.css +13 -0
  61. package/core/css/tokens.css +127 -0
  62. package/core/icons.ts +20 -0
  63. package/core/lib.ts +70 -0
  64. package/core/manifest/components.json +573 -0
  65. package/core/manifest/frontmatter.json +19 -0
  66. package/core/manifest/templates.json +77 -0
  67. package/dist/core/behaviors/code.js +78 -0
  68. package/dist/core/behaviors/comparison.js +52 -0
  69. package/dist/core/behaviors/delivery-comparison.js +52 -0
  70. package/dist/core/behaviors/faq.js +61 -0
  71. package/dist/core/behaviors/index.d.ts +3 -0
  72. package/dist/core/behaviors/index.js +35 -0
  73. package/dist/core/behaviors/keyword-table.js +52 -0
  74. package/dist/core/behaviors/toc.js +130 -0
  75. package/dist/core/css/base.css +146 -0
  76. package/dist/core/css/components.css +2632 -0
  77. package/dist/core/css/index-listing.css +207 -0
  78. package/dist/core/css/index.css +13 -0
  79. package/dist/core/css/tokens.css +127 -0
  80. package/dist/core/icons.d.ts +2 -0
  81. package/dist/core/icons.d.ts.map +1 -0
  82. package/dist/core/icons.js +20 -0
  83. package/dist/core/icons.js.map +1 -0
  84. package/dist/core/lib.d.ts +21 -0
  85. package/dist/core/lib.d.ts.map +1 -0
  86. package/dist/core/lib.js +57 -0
  87. package/dist/core/lib.js.map +1 -0
  88. package/dist/core/manifest/components.json +573 -0
  89. package/dist/core/manifest/frontmatter.json +19 -0
  90. package/dist/core/manifest/templates.json +77 -0
  91. package/dist/package/adapters/hjd-api.d.ts +14 -0
  92. package/dist/package/adapters/hjd-api.d.ts.map +1 -0
  93. package/dist/package/adapters/hjd-api.js +57 -0
  94. package/dist/package/adapters/hjd-api.js.map +1 -0
  95. package/dist/package/adapters/index.d.ts +13 -0
  96. package/dist/package/adapters/index.d.ts.map +1 -0
  97. package/dist/package/adapters/index.js +16 -0
  98. package/dist/package/adapters/index.js.map +1 -0
  99. package/dist/package/adapters/local.d.ts +13 -0
  100. package/dist/package/adapters/local.d.ts.map +1 -0
  101. package/dist/package/adapters/local.js +72 -0
  102. package/dist/package/adapters/local.js.map +1 -0
  103. package/dist/package/adapters/source.d.ts +39 -0
  104. package/dist/package/adapters/source.d.ts.map +1 -0
  105. package/dist/package/adapters/source.js +19 -0
  106. package/dist/package/adapters/source.js.map +1 -0
  107. package/dist/package/article.d.ts +17 -0
  108. package/dist/package/article.d.ts.map +1 -0
  109. package/dist/package/article.js +37 -0
  110. package/dist/package/article.js.map +1 -0
  111. package/dist/package/astro/data.d.ts +45 -0
  112. package/dist/package/astro/data.d.ts.map +1 -0
  113. package/dist/package/astro/data.js +81 -0
  114. package/dist/package/astro/data.js.map +1 -0
  115. package/dist/package/astro/freshness.d.ts +11 -0
  116. package/dist/package/astro/freshness.d.ts.map +1 -0
  117. package/dist/package/astro/freshness.js +48 -0
  118. package/dist/package/astro/freshness.js.map +1 -0
  119. package/dist/package/astro/index.d.ts +12 -0
  120. package/dist/package/astro/index.d.ts.map +1 -0
  121. package/dist/package/astro/index.js +31 -0
  122. package/dist/package/astro/index.js.map +1 -0
  123. package/dist/package/blog-index.d.ts +10 -0
  124. package/dist/package/blog-index.d.ts.map +1 -0
  125. package/dist/package/blog-index.js +27 -0
  126. package/dist/package/blog-index.js.map +1 -0
  127. package/dist/package/cli/exchange.d.ts +27 -0
  128. package/dist/package/cli/exchange.d.ts.map +1 -0
  129. package/dist/package/cli/exchange.js +94 -0
  130. package/dist/package/cli/exchange.js.map +1 -0
  131. package/dist/package/cli/index.d.ts +3 -0
  132. package/dist/package/cli/index.d.ts.map +1 -0
  133. package/dist/package/cli/index.js +301 -0
  134. package/dist/package/cli/index.js.map +1 -0
  135. package/dist/package/config/define.d.ts +13 -0
  136. package/dist/package/config/define.d.ts.map +1 -0
  137. package/dist/package/config/define.js +14 -0
  138. package/dist/package/config/define.js.map +1 -0
  139. package/dist/package/config/resolve.d.ts +11 -0
  140. package/dist/package/config/resolve.d.ts.map +1 -0
  141. package/dist/package/config/resolve.js +43 -0
  142. package/dist/package/config/resolve.js.map +1 -0
  143. package/dist/package/config/types.d.ts +74 -0
  144. package/dist/package/config/types.d.ts.map +1 -0
  145. package/dist/package/config/types.js +13 -0
  146. package/dist/package/config/types.js.map +1 -0
  147. package/dist/package/index-core.d.ts +28 -0
  148. package/dist/package/index-core.d.ts.map +1 -0
  149. package/dist/package/index-core.js +102 -0
  150. package/dist/package/index-core.js.map +1 -0
  151. package/dist/package/index.d.ts +13 -0
  152. package/dist/package/index.d.ts.map +1 -0
  153. package/dist/package/index.js +25 -0
  154. package/dist/package/index.js.map +1 -0
  155. package/dist/package/mdx/render-astro.d.ts +18 -0
  156. package/dist/package/mdx/render-astro.d.ts.map +1 -0
  157. package/dist/package/mdx/render-astro.js +75 -0
  158. package/dist/package/mdx/render-astro.js.map +1 -0
  159. package/dist/package/mdx/render.d.ts +13 -0
  160. package/dist/package/mdx/render.d.ts.map +1 -0
  161. package/dist/package/mdx/render.js +37 -0
  162. package/dist/package/mdx/render.js.map +1 -0
  163. package/dist/react/AdPreview.d.ts +26 -0
  164. package/dist/react/AdPreview.d.ts.map +1 -0
  165. package/dist/react/AdPreview.js +8 -0
  166. package/dist/react/AdPreview.js.map +1 -0
  167. package/dist/react/AdPreviewPair.d.ts +7 -0
  168. package/dist/react/AdPreviewPair.d.ts.map +1 -0
  169. package/dist/react/AdPreviewPair.js +5 -0
  170. package/dist/react/AdPreviewPair.js.map +1 -0
  171. package/dist/react/AuditFindings.d.ts +14 -0
  172. package/dist/react/AuditFindings.d.ts.map +1 -0
  173. package/dist/react/AuditFindings.js +5 -0
  174. package/dist/react/AuditFindings.js.map +1 -0
  175. package/dist/react/AuditScores.d.ts +12 -0
  176. package/dist/react/AuditScores.d.ts.map +1 -0
  177. package/dist/react/AuditScores.js +25 -0
  178. package/dist/react/AuditScores.js.map +1 -0
  179. package/dist/react/AuthorCard.d.ts +10 -0
  180. package/dist/react/AuthorCard.d.ts.map +1 -0
  181. package/dist/react/AuthorCard.js +6 -0
  182. package/dist/react/AuthorCard.js.map +1 -0
  183. package/dist/react/BeforeAfter.d.ts +12 -0
  184. package/dist/react/BeforeAfter.d.ts.map +1 -0
  185. package/dist/react/BeforeAfter.js +7 -0
  186. package/dist/react/BeforeAfter.js.map +1 -0
  187. package/dist/react/BlogBehaviors.d.ts +10 -0
  188. package/dist/react/BlogBehaviors.d.ts.map +1 -0
  189. package/dist/react/BlogBehaviors.js +20 -0
  190. package/dist/react/BlogBehaviors.js.map +1 -0
  191. package/dist/react/CTABanner.d.ts +8 -0
  192. package/dist/react/CTABanner.d.ts.map +1 -0
  193. package/dist/react/CTABanner.js +9 -0
  194. package/dist/react/CTABanner.js.map +1 -0
  195. package/dist/react/CalloutBox.d.ts +13 -0
  196. package/dist/react/CalloutBox.d.ts.map +1 -0
  197. package/dist/react/CalloutBox.js +9 -0
  198. package/dist/react/CalloutBox.js.map +1 -0
  199. package/dist/react/CaseStudyHero.d.ts +20 -0
  200. package/dist/react/CaseStudyHero.d.ts.map +1 -0
  201. package/dist/react/CaseStudyHero.js +7 -0
  202. package/dist/react/CaseStudyHero.js.map +1 -0
  203. package/dist/react/ChannelMixBars.d.ts +18 -0
  204. package/dist/react/ChannelMixBars.d.ts.map +1 -0
  205. package/dist/react/ChannelMixBars.js +6 -0
  206. package/dist/react/ChannelMixBars.js.map +1 -0
  207. package/dist/react/Checklist.d.ts +10 -0
  208. package/dist/react/Checklist.d.ts.map +1 -0
  209. package/dist/react/Checklist.js +7 -0
  210. package/dist/react/Checklist.js.map +1 -0
  211. package/dist/react/ChecklistItem.d.ts +7 -0
  212. package/dist/react/ChecklistItem.d.ts.map +1 -0
  213. package/dist/react/ChecklistItem.js +5 -0
  214. package/dist/react/ChecklistItem.js.map +1 -0
  215. package/dist/react/CodeSnippet.d.ts +17 -0
  216. package/dist/react/CodeSnippet.d.ts.map +1 -0
  217. package/dist/react/CodeSnippet.js +14 -0
  218. package/dist/react/CodeSnippet.js.map +1 -0
  219. package/dist/react/ComparisonTable.d.ts +22 -0
  220. package/dist/react/ComparisonTable.d.ts.map +1 -0
  221. package/dist/react/ComparisonTable.js +35 -0
  222. package/dist/react/ComparisonTable.js.map +1 -0
  223. package/dist/react/Definition.d.ts +9 -0
  224. package/dist/react/Definition.d.ts.map +1 -0
  225. package/dist/react/Definition.js +19 -0
  226. package/dist/react/Definition.js.map +1 -0
  227. package/dist/react/DeliveryComparison.d.ts +16 -0
  228. package/dist/react/DeliveryComparison.d.ts.map +1 -0
  229. package/dist/react/DeliveryComparison.js +7 -0
  230. package/dist/react/DeliveryComparison.js.map +1 -0
  231. package/dist/react/FAQList.d.ts +20 -0
  232. package/dist/react/FAQList.d.ts.map +1 -0
  233. package/dist/react/FAQList.js +19 -0
  234. package/dist/react/FAQList.js.map +1 -0
  235. package/dist/react/FurtherReading.d.ts +21 -0
  236. package/dist/react/FurtherReading.d.ts.map +1 -0
  237. package/dist/react/FurtherReading.js +13 -0
  238. package/dist/react/FurtherReading.js.map +1 -0
  239. package/dist/react/ImageFeature.d.ts +9 -0
  240. package/dist/react/ImageFeature.d.ts.map +1 -0
  241. package/dist/react/ImageFeature.js +6 -0
  242. package/dist/react/ImageFeature.js.map +1 -0
  243. package/dist/react/Infographic.d.ts +6 -0
  244. package/dist/react/Infographic.d.ts.map +1 -0
  245. package/dist/react/Infographic.js +7 -0
  246. package/dist/react/Infographic.js.map +1 -0
  247. package/dist/react/KeyMetric.d.ts +16 -0
  248. package/dist/react/KeyMetric.d.ts.map +1 -0
  249. package/dist/react/KeyMetric.js +15 -0
  250. package/dist/react/KeyMetric.js.map +1 -0
  251. package/dist/react/KeywordTable.d.ts +18 -0
  252. package/dist/react/KeywordTable.d.ts.map +1 -0
  253. package/dist/react/KeywordTable.js +23 -0
  254. package/dist/react/KeywordTable.js.map +1 -0
  255. package/dist/react/List.d.ts +11 -0
  256. package/dist/react/List.d.ts.map +1 -0
  257. package/dist/react/List.js +21 -0
  258. package/dist/react/List.js.map +1 -0
  259. package/dist/react/MetricHighlight.d.ts +15 -0
  260. package/dist/react/MetricHighlight.d.ts.map +1 -0
  261. package/dist/react/MetricHighlight.js +26 -0
  262. package/dist/react/MetricHighlight.js.map +1 -0
  263. package/dist/react/NewsletterCTA.d.ts +9 -0
  264. package/dist/react/NewsletterCTA.d.ts.map +1 -0
  265. package/dist/react/NewsletterCTA.js +5 -0
  266. package/dist/react/NewsletterCTA.js.map +1 -0
  267. package/dist/react/NumberedCard.d.ts +9 -0
  268. package/dist/react/NumberedCard.d.ts.map +1 -0
  269. package/dist/react/NumberedCard.js +7 -0
  270. package/dist/react/NumberedCard.js.map +1 -0
  271. package/dist/react/ProConBlock.d.ts +6 -0
  272. package/dist/react/ProConBlock.d.ts.map +1 -0
  273. package/dist/react/ProConBlock.js +7 -0
  274. package/dist/react/ProConBlock.js.map +1 -0
  275. package/dist/react/ProseList.d.ts +17 -0
  276. package/dist/react/ProseList.d.ts.map +1 -0
  277. package/dist/react/ProseList.js +26 -0
  278. package/dist/react/ProseList.js.map +1 -0
  279. package/dist/react/QuoteBlock.d.ts +17 -0
  280. package/dist/react/QuoteBlock.d.ts.map +1 -0
  281. package/dist/react/QuoteBlock.js +26 -0
  282. package/dist/react/QuoteBlock.js.map +1 -0
  283. package/dist/react/RegionCallout.d.ts +13 -0
  284. package/dist/react/RegionCallout.d.ts.map +1 -0
  285. package/dist/react/RegionCallout.js +5 -0
  286. package/dist/react/RegionCallout.js.map +1 -0
  287. package/dist/react/RelatedPosts.d.ts +20 -0
  288. package/dist/react/RelatedPosts.d.ts.map +1 -0
  289. package/dist/react/RelatedPosts.js +7 -0
  290. package/dist/react/RelatedPosts.js.map +1 -0
  291. package/dist/react/ResultsStrip.d.ts +18 -0
  292. package/dist/react/ResultsStrip.d.ts.map +1 -0
  293. package/dist/react/ResultsStrip.js +22 -0
  294. package/dist/react/ResultsStrip.js.map +1 -0
  295. package/dist/react/ScoreBar.d.ts +8 -0
  296. package/dist/react/ScoreBar.d.ts.map +1 -0
  297. package/dist/react/ScoreBar.js +6 -0
  298. package/dist/react/ScoreBar.js.map +1 -0
  299. package/dist/react/SerpPreview.d.ts +18 -0
  300. package/dist/react/SerpPreview.d.ts.map +1 -0
  301. package/dist/react/SerpPreview.js +13 -0
  302. package/dist/react/SerpPreview.js.map +1 -0
  303. package/dist/react/ServicePromoCard.d.ts +14 -0
  304. package/dist/react/ServicePromoCard.d.ts.map +1 -0
  305. package/dist/react/ServicePromoCard.js +12 -0
  306. package/dist/react/ServicePromoCard.js.map +1 -0
  307. package/dist/react/StatCard.d.ts +13 -0
  308. package/dist/react/StatCard.d.ts.map +1 -0
  309. package/dist/react/StatCard.js +20 -0
  310. package/dist/react/StatCard.js.map +1 -0
  311. package/dist/react/StepBlock.d.ts +8 -0
  312. package/dist/react/StepBlock.d.ts.map +1 -0
  313. package/dist/react/StepBlock.js +5 -0
  314. package/dist/react/StepBlock.js.map +1 -0
  315. package/dist/react/TableOfContents.d.ts +14 -0
  316. package/dist/react/TableOfContents.d.ts.map +1 -0
  317. package/dist/react/TableOfContents.js +12 -0
  318. package/dist/react/TableOfContents.js.map +1 -0
  319. package/dist/react/TimelineBlock.d.ts +14 -0
  320. package/dist/react/TimelineBlock.d.ts.map +1 -0
  321. package/dist/react/TimelineBlock.js +8 -0
  322. package/dist/react/TimelineBlock.js.map +1 -0
  323. package/dist/react/TipBox.d.ts +6 -0
  324. package/dist/react/TipBox.d.ts.map +1 -0
  325. package/dist/react/TipBox.js +5 -0
  326. package/dist/react/TipBox.js.map +1 -0
  327. package/dist/react/TrafficChart.d.ts +16 -0
  328. package/dist/react/TrafficChart.d.ts.map +1 -0
  329. package/dist/react/TrafficChart.js +14 -0
  330. package/dist/react/TrafficChart.js.map +1 -0
  331. package/dist/react/VerdictCard.d.ts +15 -0
  332. package/dist/react/VerdictCard.d.ts.map +1 -0
  333. package/dist/react/VerdictCard.js +5 -0
  334. package/dist/react/VerdictCard.js.map +1 -0
  335. package/dist/react/components-map.d.ts +133 -0
  336. package/dist/react/components-map.d.ts.map +1 -0
  337. package/dist/react/components-map.js +120 -0
  338. package/dist/react/components-map.js.map +1 -0
  339. package/dist/react/index.d.ts +5 -0
  340. package/dist/react/index.d.ts.map +1 -0
  341. package/dist/react/index.js +13 -0
  342. package/dist/react/index.js.map +1 -0
  343. package/package.json +116 -0
  344. package/react/AdPreview.tsx +94 -0
  345. package/react/AdPreviewPair.tsx +16 -0
  346. package/react/AuditFindings.tsx +43 -0
  347. package/react/AuditScores.tsx +73 -0
  348. package/react/AuthorCard.tsx +35 -0
  349. package/react/BeforeAfter.tsx +27 -0
  350. package/react/BlogBehaviors.tsx +21 -0
  351. package/react/CTABanner.tsx +32 -0
  352. package/react/CalloutBox.tsx +31 -0
  353. package/react/CaseStudyHero.tsx +71 -0
  354. package/react/ChannelMixBars.tsx +50 -0
  355. package/react/Checklist.tsx +31 -0
  356. package/react/ChecklistItem.tsx +19 -0
  357. package/react/CodeSnippet.tsx +36 -0
  358. package/react/ComparisonTable.tsx +114 -0
  359. package/react/Definition.tsx +36 -0
  360. package/react/DeliveryComparison.tsx +62 -0
  361. package/react/FAQList.tsx +61 -0
  362. package/react/FurtherReading.tsx +46 -0
  363. package/react/ImageFeature.tsx +26 -0
  364. package/react/Infographic.tsx +18 -0
  365. package/react/KeyMetric.tsx +61 -0
  366. package/react/KeywordTable.tsx +92 -0
  367. package/react/List.tsx +58 -0
  368. package/react/MetricHighlight.tsx +86 -0
  369. package/react/NewsletterCTA.tsx +48 -0
  370. package/react/NumberedCard.tsx +7 -0
  371. package/react/ProConBlock.tsx +42 -0
  372. package/react/ProseList.tsx +72 -0
  373. package/react/QuoteBlock.tsx +89 -0
  374. package/react/RegionCallout.tsx +38 -0
  375. package/react/RelatedPosts.tsx +58 -0
  376. package/react/ResultsStrip.tsx +77 -0
  377. package/react/ScoreBar.tsx +27 -0
  378. package/react/SerpPreview.tsx +59 -0
  379. package/react/ServicePromoCard.tsx +43 -0
  380. package/react/StatCard.tsx +62 -0
  381. package/react/StepBlock.tsx +5 -0
  382. package/react/TableOfContents.tsx +27 -0
  383. package/react/TimelineBlock.tsx +35 -0
  384. package/react/TipBox.tsx +16 -0
  385. package/react/TrafficChart.tsx +79 -0
  386. package/react/VerdictCard.tsx +60 -0
  387. package/react/components-map.ts +122 -0
  388. package/react/index.ts +13 -0
  389. package/templates/blogkit/app/api/blogkit/revalidate/route.ts.tmpl +32 -0
  390. package/templates/blogkit/app/blog/[slug]/page.tsx.tmpl +41 -0
  391. package/templates/blogkit/app/blog/page.tsx.tmpl +18 -0
  392. package/templates/blogkit/blogkit.config.ts.tmpl +23 -0
  393. package/templates/blogkit-astro/BLOGKIT_ASTRO_SETUP.md.tmpl +49 -0
  394. package/templates/blogkit-astro/src/blogkit.config.ts.tmpl +29 -0
  395. package/templates/blogkit-astro/src/pages/api/blogkit/revalidate.ts.tmpl +46 -0
  396. package/templates/blogkit-astro/src/pages/blog/[slug].astro.tmpl +39 -0
  397. package/templates/blogkit-astro/src/pages/blog/index.astro.tmpl +29 -0
@@ -0,0 +1,2632 @@
1
+ /* ============================================================
2
+ blog-kit — Component styles
3
+ ------------------------------------------------------------
4
+ ONE shared stylesheet of global .bk-* BEM classes, imported by
5
+ BOTH the React and Astro adapters. The adapters emit identical
6
+ markup/classnames; all styling lives here so a restyle is a
7
+ single-file change that updates every framework and every site.
8
+
9
+ Every value keys off a --blog-* token (see tokens.css) so a
10
+ tenant re-skins by overriding tokens, never by editing this file.
11
+ ============================================================ */
12
+
13
+ /* ── CalloutBox ──────────────────────────────────────────────
14
+ Canonical name: CalloutBox
15
+ Tones: info (default) | tip | success | warn | danger
16
+ The adapter maps the `tone` prop (and aliases type/variant) to a
17
+ --bk-callout--<tone> modifier class; colour logic stays here.
18
+ ──────────────────────────────────────────────────────────── */
19
+ .bk-callout {
20
+ --_c: var(--blog-info);
21
+ --_bg: var(--blog-info-bg);
22
+ display: block;
23
+ background: var(--_bg);
24
+ border: 1px solid color-mix(in srgb, var(--_c) 22%, transparent);
25
+ border-left: 4px solid var(--_c);
26
+ border-radius: var(--blog-radius-sm);
27
+ padding: var(--blog-sp-4) var(--blog-sp-5);
28
+ margin: var(--blog-sp-6) 0;
29
+ }
30
+ .bk-callout--info { --_c: var(--blog-info); --_bg: var(--blog-info-bg); }
31
+ .bk-callout--tip { --_c: var(--blog-success); --_bg: var(--blog-success-bg); }
32
+ .bk-callout--success { --_c: var(--blog-success); --_bg: var(--blog-success-bg); }
33
+ .bk-callout--warn { --_c: var(--blog-warn); --_bg: var(--blog-warn-bg); }
34
+ .bk-callout--danger { --_c: var(--blog-danger); --_bg: var(--blog-danger-bg); }
35
+
36
+ .bk-callout__title {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: var(--blog-sp-2);
40
+ margin: 0 0 var(--blog-sp-2);
41
+ font-family: var(--blog-font-display);
42
+ font-weight: 700;
43
+ font-size: var(--blog-fs-md);
44
+ line-height: 1.3;
45
+ color: var(--_c);
46
+ }
47
+
48
+ .bk-callout__icon {
49
+ display: inline-flex;
50
+ flex: 0 0 auto;
51
+ color: var(--_c);
52
+ }
53
+ .bk-callout__icon svg { display: block; width: 18px; height: 18px; }
54
+
55
+ .bk-callout__body {
56
+ font-size: var(--blog-fs-md);
57
+ line-height: 1.65;
58
+ color: var(--blog-text);
59
+ }
60
+ .bk-callout__body > :first-child { margin-top: 0; }
61
+ .bk-callout__body > :last-child { margin-bottom: 0; }
62
+
63
+ /* ============================================================
64
+ TipBox (.bk-tip) — "Pro tip" inline callout
65
+ Orange-tinted strip with a brand badge + bold lead line.
66
+ Ported from capture-ai blog TipBox (brand-orange tint/border).
67
+ ============================================================ */
68
+ .bk-tip { display:flex; align-items:flex-start; gap:var(--blog-sp-3); margin:var(--blog-sp-5) 0; padding:var(--blog-sp-3) var(--blog-sp-4); background:var(--blog-brand-tint); border-left:4px solid var(--blog-brand); border-radius:var(--blog-radius-xs); }
69
+ .bk-tip__badge { flex-shrink:0; margin-top:2px; padding:var(--blog-sp-1) var(--blog-sp-2); border-radius:var(--blog-radius-xs); background:var(--blog-brand); color:var(--blog-on-brand); font-family:var(--blog-font-display); font-weight:700; font-size: var(--blog-fs-eyebrow-sm); text-transform:uppercase; letter-spacing:var(--blog-tracking-wide); line-height:1.2; }
70
+ .bk-tip__body { margin:0; font-family:var(--blog-font-body); font-size: var(--blog-fs-base); line-height:1.55; color:var(--blog-ink); }
71
+ .bk-tip__lead { font-weight:700; }
72
+ .bk-tip__context { color:var(--blog-text); }
73
+
74
+ /* ── QuoteBlock ───────────────────────────────────────────────
75
+ Pull-quote / testimonial figure: large faded quote mark, brand
76
+ left-border, brand-tinted ground, italic body, bold uppercase
77
+ author, muted role, dashed-divider source attribution row. */
78
+ .bk-quote { position: relative; margin: var(--blog-sp-7) 0; padding: var(--blog-sp-6) var(--blog-sp-5) var(--blog-sp-6) 56px; border-left: 4px solid var(--blog-brand); border-radius: 0 var(--blog-radius-xs) var(--blog-radius-xs) 0; background: var(--blog-brand-tint); }
79
+ .bk-quote__mark { position: absolute; left: var(--blog-sp-4); top: var(--blog-sp-4); font-family: var(--blog-font-display); font-weight: 800; font-size: 56px; line-height: 1; color: var(--blog-brand); opacity: .35; user-select: none; pointer-events: none; }
80
+ .bk-quote__body { margin: 0; font-family: var(--blog-font-display); font-style: italic; font-weight: 500; font-size: var(--blog-fs-xl); line-height: 1.3; color: var(--blog-ink); text-wrap: pretty; }
81
+ .bk-quote__cite { display: flex; align-items: center; gap: var(--blog-sp-3); margin-top: var(--blog-sp-4); }
82
+ .bk-quote__avatar { width: 40px; height: 40px; flex-shrink: 0; border-radius: var(--blog-radius-pill); object-fit: contain; padding: 6px; background: var(--blog-paper); border: 1px solid var(--blog-border); }
83
+ .bk-quote__who { display: flex; flex-direction: column; }
84
+ .bk-quote__author { display: block; font-family: var(--blog-font-display); font-style: normal; font-weight: 700; font-size: var(--blog-fs-base); text-transform: uppercase; letter-spacing: var(--blog-tracking-wide); color: var(--blog-ink); }
85
+ .bk-quote__role { font-family: var(--blog-font-body); font-size: var(--blog-fs-sm); color: var(--blog-mute); }
86
+ .bk-quote__source { display: inline-flex; align-items: center; gap: var(--blog-sp-1); margin-top: var(--blog-sp-3); padding-top: var(--blog-sp-2); border-top: 1px dashed var(--blog-border); font-family: var(--blog-font-display); font-size: var(--blog-fs-eyebrow); letter-spacing: var(--blog-tracking-wide); color: var(--blog-mute); opacity: .8; text-decoration: none; transition: opacity .15s ease, color .15s ease; }
87
+ .bk-quote__source--link:hover { opacity: 1; color: var(--blog-brand); }
88
+ .bk-quote__source-kicker { font-weight: 700; text-transform: uppercase; font-size: var(--blog-fs-eyebrow-sm); letter-spacing: var(--blog-tracking-eyebrow); margin-right: 2px; color: var(--blog-mute); }
89
+ .bk-quote__source-icon svg { display: block; width: 10px; height: 10px; opacity: .7; }
90
+ @media (min-width: 640px) {
91
+ .bk-quote { padding: var(--blog-sp-8) var(--blog-sp-8) var(--blog-sp-8) 72px; }
92
+ .bk-quote__mark { left: var(--blog-sp-6); top: var(--blog-sp-5); font-size: 72px; }
93
+ .bk-quote__body { font-size: var(--blog-fs-2xl); }
94
+ }
95
+
96
+ /* ── Definition ─────────────────────────────────────────────
97
+ Term/definition block: brand monogram tile + name, optional
98
+ pronunciation, and definition body. Ported from Capture's
99
+ Definition.tsx (#FF4206→brand, #F9FAFB→bg-secondary, etc).
100
+ ──────────────────────────────────────────────────────────── */
101
+ .bk-definition { display:flex; align-items:flex-start; gap:var(--blog-sp-4); margin:var(--blog-sp-6) 0; padding:var(--blog-sp-4); background:var(--blog-bg-secondary); border:1px solid var(--blog-border); border-radius:var(--blog-radius-xs); }
102
+ .bk-definition__monogram { flex-shrink:0; display:flex; align-items:center; justify-content:center; width:88px; height:88px; background:var(--blog-brand); color:var(--blog-on-brand); border-radius:var(--blog-radius-xs); font-family:var(--blog-font-display); font-weight:800; font-size:1.5rem; letter-spacing:.02em; }
103
+ .bk-definition__content { flex:1; min-width:0; }
104
+ .bk-definition__name { margin:0 0 .125rem; font-family:var(--blog-font-display); font-weight:700; font-size: var(--blog-fs-xl); line-height:1.2; color:var(--blog-ink); }
105
+ .bk-definition__pronunciation { margin:0 0 var(--blog-sp-2); font-family:var(--blog-font-body); font-style:italic; font-size: var(--blog-fs-sm); line-height:1.3; color:var(--blog-mute); }
106
+ .bk-definition__body { margin:0; font-family:var(--blog-font-body); font-size: var(--blog-fs-md); line-height:1.55; color:var(--blog-text); }
107
+ @media (min-width:640px){ .bk-definition { gap:var(--blog-sp-5); padding:var(--blog-sp-5); } }
108
+
109
+ /* ============================================================
110
+ FAQList — expandable Q&A built on native <details>/<summary>.
111
+ First item open by default; the plus toggle rotates 45deg into
112
+ an "x" when open. A behaviour script (core/behaviors/faq.js)
113
+ lifts the rendered pairs into FAQPage JSON-LD for SEO.
114
+ ============================================================ */
115
+ .bk-faq { margin: var(--blog-sp-8) 0; }
116
+ .bk-faq__heading {
117
+ margin: 0 0 var(--blog-sp-4);
118
+ font-family: var(--blog-font-display);
119
+ font-weight: 700;
120
+ font-size: var(--blog-fs-sm);
121
+ letter-spacing: var(--blog-tracking-eyebrow);
122
+ text-transform: uppercase;
123
+ color: var(--blog-brand);
124
+ }
125
+ .bk-faq__list {
126
+ display: flex;
127
+ flex-direction: column;
128
+ border-top: 1px solid var(--blog-border);
129
+ border-bottom: 1px solid var(--blog-border);
130
+ }
131
+ .bk-faq__item { border-bottom: 1px solid var(--blog-border); }
132
+ .bk-faq__item:last-child { border-bottom: none; }
133
+ .bk-faq__summary {
134
+ display: flex;
135
+ align-items: flex-start;
136
+ justify-content: space-between;
137
+ gap: var(--blog-sp-4);
138
+ padding: var(--blog-sp-4) 0;
139
+ font-family: var(--blog-font-display);
140
+ font-weight: 600;
141
+ font-size: var(--blog-fs-lg);
142
+ line-height: 1.4;
143
+ color: var(--blog-ink);
144
+ list-style: none;
145
+ cursor: pointer;
146
+ transition: color .15s ease;
147
+ }
148
+ .bk-faq__summary::-webkit-details-marker { display: none; }
149
+ .bk-faq__summary:hover { color: var(--blog-brand); }
150
+ .bk-faq__toggle {
151
+ position: relative;
152
+ display: inline-flex;
153
+ align-items: center;
154
+ justify-content: center;
155
+ flex-shrink: 0;
156
+ width: 1.75rem;
157
+ height: 1.75rem;
158
+ border-radius: var(--blog-radius-pill);
159
+ background: var(--blog-brand-soft);
160
+ color: var(--blog-brand);
161
+ transition: background .2s ease, color .2s ease, transform .2s ease;
162
+ }
163
+ .bk-faq__item[open] .bk-faq__toggle {
164
+ background: var(--blog-brand);
165
+ color: var(--blog-on-brand);
166
+ transform: rotate(45deg);
167
+ }
168
+ .bk-faq__bar {
169
+ position: absolute;
170
+ top: 50%;
171
+ left: 50%;
172
+ transform: translate(-50%, -50%);
173
+ background: currentColor;
174
+ border-radius: 1px;
175
+ }
176
+ .bk-faq__bar--h { width: .75rem; height: 2px; }
177
+ .bk-faq__bar--v { width: 2px; height: .75rem; }
178
+ .bk-faq__answer {
179
+ padding: 0 var(--blog-sp-1) var(--blog-sp-5) 0;
180
+ font-family: var(--blog-font-body);
181
+ font-size: var(--blog-fs-md);
182
+ line-height: 1.6;
183
+ color: var(--blog-text);
184
+ }
185
+ .bk-faq__para { margin: 0 0 var(--blog-sp-3); }
186
+ .bk-faq__para:last-child { margin-bottom: 0; }
187
+
188
+ /* ── Checklist ───────────────────────────────────────────────
189
+ Canonical name: Checklist (+ sibling ChecklistItem)
190
+ Checklist: a list of {title, sub?, done?} rows on tinted tiles;
191
+ done rows get a filled brand-orange tick box + struck-through title.
192
+ ChecklistItem: a single standalone row on a paper tile; checked
193
+ rows get a filled success-green tick box + struck-through label.
194
+ Both use a text "✓" glyph (no SVG icon) faithful to the source.
195
+ ──────────────────────────────────────────────────────────── */
196
+ .bk-checklist {
197
+ list-style: none;
198
+ margin: var(--blog-sp-6) 0;
199
+ padding: 0;
200
+ display: flex;
201
+ flex-direction: column;
202
+ gap: var(--blog-sp-2);
203
+ }
204
+ .bk-checklist__item {
205
+ display: flex;
206
+ align-items: flex-start;
207
+ gap: var(--blog-sp-3);
208
+ padding: var(--blog-sp-3) var(--blog-sp-4);
209
+ background: var(--blog-bg-secondary);
210
+ border: 1px solid var(--blog-border);
211
+ border-radius: var(--blog-radius-xs);
212
+ }
213
+ .bk-checklist__box {
214
+ flex: 0 0 auto;
215
+ display: inline-flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ width: 22px;
219
+ height: 22px;
220
+ border: 1.5px solid var(--blog-border);
221
+ border-radius: var(--blog-radius-xs);
222
+ background: transparent;
223
+ color: var(--blog-on-brand);
224
+ font-family: var(--blog-font-display);
225
+ font-weight: 700;
226
+ font-size: var(--blog-fs-sm);
227
+ line-height: 1;
228
+ }
229
+ .bk-checklist__item--done .bk-checklist__box {
230
+ background: var(--blog-brand);
231
+ border-color: var(--blog-brand);
232
+ }
233
+ .bk-checklist__text {
234
+ flex: 1 1 auto;
235
+ min-width: 0;
236
+ }
237
+ .bk-checklist__title {
238
+ display: block;
239
+ font-family: var(--blog-font-body);
240
+ font-weight: 600;
241
+ font-size: var(--blog-fs-md);
242
+ line-height: 1.4;
243
+ color: var(--blog-ink);
244
+ }
245
+ .bk-checklist__item--done .bk-checklist__title {
246
+ text-decoration: line-through;
247
+ text-decoration-color: var(--blog-mute);
248
+ }
249
+ .bk-checklist__sub {
250
+ display: block;
251
+ margin-top: 2px;
252
+ font-family: var(--blog-font-body);
253
+ font-size: var(--blog-fs-sm);
254
+ line-height: 1.5;
255
+ color: var(--blog-mute);
256
+ }
257
+
258
+ /* ── ChecklistItem (single standalone row) ──────────────────── */
259
+ .bk-checklist-item {
260
+ display: flex;
261
+ align-items: flex-start;
262
+ gap: var(--blog-sp-3);
263
+ margin: var(--blog-sp-3) 0;
264
+ padding: var(--blog-sp-3) var(--blog-sp-4);
265
+ background: var(--blog-paper);
266
+ border: 1px solid var(--blog-border);
267
+ border-radius: var(--blog-radius-xs);
268
+ }
269
+ .bk-checklist-item__box {
270
+ flex: 0 0 auto;
271
+ margin-top: 1px;
272
+ display: inline-flex;
273
+ align-items: center;
274
+ justify-content: center;
275
+ width: 22px;
276
+ height: 22px;
277
+ border: 2px solid var(--blog-border);
278
+ border-radius: var(--blog-radius-xs);
279
+ background: transparent;
280
+ color: var(--blog-on-brand);
281
+ font-family: var(--blog-font-display);
282
+ font-weight: 700;
283
+ font-size: var(--blog-fs-sm);
284
+ line-height: 1;
285
+ }
286
+ .bk-checklist-item--checked .bk-checklist-item__box {
287
+ background: var(--blog-success);
288
+ border-color: var(--blog-success);
289
+ }
290
+ .bk-checklist-item__text {
291
+ flex: 1 1 auto;
292
+ min-width: 0;
293
+ }
294
+ .bk-checklist-item__label {
295
+ display: block;
296
+ font-family: var(--blog-font-display);
297
+ font-weight: 700;
298
+ font-size: var(--blog-fs-base);
299
+ line-height: 1.4;
300
+ color: var(--blog-ink);
301
+ }
302
+ .bk-checklist-item--checked .bk-checklist-item__label {
303
+ color: var(--blog-mute);
304
+ text-decoration: line-through;
305
+ }
306
+ .bk-checklist-item__desc {
307
+ display: block;
308
+ margin-top: 2px;
309
+ font-family: var(--blog-font-body);
310
+ font-size: var(--blog-fs-sm);
311
+ line-height: 1.5;
312
+ color: var(--blog-mute);
313
+ }
314
+
315
+ /* ============================================================
316
+ List — ordered / bullet / check list with branded markers
317
+ Ported from capture-ai blog List.tsx (#FF4206 → --blog-brand,
318
+ brand-orange-soft → --blog-brand-soft). Three variants share
319
+ one marker slot; ordered uses zero-padded display counters.
320
+ ============================================================ */
321
+ .bk-list { margin: var(--blog-sp-6) 0; font-family: var(--blog-font-body); }
322
+
323
+ .bk-list__heading {
324
+ margin: 0 0 var(--blog-sp-3);
325
+ font-family: var(--blog-font-display);
326
+ font-weight: 700;
327
+ font-size: var(--blog-fs-sm);
328
+ letter-spacing: var(--blog-tracking-wide);
329
+ text-transform: uppercase;
330
+ color: var(--blog-brand);
331
+ }
332
+
333
+ .bk-list__items {
334
+ display: flex;
335
+ flex-direction: column;
336
+ gap: var(--blog-sp-3);
337
+ margin: 0;
338
+ padding: 0;
339
+ list-style: none;
340
+ }
341
+
342
+ .bk-list__item {
343
+ display: flex;
344
+ align-items: flex-start;
345
+ gap: var(--blog-sp-3);
346
+ margin: 0;
347
+ font-size: var(--blog-fs-lg);
348
+ line-height: 1.55;
349
+ color: var(--blog-text);
350
+ }
351
+
352
+ .bk-list__marker { flex: 0 0 auto; }
353
+
354
+ .bk-list__text > strong { font-weight: 700; color: var(--blog-ink); }
355
+ .bk-list__text > :first-child { margin-top: 0; }
356
+ .bk-list__text > :last-child { margin-bottom: 0; }
357
+
358
+ /* ordered — zero-padded display counters */
359
+ .bk-list--ordered .bk-list__marker {
360
+ min-width: 30px;
361
+ padding-top: 2px;
362
+ font-family: var(--blog-font-display);
363
+ font-weight: 800;
364
+ font-size: var(--blog-fs-md);
365
+ line-height: 1.4;
366
+ color: var(--blog-brand);
367
+ }
368
+
369
+ /* bullet — brand dot */
370
+ .bk-list--bullet .bk-list__marker {
371
+ width: 8px;
372
+ height: 8px;
373
+ margin-top: 8px;
374
+ border-radius: var(--blog-radius-pill);
375
+ background: var(--blog-brand);
376
+ }
377
+
378
+ /* check — tick inside a tinted brand circle */
379
+ .bk-list--check .bk-list__marker {
380
+ display: inline-flex;
381
+ align-items: center;
382
+ justify-content: center;
383
+ width: 20px;
384
+ height: 20px;
385
+ margin-top: 1px;
386
+ border-radius: var(--blog-radius-pill);
387
+ background: var(--blog-brand-soft);
388
+ color: var(--blog-brand);
389
+ }
390
+ .bk-list--check .bk-list__marker svg { display: block; width: 14px; height: 14px; }
391
+
392
+ /* ============================================================
393
+ StepBlock — numbered step card (badge + title + body)
394
+ ============================================================ */
395
+ .bk-step { display:grid; grid-template-columns:36px 1fr; gap:var(--blog-sp-3); align-items:start; margin:var(--blog-sp-3) 0; padding:var(--blog-sp-3) var(--blog-sp-4); background:var(--blog-paper); border:1px solid var(--blog-border); border-radius:var(--blog-radius-xs); }
396
+ .bk-step__num { width:36px; height:36px; border-radius:var(--blog-radius-pill); display:flex; align-items:center; justify-content:center; background:var(--blog-brand); color:var(--blog-on-brand); font-family:var(--blog-font-display); font-weight:800; font-size: var(--blog-fs-lg); line-height:1; }
397
+ .bk-step__main { min-width:0; }
398
+ .bk-step__title { margin:.375rem 0 var(--blog-sp-1); font-family:var(--blog-font-display); font-weight:700; font-size: var(--blog-fs-md); line-height:1.3; text-transform:uppercase; letter-spacing:.02em; color:var(--blog-ink); }
399
+ .bk-step__body { font-family:var(--blog-font-body); font-size: var(--blog-fs-base); line-height:1.5; color:var(--blog-text); }
400
+ .bk-step__body > p { margin:0; }
401
+ .bk-step__body > p + p { margin-top:var(--blog-sp-2); }
402
+ @media (min-width:640px) { .bk-step { grid-template-columns:44px 1fr; gap:var(--blog-sp-4); padding:var(--blog-sp-4) var(--blog-sp-5); } .bk-step__num { width:44px; height:44px; font-size:1.25rem; } }
403
+
404
+ /* ── ComparisonTable ─────────────────────────────────────────
405
+ Canonical name: ComparisonTable
406
+ Side-by-side comparison of two options across features. Renders
407
+ twice from the SAME data: stacked cards (<640px, avoids the
408
+ hidden-horizontal-scroll trap) and a table (≥640px). The
409
+ [data-bk-comparison] behaviour toggles edge-fade hint classes
410
+ when the table overflows its scroll container.
411
+ Cells reading "yes"/✓ or "no"/✕ render as coloured glyph marks.
412
+ ──────────────────────────────────────────────────────────── */
413
+ .bk-comparison { margin: var(--blog-sp-7) 0; }
414
+
415
+ .bk-comparison__title {
416
+ margin: 0 0 var(--blog-sp-3);
417
+ font-family: var(--blog-font-display);
418
+ font-weight: 700;
419
+ font-size: var(--blog-fs-lg);
420
+ text-transform: uppercase;
421
+ letter-spacing: var(--blog-tracking-wide);
422
+ color: var(--blog-ink);
423
+ }
424
+
425
+ /* Mobile: stacked cards (one per feature). */
426
+ .bk-comparison__cards {
427
+ display: flex;
428
+ flex-direction: column;
429
+ gap: var(--blog-sp-3);
430
+ }
431
+ .bk-comparison__card {
432
+ border: 1px solid var(--blog-border);
433
+ border-radius: var(--blog-radius-xs);
434
+ background: var(--blog-paper);
435
+ overflow: hidden;
436
+ }
437
+ .bk-comparison__card-feature {
438
+ padding: var(--blog-sp-2) var(--blog-sp-4);
439
+ background: var(--blog-bg-secondary);
440
+ border-bottom: 1px solid var(--blog-border);
441
+ font-family: var(--blog-font-display);
442
+ font-weight: 700;
443
+ font-size: var(--blog-fs-eyebrow);
444
+ text-transform: uppercase;
445
+ letter-spacing: var(--blog-tracking-wide);
446
+ color: var(--blog-mute);
447
+ }
448
+ .bk-comparison__card-row {
449
+ display: flex;
450
+ align-items: flex-start;
451
+ justify-content: space-between;
452
+ gap: var(--blog-sp-3);
453
+ padding: var(--blog-sp-3) var(--blog-sp-4);
454
+ }
455
+ .bk-comparison__card-row:first-of-type { border-bottom: 1px dashed var(--blog-border-light); }
456
+ .bk-comparison__card-row--best { background: var(--blog-brand-tint); }
457
+ .bk-comparison__card-label {
458
+ flex: 0 0 auto;
459
+ font-family: var(--blog-font-display);
460
+ font-weight: 700;
461
+ font-size: var(--blog-fs-eyebrow);
462
+ text-transform: uppercase;
463
+ letter-spacing: var(--blog-tracking-wide);
464
+ color: var(--blog-mute);
465
+ }
466
+ .bk-comparison__card-row > :last-child {
467
+ font-family: var(--blog-font-body);
468
+ font-size: var(--blog-fs-sm);
469
+ text-align: right;
470
+ color: var(--blog-ink);
471
+ }
472
+ .bk-comparison__card-row--best > :last-child { color: var(--blog-brand); font-weight: 600; }
473
+
474
+ /* Tablet/desktop: table layout. */
475
+ .bk-comparison__table-wrap {
476
+ display: none;
477
+ position: relative;
478
+ border: 1px solid var(--blog-border);
479
+ border-radius: var(--blog-radius-xs);
480
+ background: var(--blog-paper);
481
+ overflow: hidden;
482
+ }
483
+ /* Round the scroller to the wrap's radius so the thead fills the corners
484
+ (otherwise the wrap's paper bg shows as a band above the header row). */
485
+ .bk-comparison__scroll { overflow-x: auto; border-radius: inherit; }
486
+ .bk-comparison__table { width: 100%; border-collapse: collapse; }
487
+ .bk-comparison__th {
488
+ text-align: left;
489
+ padding: var(--blog-sp-3) var(--blog-sp-4);
490
+ background: var(--blog-bg-secondary);
491
+ border-bottom: 1px solid var(--blog-border);
492
+ font-family: var(--blog-font-display);
493
+ font-weight: 700;
494
+ font-size: var(--blog-fs-xs);
495
+ text-transform: uppercase;
496
+ letter-spacing: var(--blog-tracking-wide);
497
+ color: var(--blog-mute);
498
+ }
499
+ .bk-comparison__td {
500
+ padding: var(--blog-sp-3) var(--blog-sp-4);
501
+ border-bottom: 1px solid var(--blog-border);
502
+ font-family: var(--blog-font-body);
503
+ font-size: var(--blog-fs-base);
504
+ color: var(--blog-text);
505
+ }
506
+ .bk-comparison__tr:last-child .bk-comparison__td { border-bottom: none; }
507
+ .bk-comparison__td--feature { color: var(--blog-ink); }
508
+ .bk-comparison__td--best { background: var(--blog-brand-tint); color: var(--blog-brand); font-weight: 600; }
509
+
510
+ /* Glyph marks for yes/no cells. */
511
+ .bk-comparison__mark { font-weight: 700; }
512
+ .bk-comparison__mark--yes { color: var(--blog-success); }
513
+ .bk-comparison__mark--no { color: var(--blog-danger); }
514
+ .bk-comparison__value--best { color: var(--blog-brand); font-weight: 600; }
515
+
516
+ /* Scroll-edge hint fades, toggled by the behaviour on overflow. */
517
+ .bk-comparison__table-wrap::before,
518
+ .bk-comparison__table-wrap::after {
519
+ content: "";
520
+ position: absolute;
521
+ top: 0;
522
+ bottom: 0;
523
+ width: var(--blog-sp-6);
524
+ pointer-events: none;
525
+ opacity: 0;
526
+ transition: opacity 0.15s ease;
527
+ z-index: 1;
528
+ }
529
+ .bk-comparison__table-wrap::before {
530
+ left: 0;
531
+ background: linear-gradient(to right, var(--blog-paper), transparent);
532
+ }
533
+ .bk-comparison__table-wrap::after {
534
+ right: 0;
535
+ background: linear-gradient(to left, var(--blog-paper), transparent);
536
+ }
537
+ .bk-comparison__table-wrap--hint-left::before { opacity: 1; }
538
+ .bk-comparison__table-wrap--hint-right::after { opacity: 1; }
539
+
540
+ @media (min-width: 640px) {
541
+ .bk-comparison__cards { display: none; }
542
+ .bk-comparison__table-wrap { display: block; }
543
+ }
544
+
545
+ /* ProConBlock — side-by-side pros/cons cards (aliases: ProsCons) */
546
+ .bk-procon { display:grid; grid-template-columns:1fr; gap:var(--blog-sp-3); margin:var(--blog-sp-6) 0; }
547
+ @media (min-width:640px) { .bk-procon { grid-template-columns:1fr 1fr; } }
548
+ .bk-procon__card { --_c:var(--blog-success); --_bg:var(--blog-success-bg); background:var(--_bg); border:1px solid color-mix(in srgb, var(--_c) 28%, transparent); border-radius:var(--blog-radius-xs); padding:var(--blog-sp-4); }
549
+ @media (min-width:640px) { .bk-procon__card { padding:var(--blog-sp-5); } }
550
+ .bk-procon__card--con { --_c:var(--blog-danger); --_bg:var(--blog-danger-bg); }
551
+ .bk-procon__heading { margin:0 0 var(--blog-sp-3); font-family:var(--blog-font-display); font-weight:700; font-size: var(--blog-fs-base); text-transform:uppercase; letter-spacing:var(--blog-tracking-wide); color:var(--_c); }
552
+ .bk-procon__list { list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:var(--blog-sp-2); }
553
+ .bk-procon__item { display:flex; gap:var(--blog-sp-2); font-family:var(--blog-font-body); font-size: var(--blog-fs-base); line-height:1.45; color:var(--blog-text); }
554
+ .bk-procon__mark { flex-shrink:0; width:18px; height:18px; margin-top:.1rem; border-radius:var(--blog-radius-pill); display:flex; align-items:center; justify-content:center; background:var(--_c); color:var(--blog-on-brand); font-size: var(--blog-fs-eyebrow); font-weight:700; line-height:1; }
555
+ .bk-procon__text { display:block; }
556
+
557
+ /* ============================================================
558
+ BeforeAfter — two-card comparison (muted "before" vs brand "after")
559
+ Faithful port of capture-ai BeforeAfter.tsx, tokenised.
560
+ ============================================================ */
561
+ .bk-before-after { display:grid; grid-template-columns:1fr; gap:var(--blog-sp-3); margin:var(--blog-sp-6) 0; align-items:stretch; }
562
+ @media (min-width:768px){ .bk-before-after { grid-template-columns:1fr 1fr; } }
563
+ .bk-before-after__card { padding:var(--blog-sp-4); border-radius:var(--blog-radius-xs); border:1px solid var(--blog-border); }
564
+ @media (min-width:640px){ .bk-before-after__card { padding:var(--blog-sp-5); } }
565
+ .bk-before-after__card--before { background:var(--blog-bg-secondary); border-color:var(--blog-border); }
566
+ .bk-before-after__card--after { background:var(--blog-brand); border-color:var(--blog-brand); color:var(--blog-on-brand); }
567
+ .bk-before-after__label { font-family:var(--blog-font-display); font-weight:700; text-transform:uppercase; font-size: var(--blog-fs-eyebrow); letter-spacing:var(--blog-tracking-wide); color:var(--blog-mute); }
568
+ .bk-before-after__card--after .bk-before-after__label { color:color-mix(in srgb, var(--blog-on-brand) 78%, transparent); }
569
+ .bk-before-after__value { font-family:var(--blog-font-display); font-weight:800; font-size: var(--blog-fs-7xl); line-height:.9; margin:var(--blog-sp-2) 0; color:var(--blog-ink); }
570
+ @media (min-width:640px){ .bk-before-after__value { font-size: var(--blog-fs-8xl); } }
571
+ .bk-before-after__card--after .bk-before-after__value { color:var(--blog-on-brand); }
572
+ .bk-before-after__body { font-family:var(--blog-font-body); font-size: var(--blog-fs-base); line-height:1.45; margin:var(--blog-sp-2) 0 0; color:var(--blog-text); }
573
+ .bk-before-after__card--after .bk-before-after__body { color:color-mix(in srgb, var(--blog-on-brand) 85%, transparent); }
574
+
575
+ /* ============================================================
576
+ ImageFeature — captioned figure with optional float (left/right/full)
577
+ Ported from capture-ai blog ImageFeature.tsx.
578
+ 16/9 framed image, optional caption + credit footer.
579
+ ============================================================ */
580
+ .bk-image-feature { margin: var(--blog-sp-7) 0; width: 100%; border: 1px solid var(--blog-border); border-radius: var(--blog-radius-xs); overflow: hidden; background: var(--blog-paper); }
581
+ .bk-image-feature__frame { position: relative; aspect-ratio: 16 / 9; width: 100%; overflow: hidden; background: var(--blog-dark); }
582
+ .bk-image-feature__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
583
+ .bk-image-feature__caption { display: flex; justify-content: space-between; gap: var(--blog-sp-3); padding: var(--blog-sp-3) var(--blog-sp-4); border-top: 1px solid var(--blog-border); font-family: var(--blog-font-body); font-size: var(--blog-fs-sm); line-height: 1.5; color: var(--blog-mute); }
584
+ .bk-image-feature__text { color: var(--blog-text); }
585
+ .bk-image-feature__credit { color: var(--blog-mute); white-space: nowrap; }
586
+ @media (min-width: 640px) {
587
+ .bk-image-feature--left { float: left; width: 50%; margin-right: var(--blog-sp-8); }
588
+ .bk-image-feature--right { float: right; width: 50%; margin-left: var(--blog-sp-8); }
589
+ }
590
+
591
+ /* ── Infographic ──────────────────────────────────────────────
592
+ AI-generated brand-locked infographic. Deliberately frameless,
593
+ borderless and caption-less — the image is the whole point and
594
+ renders at its natural aspect ratio so nothing is cropped. */
595
+ .bk-infographic { margin: var(--blog-sp-7) 0; }
596
+ .bk-infographic__img { display: block; width: 100%; height: auto; }
597
+
598
+ /* ── CodeSnippet ─────────────────────────────────────────────
599
+ Canonical name: CodeSnippet
600
+ Dark code block with a header bar (filename/language label +
601
+ copy button) and a scrollable <pre>. The copy interaction is
602
+ handled by core/behaviors/code.js, wired via [data-bk-code].
603
+ All ink/surface colours key off the --blog-dark* / --blog-on-dark
604
+ tokens so it reads correctly on any tenant theme.
605
+ ──────────────────────────────────────────────────────────── */
606
+ .bk-code {
607
+ margin: var(--blog-sp-6) 0;
608
+ border: 1px solid var(--blog-border-dark);
609
+ border-radius: var(--blog-radius-xs);
610
+ background: var(--blog-dark);
611
+ overflow: hidden;
612
+ }
613
+
614
+ .bk-code__bar {
615
+ display: flex;
616
+ align-items: center;
617
+ justify-content: space-between;
618
+ gap: var(--blog-sp-3);
619
+ padding: var(--blog-sp-2) var(--blog-sp-4);
620
+ background: var(--blog-dark-2);
621
+ border-bottom: 1px solid var(--blog-border-dark);
622
+ font-family: var(--blog-font-mono);
623
+ font-size: var(--blog-fs-xs);
624
+ line-height: 1.4;
625
+ }
626
+
627
+ .bk-code__label {
628
+ color: var(--blog-on-dark);
629
+ overflow: hidden;
630
+ text-overflow: ellipsis;
631
+ white-space: nowrap;
632
+ }
633
+
634
+ .bk-code__copy {
635
+ display: inline-flex;
636
+ align-items: center;
637
+ gap: var(--blog-sp-1);
638
+ flex: 0 0 auto;
639
+ margin: 0;
640
+ padding: 0;
641
+ border: 0;
642
+ background: transparent;
643
+ color: var(--blog-brand);
644
+ font-family: var(--blog-font-display);
645
+ font-size: var(--blog-fs-eyebrow-sm);
646
+ font-weight: 700;
647
+ letter-spacing: var(--blog-tracking-wide);
648
+ text-transform: uppercase;
649
+ cursor: pointer;
650
+ transition: color 0.15s ease;
651
+ }
652
+ .bk-code__copy:hover { color: var(--blog-brand-bright); }
653
+ .bk-code__copy[data-copied="true"] { color: var(--blog-success); }
654
+
655
+ .bk-code__copy-icon { display: inline-flex; }
656
+ .bk-code__copy-icon svg { display: block; width: 13px; height: 13px; }
657
+
658
+ .bk-code__pre {
659
+ margin: 0;
660
+ padding: var(--blog-sp-3) var(--blog-sp-4);
661
+ overflow-x: auto;
662
+ color: var(--blog-on-dark);
663
+ font-family: var(--blog-font-mono);
664
+ font-size: var(--blog-fs-xs);
665
+ line-height: 1.6;
666
+ tab-size: 2;
667
+ }
668
+
669
+ .bk-code__code {
670
+ font-family: inherit;
671
+ font-size: inherit;
672
+ color: inherit;
673
+ background: none;
674
+ white-space: pre;
675
+ }
676
+
677
+ @media (min-width: 640px) {
678
+ .bk-code__pre {
679
+ padding: var(--blog-sp-4) var(--blog-sp-5);
680
+ font-size: var(--blog-fs-sm);
681
+ }
682
+ }
683
+
684
+ /* ── CTABanner ───────────────────────────────────────────────
685
+ Canonical name: CTABanner
686
+ Dark, full-bleed call-to-action banner with a brand-coloured
687
+ radial glow, heading + description, and a solid brand CTA link.
688
+ Ported from capture-ai's blog CTABanner (hardcoded #000 / #fff /
689
+ #FF4206 mapped to --blog-dark / --blog-on-dark / --blog-brand).
690
+ ──────────────────────────────────────────────────────────── */
691
+ .bk-cta-banner {
692
+ position: relative;
693
+ overflow: hidden;
694
+ margin: var(--blog-sp-8) 0;
695
+ padding: var(--blog-sp-6);
696
+ border-radius: var(--blog-radius-xs);
697
+ background: var(--blog-dark);
698
+ color: var(--blog-on-dark);
699
+ }
700
+ .bk-cta-banner__glow {
701
+ position: absolute;
702
+ top: -2.5rem;
703
+ right: -2.5rem;
704
+ width: 200px;
705
+ height: 200px;
706
+ border-radius: var(--blog-radius-pill);
707
+ pointer-events: none;
708
+ background: radial-gradient(
709
+ circle at 30% 30%,
710
+ color-mix(in srgb, var(--blog-brand) 40%, transparent),
711
+ transparent 60%
712
+ );
713
+ }
714
+ .bk-cta-banner__inner {
715
+ position: relative;
716
+ display: flex;
717
+ flex-direction: column;
718
+ gap: var(--blog-sp-4);
719
+ }
720
+ .bk-cta-banner__copy { min-width: 0; }
721
+ .bk-cta-banner__heading {
722
+ margin: 0 0 var(--blog-sp-1);
723
+ font-family: var(--blog-font-display);
724
+ font-weight: 800;
725
+ text-transform: uppercase;
726
+ font-size: var(--blog-fs-2xl);
727
+ line-height: 1.1;
728
+ color: var(--blog-on-dark);
729
+ }
730
+ .bk-cta-banner__desc {
731
+ margin: 0;
732
+ font-family: var(--blog-font-body);
733
+ font-size: var(--blog-fs-base);
734
+ line-height: 1.5;
735
+ color: var(--blog-on-dark-mute);
736
+ }
737
+ .bk-cta-banner__cta {
738
+ display: inline-flex;
739
+ align-items: center;
740
+ justify-content: center;
741
+ align-self: flex-start;
742
+ flex-shrink: 0;
743
+ gap: var(--blog-sp-2);
744
+ padding: var(--blog-sp-3) var(--blog-sp-5);
745
+ border-radius: var(--blog-radius-sm);
746
+ font-family: var(--blog-font-display);
747
+ font-weight: 700;
748
+ text-transform: uppercase;
749
+ letter-spacing: var(--blog-tracking-wide);
750
+ font-size: var(--blog-fs-sm);
751
+ white-space: nowrap;
752
+ text-decoration: none;
753
+ background: var(--blog-brand);
754
+ color: var(--blog-on-brand);
755
+ }
756
+ .bk-cta-banner__cta:hover { background: var(--blog-brand-dark); }
757
+ .bk-cta-banner__cta-icon svg {
758
+ display: block;
759
+ width: 14px;
760
+ height: 12px;
761
+ }
762
+ @media (min-width: 640px) {
763
+ .bk-cta-banner { padding: var(--blog-sp-8); }
764
+ .bk-cta-banner__glow {
765
+ top: -60px;
766
+ right: -60px;
767
+ width: 300px;
768
+ height: 300px;
769
+ }
770
+ .bk-cta-banner__inner {
771
+ flex-direction: row;
772
+ align-items: center;
773
+ justify-content: space-between;
774
+ gap: var(--blog-sp-6);
775
+ }
776
+ .bk-cta-banner__cta { align-self: auto; }
777
+ .bk-cta-banner__heading { font-size: var(--blog-fs-4xl); }
778
+ }
779
+
780
+ /* ── NewsletterCTA ───────────────────────────────────────────
781
+ Canonical name: NewsletterCTA
782
+ Dark email-capture block: heading + description on one side, an
783
+ inline subscribe form (with visually-hidden honeypot) on the other.
784
+ A brand radial glow sits in the top-right corner. Form posts
785
+ natively to its `action`; the kit ships no client JS.
786
+ Ported from capture-ai's NewsletterCTA — #000 → --blog-dark,
787
+ #fff → --blog-on-dark, brand orange #FF4206 → --blog-brand,
788
+ white-70% copy → --blog-on-dark-mute.
789
+ ──────────────────────────────────────────────────────────── */
790
+ .bk-newsletter {
791
+ position: relative;
792
+ overflow: hidden;
793
+ display: grid;
794
+ grid-template-columns: 1fr;
795
+ gap: var(--blog-sp-5);
796
+ align-items: center;
797
+ margin: var(--blog-sp-8) 0;
798
+ padding: var(--blog-sp-6);
799
+ border-radius: var(--blog-radius-xs);
800
+ background: var(--blog-dark);
801
+ color: var(--blog-on-dark);
802
+ }
803
+ @media (min-width: 640px) {
804
+ .bk-newsletter { gap: var(--blog-sp-7); padding: var(--blog-sp-8); }
805
+ }
806
+ @media (min-width: 768px) {
807
+ .bk-newsletter { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); }
808
+ }
809
+
810
+ .bk-newsletter__glow {
811
+ position: absolute;
812
+ top: -2.5rem;
813
+ right: -2.5rem;
814
+ width: 200px;
815
+ height: 200px;
816
+ border-radius: var(--blog-radius-pill);
817
+ background: radial-gradient(circle at 30% 30%, color-mix(in srgb, var(--blog-brand) 40%, transparent), transparent 60%);
818
+ pointer-events: none;
819
+ }
820
+ @media (min-width: 640px) {
821
+ .bk-newsletter__glow { top: -60px; right: -60px; width: 300px; height: 300px; }
822
+ }
823
+
824
+ .bk-newsletter__copy { position: relative; }
825
+ .bk-newsletter__heading {
826
+ margin: 0 0 var(--blog-sp-2);
827
+ font-family: var(--blog-font-display);
828
+ font-weight: 800;
829
+ font-size: var(--blog-fs-3xl);
830
+ line-height: 1.05;
831
+ text-transform: uppercase;
832
+ letter-spacing: var(--blog-tracking-tight);
833
+ color: var(--blog-on-dark);
834
+ }
835
+ @media (min-width: 640px) {
836
+ .bk-newsletter__heading { font-size: var(--blog-fs-5xl); line-height: 1; }
837
+ }
838
+ .bk-newsletter__desc {
839
+ margin: 0;
840
+ font-family: var(--blog-font-body);
841
+ font-size: var(--blog-fs-base);
842
+ line-height: 1.5;
843
+ color: var(--blog-on-dark-mute);
844
+ }
845
+
846
+ .bk-newsletter__action { position: relative; }
847
+ .bk-newsletter__form { display: flex; gap: var(--blog-sp-2); }
848
+
849
+ .bk-newsletter__honeypot {
850
+ position: absolute;
851
+ left: -9999px;
852
+ width: 0;
853
+ height: 0;
854
+ opacity: 0;
855
+ pointer-events: none;
856
+ }
857
+
858
+ .bk-newsletter__input {
859
+ flex: 1 1 auto;
860
+ min-width: 0;
861
+ padding: var(--blog-sp-3) var(--blog-sp-3);
862
+ border: 1px solid var(--blog-paper);
863
+ border-radius: var(--blog-radius-sm);
864
+ background: var(--blog-paper);
865
+ font-family: var(--blog-font-body);
866
+ font-size: var(--blog-fs-base);
867
+ color: var(--blog-ink);
868
+ outline: none;
869
+ }
870
+ .bk-newsletter__input:focus-visible {
871
+ border-color: var(--blog-brand);
872
+ box-shadow: var(--blog-shadow-focus-ring);
873
+ }
874
+ .bk-newsletter__input::placeholder { color: var(--blog-mute); }
875
+
876
+ .bk-newsletter__button {
877
+ flex: 0 0 auto;
878
+ padding: var(--blog-sp-3) var(--blog-sp-5);
879
+ border: 0;
880
+ border-radius: var(--blog-radius-sm);
881
+ background: var(--blog-brand);
882
+ color: var(--blog-on-brand);
883
+ font-family: var(--blog-font-display);
884
+ font-weight: 700;
885
+ font-size: var(--blog-fs-sm);
886
+ text-transform: uppercase;
887
+ letter-spacing: var(--blog-tracking-wide);
888
+ white-space: nowrap;
889
+ cursor: pointer;
890
+ }
891
+ .bk-newsletter__button:hover { background: var(--blog-brand-dark); }
892
+
893
+ /* ============================================================
894
+ AuthorCard — .bk-author
895
+ Byline card: avatar (or initials fallback) + name / role / bio / links.
896
+ Ported from capture-ai blog AuthorCard; tokenised, self-contained.
897
+ ============================================================ */
898
+ .bk-author { display:flex; align-items:center; gap:var(--blog-sp-3); margin:var(--blog-sp-6) 0; padding:var(--blog-sp-4) var(--blog-sp-4); background:var(--blog-bg-secondary); border:1px solid var(--blog-border); border-radius:var(--blog-radius-xs); }
899
+ .bk-author__media { flex:0 0 auto; }
900
+ .bk-author__avatar { display:block; width:56px; height:56px; border-radius:var(--blog-radius-pill); object-fit:cover; }
901
+ .bk-author__avatar--fallback { display:flex; align-items:center; justify-content:center; background:var(--blog-brand-tint); color:var(--blog-brand); font-family:var(--blog-font-display); font-weight:800; font-size: var(--blog-fs-xl); text-transform:uppercase; letter-spacing:var(--blog-tracking-tight); }
902
+ .bk-author__body { flex:1 1 auto; min-width:0; }
903
+ .bk-author__name { margin:0; font-family:var(--blog-font-display); font-weight:800; text-transform:uppercase; font-size: var(--blog-fs-xl); line-height:1.2; color:var(--blog-ink); }
904
+ .bk-author__role { margin:.125rem 0 0; font-family:var(--blog-font-body); font-size: var(--blog-fs-sm); color:var(--blog-mute); }
905
+ .bk-author__bio { margin:var(--blog-sp-2) 0 0; font-family:var(--blog-font-body); font-size: var(--blog-fs-sm); line-height:1.5; color:var(--blog-text); }
906
+ .bk-author__links { display:flex; flex-wrap:wrap; gap:var(--blog-sp-3); margin-top:var(--blog-sp-3); }
907
+ .bk-author__link { font-family:var(--blog-font-display); font-weight:700; text-transform:uppercase; font-size: var(--blog-fs-eyebrow); letter-spacing:var(--blog-tracking-wide); color:var(--blog-brand); text-decoration:none; }
908
+ .bk-author__link:hover { color:var(--blog-brand-dark); }
909
+ @media (min-width:640px) { .bk-author { gap:var(--blog-sp-4); padding:var(--blog-sp-5) var(--blog-sp-5); } .bk-author__avatar { width:64px; height:64px; } }
910
+
911
+ /* ============================================================
912
+ RelatedPosts — "Keep reading" grid of related-post cards.
913
+ Responsive 1/2/3-col grid; featured-image thumbnail with a
914
+ tokenised gradient placeholder fallback cycled per index.
915
+ ============================================================ */
916
+ .bk-related { margin: var(--blog-sp-10) 0; }
917
+ .bk-related__eyebrow { margin: 0 0 var(--blog-sp-3); font-family: var(--blog-font-display); font-weight: 700; text-transform: uppercase; font-size: var(--blog-fs-sm); letter-spacing: var(--blog-tracking-wide); color: var(--blog-brand); }
918
+ .bk-related__grid { display: grid; grid-template-columns: 1fr; gap: var(--blog-sp-3); }
919
+ @media (min-width: 640px) { .bk-related__grid { grid-template-columns: repeat(2, 1fr); } }
920
+ @media (min-width: 1024px) { .bk-related__grid { grid-template-columns: repeat(3, 1fr); } }
921
+ .bk-related__card { display: block; overflow: hidden; border: 1px solid var(--blog-border); border-radius: var(--blog-radius-xs); background: var(--blog-paper); text-decoration: none; transition: box-shadow .2s ease, transform .2s ease; }
922
+ .bk-related__card:hover { box-shadow: var(--blog-shadow-lg); }
923
+ .bk-related__thumb { position: relative; width: 100%; aspect-ratio: 16 / 10; background: var(--blog-bg-secondary); }
924
+ .bk-related__thumb--g1 { background: linear-gradient(135deg, var(--blog-brand-dark), var(--blog-brand) 70%, var(--blog-brand-soft)); }
925
+ .bk-related__thumb--g2 { background: linear-gradient(135deg, var(--blog-brand-dark), var(--blog-success)); }
926
+ .bk-related__thumb--g3 { background: linear-gradient(135deg, var(--blog-dark), var(--blog-dark-3)); }
927
+ .bk-related__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
928
+ .bk-related__body { padding: var(--blog-sp-4); }
929
+ .bk-related__cat { display: block; font-family: var(--blog-font-display); font-weight: 700; text-transform: uppercase; font-size: var(--blog-fs-eyebrow-sm); letter-spacing: var(--blog-tracking-wide); color: var(--blog-brand); }
930
+ .bk-related__title { margin: var(--blog-sp-1) 0 0; font-family: var(--blog-font-display); font-weight: 700; text-transform: uppercase; font-size: var(--blog-fs-md); line-height: 1.25; color: var(--blog-ink); text-wrap: pretty; }
931
+ .bk-related__excerpt { margin: var(--blog-sp-2) 0 0; font-family: var(--blog-font-body); font-size: var(--blog-fs-sm); line-height: 1.45; color: var(--blog-mute); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
932
+
933
+ /* ── FurtherReading ──────────────────────────────────────────
934
+ Canonical name: FurtherReading
935
+ Card listing external resources. Each row: a title link (left)
936
+ + a source/publisher label (right). Rows are dashed-separated;
937
+ the last row drops its separator. Stacks on narrow viewports.
938
+ ──────────────────────────────────────────────────────────── */
939
+ .bk-further-reading {
940
+ margin: var(--blog-sp-6) 0;
941
+ padding: var(--blog-sp-4) var(--blog-sp-5);
942
+ background: var(--blog-paper);
943
+ border: 1px solid var(--blog-border);
944
+ border-radius: var(--blog-radius-xs);
945
+ }
946
+ @media (min-width: 640px) {
947
+ .bk-further-reading { padding: var(--blog-sp-5) var(--blog-sp-6); }
948
+ }
949
+
950
+ .bk-further-reading__title {
951
+ display: flex;
952
+ align-items: center;
953
+ gap: var(--blog-sp-2);
954
+ margin: 0 0 var(--blog-sp-3);
955
+ font-family: var(--blog-font-display);
956
+ font-weight: 700;
957
+ font-size: var(--blog-fs-sm);
958
+ line-height: 1.3;
959
+ text-transform: uppercase;
960
+ letter-spacing: var(--blog-tracking-eyebrow);
961
+ color: var(--blog-brand);
962
+ }
963
+
964
+ .bk-further-reading__list {
965
+ display: flex;
966
+ flex-direction: column;
967
+ list-style: none;
968
+ margin: 0;
969
+ padding: 0;
970
+ }
971
+
972
+ .bk-further-reading__item {
973
+ display: flex;
974
+ flex-direction: column;
975
+ gap: var(--blog-sp-1);
976
+ padding: var(--blog-sp-2) 0;
977
+ border-bottom: 1px dashed var(--blog-border-light);
978
+ }
979
+ .bk-further-reading__item:last-child { border-bottom: none; }
980
+ @media (min-width: 640px) {
981
+ .bk-further-reading__item {
982
+ flex-direction: row;
983
+ align-items: center;
984
+ justify-content: space-between;
985
+ gap: var(--blog-sp-3);
986
+ }
987
+ }
988
+
989
+ .bk-further-reading__link {
990
+ font-family: var(--blog-font-body);
991
+ font-size: var(--blog-fs-base);
992
+ line-height: 1.5;
993
+ color: var(--blog-text);
994
+ text-decoration: none;
995
+ transition: color 0.15s ease;
996
+ }
997
+ .bk-further-reading__link:hover { text-decoration: underline; }
998
+ @media (min-width: 640px) {
999
+ .bk-further-reading__link { font-size: var(--blog-fs-md); }
1000
+ }
1001
+
1002
+ .bk-further-reading__source {
1003
+ font-family: var(--blog-font-mono);
1004
+ font-size: var(--blog-fs-eyebrow);
1005
+ text-transform: uppercase;
1006
+ letter-spacing: var(--blog-tracking-wide);
1007
+ color: var(--blog-mute);
1008
+ }
1009
+ @media (min-width: 640px) {
1010
+ .bk-further-reading__source { white-space: nowrap; }
1011
+ }
1012
+
1013
+ /* ── TableOfContents ─────────────────────────────────────────
1014
+ Canonical name: TableOfContents
1015
+ "In this article" nav. The <ul> is empty in markup — the toc
1016
+ behaviour ([data-bk-toc]) scans the article for <h2>s, fills
1017
+ the list with numbered entries, smooth-scrolls on click, and
1018
+ flags the in-view heading with .bk-toc__link--active. The nav
1019
+ hides itself (hidden attr) when there are no headings.
1020
+ ──────────────────────────────────────────────────────────── */
1021
+ .bk-toc {
1022
+ display: block;
1023
+ margin: var(--blog-sp-6) 0;
1024
+ padding: var(--blog-sp-4) var(--blog-sp-5);
1025
+ border: 1px solid var(--blog-border);
1026
+ border-radius: var(--blog-radius-xs);
1027
+ background: var(--blog-bg-secondary);
1028
+ }
1029
+ .bk-toc[hidden] { display: none; }
1030
+
1031
+ .bk-toc__heading {
1032
+ margin: 0 0 var(--blog-sp-3);
1033
+ font-family: var(--blog-font-display);
1034
+ font-weight: 700;
1035
+ font-size: var(--blog-fs-sm);
1036
+ text-transform: uppercase;
1037
+ letter-spacing: var(--blog-tracking-eyebrow);
1038
+ color: var(--blog-brand);
1039
+ }
1040
+
1041
+ .bk-toc__list {
1042
+ list-style: none;
1043
+ margin: 0;
1044
+ padding: 0;
1045
+ display: flex;
1046
+ flex-direction: column;
1047
+ }
1048
+
1049
+ .bk-toc__item {
1050
+ display: flex;
1051
+ align-items: baseline;
1052
+ gap: var(--blog-sp-3);
1053
+ padding: 0.625rem 0;
1054
+ border-bottom: 1px dashed var(--blog-border-light);
1055
+ }
1056
+ .bk-toc__item:last-child { border-bottom: none; }
1057
+
1058
+ .bk-toc__num {
1059
+ flex: 0 0 auto;
1060
+ width: 1.5rem;
1061
+ font-family: var(--blog-font-mono);
1062
+ font-size: var(--blog-fs-xs);
1063
+ color: var(--blog-mute);
1064
+ }
1065
+
1066
+ .bk-toc__link {
1067
+ flex: 1 1 auto;
1068
+ font-family: var(--blog-font-body);
1069
+ font-size: var(--blog-fs-md);
1070
+ line-height: 1.4;
1071
+ text-decoration: none;
1072
+ color: var(--blog-text);
1073
+ transition: color 0.15s ease;
1074
+ }
1075
+ .bk-toc__link:hover { color: var(--blog-brand); }
1076
+ .bk-toc__link--active { color: var(--blog-brand); }
1077
+
1078
+ /* ============================================================
1079
+ TimelineBlock — vertical timeline / recap of dated milestones.
1080
+ Ported from Capture AI's TimelineBlock (was TimelineRecap).
1081
+ A 2px rail runs the height of the list; each event hangs a
1082
+ ringed brand dot, a mono date, a display title and body copy.
1083
+ ============================================================ */
1084
+ .bk-timeline { position: relative; padding-left: var(--blog-sp-6); margin: var(--blog-sp-6) 0; }
1085
+ .bk-timeline__rail { position: absolute; top: var(--blog-sp-2); bottom: var(--blog-sp-2); left: 6px; width: 2px; background: var(--blog-border); }
1086
+ .bk-timeline__item { position: relative; }
1087
+ .bk-timeline__item:not(:last-child) { padding-bottom: var(--blog-sp-5); }
1088
+ .bk-timeline__dot { position: absolute; left: calc(-1 * var(--blog-sp-6)); top: 6px; width: 14px; height: 14px; border-radius: var(--blog-radius-pill); background: var(--blog-brand); border: 3px solid var(--blog-paper); box-shadow: var(--blog-shadow-ring); }
1089
+ .bk-timeline__date { font-family: var(--blog-font-mono); font-size: var(--blog-fs-eyebrow); line-height: 1.4; text-transform: uppercase; letter-spacing: var(--blog-tracking-wide); color: var(--blog-brand); }
1090
+ .bk-timeline__title { margin: var(--blog-sp-1) 0 var(--blog-sp-1); font-family: var(--blog-font-display); font-weight: 700; text-transform: uppercase; font-size: var(--blog-fs-lg); line-height: 1.3; color: var(--blog-ink); }
1091
+ .bk-timeline__desc { margin: 0; font-family: var(--blog-font-body); font-size: var(--blog-fs-base); line-height: 1.5; color: var(--blog-text); }
1092
+
1093
+ /* ============================================================
1094
+ StatCard (.bk-stat-card) — capture pack
1095
+ A single highlighted metric: big brand-coloured number (+ optional
1096
+ unit), an uppercase label, optional description, and an optional
1097
+ dashed-divider "SOURCE" attribution row that links out when given a
1098
+ URL. Ported from capture-ai's blog StatCard (+ inlined _SourceRow).
1099
+ ============================================================ */
1100
+ .bk-stat-card {
1101
+ margin: var(--blog-sp-6) 0;
1102
+ padding: var(--blog-sp-4) var(--blog-sp-5);
1103
+ background: var(--blog-paper);
1104
+ border: 1px solid var(--blog-border);
1105
+ border-radius: var(--blog-radius-xs);
1106
+ }
1107
+ .bk-stat-card__value {
1108
+ display: flex;
1109
+ align-items: baseline;
1110
+ font-family: var(--blog-font-display);
1111
+ color: var(--blog-brand);
1112
+ }
1113
+ .bk-stat-card__num {
1114
+ font-weight: 800;
1115
+ font-size: var(--blog-fs-7xl);
1116
+ line-height: .95;
1117
+ }
1118
+ .bk-stat-card__unit {
1119
+ margin-left: .125rem;
1120
+ font-weight: 500;
1121
+ font-size: var(--blog-fs-2xl);
1122
+ }
1123
+ .bk-stat-card__label {
1124
+ margin-top: var(--blog-sp-1);
1125
+ font-family: var(--blog-font-display);
1126
+ font-weight: 700;
1127
+ font-size: var(--blog-fs-xs);
1128
+ text-transform: uppercase;
1129
+ letter-spacing: .06em;
1130
+ color: var(--blog-mute);
1131
+ }
1132
+ .bk-stat-card__desc {
1133
+ margin-top: var(--blog-sp-1);
1134
+ font-family: var(--blog-font-body);
1135
+ font-size: var(--blog-fs-sm);
1136
+ line-height: 1.55;
1137
+ color: var(--blog-mute);
1138
+ }
1139
+ .bk-stat-card__source {
1140
+ display: inline-flex;
1141
+ align-items: center;
1142
+ gap: var(--blog-sp-1);
1143
+ margin-top: var(--blog-sp-3);
1144
+ padding-top: var(--blog-sp-2);
1145
+ border-top: 1px dashed var(--blog-border);
1146
+ font-family: var(--blog-font-display);
1147
+ font-size: var(--blog-fs-eyebrow);
1148
+ letter-spacing: .04em;
1149
+ color: var(--blog-mute);
1150
+ opacity: .8;
1151
+ text-decoration: none;
1152
+ transition: opacity .15s ease, color .15s ease;
1153
+ }
1154
+ .bk-stat-card__source--link:hover {
1155
+ opacity: 1;
1156
+ color: var(--blog-brand);
1157
+ }
1158
+ .bk-stat-card__source-kicker {
1159
+ margin-right: .125rem;
1160
+ font-weight: 700;
1161
+ font-size: var(--blog-fs-eyebrow-sm);
1162
+ text-transform: uppercase;
1163
+ letter-spacing: .08em;
1164
+ color: var(--blog-mute-2);
1165
+ }
1166
+ .bk-stat-card__source-icon svg {
1167
+ display: block;
1168
+ width: 10px;
1169
+ height: 10px;
1170
+ opacity: .7;
1171
+ }
1172
+
1173
+ /* ============================================================
1174
+ VerdictCard — dark, brand-bordered verdict panel
1175
+ Header: uppercase kicker + optional /10 score.
1176
+ Body: optional winner pill, big verdict headline, summary,
1177
+ and optional bullet chips. Ported from capture-ai's blog
1178
+ VerdictCard (hardcoded #000 / #FF4206 mapped to tokens).
1179
+ ============================================================ */
1180
+ .bk-verdict-card {
1181
+ --_accent: var(--blog-brand-bright);
1182
+ margin: var(--blog-sp-8) 0;
1183
+ overflow: hidden;
1184
+ color: var(--blog-on-dark);
1185
+ background: var(--blog-dark);
1186
+ border: 1px solid var(--_accent);
1187
+ border-radius: var(--blog-radius-xs);
1188
+ box-shadow: var(--blog-shadow-verdict);
1189
+ }
1190
+ .bk-verdict-card__header {
1191
+ display: flex;
1192
+ align-items: center;
1193
+ justify-content: space-between;
1194
+ gap: var(--blog-sp-3);
1195
+ padding: var(--blog-sp-4) var(--blog-sp-5);
1196
+ border-bottom: 1px solid color-mix(in srgb, var(--blog-on-dark) 10%, transparent);
1197
+ }
1198
+ .bk-verdict-card__kicker {
1199
+ font-family: var(--blog-font-display);
1200
+ font-weight: 700;
1201
+ font-size: var(--blog-fs-eyebrow);
1202
+ letter-spacing: var(--blog-tracking-eyebrow);
1203
+ text-transform: uppercase;
1204
+ color: var(--_accent);
1205
+ }
1206
+ .bk-verdict-card__score {
1207
+ font-family: var(--blog-font-display);
1208
+ font-weight: 800;
1209
+ font-size: var(--blog-fs-4xl);
1210
+ line-height: 1;
1211
+ color: var(--_accent);
1212
+ }
1213
+ .bk-verdict-card__score-max {
1214
+ font-size: var(--blog-fs-lg);
1215
+ font-weight: 500;
1216
+ color: color-mix(in srgb, var(--blog-on-dark) 50%, transparent);
1217
+ }
1218
+ .bk-verdict-card__body {
1219
+ padding: var(--blog-sp-5);
1220
+ }
1221
+ .bk-verdict-card__winner {
1222
+ margin: 0 0 var(--blog-sp-2);
1223
+ font-family: var(--blog-font-display);
1224
+ font-weight: 700;
1225
+ font-size: var(--blog-fs-eyebrow);
1226
+ letter-spacing: var(--blog-tracking-wide);
1227
+ text-transform: uppercase;
1228
+ color: color-mix(in srgb, var(--blog-on-dark) 50%, transparent);
1229
+ }
1230
+ .bk-verdict-card__winner-name {
1231
+ color: var(--_accent);
1232
+ }
1233
+ .bk-verdict-card__verdict {
1234
+ margin: 0 0 var(--blog-sp-2);
1235
+ font-family: var(--blog-font-display);
1236
+ font-weight: 800;
1237
+ font-size: var(--blog-fs-2xl);
1238
+ line-height: 1.05;
1239
+ text-transform: uppercase;
1240
+ color: var(--blog-on-dark);
1241
+ }
1242
+ .bk-verdict-card__summary {
1243
+ margin: 0;
1244
+ font-family: var(--blog-font-body);
1245
+ font-size: var(--blog-fs-md);
1246
+ line-height: 1.55;
1247
+ color: color-mix(in srgb, var(--blog-on-dark) 80%, transparent);
1248
+ }
1249
+ .bk-verdict-card__bullets {
1250
+ display: flex;
1251
+ flex-wrap: wrap;
1252
+ gap: var(--blog-sp-2);
1253
+ margin-top: var(--blog-sp-4);
1254
+ }
1255
+ .bk-verdict-card__chip {
1256
+ padding: var(--blog-sp-1) var(--blog-sp-3);
1257
+ font-family: var(--blog-font-display);
1258
+ font-weight: 700;
1259
+ font-size: var(--blog-fs-eyebrow);
1260
+ letter-spacing: var(--blog-tracking-wide);
1261
+ text-transform: uppercase;
1262
+ color: var(--blog-on-dark);
1263
+ background: color-mix(in srgb, var(--_accent) 15%, transparent);
1264
+ border: 1px solid color-mix(in srgb, var(--_accent) 40%, transparent);
1265
+ border-radius: var(--blog-radius-pill);
1266
+ }
1267
+ @media (min-width: 640px) {
1268
+ .bk-verdict-card__header { padding: var(--blog-sp-5) var(--blog-sp-6); }
1269
+ .bk-verdict-card__score { font-size: var(--blog-fs-6xl); }
1270
+ .bk-verdict-card__score-max { font-size: var(--blog-fs-xl); }
1271
+ .bk-verdict-card__body { padding: var(--blog-sp-6); }
1272
+ .bk-verdict-card__verdict { font-size: var(--blog-fs-4xl); line-height: 1; }
1273
+ }
1274
+
1275
+ /* ── ScoreBar ────────────────────────────────────────────────
1276
+ Canonical name: ScoreBar
1277
+ A labelled rating row: uppercase label + numeric score + a
1278
+ gradient-filled progress track. The fill width is set inline
1279
+ (data-driven score/maxScore %); all colour/type/spacing here.
1280
+ Responsive: wide viewports lay label/track/score on a
1281
+ 140px 1fr 48px grid; narrow viewports stack label+score above
1282
+ a full-width track (matches the Capture source layout).
1283
+ ──────────────────────────────────────────────────────────── */
1284
+ .bk-score-bar {
1285
+ margin: var(--blog-sp-3) 0;
1286
+ }
1287
+ .bk-score-bar__head {
1288
+ display: flex;
1289
+ align-items: baseline;
1290
+ justify-content: space-between;
1291
+ gap: var(--blog-sp-3);
1292
+ }
1293
+ .bk-score-bar__label {
1294
+ font-family: var(--blog-font-display);
1295
+ font-weight: 700;
1296
+ text-transform: uppercase;
1297
+ font-size: var(--blog-fs-xs);
1298
+ letter-spacing: var(--blog-tracking-wide);
1299
+ color: var(--blog-mute);
1300
+ }
1301
+ .bk-score-bar__score {
1302
+ font-family: var(--blog-font-display);
1303
+ font-weight: 800;
1304
+ font-size: var(--blog-fs-lg);
1305
+ line-height: 1;
1306
+ color: var(--blog-brand);
1307
+ }
1308
+ .bk-score-bar__track {
1309
+ position: relative;
1310
+ height: 8px;
1311
+ margin-top: var(--blog-sp-2);
1312
+ border-radius: var(--blog-radius-pill);
1313
+ overflow: hidden;
1314
+ background: var(--blog-bg-tertiary);
1315
+ }
1316
+ .bk-score-bar__fill {
1317
+ position: absolute;
1318
+ inset: 0 auto 0 0;
1319
+ height: 100%;
1320
+ border-radius: var(--blog-radius-pill);
1321
+ background: linear-gradient(90deg, var(--blog-brand-bright), var(--blog-brand));
1322
+ transition: width 0.7s ease-out;
1323
+ }
1324
+ @media (min-width: 640px) {
1325
+ .bk-score-bar {
1326
+ display: grid;
1327
+ align-items: center;
1328
+ gap: var(--blog-sp-3);
1329
+ grid-template-columns: 140px 1fr 48px;
1330
+ }
1331
+ /* head dissolves so its children join the grid directly */
1332
+ .bk-score-bar__head {
1333
+ display: contents;
1334
+ }
1335
+ .bk-score-bar__score {
1336
+ order: 3;
1337
+ text-align: right;
1338
+ }
1339
+ .bk-score-bar__track {
1340
+ order: 2;
1341
+ margin-top: 0;
1342
+ }
1343
+ }
1344
+
1345
+ /* ============================================================
1346
+ NumberedCard — card with a floating zero-padded number badge,
1347
+ an uppercase display title, and a short body paragraph.
1348
+ Ported from capture-ai blog _components/NumberedCard.
1349
+ ============================================================ */
1350
+ .bk-numbered-card { position: relative; margin: var(--blog-sp-6) 0; padding: var(--blog-sp-5); background: var(--blog-paper); border: 1px solid var(--blog-border); border-radius: var(--blog-radius-xs); }
1351
+ .bk-numbered-card__badge { position: absolute; top: calc(-1 * var(--blog-sp-3)); left: var(--blog-sp-5); display: inline-block; padding: var(--blog-sp-1) var(--blog-sp-2); background: var(--blog-brand); color: var(--blog-on-brand); border-radius: var(--blog-radius-pill); font-family: var(--blog-font-display); font-weight: 800; font-size: var(--blog-fs-base); letter-spacing: var(--blog-tracking-wide); line-height: 1; }
1352
+ .bk-numbered-card__title { margin: var(--blog-sp-2) 0 var(--blog-sp-1); font-family: var(--blog-font-display); font-weight: 800; font-size: var(--blog-fs-xl); text-transform: uppercase; color: var(--blog-ink); }
1353
+ .bk-numbered-card__body { margin: 0; font-family: var(--blog-font-body); font-size: var(--blog-fs-base); line-height: 1.5; color: var(--blog-text); }
1354
+
1355
+ /* ── MetricHighlight ─────────────────────────────────────────
1356
+ Canonical name: MetricHighlight
1357
+ One metric → a big brand-filled hero (giant value + label +
1358
+ optional change + SOURCE row). Two or more → a responsive grid
1359
+ of bordered cards; column count comes from a
1360
+ --metric-highlight--<n> modifier (2 | 3 | 4+).
1361
+ Self-contained: its own dashed-divider source row (minor repetition
1362
+ across components is preferred over shared cross-component classes).
1363
+ ──────────────────────────────────────────────────────────── */
1364
+ .bk-metric-highlight { display: block; }
1365
+
1366
+ /* —— hero (single metric) —— */
1367
+ .bk-metric-highlight--hero {
1368
+ margin: var(--blog-sp-8) 0;
1369
+ padding: var(--blog-sp-6) var(--blog-sp-5);
1370
+ border-radius: var(--blog-radius-xs);
1371
+ background: var(--blog-brand);
1372
+ color: var(--blog-on-brand);
1373
+ display: flex;
1374
+ align-items: center;
1375
+ justify-content: space-between;
1376
+ flex-wrap: wrap;
1377
+ gap: var(--blog-sp-4);
1378
+ }
1379
+ @media (min-width: 640px) {
1380
+ .bk-metric-highlight--hero { padding: var(--blog-sp-10) var(--blog-sp-8); gap: var(--blog-sp-6); }
1381
+ }
1382
+ .bk-metric-highlight__hero-value {
1383
+ font-family: var(--blog-font-display);
1384
+ font-weight: 800;
1385
+ line-height: .85;
1386
+ font-size: var(--blog-fs-display);
1387
+ }
1388
+ .bk-metric-highlight__hero-body { flex: 1 1 0%; min-width: 0; }
1389
+ @media (min-width: 640px) { .bk-metric-highlight__hero-body { min-width: 260px; } }
1390
+ .bk-metric-highlight__hero-change {
1391
+ font-family: var(--blog-font-body);
1392
+ font-weight: 700;
1393
+ text-transform: uppercase;
1394
+ font-size: var(--blog-fs-sm);
1395
+ letter-spacing: var(--blog-tracking-eyebrow);
1396
+ color: color-mix(in srgb, var(--blog-on-brand) 72%, transparent);
1397
+ }
1398
+ @media (min-width: 640px) { .bk-metric-highlight__hero-change { font-size: var(--blog-fs-base); } }
1399
+ .bk-metric-highlight__hero-label {
1400
+ font-family: var(--blog-font-display);
1401
+ font-weight: 700;
1402
+ text-transform: uppercase;
1403
+ font-size: var(--blog-fs-2xl);
1404
+ line-height: 1.1;
1405
+ margin-top: var(--blog-sp-1);
1406
+ }
1407
+ @media (min-width: 640px) { .bk-metric-highlight__hero-label { font-size: var(--blog-fs-3xl); } }
1408
+
1409
+ /* —— grid (2+ metrics) —— */
1410
+ .bk-metric-highlight--grid {
1411
+ display: grid;
1412
+ gap: var(--blog-sp-3);
1413
+ margin: var(--blog-sp-7) 0;
1414
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1415
+ }
1416
+ .bk-metric-highlight--2 { grid-template-columns: minmax(0, 1fr); }
1417
+ @media (min-width: 640px) { .bk-metric-highlight--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
1418
+ @media (min-width: 768px) {
1419
+ .bk-metric-highlight--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
1420
+ .bk-metric-highlight--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
1421
+ }
1422
+ .bk-metric-highlight__card {
1423
+ display: flex;
1424
+ flex-direction: column;
1425
+ padding: var(--blog-sp-4);
1426
+ border-radius: var(--blog-radius-xs);
1427
+ border: 1px solid var(--blog-border);
1428
+ background: var(--blog-paper);
1429
+ }
1430
+ @media (min-width: 640px) { .bk-metric-highlight__card { padding: var(--blog-sp-5); } }
1431
+ .bk-metric-highlight__value {
1432
+ font-family: var(--blog-font-display);
1433
+ font-weight: 800;
1434
+ font-size: var(--blog-fs-5xl);
1435
+ line-height: .95;
1436
+ color: var(--blog-brand);
1437
+ }
1438
+ @media (min-width: 640px) { .bk-metric-highlight__value { font-size: var(--blog-fs-6xl); } }
1439
+ .bk-metric-highlight__label {
1440
+ font-family: var(--blog-font-body);
1441
+ font-weight: 700;
1442
+ text-transform: uppercase;
1443
+ letter-spacing: var(--blog-tracking-wide);
1444
+ font-size: var(--blog-fs-xs);
1445
+ margin-top: calc(var(--blog-sp-1) * 1.5);
1446
+ color: var(--blog-mute);
1447
+ }
1448
+ .bk-metric-highlight__change {
1449
+ font-family: var(--blog-font-body);
1450
+ font-size: var(--blog-fs-sm);
1451
+ margin-top: var(--blog-sp-1);
1452
+ color: var(--blog-mute);
1453
+ }
1454
+ .bk-metric-highlight__source-wrap { margin-top: auto; }
1455
+
1456
+ /* —— source attribution row (dashed divider, links out) —— */
1457
+ .bk-metric-highlight__source {
1458
+ display: inline-flex;
1459
+ align-items: center;
1460
+ gap: var(--blog-sp-1);
1461
+ margin-top: calc(var(--blog-sp-1) * 3.5);
1462
+ padding-top: calc(var(--blog-sp-1) * 2.5);
1463
+ font-family: var(--blog-font-body);
1464
+ font-size: var(--blog-fs-eyebrow);
1465
+ letter-spacing: var(--blog-tracking-wide);
1466
+ text-decoration: none;
1467
+ opacity: .8;
1468
+ color: var(--blog-mute);
1469
+ border-top: 1px dashed var(--blog-border);
1470
+ }
1471
+ .bk-metric-highlight__source--dark {
1472
+ color: color-mix(in srgb, var(--blog-on-brand) 75%, transparent);
1473
+ border-top-color: color-mix(in srgb, var(--blog-on-brand) 18%, transparent);
1474
+ }
1475
+ .bk-metric-highlight__source--link { transition: opacity .15s, color .15s; }
1476
+ .bk-metric-highlight__source--link:hover { opacity: 1; color: var(--blog-brand); }
1477
+ .bk-metric-highlight__source-kicker {
1478
+ font-weight: 700;
1479
+ text-transform: uppercase;
1480
+ font-size: var(--blog-fs-eyebrow-sm);
1481
+ letter-spacing: var(--blog-tracking-eyebrow);
1482
+ margin-right: 2px;
1483
+ color: var(--blog-mute);
1484
+ }
1485
+ .bk-metric-highlight__source--dark .bk-metric-highlight__source-kicker {
1486
+ color: color-mix(in srgb, var(--blog-on-brand) 55%, transparent);
1487
+ }
1488
+ .bk-metric-highlight__source-icon svg { display: block; width: 10px; height: 10px; opacity: .7; }
1489
+
1490
+ /* ============================================================
1491
+ CaseStudyHero (.bk-case-study-hero) — hjd pack
1492
+ A dark case-study banner: a light logo plate (client logo image,
1493
+ an HTML/text wordmark, or the auto-broken client name) beside a
1494
+ body with uppercase chips, a headline, a sub-line, and a row of
1495
+ brand-coloured result tiles (big number + uppercase label).
1496
+ Ported from hjd's blog CaseStudyHero (.b-cs). The cyan/dark night
1497
+ theme (#052230→#010E14 gradient, #fff text, #10C8F0 cyan results)
1498
+ is mapped to neutral tokens: dark gradient → --blog-dark-3/-2/dark,
1499
+ text → --blog-on-dark(/-mute), logo plate → --blog-paper/--blog-ink,
1500
+ cyan result tiles → --blog-brand (+ tint/border via color-mix).
1501
+ ============================================================ */
1502
+ .bk-case-study-hero {
1503
+ display: grid;
1504
+ grid-template-columns: auto 1fr;
1505
+ gap: var(--blog-sp-8);
1506
+ margin: var(--blog-sp-6) 0;
1507
+ padding: var(--blog-sp-8);
1508
+ align-items: center;
1509
+ position: relative;
1510
+ overflow: hidden;
1511
+ border-radius: var(--blog-radius-md);
1512
+ background: radial-gradient(
1513
+ 120% 140% at 88% 110%,
1514
+ var(--blog-dark-3) 0%,
1515
+ var(--blog-dark-2) 45%,
1516
+ var(--blog-dark) 100%
1517
+ );
1518
+ color: var(--blog-on-dark);
1519
+ }
1520
+ .bk-case-study-hero__logo {
1521
+ width: 140px;
1522
+ height: 140px;
1523
+ flex-shrink: 0;
1524
+ position: relative;
1525
+ overflow: hidden;
1526
+ display: flex;
1527
+ align-items: center;
1528
+ justify-content: center;
1529
+ padding: var(--blog-sp-4);
1530
+ border-radius: var(--blog-radius-lg);
1531
+ background: var(--blog-paper);
1532
+ }
1533
+ .bk-case-study-hero__logo strong {
1534
+ font-family: var(--blog-font-display);
1535
+ font-weight: 700;
1536
+ font-size: var(--blog-fs-2xl);
1537
+ line-height: 1;
1538
+ text-align: center;
1539
+ text-transform: uppercase;
1540
+ letter-spacing: var(--blog-tracking-wide);
1541
+ color: var(--blog-ink);
1542
+ }
1543
+ .bk-case-study-hero__logo img {
1544
+ max-width: 100%;
1545
+ max-height: 100%;
1546
+ width: auto;
1547
+ height: auto;
1548
+ object-fit: contain;
1549
+ display: block;
1550
+ }
1551
+ .bk-case-study-hero__body {
1552
+ position: relative;
1553
+ min-width: 0;
1554
+ }
1555
+ .bk-case-study-hero__chips {
1556
+ display: flex;
1557
+ gap: var(--blog-sp-2);
1558
+ flex-wrap: wrap;
1559
+ margin-bottom: var(--blog-sp-2);
1560
+ }
1561
+ .bk-case-study-hero__chip {
1562
+ font-family: var(--blog-font-display);
1563
+ font-weight: 700;
1564
+ text-transform: uppercase;
1565
+ letter-spacing: var(--blog-tracking-wide);
1566
+ font-size: var(--blog-fs-eyebrow);
1567
+ padding: 5px 11px;
1568
+ border-radius: var(--blog-radius-pill);
1569
+ background: color-mix(in srgb, var(--blog-on-dark) 8%, transparent);
1570
+ color: color-mix(in srgb, var(--blog-on-dark) 85%, transparent);
1571
+ border: 1px solid color-mix(in srgb, var(--blog-on-dark) 12%, transparent);
1572
+ }
1573
+ .bk-case-study-hero__heading {
1574
+ margin: 0;
1575
+ font-family: var(--blog-font-display);
1576
+ font-weight: 700;
1577
+ font-size: var(--blog-fs-6xl);
1578
+ line-height: 1.05;
1579
+ text-transform: uppercase;
1580
+ letter-spacing: var(--blog-tracking-tight);
1581
+ color: var(--blog-on-dark);
1582
+ }
1583
+ .bk-case-study-hero__sub {
1584
+ margin: var(--blog-sp-2) 0 var(--blog-sp-4);
1585
+ font-family: var(--blog-font-body);
1586
+ line-height: 1.55;
1587
+ color: var(--blog-on-dark-mute);
1588
+ }
1589
+ .bk-case-study-hero__results {
1590
+ display: flex;
1591
+ gap: var(--blog-sp-3);
1592
+ flex-wrap: wrap;
1593
+ }
1594
+ .bk-case-study-hero__result {
1595
+ padding: var(--blog-sp-3) var(--blog-sp-4);
1596
+ border-radius: var(--blog-radius-md);
1597
+ background: color-mix(in srgb, var(--blog-brand) 10%, transparent);
1598
+ border: 1px solid color-mix(in srgb, var(--blog-brand) 40%, transparent);
1599
+ }
1600
+ .bk-case-study-hero__result-num {
1601
+ font-family: var(--blog-font-display);
1602
+ font-weight: 700;
1603
+ font-size: var(--blog-fs-2xl);
1604
+ line-height: 1;
1605
+ color: var(--blog-brand);
1606
+ }
1607
+ .bk-case-study-hero__result-label {
1608
+ margin-top: var(--blog-sp-1);
1609
+ font-family: var(--blog-font-display);
1610
+ font-weight: 700;
1611
+ text-transform: uppercase;
1612
+ letter-spacing: var(--blog-tracking-wide);
1613
+ font-size: var(--blog-fs-eyebrow-sm);
1614
+ color: var(--blog-on-dark-mute);
1615
+ }
1616
+ @media (max-width: 640px) {
1617
+ .bk-case-study-hero {
1618
+ grid-template-columns: 1fr;
1619
+ gap: var(--blog-sp-5);
1620
+ padding: var(--blog-sp-6);
1621
+ }
1622
+ .bk-case-study-hero__logo {
1623
+ width: 96px;
1624
+ height: 96px;
1625
+ }
1626
+ .bk-case-study-hero__heading { font-size: var(--blog-fs-4xl); }
1627
+ }
1628
+
1629
+ /* ============================================================
1630
+ ResultsStrip — horizontal strip of bordered KPI cells.
1631
+ Each cell: uppercase label, big brand number, optional mono
1632
+ delta (green up / red down), optional dashed-divider SOURCE
1633
+ row. Collapses to 2-up on narrow screens.
1634
+ hjd source maps: cyan → --blog-brand, line-2 → --blog-border,
1635
+ white cell → --blog-paper, mute → --blog-mute, cyan-deep
1636
+ hover → --blog-brand-dark, success/danger → state tokens.
1637
+ ============================================================ */
1638
+ .bk-results-strip {
1639
+ display: grid;
1640
+ grid-template-columns: repeat(4, 1fr);
1641
+ gap: 0;
1642
+ margin: calc(var(--blog-sp-1) * 3) 0;
1643
+ border: 1px solid var(--blog-border);
1644
+ border-radius: var(--blog-radius-md);
1645
+ overflow: hidden;
1646
+ }
1647
+ @media (max-width: 700px) {
1648
+ .bk-results-strip { grid-template-columns: 1fr 1fr; }
1649
+ }
1650
+ .bk-results-strip__cell {
1651
+ padding: var(--blog-sp-3) calc(var(--blog-sp-1) * 2.75);
1652
+ background: var(--blog-paper);
1653
+ border-right: 1px solid var(--blog-border);
1654
+ }
1655
+ .bk-results-strip__cell:last-child { border-right: none; }
1656
+ @media (max-width: 700px) {
1657
+ /* in a 2-col grid, clear the right border on the right column */
1658
+ .bk-results-strip__cell:nth-child(2n) { border-right: none; }
1659
+ }
1660
+ .bk-results-strip__label {
1661
+ font-family: var(--blog-font-display);
1662
+ font-weight: 700;
1663
+ text-transform: uppercase;
1664
+ letter-spacing: var(--blog-tracking-wide);
1665
+ font-size: var(--blog-fs-eyebrow);
1666
+ color: var(--blog-mute);
1667
+ }
1668
+ .bk-results-strip__num {
1669
+ font-family: var(--blog-font-display);
1670
+ font-weight: 700;
1671
+ font-size: var(--blog-fs-6xl);
1672
+ line-height: 1;
1673
+ color: var(--blog-brand);
1674
+ margin-top: 6px;
1675
+ }
1676
+ .bk-results-strip__delta {
1677
+ font-family: var(--blog-font-mono);
1678
+ font-size: var(--blog-fs-eyebrow);
1679
+ color: var(--blog-success);
1680
+ margin-top: 6px;
1681
+ display: inline-flex;
1682
+ align-items: center;
1683
+ gap: 4px;
1684
+ }
1685
+ .bk-results-strip__delta--down { color: var(--blog-danger); }
1686
+
1687
+ /* —— source attribution row (dashed divider, links out) —— */
1688
+ .bk-results-strip__source {
1689
+ display: inline-flex;
1690
+ align-items: center;
1691
+ gap: var(--blog-sp-1);
1692
+ margin-top: calc(var(--blog-sp-1) * 1.5);
1693
+ padding-top: var(--blog-sp-1);
1694
+ border-top: 1px dashed var(--blog-border);
1695
+ font-family: var(--blog-font-body);
1696
+ font-size: var(--blog-fs-eyebrow);
1697
+ letter-spacing: var(--blog-tracking-wide);
1698
+ text-decoration: none;
1699
+ opacity: .85;
1700
+ color: var(--blog-mute);
1701
+ }
1702
+ .bk-results-strip__source--link { transition: opacity .15s, color .15s; }
1703
+ .bk-results-strip__source--link:hover { opacity: 1; color: var(--blog-brand-dark); }
1704
+ .bk-results-strip__source-kicker {
1705
+ font-family: var(--blog-font-display);
1706
+ font-weight: 700;
1707
+ text-transform: uppercase;
1708
+ font-size: var(--blog-fs-eyebrow-sm);
1709
+ letter-spacing: var(--blog-tracking-eyebrow);
1710
+ margin-right: 2px;
1711
+ color: var(--blog-mute);
1712
+ }
1713
+ .bk-results-strip__source-icon svg { display: block; width: 10px; height: 10px; opacity: .7; }
1714
+
1715
+ /* ============================================================
1716
+ KeyMetric (.bk-key-metric) — hjd pack
1717
+ A dark, full-width hero metric panel: one oversized brand-coloured
1718
+ number alongside a copy column (uppercase label, rich-text title,
1719
+ sub-line) and an optional dashed-divider "SOURCE" attribution row
1720
+ that links out when a URL is given. Ported from hjd's blog KeyMetric
1721
+ (+ inlined .b-stat-src override); cyan (#10C8F0) mapped to --blog-brand,
1722
+ the dark radial gradient (#052230/#021821/#010E14) to the --blog-dark
1723
+ surfaces, and white/rgba text to --blog-on-dark tokens.
1724
+ ============================================================ */
1725
+ .bk-key-metric {
1726
+ display: flex;
1727
+ align-items: center;
1728
+ justify-content: space-between;
1729
+ flex-wrap: wrap;
1730
+ gap: var(--blog-sp-8);
1731
+ position: relative;
1732
+ overflow: hidden;
1733
+ margin: var(--blog-sp-7) 0;
1734
+ padding: var(--blog-sp-12) var(--blog-sp-10);
1735
+ border-radius: var(--blog-radius-md);
1736
+ background: radial-gradient(120% 140% at 88% 110%, var(--blog-dark) 0%, var(--blog-dark-2) 45%, var(--blog-dark-3) 100%);
1737
+ color: var(--blog-on-dark);
1738
+ }
1739
+ .bk-key-metric__num {
1740
+ position: relative;
1741
+ font-family: var(--blog-font-display);
1742
+ font-weight: 700;
1743
+ font-size: var(--blog-fs-display-2);
1744
+ line-height: .85;
1745
+ letter-spacing: -.02em;
1746
+ color: var(--blog-brand);
1747
+ }
1748
+ .bk-key-metric__copy {
1749
+ position: relative;
1750
+ flex: 1;
1751
+ min-width: 260px;
1752
+ }
1753
+ /* Narrow screens: drop the 260px floor (it overflows the padded card under
1754
+ ~360px) and ease the generous padding so the panel fits. */
1755
+ @media (max-width: 640px) {
1756
+ .bk-key-metric { padding: var(--blog-sp-6) var(--blog-sp-5); }
1757
+ .bk-key-metric__copy { min-width: 0; }
1758
+ }
1759
+ .bk-key-metric__label {
1760
+ font-family: var(--blog-font-display);
1761
+ font-weight: 700;
1762
+ text-transform: uppercase;
1763
+ font-size: var(--blog-fs-base);
1764
+ letter-spacing: .08em;
1765
+ color: var(--blog-brand);
1766
+ }
1767
+ .bk-key-metric__title {
1768
+ margin: var(--blog-sp-1) 0 0;
1769
+ font-family: var(--blog-font-display);
1770
+ font-weight: 700;
1771
+ font-size: var(--blog-fs-3xl);
1772
+ line-height: 1.15;
1773
+ text-transform: uppercase;
1774
+ letter-spacing: var(--blog-tracking-tight);
1775
+ color: var(--blog-on-dark);
1776
+ }
1777
+ .bk-key-metric__sub {
1778
+ margin-top: var(--blog-sp-2);
1779
+ font-family: var(--blog-font-body);
1780
+ font-size: var(--blog-fs-base);
1781
+ line-height: 1.55;
1782
+ color: var(--blog-on-dark-mute);
1783
+ }
1784
+ .bk-key-metric__source {
1785
+ display: inline-flex;
1786
+ align-items: center;
1787
+ gap: var(--blog-sp-1);
1788
+ margin-top: var(--blog-sp-3);
1789
+ padding-top: var(--blog-sp-2);
1790
+ border-top: 1px dashed color-mix(in srgb, var(--blog-on-dark) 18%, transparent);
1791
+ font-family: var(--blog-font-body);
1792
+ font-size: var(--blog-fs-eyebrow);
1793
+ letter-spacing: .04em;
1794
+ color: color-mix(in srgb, var(--blog-on-dark) 65%, transparent);
1795
+ text-decoration: none;
1796
+ opacity: .9;
1797
+ transition: opacity .15s ease, color .15s ease;
1798
+ }
1799
+ .bk-key-metric__source--link:hover {
1800
+ opacity: 1;
1801
+ color: var(--blog-on-dark);
1802
+ }
1803
+ .bk-key-metric__source-kicker {
1804
+ margin-right: .125rem;
1805
+ font-family: var(--blog-font-display);
1806
+ font-weight: 700;
1807
+ text-transform: uppercase;
1808
+ font-size: var(--blog-fs-eyebrow-sm);
1809
+ letter-spacing: .08em;
1810
+ color: color-mix(in srgb, var(--blog-on-dark) 50%, transparent);
1811
+ }
1812
+ .bk-key-metric__source-icon svg {
1813
+ display: block;
1814
+ width: 10px;
1815
+ height: 10px;
1816
+ }
1817
+
1818
+ /* ============================================================
1819
+ KeywordTable — SEO keyword-ranking table
1820
+ Faithful port of hjd .b-kw, tokenised. Columns: keyword, search
1821
+ volume, a colour-coded difficulty pill (low/med/high via the
1822
+ state tokens), before/after rank positions (mono), and a coloured
1823
+ up/down rank-change delta with a ▲/▼ glyph. Overflows horizontally
1824
+ on narrow viewports; the [data-bk-keyword-table] behaviour toggles
1825
+ edge-fade hint classes when the scroll container can scroll.
1826
+ hjd mapping: --hjd-line-2 → --blog-border, --hjd-mist →
1827
+ --blog-bg-secondary, --hjd-r-md → --blog-radius-md, difficulty
1828
+ pill colours → --blog-success/-warn/-danger (+ -bg).
1829
+ ──────────────────────────────────────────────────────────── */
1830
+ .bk-keyword-table {
1831
+ position: relative;
1832
+ margin: var(--blog-sp-7) 0;
1833
+ border: 1px solid var(--blog-border);
1834
+ border-radius: var(--blog-radius-md);
1835
+ background: var(--blog-paper);
1836
+ overflow: hidden;
1837
+ }
1838
+ .bk-keyword-table__scroll { overflow-x: auto; border-radius: inherit; }
1839
+ .bk-keyword-table__table {
1840
+ width: 100%;
1841
+ border-collapse: collapse;
1842
+ font-family: var(--blog-font-body);
1843
+ font-size: var(--blog-fs-base);
1844
+ }
1845
+ .bk-keyword-table__th {
1846
+ padding: var(--blog-sp-3) var(--blog-sp-4);
1847
+ text-align: left;
1848
+ border-bottom: 1px solid var(--blog-border);
1849
+ background: var(--blog-bg-secondary);
1850
+ font-family: var(--blog-font-display);
1851
+ font-weight: 700;
1852
+ font-size: var(--blog-fs-eyebrow);
1853
+ text-transform: uppercase;
1854
+ letter-spacing: var(--blog-tracking-wide);
1855
+ color: var(--blog-ink);
1856
+ white-space: nowrap;
1857
+ }
1858
+ .bk-keyword-table__td {
1859
+ padding: var(--blog-sp-3) var(--blog-sp-4);
1860
+ text-align: left;
1861
+ border-bottom: 1px solid var(--blog-border);
1862
+ color: var(--blog-text);
1863
+ white-space: nowrap;
1864
+ }
1865
+ .bk-keyword-table__th--r,
1866
+ .bk-keyword-table__td--r { text-align: right; }
1867
+ .bk-keyword-table__tr:last-child .bk-keyword-table__td { border-bottom: none; }
1868
+
1869
+ .bk-keyword-table__td--kw {
1870
+ font-family: var(--blog-font-display);
1871
+ font-weight: 600;
1872
+ color: var(--blog-ink);
1873
+ letter-spacing: var(--blog-tracking-tight);
1874
+ white-space: normal;
1875
+ }
1876
+ .bk-keyword-table__rank { font-family: var(--blog-font-mono); }
1877
+
1878
+ /* Difficulty pill — low / med / high via the neutral state tokens. */
1879
+ .bk-keyword-table__diff {
1880
+ display: inline-block;
1881
+ padding: 2px 8px;
1882
+ border-radius: var(--blog-radius-xs);
1883
+ font-family: var(--blog-font-mono);
1884
+ font-size: var(--blog-fs-eyebrow);
1885
+ }
1886
+ .bk-keyword-table__diff--low { background: var(--blog-success-bg); color: var(--blog-success); }
1887
+ .bk-keyword-table__diff--med { background: var(--blog-warn-bg); color: var(--blog-warn); }
1888
+ .bk-keyword-table__diff--high { background: var(--blog-danger-bg); color: var(--blog-danger); }
1889
+
1890
+ /* Rank-change delta — coloured by direction, with a leading arrow glyph. */
1891
+ .bk-keyword-table__delta {
1892
+ display: inline-flex;
1893
+ align-items: center;
1894
+ gap: 4px;
1895
+ font-family: var(--blog-font-mono);
1896
+ font-size: var(--blog-fs-xs);
1897
+ font-weight: 700;
1898
+ color: var(--blog-success);
1899
+ }
1900
+ .bk-keyword-table__delta--up::before { content: "\25B2"; font-size: var(--blog-fs-eyebrow-sm); }
1901
+ .bk-keyword-table__delta--down { color: var(--blog-danger); }
1902
+ .bk-keyword-table__delta--down::before { content: "\25BC"; font-size: var(--blog-fs-eyebrow-sm); }
1903
+
1904
+ /* Scroll-edge hint fades, toggled by the behaviour on overflow. */
1905
+ .bk-keyword-table::before,
1906
+ .bk-keyword-table::after {
1907
+ content: "";
1908
+ position: absolute;
1909
+ top: 0;
1910
+ bottom: 0;
1911
+ width: var(--blog-sp-6);
1912
+ pointer-events: none;
1913
+ opacity: 0;
1914
+ transition: opacity 0.15s ease;
1915
+ z-index: 1;
1916
+ }
1917
+ .bk-keyword-table::before {
1918
+ left: 0;
1919
+ background: linear-gradient(to right, var(--blog-paper), transparent);
1920
+ }
1921
+ .bk-keyword-table::after {
1922
+ right: 0;
1923
+ background: linear-gradient(to left, var(--blog-paper), transparent);
1924
+ }
1925
+ .bk-keyword-table--hint-left::before { opacity: 1; }
1926
+ .bk-keyword-table--hint-right::after { opacity: 1; }
1927
+
1928
+ /* ============================================================
1929
+ ChannelMixBars (.bk-channel-mix) — hjd pack
1930
+ A horizontal bar breakdown of one metric across channels:
1931
+ an uppercase brand heading + optional total, then one labelled
1932
+ row per channel with a proportional fill and a right-aligned
1933
+ value. The first row uses the brand fill; subsequent rows step
1934
+ through a neutral colour ramp. Ported from hjd-website's blog
1935
+ ChannelMixBars (cyan/dark source mapped to neutral tokens).
1936
+ ============================================================ */
1937
+ .bk-channel-mix {
1938
+ margin: var(--blog-sp-6) 0;
1939
+ padding: var(--blog-sp-4) var(--blog-sp-5);
1940
+ background: var(--blog-paper);
1941
+ border: 1px solid var(--blog-border);
1942
+ border-radius: var(--blog-radius-md);
1943
+ }
1944
+ .bk-channel-mix__head {
1945
+ display: flex;
1946
+ justify-content: space-between;
1947
+ align-items: baseline;
1948
+ margin-bottom: var(--blog-sp-3);
1949
+ }
1950
+ .bk-channel-mix__title {
1951
+ font-family: var(--blog-font-display);
1952
+ font-weight: 700;
1953
+ text-transform: uppercase;
1954
+ font-size: var(--blog-fs-sm);
1955
+ letter-spacing: .08em;
1956
+ color: var(--blog-brand);
1957
+ }
1958
+ .bk-channel-mix__total {
1959
+ font-family: var(--blog-font-mono);
1960
+ font-size: var(--blog-fs-xs);
1961
+ color: var(--blog-mute);
1962
+ }
1963
+ .bk-channel-mix__row {
1964
+ display: grid;
1965
+ grid-template-columns: 120px 1fr 80px;
1966
+ gap: var(--blog-sp-2);
1967
+ align-items: center;
1968
+ padding: var(--blog-sp-1) 0;
1969
+ }
1970
+ /* Narrow screens: lift the channel name onto its own row so the bar + value
1971
+ keep usable width instead of crushing against two fixed columns. */
1972
+ @media (max-width: 600px) {
1973
+ .bk-channel-mix__row { grid-template-columns: 1fr auto; }
1974
+ .bk-channel-mix__name { grid-column: 1 / -1; }
1975
+ }
1976
+ .bk-channel-mix__name {
1977
+ font-family: var(--blog-font-display);
1978
+ font-weight: 700;
1979
+ text-transform: uppercase;
1980
+ font-size: var(--blog-fs-xs);
1981
+ letter-spacing: .04em;
1982
+ color: var(--blog-ink);
1983
+ }
1984
+ .bk-channel-mix__bar {
1985
+ height: 14px;
1986
+ background: var(--blog-bg-tertiary);
1987
+ border-radius: var(--blog-radius-xs);
1988
+ position: relative;
1989
+ overflow: hidden;
1990
+ }
1991
+ .bk-channel-mix__fill {
1992
+ position: absolute;
1993
+ inset: 0 auto 0 0;
1994
+ background: var(--blog-brand);
1995
+ border-radius: var(--blog-radius-xs);
1996
+ }
1997
+ .bk-channel-mix__fill--2 { background: var(--blog-brand-dark); }
1998
+ .bk-channel-mix__fill--3 { background: var(--blog-dark); }
1999
+ .bk-channel-mix__fill--4 { background: var(--blog-mute); }
2000
+ .bk-channel-mix__fill--5 { background: var(--blog-mute-2); }
2001
+ .bk-channel-mix__val {
2002
+ font-family: var(--blog-font-mono);
2003
+ font-size: var(--blog-fs-xs);
2004
+ color: var(--blog-ink);
2005
+ text-align: right;
2006
+ }
2007
+
2008
+ /* ── TrafficChart ─────────────────────────────────────────────────────────
2009
+ Compact SVG line chart comparing a current vs previous series over time.
2010
+ Ported from hjd-website's blog TrafficChart (.b-tc). Cyan #10C8F0 → --blog-brand,
2011
+ greys (#ADADAD / #6B7280 / #EDEFF2) → --blog-mute-2 / --blog-mute / --blog-border-light,
2012
+ white card → --blog-paper, --hjd-line-2 → --blog-border. All colours live on
2013
+ .bk-traffic-chart classes (SVG strokes/fills via CSS), so the same chart renders
2014
+ orange on Capture and cyan on HJD purely through tokens. */
2015
+ .bk-traffic-chart { margin: var(--blog-sp-6) 0; padding: var(--blog-sp-6); border: 1px solid var(--blog-border); border-radius: var(--blog-radius-md); background: var(--blog-paper); }
2016
+ .bk-traffic-chart__head { display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap; gap: var(--blog-sp-3); margin-bottom: var(--blog-sp-3); }
2017
+ .bk-traffic-chart__title { font-family: var(--blog-font-display); font-weight: 700; text-transform: uppercase; font-size: var(--blog-fs-xl); letter-spacing: var(--blog-tracking-tight); color: var(--blog-ink); }
2018
+ .bk-traffic-chart__legend { display: flex; gap: var(--blog-sp-4); }
2019
+ .bk-traffic-chart__item { display: inline-flex; align-items: center; gap: var(--blog-sp-2); font-family: var(--blog-font-body); font-size: var(--blog-fs-xs); color: var(--blog-mute); }
2020
+ .bk-traffic-chart__dot { width: 10px; height: 2px; background: var(--blog-brand); border-radius: 2px; }
2021
+ .bk-traffic-chart__dot--prev { height: 0; background: transparent; border-top: 2px dashed var(--blog-mute-2); border-radius: 0; }
2022
+ .bk-traffic-chart__svg { display: block; width: 100%; height: auto; font-family: var(--blog-font-mono); font-size: var(--blog-fs-eyebrow-sm); }
2023
+ .bk-traffic-chart__axis { stroke: var(--blog-border-light); stroke-width: 1; }
2024
+ .bk-traffic-chart__line { fill: none; stroke: var(--blog-brand); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
2025
+ .bk-traffic-chart__line--prev { stroke: var(--blog-mute-2); stroke-width: 2; stroke-dasharray: 4 4; stroke-linecap: butt; }
2026
+ .bk-traffic-chart__pt { fill: var(--blog-brand); }
2027
+ .bk-traffic-chart__labels text { fill: var(--blog-mute); }
2028
+
2029
+ /* ============================================================
2030
+ SerpPreview (.bk-serp-preview) — hjd pack
2031
+ A mock search-engine results page: a rounded "search bar"
2032
+ showing the query, then a stack of result rows (URL
2033
+ breadcrumb, blue heading, snippet) with an optional
2034
+ "Sponsored" tag for ad results. Ported from hjd's b-serp
2035
+ (--hjd-mist→bg-secondary, --hjd-line-2→border, #fff→paper,
2036
+ --hjd-cyan→brand, --hjd-night→on-brand, #0a4280 Google-blue
2037
+ link→--blog-info, #3E444A/--hjd-ink-3→mute-2).
2038
+ ============================================================ */
2039
+ .bk-serp-preview {
2040
+ margin: var(--blog-sp-6) 0;
2041
+ padding: var(--blog-sp-6);
2042
+ background: var(--blog-bg-secondary);
2043
+ border: 1px solid var(--blog-border);
2044
+ border-radius: var(--blog-radius-sm);
2045
+ }
2046
+ .bk-serp-preview__bar {
2047
+ display: flex;
2048
+ align-items: center;
2049
+ gap: var(--blog-sp-2);
2050
+ padding: var(--blog-sp-2) var(--blog-sp-4);
2051
+ background: var(--blog-paper);
2052
+ border-radius: var(--blog-radius-pill);
2053
+ box-shadow: var(--blog-shadow-sm);
2054
+ }
2055
+ .bk-serp-preview__bar-icon {
2056
+ flex-shrink: 0;
2057
+ color: var(--blog-mute);
2058
+ }
2059
+ .bk-serp-preview__bar-icon svg {
2060
+ display: block;
2061
+ width: 18px;
2062
+ height: 18px;
2063
+ }
2064
+ .bk-serp-preview__input {
2065
+ width: 100%;
2066
+ border: none;
2067
+ outline: none;
2068
+ background: none;
2069
+ font-family: var(--blog-font-body);
2070
+ font-size: var(--blog-fs-base);
2071
+ color: var(--blog-ink);
2072
+ }
2073
+ .bk-serp-preview__results {
2074
+ margin-top: var(--blog-sp-4);
2075
+ padding: 0 var(--blog-sp-1);
2076
+ }
2077
+ .bk-serp-preview__result {
2078
+ padding: var(--blog-sp-3) 0;
2079
+ border-bottom: 1px dashed var(--blog-border);
2080
+ }
2081
+ .bk-serp-preview__result:last-child {
2082
+ border-bottom: none;
2083
+ }
2084
+ .bk-serp-preview__tag {
2085
+ display: inline-block;
2086
+ margin-right: var(--blog-sp-2);
2087
+ padding: 1px 6px;
2088
+ border-radius: var(--blog-radius-xs);
2089
+ font-family: var(--blog-font-display);
2090
+ font-weight: 700;
2091
+ font-size: var(--blog-fs-eyebrow-sm);
2092
+ letter-spacing: .06em;
2093
+ text-transform: uppercase;
2094
+ vertical-align: middle;
2095
+ }
2096
+ .bk-serp-preview__tag--ad {
2097
+ background: var(--blog-brand);
2098
+ color: var(--blog-on-brand);
2099
+ }
2100
+ .bk-serp-preview__url {
2101
+ font-family: var(--blog-font-body);
2102
+ font-size: var(--blog-fs-sm);
2103
+ color: var(--blog-mute-2);
2104
+ }
2105
+ .bk-serp-preview__url strong {
2106
+ color: var(--blog-ink);
2107
+ }
2108
+ .bk-serp-preview__heading {
2109
+ margin: var(--blog-sp-1) 0;
2110
+ font-family: var(--blog-font-body);
2111
+ font-size: var(--blog-fs-xl);
2112
+ line-height: 1.3;
2113
+ color: var(--blog-info);
2114
+ }
2115
+ .bk-serp-preview__heading:hover {
2116
+ text-decoration: underline;
2117
+ }
2118
+ .bk-serp-preview__desc {
2119
+ margin: 0;
2120
+ font-family: var(--blog-font-body);
2121
+ font-size: var(--blog-fs-sm);
2122
+ line-height: 1.4;
2123
+ color: var(--blog-mute-2);
2124
+ }
2125
+ .bk-serp-preview__desc em {
2126
+ font-style: normal;
2127
+ font-weight: 600;
2128
+ color: var(--blog-ink);
2129
+ }
2130
+
2131
+ /* ── AdPreview ───────────────────────────────────────────────
2132
+ Mock paid-ad creative in two platform styles. Ported from hjd's
2133
+ .b-ad: cyan/dark mapped to neutral tokens (cyan → --blog-brand,
2134
+ night → --blog-dark, #fff → --blog-paper, mist → --blog-bg-secondary,
2135
+ greys → ink/border tokens). The Google link-blue (#0a4280) maps to
2136
+ --blog-info to match SerpPreview. */
2137
+ .bk-ad-preview {
2138
+ padding: 0;
2139
+ border: 1px solid var(--blog-border-light);
2140
+ border-radius: var(--blog-radius-md);
2141
+ background: var(--blog-paper);
2142
+ overflow: hidden;
2143
+ margin: var(--blog-sp-6) 0;
2144
+ }
2145
+ .bk-ad-preview__head {
2146
+ padding: var(--blog-sp-3) var(--blog-sp-4);
2147
+ display: flex;
2148
+ align-items: center;
2149
+ gap: var(--blog-sp-3);
2150
+ border-bottom: 1px solid var(--blog-border-light);
2151
+ }
2152
+ .bk-ad-preview__avatar {
2153
+ width: 32px;
2154
+ height: 32px;
2155
+ flex: 0 0 32px;
2156
+ border-radius: var(--blog-radius-pill);
2157
+ background: var(--blog-dark);
2158
+ color: var(--blog-brand);
2159
+ font-family: var(--blog-font-display);
2160
+ font-weight: 700;
2161
+ display: flex;
2162
+ align-items: center;
2163
+ justify-content: center;
2164
+ font-size: var(--blog-fs-sm);
2165
+ }
2166
+ .bk-ad-preview__brand {
2167
+ font-family: var(--blog-font-display);
2168
+ font-weight: 700;
2169
+ font-size: var(--blog-fs-sm);
2170
+ color: var(--blog-text);
2171
+ letter-spacing: var(--blog-tracking-tight);
2172
+ }
2173
+ .bk-ad-preview__sponsored {
2174
+ font-family: var(--blog-font-body);
2175
+ font-size: var(--blog-fs-eyebrow);
2176
+ color: var(--blog-mute);
2177
+ }
2178
+ .bk-ad-preview__copy {
2179
+ padding: var(--blog-sp-4);
2180
+ font-family: var(--blog-font-body);
2181
+ font-size: var(--blog-fs-base);
2182
+ color: var(--blog-text);
2183
+ line-height: 1.55;
2184
+ }
2185
+ .bk-ad-preview__media {
2186
+ aspect-ratio: 1.91 / 1;
2187
+ background: linear-gradient(135deg, var(--blog-dark), var(--blog-brand-dark) 65%, var(--blog-brand));
2188
+ position: relative;
2189
+ }
2190
+ .bk-ad-preview__media img {
2191
+ width: 100%;
2192
+ height: 100%;
2193
+ object-fit: cover;
2194
+ display: block;
2195
+ }
2196
+ .bk-ad-preview__cta {
2197
+ padding: var(--blog-sp-3) var(--blog-sp-4);
2198
+ background: var(--blog-bg-secondary);
2199
+ display: flex;
2200
+ justify-content: space-between;
2201
+ align-items: center;
2202
+ gap: var(--blog-sp-3);
2203
+ border-top: 1px solid var(--blog-border-light);
2204
+ }
2205
+ .bk-ad-preview__site {
2206
+ font-family: var(--blog-font-mono);
2207
+ font-size: var(--blog-fs-eyebrow);
2208
+ color: var(--blog-mute);
2209
+ text-transform: uppercase;
2210
+ letter-spacing: 0.06em;
2211
+ }
2212
+ .bk-ad-preview__site strong { color: var(--blog-text); }
2213
+ .bk-ad-preview__btn {
2214
+ background: var(--blog-brand);
2215
+ color: var(--blog-on-brand);
2216
+ border: none;
2217
+ border-radius: var(--blog-radius-sm);
2218
+ padding: 7px 14px;
2219
+ font-family: var(--blog-font-display);
2220
+ font-weight: 700;
2221
+ text-transform: uppercase;
2222
+ letter-spacing: 0.04em;
2223
+ font-size: var(--blog-fs-eyebrow);
2224
+ cursor: pointer;
2225
+ flex: 0 0 auto;
2226
+ }
2227
+
2228
+ /* ── Google search-ad variant ── */
2229
+ .bk-ad-preview--google {
2230
+ padding: 18px 20px;
2231
+ overflow: visible;
2232
+ }
2233
+ .bk-ad-preview__g-head {
2234
+ display: flex;
2235
+ gap: var(--blog-sp-2);
2236
+ align-items: center;
2237
+ margin-bottom: 6px;
2238
+ }
2239
+ .bk-ad-preview__g-tag {
2240
+ font-family: var(--blog-font-display);
2241
+ font-size: var(--blog-fs-eyebrow);
2242
+ font-weight: 700;
2243
+ color: var(--blog-dark);
2244
+ background: var(--blog-paper);
2245
+ border: 1px solid var(--blog-dark);
2246
+ border-radius: var(--blog-radius-xs);
2247
+ padding: 1px 6px;
2248
+ text-transform: uppercase;
2249
+ letter-spacing: 0.06em;
2250
+ }
2251
+ .bk-ad-preview__g-dot {
2252
+ font-family: var(--blog-font-body);
2253
+ font-size: var(--blog-fs-sm);
2254
+ color: var(--blog-mute);
2255
+ }
2256
+ .bk-ad-preview__g-site {
2257
+ font-family: var(--blog-font-body);
2258
+ font-size: var(--blog-fs-sm);
2259
+ color: var(--blog-mute-2);
2260
+ }
2261
+ .bk-ad-preview__g-url {
2262
+ font-family: var(--blog-font-body);
2263
+ font-size: var(--blog-fs-sm);
2264
+ color: var(--blog-mute-2);
2265
+ margin-top: 6px;
2266
+ }
2267
+ .bk-ad-preview__g-url strong { color: var(--blog-text); }
2268
+ .bk-ad-preview__g-headline {
2269
+ font-family: var(--blog-font-body);
2270
+ font-size: var(--blog-fs-xl);
2271
+ color: var(--blog-info);
2272
+ margin: 4px 0;
2273
+ line-height: 1.3;
2274
+ cursor: pointer;
2275
+ }
2276
+ .bk-ad-preview__g-desc {
2277
+ font-family: var(--blog-font-body);
2278
+ font-size: var(--blog-fs-sm);
2279
+ color: var(--blog-mute-2);
2280
+ line-height: 1.4;
2281
+ margin: 0;
2282
+ }
2283
+ .bk-ad-preview__g-sitelinks {
2284
+ display: flex;
2285
+ gap: var(--blog-sp-4);
2286
+ margin-top: var(--blog-sp-2);
2287
+ padding-top: var(--blog-sp-2);
2288
+ border-top: 1px dashed var(--blog-border-light);
2289
+ }
2290
+ .bk-ad-preview__g-sitelink {
2291
+ font-family: var(--blog-font-body);
2292
+ font-size: var(--blog-fs-xs);
2293
+ color: var(--blog-info);
2294
+ }
2295
+ @media (max-width: 700px) {
2296
+ .bk-ad-preview__cta { flex-wrap: wrap; }
2297
+ }
2298
+
2299
+ /* ── AdPreviewPair ─────────────────────────────────────────────
2300
+ hjd b-ads → tokenised. A layout-only container: two ad mockups
2301
+ side by side, collapsing to one column on narrow screens. The
2302
+ hjd source had no colours of its own, so only spacing tokens. */
2303
+ .bk-ad-preview-pair { display:grid; grid-template-columns:1fr; gap:var(--blog-sp-3); margin:var(--blog-sp-6) 0; align-items:start; }
2304
+ @media (min-width:768px){ .bk-ad-preview-pair { grid-template-columns:1fr 1fr; } }
2305
+
2306
+ /* ============================================================
2307
+ AuditScores (.bk-audit-scores) — hjd pack
2308
+ A responsive row of semicircular score gauges (0–100). Each card
2309
+ draws a faint neutral track arc plus a tone-coloured progress arc
2310
+ whose sweep is computed (in the wrapper) from the score, a big
2311
+ tone-coloured number, an uppercase label, and an optional sub-line.
2312
+ Tone (good / warn / bad) is expressed purely as a token-driven
2313
+ `--_c` custom property on the card modifier; the arc + number both
2314
+ inherit it, so the SAME component renders in each pack's brand
2315
+ colour for a passing score. Ported from hjd's blog AuditScores —
2316
+ hardcoded #10C8F0 / #FFB020 / #F04D4D mapped to --blog-brand /
2317
+ --blog-warn / --blog-danger, the #EDEFF2 track to --blog-bg-tertiary,
2318
+ and the #fff card to --blog-paper.
2319
+ ============================================================ */
2320
+ .bk-audit-scores {
2321
+ display: grid;
2322
+ grid-template-columns: repeat(3, 1fr);
2323
+ gap: var(--blog-sp-3);
2324
+ margin: var(--blog-sp-6) 0;
2325
+ }
2326
+ @media (max-width: 700px) {
2327
+ .bk-audit-scores { grid-template-columns: 1fr; }
2328
+ }
2329
+ .bk-audit-scores__card {
2330
+ --_c: var(--blog-brand);
2331
+ padding: var(--blog-sp-5);
2332
+ border: 1px solid var(--blog-border);
2333
+ border-radius: var(--blog-radius-md);
2334
+ background: var(--blog-paper);
2335
+ text-align: center;
2336
+ }
2337
+ .bk-audit-scores__card--warn { --_c: var(--blog-warn); }
2338
+ .bk-audit-scores__card--bad { --_c: var(--blog-danger); }
2339
+ .bk-audit-scores__gauge {
2340
+ display: block;
2341
+ width: 140px;
2342
+ height: 84px;
2343
+ margin: 0 auto var(--blog-sp-2);
2344
+ }
2345
+ .bk-audit-scores__track {
2346
+ stroke: var(--blog-bg-tertiary);
2347
+ }
2348
+ .bk-audit-scores__arc {
2349
+ stroke: var(--_c);
2350
+ }
2351
+ .bk-audit-scores__num {
2352
+ font-family: var(--blog-font-display);
2353
+ font-weight: 700;
2354
+ font-size: var(--blog-fs-6xl);
2355
+ line-height: 1;
2356
+ color: var(--_c);
2357
+ }
2358
+ .bk-audit-scores__label {
2359
+ margin-top: var(--blog-sp-2);
2360
+ font-family: var(--blog-font-display);
2361
+ font-weight: 700;
2362
+ font-size: var(--blog-fs-eyebrow);
2363
+ text-transform: uppercase;
2364
+ letter-spacing: .06em;
2365
+ color: var(--blog-ink);
2366
+ }
2367
+ .bk-audit-scores__sub {
2368
+ margin-top: .125rem;
2369
+ font-family: var(--blog-font-body);
2370
+ font-size: var(--blog-fs-xs);
2371
+ color: var(--blog-mute);
2372
+ }
2373
+
2374
+ /* ============================================================
2375
+ AuditFindings (.bk-audit-findings) — hjd pack
2376
+ A bordered, divided list of audit findings. Each row leads with a
2377
+ small severity dot (high / med / low), then a title + description
2378
+ block, and a pill-shaped count on the right. Severity tone is a
2379
+ token-driven CSS class (the dot colour resolves to the matching
2380
+ state token) so the SAME component renders in each pack's palette.
2381
+ Ported from hjd's blog AuditFindings (b-saf; #fff panel +
2382
+ #F04D4D / #FFB020 / good-green dots + greys mapped to tokens).
2383
+ ============================================================ */
2384
+ .bk-audit-findings {
2385
+ margin: var(--blog-sp-6) 0;
2386
+ border: 1px solid var(--blog-border);
2387
+ border-radius: var(--blog-radius-md);
2388
+ overflow: hidden;
2389
+ background: var(--blog-paper);
2390
+ }
2391
+ .bk-audit-findings__row {
2392
+ display: grid;
2393
+ grid-template-columns: auto 1fr auto;
2394
+ gap: var(--blog-sp-4);
2395
+ padding: var(--blog-sp-4) var(--blog-sp-5);
2396
+ border-bottom: 1px solid var(--blog-border);
2397
+ align-items: center;
2398
+ }
2399
+ .bk-audit-findings__row:last-child {
2400
+ border-bottom: none;
2401
+ }
2402
+ .bk-audit-findings__sev {
2403
+ width: 10px;
2404
+ height: 10px;
2405
+ border-radius: var(--blog-radius-pill);
2406
+ flex-shrink: 0;
2407
+ }
2408
+ .bk-audit-findings__sev--high { background: var(--blog-danger); }
2409
+ .bk-audit-findings__sev--med { background: var(--blog-warn); }
2410
+ .bk-audit-findings__sev--low { background: var(--blog-success); }
2411
+ .bk-audit-findings__title {
2412
+ font-family: var(--blog-font-display);
2413
+ font-weight: 700;
2414
+ font-size: var(--blog-fs-base);
2415
+ color: var(--blog-ink);
2416
+ text-transform: uppercase;
2417
+ letter-spacing: var(--blog-tracking-wide);
2418
+ }
2419
+ .bk-audit-findings__desc {
2420
+ margin-top: 2px;
2421
+ font-family: var(--blog-font-body);
2422
+ font-size: var(--blog-fs-sm);
2423
+ line-height: 1.5;
2424
+ color: var(--blog-mute);
2425
+ }
2426
+ .bk-audit-findings__count {
2427
+ font-family: var(--blog-font-mono);
2428
+ font-size: var(--blog-fs-sm);
2429
+ color: var(--blog-ink);
2430
+ padding: 4px 10px;
2431
+ border: 1px solid var(--blog-border);
2432
+ border-radius: var(--blog-radius-pill);
2433
+ }
2434
+
2435
+ /* ────────────────────────────────────────────────────────────
2436
+ Canonical name: DeliveryComparison
2437
+ A flexible N-column comparison matrix. A header row of column
2438
+ labels (the first header cell is blank, sitting above the
2439
+ row-label column), then one row per criterion: a bold row label
2440
+ with optional sub-text followed by one cell per column. The
2441
+ table overflows its container on narrow viewports; the
2442
+ [data-bk-delivery-comparison] behaviour toggles edge-fade hint
2443
+ classes when it can scroll left/right (the hidden-horizontal-
2444
+ scroll trap). Ported from hjd-website's blog DeliveryComparison;
2445
+ cyan/dark source mapped to neutral --blog-* tokens.
2446
+ ──────────────────────────────────────────────────────────── */
2447
+ .bk-delivery-comparison {
2448
+ margin: var(--blog-sp-7) 0;
2449
+ position: relative;
2450
+ border: 1px solid var(--blog-border);
2451
+ border-radius: var(--blog-radius-sm);
2452
+ background: var(--blog-paper);
2453
+ overflow: hidden;
2454
+ }
2455
+ .bk-delivery-comparison__scroll { overflow-x: auto; border-radius: inherit; }
2456
+ .bk-delivery-comparison__table {
2457
+ width: 100%;
2458
+ border-collapse: collapse;
2459
+ font-family: var(--blog-font-body);
2460
+ font-size: var(--blog-fs-base);
2461
+ }
2462
+ .bk-delivery-comparison__th {
2463
+ text-align: left;
2464
+ padding: var(--blog-sp-3) var(--blog-sp-4);
2465
+ background: var(--blog-bg-secondary);
2466
+ border-bottom: 1px solid var(--blog-border);
2467
+ font-family: var(--blog-font-display);
2468
+ font-weight: 700;
2469
+ font-size: var(--blog-fs-xs);
2470
+ text-transform: uppercase;
2471
+ letter-spacing: var(--blog-tracking-wide);
2472
+ color: var(--blog-mute);
2473
+ white-space: nowrap;
2474
+ }
2475
+ .bk-delivery-comparison__td {
2476
+ padding: var(--blog-sp-3) var(--blog-sp-4);
2477
+ border-bottom: 1px solid var(--blog-border);
2478
+ text-align: left;
2479
+ vertical-align: top;
2480
+ line-height: 1.5;
2481
+ color: var(--blog-text);
2482
+ }
2483
+ .bk-delivery-comparison__tr:last-child .bk-delivery-comparison__td { border-bottom: none; }
2484
+ .bk-delivery-comparison__label {
2485
+ display: block;
2486
+ margin-bottom: 2px;
2487
+ font-weight: 700;
2488
+ color: var(--blog-ink);
2489
+ }
2490
+
2491
+ /* Scroll-edge hint fades, toggled by the behaviour on overflow. */
2492
+ .bk-delivery-comparison::before,
2493
+ .bk-delivery-comparison::after {
2494
+ content: "";
2495
+ position: absolute;
2496
+ top: 0;
2497
+ bottom: 0;
2498
+ width: var(--blog-sp-6);
2499
+ pointer-events: none;
2500
+ opacity: 0;
2501
+ transition: opacity 0.15s ease;
2502
+ z-index: 1;
2503
+ }
2504
+ .bk-delivery-comparison::before {
2505
+ left: 0;
2506
+ background: linear-gradient(to right, var(--blog-paper), transparent);
2507
+ }
2508
+ .bk-delivery-comparison::after {
2509
+ right: 0;
2510
+ background: linear-gradient(to left, var(--blog-paper), transparent);
2511
+ }
2512
+ .bk-delivery-comparison--hint-left::before { opacity: 1; }
2513
+ .bk-delivery-comparison--hint-right::after { opacity: 1; }
2514
+
2515
+ /* ============================================================
2516
+ RegionCallout — bordered grid of office / region cells, each
2517
+ pairing a flag/colour swatch with an uppercase office name and
2518
+ a brand-coloured monospace phone number. Ported from hjd
2519
+ (.b-region): cyan phone (--hjd-cyan) → --blog-brand, #fff cells
2520
+ → --blog-paper, --hjd-mist swatch → --blog-bg-tertiary, greys
2521
+ → border/ink tokens, --hjd-r-md → --blog-radius-md.
2522
+ ============================================================ */
2523
+ .bk-region-callout { display:grid; grid-template-columns:repeat(3,1fr); gap:0; margin:var(--blog-sp-6) 0; border:1px solid var(--blog-border); border-radius:var(--blog-radius-md); overflow:hidden; }
2524
+ .bk-region-callout__cell { display:flex; align-items:center; gap:var(--blog-sp-3); padding:var(--blog-sp-4) var(--blog-sp-5); background:var(--blog-paper); border-right:1px solid var(--blog-border); }
2525
+ .bk-region-callout__cell:last-child { border-right:none; }
2526
+ .bk-region-callout__flag { flex-shrink:0; width:40px; height:30px; border-radius:var(--blog-radius-xs); background:var(--blog-bg-tertiary); border:1px solid var(--blog-border); position:relative; overflow:hidden; }
2527
+ .bk-region-callout__info { min-width:0; }
2528
+ .bk-region-callout__name { font-family:var(--blog-font-display); font-weight:700; text-transform:uppercase; font-size: var(--blog-fs-xs); letter-spacing:var(--blog-tracking-wide); color:var(--blog-ink); }
2529
+ .bk-region-callout__phone { margin-top:2px; font-family:var(--blog-font-mono); font-size: var(--blog-fs-sm); color:var(--blog-brand); }
2530
+ @media (max-width:700px){ .bk-region-callout { grid-template-columns:1fr; } .bk-region-callout__cell { border-right:none; border-bottom:1px solid var(--blog-border); } .bk-region-callout__cell:last-child { border-bottom:none; } }
2531
+
2532
+ /* ── ServicePromoCard ────────────────────────────────────────
2533
+ Ported from hjd .b-svc. Cyan accents → --blog-brand + brand tint/soft;
2534
+ greys → ink/mute; dark-theme stays neutral via tokens. */
2535
+ .bk-service-promo-card {
2536
+ display: grid;
2537
+ grid-template-columns: auto 1fr auto;
2538
+ align-items: center;
2539
+ gap: var(--blog-sp-4);
2540
+ margin: var(--blog-sp-6) 0;
2541
+ padding: var(--blog-sp-4) var(--blog-sp-5);
2542
+ border: 1px solid var(--blog-border);
2543
+ border-radius: var(--blog-radius-sm);
2544
+ background: linear-gradient(90deg, var(--blog-brand-tint), transparent);
2545
+ color: inherit;
2546
+ text-decoration: none;
2547
+ transition: border-color 0.15s;
2548
+ }
2549
+ .bk-service-promo-card:hover { border-color: var(--blog-brand); }
2550
+ .bk-service-promo-card__icon {
2551
+ display: flex;
2552
+ align-items: center;
2553
+ justify-content: center;
2554
+ flex-shrink: 0;
2555
+ width: 44px;
2556
+ height: 44px;
2557
+ border-radius: var(--blog-radius-sm);
2558
+ background: var(--blog-brand-soft);
2559
+ color: var(--blog-brand);
2560
+ }
2561
+ .bk-service-promo-card__icon svg {
2562
+ display: block;
2563
+ width: 22px;
2564
+ height: 22px;
2565
+ }
2566
+ .bk-service-promo-card__body { min-width: 0; }
2567
+ .bk-service-promo-card__title {
2568
+ display: block;
2569
+ font-family: var(--blog-font-display);
2570
+ font-weight: 700;
2571
+ font-size: var(--blog-fs-md);
2572
+ text-transform: uppercase;
2573
+ letter-spacing: var(--blog-tracking-tight);
2574
+ color: var(--blog-ink);
2575
+ }
2576
+ .bk-service-promo-card__sub {
2577
+ display: block;
2578
+ margin-top: 2px;
2579
+ font-family: var(--blog-font-body);
2580
+ font-size: var(--blog-fs-sm);
2581
+ color: var(--blog-mute);
2582
+ }
2583
+ .bk-service-promo-card__arrow {
2584
+ flex-shrink: 0;
2585
+ font-family: var(--blog-font-display);
2586
+ font-weight: 700;
2587
+ font-size: var(--blog-fs-sm);
2588
+ text-transform: uppercase;
2589
+ letter-spacing: var(--blog-tracking-wide);
2590
+ color: var(--blog-brand);
2591
+ white-space: nowrap;
2592
+ }
2593
+
2594
+ /* ============================================================
2595
+ ProseList (.bk-prose-list) — body-copy bullet/ordered lists
2596
+ Two variants: --ul (brand dash marker) and --ol (zero-padded
2597
+ brand counter). Add --divided for dashed-divider breathing
2598
+ room between items. --grid mode aligns {title, description}
2599
+ pairs into two columns across every row.
2600
+ ============================================================ */
2601
+ .bk-prose-list { margin: 20px 0; padding: 0; padding-inline-start: 0; }
2602
+ .bk-prose-list--ul { list-style: none; }
2603
+ .bk-prose-list--ul .bk-prose-list__item { display: flex; align-items: flex-start; gap: 14px; padding: 6px 0 6px 6px; font-family: var(--blog-font-body); font-size: var(--blog-fs-md); line-height: 1.65; color: var(--blog-text); }
2604
+ .bk-prose-list--ul .bk-prose-list__item::before { content: ""; flex-shrink: 0; width: 8px; height: 2px; background: var(--blog-brand); border-radius: 1px; margin-top: calc((1em * 1.65 - 2px) / 2); }
2605
+ .bk-prose-list--ol { list-style: none; counter-reset: bkproselist; }
2606
+ .bk-prose-list--ol .bk-prose-list__item { display: flex; align-items: flex-start; gap: 14px; padding: 6px 0; counter-increment: bkproselist; font-family: var(--blog-font-body); font-size: var(--blog-fs-md); line-height: 1.65; color: var(--blog-text); }
2607
+ .bk-prose-list--ol .bk-prose-list__item::before { content: counter(bkproselist, decimal-leading-zero); font-family: var(--blog-font-display); font-weight: 700; font-size: var(--blog-fs-xs); line-height: calc(1.65 * 15 / 12); color: var(--blog-brand); letter-spacing: .04em; flex-shrink: 0; min-width: 22px; }
2608
+ .bk-prose-list__item strong { color: var(--blog-ink); font-weight: 700; }
2609
+ .bk-prose-list__item + .bk-prose-list__item { border-top: 1px dashed transparent; }
2610
+ .bk-prose-list--divided .bk-prose-list__item + .bk-prose-list__item { border-top-color: var(--blog-border-light); padding-top: 10px; margin-top: 4px; }
2611
+
2612
+ /* Grid mode: title + description align as columns across rows. Each <li> uses
2613
+ display:contents so its two spans participate in the parent grid. The marker
2614
+ (dash or counter) renders as a ::before on the title so it tracks the
2615
+ title's first-line baseline cleanly. */
2616
+ .bk-prose-list--grid { display: grid; grid-template-columns: minmax(200px, 1.4fr) minmax(0, 2fr); column-gap: 28px; row-gap: 14px; counter-reset: bkproselist; }
2617
+ .bk-prose-list--grid .bk-prose-list__item { display: contents; }
2618
+ .bk-prose-list--grid .bk-prose-list__item::before { content: none; }
2619
+ .bk-prose-list--grid .bk-prose-list__marker { display: none; }
2620
+ .bk-prose-list--grid .bk-prose-list__title { counter-increment: bkproselist; position: relative; padding-left: 28px; font-family: var(--blog-font-body); font-weight: 700; font-size: var(--blog-fs-md); line-height: 1.55; color: var(--blog-ink); align-self: start; text-wrap: pretty; }
2621
+ .bk-prose-list--grid .bk-prose-list__desc { font-family: var(--blog-font-body); font-size: var(--blog-fs-md); line-height: 1.65; color: var(--blog-text); align-self: start; }
2622
+ .bk-prose-list--grid.bk-prose-list--ol .bk-prose-list__title::before { content: counter(bkproselist, decimal-leading-zero); position: absolute; left: 0; top: .1em; font-family: var(--blog-font-display); font-weight: 700; font-size: var(--blog-fs-xs); color: var(--blog-brand); letter-spacing: .04em; }
2623
+ .bk-prose-list--grid.bk-prose-list--ul .bk-prose-list__title::before { content: ""; position: absolute; left: 0; top: .7em; width: 10px; height: 2px; background: var(--blog-brand); border-radius: 1px; }
2624
+ .bk-prose-list--grid.bk-prose-list--divided .bk-prose-list__item:not(:first-child) .bk-prose-list__title,
2625
+ .bk-prose-list--grid.bk-prose-list--divided .bk-prose-list__item:not(:first-child) .bk-prose-list__desc { border-top: 1px dashed var(--blog-border-light); padding-top: 14px; }
2626
+ .bk-prose-list--grid.bk-prose-list--divided .bk-prose-list__item:not(:first-child) .bk-prose-list__title { padding-top: 14px; }
2627
+ .bk-prose-list--grid.bk-prose-list--divided.bk-prose-list--ol .bk-prose-list__item:not(:first-child) .bk-prose-list__title::before { top: calc(14px + .1em); }
2628
+ .bk-prose-list--grid.bk-prose-list--divided.bk-prose-list--ul .bk-prose-list__item:not(:first-child) .bk-prose-list__title::before { top: calc(14px + .7em); }
2629
+ @media (max-width: 640px) {
2630
+ .bk-prose-list--grid { grid-template-columns: 1fr; row-gap: 6px; }
2631
+ .bk-prose-list--grid.bk-prose-list--divided .bk-prose-list__item:not(:first-child) .bk-prose-list__desc { border-top: none; padding-top: 2px; }
2632
+ }