abqari 1.1.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 (1509) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +889 -0
  3. data/LICENSE +21 -0
  4. data/README.md +2739 -0
  5. data/SECURITY.md +73 -0
  6. data/THIRD_PARTY_NOTICES.md +46 -0
  7. data/app/assets/css/_common.css +3125 -0
  8. data/app/assets/js/carousel.js +39 -0
  9. data/app/assets/js/contact-button.js +28 -0
  10. data/app/assets/js/random-pool.js +44 -0
  11. data/app/assets/js/search-init.js +11 -0
  12. data/app/assets/js/theme-toggle.js +39 -0
  13. data/app/assets/js/viz-tag-bubble.js +108 -0
  14. data/app/assets/js/viz-tag-cooccurrence.js +125 -0
  15. data/app/assets/js/viz-topic-constellation.js +142 -0
  16. data/app/icons/bluesky.svg +3 -0
  17. data/app/icons/github.svg +3 -0
  18. data/app/icons/linkedin.svg +3 -0
  19. data/app/icons/mail.svg +4 -0
  20. data/app/icons/mastodon.svg +3 -0
  21. data/app/icons/moon.svg +3 -0
  22. data/app/icons/rss.svg +3 -0
  23. data/app/icons/sun.svg +4 -0
  24. data/app/icons/x.svg +3 -0
  25. data/app/views/layouts/about.html.erb +70 -0
  26. data/app/views/layouts/application.html.erb +65 -0
  27. data/app/views/layouts/book_series_index.html.erb +43 -0
  28. data/app/views/layouts/bundle.html.erb +111 -0
  29. data/app/views/layouts/bundles_index.html.erb +46 -0
  30. data/app/views/layouts/country_index.html.erb +59 -0
  31. data/app/views/layouts/gallery_index.html.erb +126 -0
  32. data/app/views/layouts/home.html.erb +107 -0
  33. data/app/views/layouts/photo.html.erb +100 -0
  34. data/app/views/layouts/photos_archive.html.erb +101 -0
  35. data/app/views/layouts/photos_index.html.erb +204 -0
  36. data/app/views/layouts/post.html.erb +153 -0
  37. data/app/views/layouts/posts_archive.html.erb +98 -0
  38. data/app/views/layouts/posts_index.html.erb +80 -0
  39. data/app/views/layouts/publication.html.erb +116 -0
  40. data/app/views/layouts/publications_archive.html.erb +89 -0
  41. data/app/views/layouts/publications_index.html.erb +246 -0
  42. data/app/views/layouts/related_index.html.erb +48 -0
  43. data/app/views/layouts/series.html.erb +110 -0
  44. data/app/views/layouts/series_index.html.erb +202 -0
  45. data/app/views/layouts/tag.html.erb +16 -0
  46. data/app/views/layouts/visualization.html.erb +32 -0
  47. data/app/views/layouts/workshop.html.erb +163 -0
  48. data/app/views/layouts/workshops_index.html.erb +209 -0
  49. data/app/views/partials/_back_link.html.erb +27 -0
  50. data/app/views/partials/_back_to_index.html.erb +25 -0
  51. data/app/views/partials/_book_grid.html.erb +76 -0
  52. data/app/views/partials/_book_jsonld.html.erb +72 -0
  53. data/app/views/partials/_book_related.html.erb +87 -0
  54. data/app/views/partials/_breadcrumb_jsonld.html.erb +60 -0
  55. data/app/views/partials/_bundle_cta.html.erb +26 -0
  56. data/app/views/partials/_carousel.html.erb +64 -0
  57. data/app/views/partials/_collection_page_jsonld.html.erb +81 -0
  58. data/app/views/partials/_contact_button.html.erb +42 -0
  59. data/app/views/partials/_course_jsonld.html.erb +95 -0
  60. data/app/views/partials/_draft_banner.html.erb +20 -0
  61. data/app/views/partials/_event_jsonld.html.erb +122 -0
  62. data/app/views/partials/_footer.html.erb +88 -0
  63. data/app/views/partials/_future_banner.html.erb +25 -0
  64. data/app/views/partials/_head.html.erb +440 -0
  65. data/app/views/partials/_image_gallery.html.erb +64 -0
  66. data/app/views/partials/_image_object_jsonld.html.erb +61 -0
  67. data/app/views/partials/_nav.html.erb +63 -0
  68. data/app/views/partials/_newsletter_subscribe.html.erb +85 -0
  69. data/app/views/partials/_next_in_series.html.erb +27 -0
  70. data/app/views/partials/_next_item.html.erb +38 -0
  71. data/app/views/partials/_pagination.html.erb +15 -0
  72. data/app/views/partials/_person_jsonld.html.erb +46 -0
  73. data/app/views/partials/_plausible.html.erb +24 -0
  74. data/app/views/partials/_post_list.html.erb +101 -0
  75. data/app/views/partials/_post_series_previews.html.erb +92 -0
  76. data/app/views/partials/_publication_card.html.erb +75 -0
  77. data/app/views/partials/_publication_header.html.erb +61 -0
  78. data/app/views/partials/_related_item.html.erb +68 -0
  79. data/app/views/partials/_related_items.html.erb +105 -0
  80. data/app/views/partials/_search.html.erb +26 -0
  81. data/app/views/partials/_series_pager.html.erb +48 -0
  82. data/app/views/partials/_skip_link.html.erb +12 -0
  83. data/app/views/partials/_taxonomy_row.html.erb +62 -0
  84. data/app/views/partials/_testimonials.html.erb +149 -0
  85. data/app/views/partials/_theme_toggle.html.erb +19 -0
  86. data/app/views/partials/_toc.html.erb +136 -0
  87. data/app/views/partials/_webmentions.html.erb +131 -0
  88. data/app/views/partials/_website_jsonld.html.erb +39 -0
  89. data/app/views/partials/home/_contact.html.erb +19 -0
  90. data/app/views/partials/home/_featured_publication.html.erb +107 -0
  91. data/app/views/partials/home/_latest_photo.html.erb +95 -0
  92. data/app/views/partials/home/_latest_post.html.erb +48 -0
  93. data/app/views/partials/home/_latest_publication.html.erb +89 -0
  94. data/app/views/partials/home/_next_workshop.html.erb +119 -0
  95. data/app/views/partials/home/_photo_gallery.html.erb +71 -0
  96. data/app/views/partials/home/_random_photo.html.erb +106 -0
  97. data/app/views/partials/home/_random_post.html.erb +64 -0
  98. data/exe/abqari +37 -0
  99. data/lib/abqari/artifact_writer.rb +196 -0
  100. data/lib/abqari/asset_pipeline.rb +235 -0
  101. data/lib/abqari/audit/a11y.rb +80 -0
  102. data/lib/abqari/audit/content.rb +154 -0
  103. data/lib/abqari/audit/dependencies.rb +127 -0
  104. data/lib/abqari/audit/links.rb +120 -0
  105. data/lib/abqari/audit/performance.rb +120 -0
  106. data/lib/abqari/audit/privacy.rb +42 -0
  107. data/lib/abqari/audit/rule.rb +56 -0
  108. data/lib/abqari/audit/seo.rb +105 -0
  109. data/lib/abqari/audit.rb +149 -0
  110. data/lib/abqari/bundle_assets.rb +127 -0
  111. data/lib/abqari/cli/new.rb +541 -0
  112. data/lib/abqari/cli/theme.rb +181 -0
  113. data/lib/abqari/cli.rb +130 -0
  114. data/lib/abqari/erbi_template.rb +72 -0
  115. data/lib/abqari/feed.rb +159 -0
  116. data/lib/abqari/folio.rb +195 -0
  117. data/lib/abqari/font_pipeline.rb +104 -0
  118. data/lib/abqari/headers_file.rb +324 -0
  119. data/lib/abqari/helpers.rb +308 -0
  120. data/lib/abqari/hooks.rb +136 -0
  121. data/lib/abqari/http_safe.rb +222 -0
  122. data/lib/abqari/image_pipeline.rb +800 -0
  123. data/lib/abqari/importers/base.rb +351 -0
  124. data/lib/abqari/importers/cli.rb +169 -0
  125. data/lib/abqari/importers/ghost.rb +113 -0
  126. data/lib/abqari/importers/jekyll.rb +256 -0
  127. data/lib/abqari/importers/substack.rb +204 -0
  128. data/lib/abqari/importers/support/html_to_markdown.rb +126 -0
  129. data/lib/abqari/importers/support/image_downloader.rb +170 -0
  130. data/lib/abqari/importers/support/report.rb +87 -0
  131. data/lib/abqari/importers/support/slug_normalizer.rb +53 -0
  132. data/lib/abqari/importers.rb +64 -0
  133. data/lib/abqari/indieweb.rb +551 -0
  134. data/lib/abqari/llms_txt.rb +110 -0
  135. data/lib/abqari/log.rb +61 -0
  136. data/lib/abqari/manifest.rb +58 -0
  137. data/lib/abqari/minifier.rb +108 -0
  138. data/lib/abqari/og_image_generator.rb +223 -0
  139. data/lib/abqari/page/bundle.rb +152 -0
  140. data/lib/abqari/page/incremental.rb +74 -0
  141. data/lib/abqari/page/parser.rb +129 -0
  142. data/lib/abqari/page/path.rb +153 -0
  143. data/lib/abqari/page.rb +424 -0
  144. data/lib/abqari/paginated_shard.rb +109 -0
  145. data/lib/abqari/paginator.rb +35 -0
  146. data/lib/abqari/path_safe.rb +62 -0
  147. data/lib/abqari/plausible_script.rb +20 -0
  148. data/lib/abqari/publication_normaliser.rb +111 -0
  149. data/lib/abqari/publisher_pages.rb +342 -0
  150. data/lib/abqari/redirects.rb +134 -0
  151. data/lib/abqari/related_index_page.rb +79 -0
  152. data/lib/abqari/render_context/cover_helpers.rb +338 -0
  153. data/lib/abqari/render_context/picture_helpers.rb +178 -0
  154. data/lib/abqari/render_context/publication_helpers.rb +120 -0
  155. data/lib/abqari/render_context.rb +251 -0
  156. data/lib/abqari/renderer.rb +788 -0
  157. data/lib/abqari/robots.rb +93 -0
  158. data/lib/abqari/search.rb +68 -0
  159. data/lib/abqari/security_txt.rb +44 -0
  160. data/lib/abqari/server.rb +508 -0
  161. data/lib/abqari/site.rb +952 -0
  162. data/lib/abqari/site_config.rb +212 -0
  163. data/lib/abqari/site_loader.rb +265 -0
  164. data/lib/abqari/sitemap.rb +87 -0
  165. data/lib/abqari/speculation_rules_guard.rb +26 -0
  166. data/lib/abqari/syndication.rb +466 -0
  167. data/lib/abqari/syntax_highlighter.rb +146 -0
  168. data/lib/abqari/taxonomy_page.rb +129 -0
  169. data/lib/abqari/templates/site_skeleton/.github/dependabot.yml +53 -0
  170. data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-cloudflare.yml +107 -0
  171. data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-github-pages.yml +107 -0
  172. data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-render.yml +87 -0
  173. data/lib/abqari/templates/site_skeleton/.gitignore +24 -0
  174. data/lib/abqari/templates/site_skeleton/.ruby-version.tt +1 -0
  175. data/lib/abqari/templates/site_skeleton/Gemfile.tt +20 -0
  176. data/lib/abqari/templates/site_skeleton/README.md.tt +60 -0
  177. data/lib/abqari/templates/site_skeleton/app/assets/css/site.css +9 -0
  178. data/lib/abqari/templates/site_skeleton/bin/audit +46 -0
  179. data/lib/abqari/templates/site_skeleton/bin/build +32 -0
  180. data/lib/abqari/templates/site_skeleton/bin/fetch-folio +32 -0
  181. data/lib/abqari/templates/site_skeleton/bin/fetch-fonts +20 -0
  182. data/lib/abqari/templates/site_skeleton/bin/import +31 -0
  183. data/lib/abqari/templates/site_skeleton/bin/index +30 -0
  184. data/lib/abqari/templates/site_skeleton/bin/new +235 -0
  185. data/lib/abqari/templates/site_skeleton/bin/serve +30 -0
  186. data/lib/abqari/templates/site_skeleton/config/site.blank.yml.tt +65 -0
  187. data/lib/abqari/templates/site_skeleton/config/site.yml.tt +266 -0
  188. data/lib/abqari/templates/site_skeleton/content/404.md +17 -0
  189. data/lib/abqari/templates/site_skeleton/content/about.blank.md.tt +12 -0
  190. data/lib/abqari/templates/site_skeleton/content/about.md.tt +18 -0
  191. data/lib/abqari/templates/site_skeleton/content/index.blank.md.tt +11 -0
  192. data/lib/abqari/templates/site_skeleton/content/index.md.tt +34 -0
  193. data/lib/abqari/templates/site_skeleton/content/photos/index.md.tt +12 -0
  194. data/lib/abqari/templates/site_skeleton/content/posts/index.md +12 -0
  195. data/lib/abqari/templates/site_skeleton/content/posts/welcome/index.md.tt +50 -0
  196. data/lib/abqari/templates/site_skeleton/content/publications/index.md.tt +13 -0
  197. data/lib/abqari/templates/site_skeleton/content/workshops/index.md.tt +13 -0
  198. data/lib/abqari/templates/site_skeleton/public/robots.txt +6 -0
  199. data/lib/abqari/templates/site_skeleton/themes/.gitkeep +0 -0
  200. data/lib/abqari/templates/site_skeleton/vendor/folio/.gitkeep +0 -0
  201. data/lib/abqari/templates/site_skeleton/vendor/fonts/.gitkeep +0 -0
  202. data/lib/abqari/theme_bootstrap.rb +19 -0
  203. data/lib/abqari/theme_fonts.rb +51 -0
  204. data/lib/abqari/version.rb +18 -0
  205. data/lib/abqari/visualizations.rb +215 -0
  206. data/lib/abqari.rb +154 -0
  207. data/themes/bootstrap/css/app.css +97 -0
  208. data/themes/bootstrap/public/LICENSE +21 -0
  209. data/themes/bootstrap/public/css/bootstrap.min.css +6 -0
  210. data/themes/bootstrap/public/css/bootstrap.min.css.map +1 -0
  211. data/themes/bootstrap/public/js/bootstrap.bundle.min.js +7 -0
  212. data/themes/bootstrap/public/js/bootstrap.bundle.min.js.map +1 -0
  213. data/themes/custom/css/app.css +176 -0
  214. data/themes/magazine/css/app.css +242 -0
  215. data/themes/minimal/css/app.css +151 -0
  216. data/themes/notebook/css/app.css +205 -0
  217. data/themes/sand/css/app.css +179 -0
  218. data/vendor/d3/d3.v7.min.js +2 -0
  219. data/vendor/heroicons/16/solid/academic-cap.svg +4 -0
  220. data/vendor/heroicons/16/solid/adjustments-horizontal.svg +3 -0
  221. data/vendor/heroicons/16/solid/adjustments-vertical.svg +3 -0
  222. data/vendor/heroicons/16/solid/archive-box-arrow-down.svg +4 -0
  223. data/vendor/heroicons/16/solid/archive-box-x-mark.svg +4 -0
  224. data/vendor/heroicons/16/solid/archive-box.svg +4 -0
  225. data/vendor/heroicons/16/solid/arrow-down-circle.svg +3 -0
  226. data/vendor/heroicons/16/solid/arrow-down-left.svg +3 -0
  227. data/vendor/heroicons/16/solid/arrow-down-on-square-stack.svg +4 -0
  228. data/vendor/heroicons/16/solid/arrow-down-on-square.svg +3 -0
  229. data/vendor/heroicons/16/solid/arrow-down-right.svg +3 -0
  230. data/vendor/heroicons/16/solid/arrow-down-tray.svg +4 -0
  231. data/vendor/heroicons/16/solid/arrow-down.svg +3 -0
  232. data/vendor/heroicons/16/solid/arrow-left-circle.svg +3 -0
  233. data/vendor/heroicons/16/solid/arrow-left-end-on-rectangle.svg +4 -0
  234. data/vendor/heroicons/16/solid/arrow-left-start-on-rectangle.svg +3 -0
  235. data/vendor/heroicons/16/solid/arrow-left.svg +3 -0
  236. data/vendor/heroicons/16/solid/arrow-long-down.svg +3 -0
  237. data/vendor/heroicons/16/solid/arrow-long-left.svg +3 -0
  238. data/vendor/heroicons/16/solid/arrow-long-right.svg +3 -0
  239. data/vendor/heroicons/16/solid/arrow-long-up.svg +3 -0
  240. data/vendor/heroicons/16/solid/arrow-path-rounded-square.svg +3 -0
  241. data/vendor/heroicons/16/solid/arrow-path.svg +3 -0
  242. data/vendor/heroicons/16/solid/arrow-right-circle.svg +3 -0
  243. data/vendor/heroicons/16/solid/arrow-right-end-on-rectangle.svg +4 -0
  244. data/vendor/heroicons/16/solid/arrow-right-start-on-rectangle.svg +3 -0
  245. data/vendor/heroicons/16/solid/arrow-right.svg +3 -0
  246. data/vendor/heroicons/16/solid/arrow-top-right-on-square.svg +4 -0
  247. data/vendor/heroicons/16/solid/arrow-trending-down.svg +3 -0
  248. data/vendor/heroicons/16/solid/arrow-trending-up.svg +3 -0
  249. data/vendor/heroicons/16/solid/arrow-turn-down-left.svg +3 -0
  250. data/vendor/heroicons/16/solid/arrow-turn-down-right.svg +3 -0
  251. data/vendor/heroicons/16/solid/arrow-turn-left-down.svg +3 -0
  252. data/vendor/heroicons/16/solid/arrow-turn-left-up.svg +3 -0
  253. data/vendor/heroicons/16/solid/arrow-turn-right-down.svg +3 -0
  254. data/vendor/heroicons/16/solid/arrow-turn-right-up.svg +3 -0
  255. data/vendor/heroicons/16/solid/arrow-turn-up-left.svg +3 -0
  256. data/vendor/heroicons/16/solid/arrow-turn-up-right.svg +3 -0
  257. data/vendor/heroicons/16/solid/arrow-up-circle.svg +3 -0
  258. data/vendor/heroicons/16/solid/arrow-up-left.svg +3 -0
  259. data/vendor/heroicons/16/solid/arrow-up-on-square-stack.svg +4 -0
  260. data/vendor/heroicons/16/solid/arrow-up-on-square.svg +3 -0
  261. data/vendor/heroicons/16/solid/arrow-up-right.svg +3 -0
  262. data/vendor/heroicons/16/solid/arrow-up-tray.svg +4 -0
  263. data/vendor/heroicons/16/solid/arrow-up.svg +3 -0
  264. data/vendor/heroicons/16/solid/arrow-uturn-down.svg +3 -0
  265. data/vendor/heroicons/16/solid/arrow-uturn-left.svg +3 -0
  266. data/vendor/heroicons/16/solid/arrow-uturn-right.svg +3 -0
  267. data/vendor/heroicons/16/solid/arrow-uturn-up.svg +3 -0
  268. data/vendor/heroicons/16/solid/arrows-pointing-in.svg +3 -0
  269. data/vendor/heroicons/16/solid/arrows-pointing-out.svg +3 -0
  270. data/vendor/heroicons/16/solid/arrows-right-left.svg +3 -0
  271. data/vendor/heroicons/16/solid/arrows-up-down.svg +3 -0
  272. data/vendor/heroicons/16/solid/at-symbol.svg +3 -0
  273. data/vendor/heroicons/16/solid/backspace.svg +3 -0
  274. data/vendor/heroicons/16/solid/backward.svg +3 -0
  275. data/vendor/heroicons/16/solid/banknotes.svg +4 -0
  276. data/vendor/heroicons/16/solid/bars-2.svg +3 -0
  277. data/vendor/heroicons/16/solid/bars-3-bottom-left.svg +3 -0
  278. data/vendor/heroicons/16/solid/bars-3-bottom-right.svg +3 -0
  279. data/vendor/heroicons/16/solid/bars-3-center-left.svg +3 -0
  280. data/vendor/heroicons/16/solid/bars-3.svg +3 -0
  281. data/vendor/heroicons/16/solid/bars-4.svg +3 -0
  282. data/vendor/heroicons/16/solid/bars-arrow-down.svg +3 -0
  283. data/vendor/heroicons/16/solid/bars-arrow-up.svg +3 -0
  284. data/vendor/heroicons/16/solid/battery-0.svg +3 -0
  285. data/vendor/heroicons/16/solid/battery-100.svg +4 -0
  286. data/vendor/heroicons/16/solid/battery-50.svg +4 -0
  287. data/vendor/heroicons/16/solid/beaker.svg +3 -0
  288. data/vendor/heroicons/16/solid/bell-alert.svg +4 -0
  289. data/vendor/heroicons/16/solid/bell-slash.svg +4 -0
  290. data/vendor/heroicons/16/solid/bell-snooze.svg +3 -0
  291. data/vendor/heroicons/16/solid/bell.svg +3 -0
  292. data/vendor/heroicons/16/solid/bold.svg +3 -0
  293. data/vendor/heroicons/16/solid/bolt-slash.svg +3 -0
  294. data/vendor/heroicons/16/solid/bolt.svg +3 -0
  295. data/vendor/heroicons/16/solid/book-open.svg +3 -0
  296. data/vendor/heroicons/16/solid/bookmark-slash.svg +3 -0
  297. data/vendor/heroicons/16/solid/bookmark-square.svg +3 -0
  298. data/vendor/heroicons/16/solid/bookmark.svg +3 -0
  299. data/vendor/heroicons/16/solid/briefcase.svg +4 -0
  300. data/vendor/heroicons/16/solid/bug-ant.svg +3 -0
  301. data/vendor/heroicons/16/solid/building-library.svg +3 -0
  302. data/vendor/heroicons/16/solid/building-office-2.svg +3 -0
  303. data/vendor/heroicons/16/solid/building-office.svg +3 -0
  304. data/vendor/heroicons/16/solid/building-storefront.svg +3 -0
  305. data/vendor/heroicons/16/solid/cake.svg +3 -0
  306. data/vendor/heroicons/16/solid/calculator.svg +3 -0
  307. data/vendor/heroicons/16/solid/calendar-date-range.svg +4 -0
  308. data/vendor/heroicons/16/solid/calendar-days.svg +4 -0
  309. data/vendor/heroicons/16/solid/calendar.svg +3 -0
  310. data/vendor/heroicons/16/solid/camera.svg +4 -0
  311. data/vendor/heroicons/16/solid/chart-bar-square.svg +3 -0
  312. data/vendor/heroicons/16/solid/chart-bar.svg +3 -0
  313. data/vendor/heroicons/16/solid/chart-pie.svg +4 -0
  314. data/vendor/heroicons/16/solid/chat-bubble-bottom-center-text.svg +3 -0
  315. data/vendor/heroicons/16/solid/chat-bubble-bottom-center.svg +3 -0
  316. data/vendor/heroicons/16/solid/chat-bubble-left-ellipsis.svg +3 -0
  317. data/vendor/heroicons/16/solid/chat-bubble-left-right.svg +4 -0
  318. data/vendor/heroicons/16/solid/chat-bubble-left.svg +3 -0
  319. data/vendor/heroicons/16/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
  320. data/vendor/heroicons/16/solid/chat-bubble-oval-left.svg +3 -0
  321. data/vendor/heroicons/16/solid/check-badge.svg +3 -0
  322. data/vendor/heroicons/16/solid/check-circle.svg +3 -0
  323. data/vendor/heroicons/16/solid/check.svg +3 -0
  324. data/vendor/heroicons/16/solid/chevron-double-down.svg +3 -0
  325. data/vendor/heroicons/16/solid/chevron-double-left.svg +3 -0
  326. data/vendor/heroicons/16/solid/chevron-double-right.svg +3 -0
  327. data/vendor/heroicons/16/solid/chevron-double-up.svg +3 -0
  328. data/vendor/heroicons/16/solid/chevron-down.svg +3 -0
  329. data/vendor/heroicons/16/solid/chevron-left.svg +3 -0
  330. data/vendor/heroicons/16/solid/chevron-right.svg +3 -0
  331. data/vendor/heroicons/16/solid/chevron-up-down.svg +3 -0
  332. data/vendor/heroicons/16/solid/chevron-up.svg +3 -0
  333. data/vendor/heroicons/16/solid/circle-stack.svg +5 -0
  334. data/vendor/heroicons/16/solid/clipboard-document-check.svg +4 -0
  335. data/vendor/heroicons/16/solid/clipboard-document-list.svg +4 -0
  336. data/vendor/heroicons/16/solid/clipboard-document.svg +4 -0
  337. data/vendor/heroicons/16/solid/clipboard.svg +3 -0
  338. data/vendor/heroicons/16/solid/clock.svg +3 -0
  339. data/vendor/heroicons/16/solid/cloud-arrow-down.svg +3 -0
  340. data/vendor/heroicons/16/solid/cloud-arrow-up.svg +3 -0
  341. data/vendor/heroicons/16/solid/cloud.svg +3 -0
  342. data/vendor/heroicons/16/solid/code-bracket-square.svg +3 -0
  343. data/vendor/heroicons/16/solid/code-bracket.svg +3 -0
  344. data/vendor/heroicons/16/solid/cog-6-tooth.svg +3 -0
  345. data/vendor/heroicons/16/solid/cog-8-tooth.svg +3 -0
  346. data/vendor/heroicons/16/solid/cog.svg +3 -0
  347. data/vendor/heroicons/16/solid/command-line.svg +3 -0
  348. data/vendor/heroicons/16/solid/computer-desktop.svg +3 -0
  349. data/vendor/heroicons/16/solid/cpu-chip.svg +4 -0
  350. data/vendor/heroicons/16/solid/credit-card.svg +4 -0
  351. data/vendor/heroicons/16/solid/cube-transparent.svg +3 -0
  352. data/vendor/heroicons/16/solid/cube.svg +3 -0
  353. data/vendor/heroicons/16/solid/currency-bangladeshi.svg +3 -0
  354. data/vendor/heroicons/16/solid/currency-dollar.svg +4 -0
  355. data/vendor/heroicons/16/solid/currency-euro.svg +3 -0
  356. data/vendor/heroicons/16/solid/currency-pound.svg +3 -0
  357. data/vendor/heroicons/16/solid/currency-rupee.svg +3 -0
  358. data/vendor/heroicons/16/solid/currency-yen.svg +3 -0
  359. data/vendor/heroicons/16/solid/cursor-arrow-rays.svg +3 -0
  360. data/vendor/heroicons/16/solid/cursor-arrow-ripple.svg +5 -0
  361. data/vendor/heroicons/16/solid/device-phone-mobile.svg +4 -0
  362. data/vendor/heroicons/16/solid/device-tablet.svg +4 -0
  363. data/vendor/heroicons/16/solid/divide.svg +4 -0
  364. data/vendor/heroicons/16/solid/document-arrow-down.svg +3 -0
  365. data/vendor/heroicons/16/solid/document-arrow-up.svg +3 -0
  366. data/vendor/heroicons/16/solid/document-chart-bar.svg +3 -0
  367. data/vendor/heroicons/16/solid/document-check.svg +3 -0
  368. data/vendor/heroicons/16/solid/document-currency-bangladeshi.svg +3 -0
  369. data/vendor/heroicons/16/solid/document-currency-dollar.svg +4 -0
  370. data/vendor/heroicons/16/solid/document-currency-euro.svg +3 -0
  371. data/vendor/heroicons/16/solid/document-currency-pound.svg +3 -0
  372. data/vendor/heroicons/16/solid/document-currency-rupee.svg +3 -0
  373. data/vendor/heroicons/16/solid/document-currency-yen.svg +3 -0
  374. data/vendor/heroicons/16/solid/document-duplicate.svg +4 -0
  375. data/vendor/heroicons/16/solid/document-magnifying-glass.svg +4 -0
  376. data/vendor/heroicons/16/solid/document-minus.svg +3 -0
  377. data/vendor/heroicons/16/solid/document-plus.svg +3 -0
  378. data/vendor/heroicons/16/solid/document-text.svg +3 -0
  379. data/vendor/heroicons/16/solid/document.svg +3 -0
  380. data/vendor/heroicons/16/solid/ellipsis-horizontal-circle.svg +3 -0
  381. data/vendor/heroicons/16/solid/ellipsis-horizontal.svg +3 -0
  382. data/vendor/heroicons/16/solid/ellipsis-vertical.svg +3 -0
  383. data/vendor/heroicons/16/solid/envelope-open.svg +3 -0
  384. data/vendor/heroicons/16/solid/envelope.svg +4 -0
  385. data/vendor/heroicons/16/solid/equals.svg +3 -0
  386. data/vendor/heroicons/16/solid/exclamation-circle.svg +3 -0
  387. data/vendor/heroicons/16/solid/exclamation-triangle.svg +3 -0
  388. data/vendor/heroicons/16/solid/eye-dropper.svg +3 -0
  389. data/vendor/heroicons/16/solid/eye-slash.svg +4 -0
  390. data/vendor/heroicons/16/solid/eye.svg +4 -0
  391. data/vendor/heroicons/16/solid/face-frown.svg +3 -0
  392. data/vendor/heroicons/16/solid/face-smile.svg +3 -0
  393. data/vendor/heroicons/16/solid/film.svg +3 -0
  394. data/vendor/heroicons/16/solid/finger-print.svg +3 -0
  395. data/vendor/heroicons/16/solid/fire.svg +3 -0
  396. data/vendor/heroicons/16/solid/flag.svg +3 -0
  397. data/vendor/heroicons/16/solid/folder-arrow-down.svg +3 -0
  398. data/vendor/heroicons/16/solid/folder-minus.svg +3 -0
  399. data/vendor/heroicons/16/solid/folder-open.svg +3 -0
  400. data/vendor/heroicons/16/solid/folder-plus.svg +3 -0
  401. data/vendor/heroicons/16/solid/folder.svg +3 -0
  402. data/vendor/heroicons/16/solid/forward.svg +3 -0
  403. data/vendor/heroicons/16/solid/funnel.svg +3 -0
  404. data/vendor/heroicons/16/solid/gif.svg +3 -0
  405. data/vendor/heroicons/16/solid/gift-top.svg +4 -0
  406. data/vendor/heroicons/16/solid/gift.svg +4 -0
  407. data/vendor/heroicons/16/solid/globe-alt.svg +3 -0
  408. data/vendor/heroicons/16/solid/globe-americas.svg +3 -0
  409. data/vendor/heroicons/16/solid/globe-asia-australia.svg +3 -0
  410. data/vendor/heroicons/16/solid/globe-europe-africa.svg +3 -0
  411. data/vendor/heroicons/16/solid/h1.svg +3 -0
  412. data/vendor/heroicons/16/solid/h2.svg +3 -0
  413. data/vendor/heroicons/16/solid/h3.svg +3 -0
  414. data/vendor/heroicons/16/solid/hand-raised.svg +3 -0
  415. data/vendor/heroicons/16/solid/hand-thumb-down.svg +3 -0
  416. data/vendor/heroicons/16/solid/hand-thumb-up.svg +3 -0
  417. data/vendor/heroicons/16/solid/hashtag.svg +3 -0
  418. data/vendor/heroicons/16/solid/heart.svg +3 -0
  419. data/vendor/heroicons/16/solid/home-modern.svg +3 -0
  420. data/vendor/heroicons/16/solid/home.svg +3 -0
  421. data/vendor/heroicons/16/solid/identification.svg +3 -0
  422. data/vendor/heroicons/16/solid/inbox-arrow-down.svg +4 -0
  423. data/vendor/heroicons/16/solid/inbox-stack.svg +4 -0
  424. data/vendor/heroicons/16/solid/inbox.svg +3 -0
  425. data/vendor/heroicons/16/solid/information-circle.svg +3 -0
  426. data/vendor/heroicons/16/solid/italic.svg +3 -0
  427. data/vendor/heroicons/16/solid/key.svg +3 -0
  428. data/vendor/heroicons/16/solid/language.svg +3 -0
  429. data/vendor/heroicons/16/solid/lifebuoy.svg +3 -0
  430. data/vendor/heroicons/16/solid/light-bulb.svg +3 -0
  431. data/vendor/heroicons/16/solid/link-slash.svg +3 -0
  432. data/vendor/heroicons/16/solid/link.svg +4 -0
  433. data/vendor/heroicons/16/solid/list-bullet.svg +3 -0
  434. data/vendor/heroicons/16/solid/lock-closed.svg +3 -0
  435. data/vendor/heroicons/16/solid/lock-open.svg +3 -0
  436. data/vendor/heroicons/16/solid/magnifying-glass-circle.svg +4 -0
  437. data/vendor/heroicons/16/solid/magnifying-glass-minus.svg +4 -0
  438. data/vendor/heroicons/16/solid/magnifying-glass-plus.svg +4 -0
  439. data/vendor/heroicons/16/solid/magnifying-glass.svg +3 -0
  440. data/vendor/heroicons/16/solid/map-pin.svg +3 -0
  441. data/vendor/heroicons/16/solid/map.svg +3 -0
  442. data/vendor/heroicons/16/solid/megaphone.svg +3 -0
  443. data/vendor/heroicons/16/solid/microphone.svg +4 -0
  444. data/vendor/heroicons/16/solid/minus-circle.svg +3 -0
  445. data/vendor/heroicons/16/solid/minus.svg +3 -0
  446. data/vendor/heroicons/16/solid/moon.svg +3 -0
  447. data/vendor/heroicons/16/solid/musical-note.svg +3 -0
  448. data/vendor/heroicons/16/solid/newspaper.svg +4 -0
  449. data/vendor/heroicons/16/solid/no-symbol.svg +3 -0
  450. data/vendor/heroicons/16/solid/numbered-list.svg +3 -0
  451. data/vendor/heroicons/16/solid/paint-brush.svg +3 -0
  452. data/vendor/heroicons/16/solid/paper-airplane.svg +3 -0
  453. data/vendor/heroicons/16/solid/paper-clip.svg +3 -0
  454. data/vendor/heroicons/16/solid/pause-circle.svg +3 -0
  455. data/vendor/heroicons/16/solid/pause.svg +3 -0
  456. data/vendor/heroicons/16/solid/pencil-square.svg +4 -0
  457. data/vendor/heroicons/16/solid/pencil.svg +3 -0
  458. data/vendor/heroicons/16/solid/percent-badge.svg +3 -0
  459. data/vendor/heroicons/16/solid/phone-arrow-down-left.svg +4 -0
  460. data/vendor/heroicons/16/solid/phone-arrow-up-right.svg +4 -0
  461. data/vendor/heroicons/16/solid/phone-x-mark.svg +4 -0
  462. data/vendor/heroicons/16/solid/phone.svg +3 -0
  463. data/vendor/heroicons/16/solid/photo.svg +3 -0
  464. data/vendor/heroicons/16/solid/play-circle.svg +3 -0
  465. data/vendor/heroicons/16/solid/play-pause.svg +3 -0
  466. data/vendor/heroicons/16/solid/play.svg +3 -0
  467. data/vendor/heroicons/16/solid/plus-circle.svg +3 -0
  468. data/vendor/heroicons/16/solid/plus.svg +3 -0
  469. data/vendor/heroicons/16/solid/power.svg +3 -0
  470. data/vendor/heroicons/16/solid/presentation-chart-bar.svg +3 -0
  471. data/vendor/heroicons/16/solid/presentation-chart-line.svg +3 -0
  472. data/vendor/heroicons/16/solid/printer.svg +3 -0
  473. data/vendor/heroicons/16/solid/puzzle-piece.svg +3 -0
  474. data/vendor/heroicons/16/solid/qr-code.svg +9 -0
  475. data/vendor/heroicons/16/solid/question-mark-circle.svg +3 -0
  476. data/vendor/heroicons/16/solid/queue-list.svg +3 -0
  477. data/vendor/heroicons/16/solid/radio.svg +3 -0
  478. data/vendor/heroicons/16/solid/receipt-percent.svg +3 -0
  479. data/vendor/heroicons/16/solid/receipt-refund.svg +3 -0
  480. data/vendor/heroicons/16/solid/rectangle-group.svg +3 -0
  481. data/vendor/heroicons/16/solid/rectangle-stack.svg +3 -0
  482. data/vendor/heroicons/16/solid/rocket-launch.svg +4 -0
  483. data/vendor/heroicons/16/solid/rss.svg +3 -0
  484. data/vendor/heroicons/16/solid/scale.svg +3 -0
  485. data/vendor/heroicons/16/solid/scissors.svg +4 -0
  486. data/vendor/heroicons/16/solid/server-stack.svg +4 -0
  487. data/vendor/heroicons/16/solid/server.svg +4 -0
  488. data/vendor/heroicons/16/solid/share.svg +3 -0
  489. data/vendor/heroicons/16/solid/shield-check.svg +3 -0
  490. data/vendor/heroicons/16/solid/shield-exclamation.svg +3 -0
  491. data/vendor/heroicons/16/solid/shopping-bag.svg +3 -0
  492. data/vendor/heroicons/16/solid/shopping-cart.svg +3 -0
  493. data/vendor/heroicons/16/solid/signal-slash.svg +3 -0
  494. data/vendor/heroicons/16/solid/signal.svg +5 -0
  495. data/vendor/heroicons/16/solid/slash.svg +3 -0
  496. data/vendor/heroicons/16/solid/sparkles.svg +3 -0
  497. data/vendor/heroicons/16/solid/speaker-wave.svg +4 -0
  498. data/vendor/heroicons/16/solid/speaker-x-mark.svg +3 -0
  499. data/vendor/heroicons/16/solid/square-2-stack.svg +4 -0
  500. data/vendor/heroicons/16/solid/square-3-stack-3d.svg +5 -0
  501. data/vendor/heroicons/16/solid/squares-2x2.svg +3 -0
  502. data/vendor/heroicons/16/solid/squares-plus.svg +3 -0
  503. data/vendor/heroicons/16/solid/star.svg +3 -0
  504. data/vendor/heroicons/16/solid/stop-circle.svg +3 -0
  505. data/vendor/heroicons/16/solid/stop.svg +3 -0
  506. data/vendor/heroicons/16/solid/strikethrough.svg +3 -0
  507. data/vendor/heroicons/16/solid/sun.svg +3 -0
  508. data/vendor/heroicons/16/solid/swatch.svg +4 -0
  509. data/vendor/heroicons/16/solid/table-cells.svg +3 -0
  510. data/vendor/heroicons/16/solid/tag.svg +3 -0
  511. data/vendor/heroicons/16/solid/ticket.svg +3 -0
  512. data/vendor/heroicons/16/solid/trash.svg +3 -0
  513. data/vendor/heroicons/16/solid/trophy.svg +3 -0
  514. data/vendor/heroicons/16/solid/truck.svg +5 -0
  515. data/vendor/heroicons/16/solid/tv.svg +4 -0
  516. data/vendor/heroicons/16/solid/underline.svg +3 -0
  517. data/vendor/heroicons/16/solid/user-circle.svg +3 -0
  518. data/vendor/heroicons/16/solid/user-group.svg +3 -0
  519. data/vendor/heroicons/16/solid/user-minus.svg +3 -0
  520. data/vendor/heroicons/16/solid/user-plus.svg +3 -0
  521. data/vendor/heroicons/16/solid/user.svg +3 -0
  522. data/vendor/heroicons/16/solid/users.svg +3 -0
  523. data/vendor/heroicons/16/solid/variable.svg +3 -0
  524. data/vendor/heroicons/16/solid/video-camera-slash.svg +3 -0
  525. data/vendor/heroicons/16/solid/video-camera.svg +3 -0
  526. data/vendor/heroicons/16/solid/view-columns.svg +3 -0
  527. data/vendor/heroicons/16/solid/viewfinder-circle.svg +3 -0
  528. data/vendor/heroicons/16/solid/wallet.svg +3 -0
  529. data/vendor/heroicons/16/solid/wifi.svg +3 -0
  530. data/vendor/heroicons/16/solid/window.svg +3 -0
  531. data/vendor/heroicons/16/solid/wrench-screwdriver.svg +4 -0
  532. data/vendor/heroicons/16/solid/wrench.svg +3 -0
  533. data/vendor/heroicons/16/solid/x-circle.svg +3 -0
  534. data/vendor/heroicons/16/solid/x-mark.svg +3 -0
  535. data/vendor/heroicons/20/solid/academic-cap.svg +3 -0
  536. data/vendor/heroicons/20/solid/adjustments-horizontal.svg +3 -0
  537. data/vendor/heroicons/20/solid/adjustments-vertical.svg +3 -0
  538. data/vendor/heroicons/20/solid/archive-box-arrow-down.svg +3 -0
  539. data/vendor/heroicons/20/solid/archive-box-x-mark.svg +4 -0
  540. data/vendor/heroicons/20/solid/archive-box.svg +4 -0
  541. data/vendor/heroicons/20/solid/arrow-down-circle.svg +3 -0
  542. data/vendor/heroicons/20/solid/arrow-down-left.svg +3 -0
  543. data/vendor/heroicons/20/solid/arrow-down-on-square-stack.svg +3 -0
  544. data/vendor/heroicons/20/solid/arrow-down-on-square.svg +3 -0
  545. data/vendor/heroicons/20/solid/arrow-down-right.svg +3 -0
  546. data/vendor/heroicons/20/solid/arrow-down-tray.svg +4 -0
  547. data/vendor/heroicons/20/solid/arrow-down.svg +3 -0
  548. data/vendor/heroicons/20/solid/arrow-left-circle.svg +3 -0
  549. data/vendor/heroicons/20/solid/arrow-left-end-on-rectangle.svg +4 -0
  550. data/vendor/heroicons/20/solid/arrow-left-on-rectangle.svg +4 -0
  551. data/vendor/heroicons/20/solid/arrow-left-start-on-rectangle.svg +4 -0
  552. data/vendor/heroicons/20/solid/arrow-left.svg +3 -0
  553. data/vendor/heroicons/20/solid/arrow-long-down.svg +3 -0
  554. data/vendor/heroicons/20/solid/arrow-long-left.svg +3 -0
  555. data/vendor/heroicons/20/solid/arrow-long-right.svg +3 -0
  556. data/vendor/heroicons/20/solid/arrow-long-up.svg +3 -0
  557. data/vendor/heroicons/20/solid/arrow-path-rounded-square.svg +3 -0
  558. data/vendor/heroicons/20/solid/arrow-path.svg +3 -0
  559. data/vendor/heroicons/20/solid/arrow-right-circle.svg +3 -0
  560. data/vendor/heroicons/20/solid/arrow-right-end-on-rectangle.svg +4 -0
  561. data/vendor/heroicons/20/solid/arrow-right-on-rectangle.svg +4 -0
  562. data/vendor/heroicons/20/solid/arrow-right-start-on-rectangle.svg +4 -0
  563. data/vendor/heroicons/20/solid/arrow-right.svg +3 -0
  564. data/vendor/heroicons/20/solid/arrow-small-down.svg +3 -0
  565. data/vendor/heroicons/20/solid/arrow-small-left.svg +3 -0
  566. data/vendor/heroicons/20/solid/arrow-small-right.svg +3 -0
  567. data/vendor/heroicons/20/solid/arrow-small-up.svg +3 -0
  568. data/vendor/heroicons/20/solid/arrow-top-right-on-square.svg +4 -0
  569. data/vendor/heroicons/20/solid/arrow-trending-down.svg +3 -0
  570. data/vendor/heroicons/20/solid/arrow-trending-up.svg +3 -0
  571. data/vendor/heroicons/20/solid/arrow-turn-down-left.svg +3 -0
  572. data/vendor/heroicons/20/solid/arrow-turn-down-right.svg +3 -0
  573. data/vendor/heroicons/20/solid/arrow-turn-left-down.svg +3 -0
  574. data/vendor/heroicons/20/solid/arrow-turn-left-up.svg +3 -0
  575. data/vendor/heroicons/20/solid/arrow-turn-right-down.svg +3 -0
  576. data/vendor/heroicons/20/solid/arrow-turn-right-up.svg +3 -0
  577. data/vendor/heroicons/20/solid/arrow-turn-up-left.svg +3 -0
  578. data/vendor/heroicons/20/solid/arrow-turn-up-right.svg +3 -0
  579. data/vendor/heroicons/20/solid/arrow-up-circle.svg +3 -0
  580. data/vendor/heroicons/20/solid/arrow-up-left.svg +3 -0
  581. data/vendor/heroicons/20/solid/arrow-up-on-square-stack.svg +3 -0
  582. data/vendor/heroicons/20/solid/arrow-up-on-square.svg +3 -0
  583. data/vendor/heroicons/20/solid/arrow-up-right.svg +3 -0
  584. data/vendor/heroicons/20/solid/arrow-up-tray.svg +4 -0
  585. data/vendor/heroicons/20/solid/arrow-up.svg +3 -0
  586. data/vendor/heroicons/20/solid/arrow-uturn-down.svg +3 -0
  587. data/vendor/heroicons/20/solid/arrow-uturn-left.svg +3 -0
  588. data/vendor/heroicons/20/solid/arrow-uturn-right.svg +3 -0
  589. data/vendor/heroicons/20/solid/arrow-uturn-up.svg +3 -0
  590. data/vendor/heroicons/20/solid/arrows-pointing-in.svg +3 -0
  591. data/vendor/heroicons/20/solid/arrows-pointing-out.svg +3 -0
  592. data/vendor/heroicons/20/solid/arrows-right-left.svg +3 -0
  593. data/vendor/heroicons/20/solid/arrows-up-down.svg +3 -0
  594. data/vendor/heroicons/20/solid/at-symbol.svg +3 -0
  595. data/vendor/heroicons/20/solid/backspace.svg +3 -0
  596. data/vendor/heroicons/20/solid/backward.svg +3 -0
  597. data/vendor/heroicons/20/solid/banknotes.svg +3 -0
  598. data/vendor/heroicons/20/solid/bars-2.svg +3 -0
  599. data/vendor/heroicons/20/solid/bars-3-bottom-left.svg +3 -0
  600. data/vendor/heroicons/20/solid/bars-3-bottom-right.svg +3 -0
  601. data/vendor/heroicons/20/solid/bars-3-center-left.svg +3 -0
  602. data/vendor/heroicons/20/solid/bars-3.svg +3 -0
  603. data/vendor/heroicons/20/solid/bars-4.svg +3 -0
  604. data/vendor/heroicons/20/solid/bars-arrow-down.svg +3 -0
  605. data/vendor/heroicons/20/solid/bars-arrow-up.svg +3 -0
  606. data/vendor/heroicons/20/solid/battery-0.svg +3 -0
  607. data/vendor/heroicons/20/solid/battery-100.svg +4 -0
  608. data/vendor/heroicons/20/solid/battery-50.svg +4 -0
  609. data/vendor/heroicons/20/solid/beaker.svg +3 -0
  610. data/vendor/heroicons/20/solid/bell-alert.svg +4 -0
  611. data/vendor/heroicons/20/solid/bell-slash.svg +3 -0
  612. data/vendor/heroicons/20/solid/bell-snooze.svg +3 -0
  613. data/vendor/heroicons/20/solid/bell.svg +3 -0
  614. data/vendor/heroicons/20/solid/bold.svg +3 -0
  615. data/vendor/heroicons/20/solid/bolt-slash.svg +4 -0
  616. data/vendor/heroicons/20/solid/bolt.svg +3 -0
  617. data/vendor/heroicons/20/solid/book-open.svg +3 -0
  618. data/vendor/heroicons/20/solid/bookmark-slash.svg +3 -0
  619. data/vendor/heroicons/20/solid/bookmark-square.svg +3 -0
  620. data/vendor/heroicons/20/solid/bookmark.svg +3 -0
  621. data/vendor/heroicons/20/solid/briefcase.svg +4 -0
  622. data/vendor/heroicons/20/solid/bug-ant.svg +3 -0
  623. data/vendor/heroicons/20/solid/building-library.svg +3 -0
  624. data/vendor/heroicons/20/solid/building-office-2.svg +3 -0
  625. data/vendor/heroicons/20/solid/building-office.svg +3 -0
  626. data/vendor/heroicons/20/solid/building-storefront.svg +3 -0
  627. data/vendor/heroicons/20/solid/cake.svg +3 -0
  628. data/vendor/heroicons/20/solid/calculator.svg +3 -0
  629. data/vendor/heroicons/20/solid/calendar-date-range.svg +4 -0
  630. data/vendor/heroicons/20/solid/calendar-days.svg +4 -0
  631. data/vendor/heroicons/20/solid/calendar.svg +3 -0
  632. data/vendor/heroicons/20/solid/camera.svg +3 -0
  633. data/vendor/heroicons/20/solid/chart-bar-square.svg +3 -0
  634. data/vendor/heroicons/20/solid/chart-bar.svg +3 -0
  635. data/vendor/heroicons/20/solid/chart-pie.svg +4 -0
  636. data/vendor/heroicons/20/solid/chat-bubble-bottom-center-text.svg +3 -0
  637. data/vendor/heroicons/20/solid/chat-bubble-bottom-center.svg +3 -0
  638. data/vendor/heroicons/20/solid/chat-bubble-left-ellipsis.svg +3 -0
  639. data/vendor/heroicons/20/solid/chat-bubble-left-right.svg +4 -0
  640. data/vendor/heroicons/20/solid/chat-bubble-left.svg +3 -0
  641. data/vendor/heroicons/20/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
  642. data/vendor/heroicons/20/solid/chat-bubble-oval-left.svg +3 -0
  643. data/vendor/heroicons/20/solid/check-badge.svg +3 -0
  644. data/vendor/heroicons/20/solid/check-circle.svg +3 -0
  645. data/vendor/heroicons/20/solid/check.svg +3 -0
  646. data/vendor/heroicons/20/solid/chevron-double-down.svg +3 -0
  647. data/vendor/heroicons/20/solid/chevron-double-left.svg +3 -0
  648. data/vendor/heroicons/20/solid/chevron-double-right.svg +3 -0
  649. data/vendor/heroicons/20/solid/chevron-double-up.svg +3 -0
  650. data/vendor/heroicons/20/solid/chevron-down.svg +3 -0
  651. data/vendor/heroicons/20/solid/chevron-left.svg +3 -0
  652. data/vendor/heroicons/20/solid/chevron-right.svg +3 -0
  653. data/vendor/heroicons/20/solid/chevron-up-down.svg +3 -0
  654. data/vendor/heroicons/20/solid/chevron-up.svg +3 -0
  655. data/vendor/heroicons/20/solid/circle-stack.svg +3 -0
  656. data/vendor/heroicons/20/solid/clipboard-document-check.svg +4 -0
  657. data/vendor/heroicons/20/solid/clipboard-document-list.svg +4 -0
  658. data/vendor/heroicons/20/solid/clipboard-document.svg +4 -0
  659. data/vendor/heroicons/20/solid/clipboard.svg +3 -0
  660. data/vendor/heroicons/20/solid/clock.svg +3 -0
  661. data/vendor/heroicons/20/solid/cloud-arrow-down.svg +3 -0
  662. data/vendor/heroicons/20/solid/cloud-arrow-up.svg +3 -0
  663. data/vendor/heroicons/20/solid/cloud.svg +3 -0
  664. data/vendor/heroicons/20/solid/code-bracket-square.svg +3 -0
  665. data/vendor/heroicons/20/solid/code-bracket.svg +3 -0
  666. data/vendor/heroicons/20/solid/cog-6-tooth.svg +3 -0
  667. data/vendor/heroicons/20/solid/cog-8-tooth.svg +3 -0
  668. data/vendor/heroicons/20/solid/cog.svg +4 -0
  669. data/vendor/heroicons/20/solid/command-line.svg +3 -0
  670. data/vendor/heroicons/20/solid/computer-desktop.svg +3 -0
  671. data/vendor/heroicons/20/solid/cpu-chip.svg +4 -0
  672. data/vendor/heroicons/20/solid/credit-card.svg +3 -0
  673. data/vendor/heroicons/20/solid/cube-transparent.svg +3 -0
  674. data/vendor/heroicons/20/solid/cube.svg +3 -0
  675. data/vendor/heroicons/20/solid/currency-bangladeshi.svg +3 -0
  676. data/vendor/heroicons/20/solid/currency-dollar.svg +4 -0
  677. data/vendor/heroicons/20/solid/currency-euro.svg +3 -0
  678. data/vendor/heroicons/20/solid/currency-pound.svg +3 -0
  679. data/vendor/heroicons/20/solid/currency-rupee.svg +3 -0
  680. data/vendor/heroicons/20/solid/currency-yen.svg +3 -0
  681. data/vendor/heroicons/20/solid/cursor-arrow-rays.svg +3 -0
  682. data/vendor/heroicons/20/solid/cursor-arrow-ripple.svg +5 -0
  683. data/vendor/heroicons/20/solid/device-phone-mobile.svg +4 -0
  684. data/vendor/heroicons/20/solid/device-tablet.svg +3 -0
  685. data/vendor/heroicons/20/solid/divide.svg +3 -0
  686. data/vendor/heroicons/20/solid/document-arrow-down.svg +3 -0
  687. data/vendor/heroicons/20/solid/document-arrow-up.svg +3 -0
  688. data/vendor/heroicons/20/solid/document-chart-bar.svg +3 -0
  689. data/vendor/heroicons/20/solid/document-check.svg +3 -0
  690. data/vendor/heroicons/20/solid/document-currency-bangladeshi.svg +3 -0
  691. data/vendor/heroicons/20/solid/document-currency-dollar.svg +3 -0
  692. data/vendor/heroicons/20/solid/document-currency-euro.svg +3 -0
  693. data/vendor/heroicons/20/solid/document-currency-pound.svg +3 -0
  694. data/vendor/heroicons/20/solid/document-currency-rupee.svg +3 -0
  695. data/vendor/heroicons/20/solid/document-currency-yen.svg +3 -0
  696. data/vendor/heroicons/20/solid/document-duplicate.svg +4 -0
  697. data/vendor/heroicons/20/solid/document-magnifying-glass.svg +4 -0
  698. data/vendor/heroicons/20/solid/document-minus.svg +3 -0
  699. data/vendor/heroicons/20/solid/document-plus.svg +3 -0
  700. data/vendor/heroicons/20/solid/document-text.svg +3 -0
  701. data/vendor/heroicons/20/solid/document.svg +3 -0
  702. data/vendor/heroicons/20/solid/ellipsis-horizontal-circle.svg +3 -0
  703. data/vendor/heroicons/20/solid/ellipsis-horizontal.svg +3 -0
  704. data/vendor/heroicons/20/solid/ellipsis-vertical.svg +3 -0
  705. data/vendor/heroicons/20/solid/envelope-open.svg +3 -0
  706. data/vendor/heroicons/20/solid/envelope.svg +4 -0
  707. data/vendor/heroicons/20/solid/equals.svg +3 -0
  708. data/vendor/heroicons/20/solid/exclamation-circle.svg +3 -0
  709. data/vendor/heroicons/20/solid/exclamation-triangle.svg +3 -0
  710. data/vendor/heroicons/20/solid/eye-dropper.svg +3 -0
  711. data/vendor/heroicons/20/solid/eye-slash.svg +4 -0
  712. data/vendor/heroicons/20/solid/eye.svg +4 -0
  713. data/vendor/heroicons/20/solid/face-frown.svg +3 -0
  714. data/vendor/heroicons/20/solid/face-smile.svg +3 -0
  715. data/vendor/heroicons/20/solid/film.svg +3 -0
  716. data/vendor/heroicons/20/solid/finger-print.svg +3 -0
  717. data/vendor/heroicons/20/solid/fire.svg +3 -0
  718. data/vendor/heroicons/20/solid/flag.svg +3 -0
  719. data/vendor/heroicons/20/solid/folder-arrow-down.svg +3 -0
  720. data/vendor/heroicons/20/solid/folder-minus.svg +3 -0
  721. data/vendor/heroicons/20/solid/folder-open.svg +3 -0
  722. data/vendor/heroicons/20/solid/folder-plus.svg +3 -0
  723. data/vendor/heroicons/20/solid/folder.svg +3 -0
  724. data/vendor/heroicons/20/solid/forward.svg +3 -0
  725. data/vendor/heroicons/20/solid/funnel.svg +3 -0
  726. data/vendor/heroicons/20/solid/gif.svg +3 -0
  727. data/vendor/heroicons/20/solid/gift-top.svg +3 -0
  728. data/vendor/heroicons/20/solid/gift.svg +4 -0
  729. data/vendor/heroicons/20/solid/globe-alt.svg +3 -0
  730. data/vendor/heroicons/20/solid/globe-americas.svg +3 -0
  731. data/vendor/heroicons/20/solid/globe-asia-australia.svg +3 -0
  732. data/vendor/heroicons/20/solid/globe-europe-africa.svg +3 -0
  733. data/vendor/heroicons/20/solid/h1.svg +3 -0
  734. data/vendor/heroicons/20/solid/h2.svg +3 -0
  735. data/vendor/heroicons/20/solid/h3.svg +3 -0
  736. data/vendor/heroicons/20/solid/hand-raised.svg +3 -0
  737. data/vendor/heroicons/20/solid/hand-thumb-down.svg +3 -0
  738. data/vendor/heroicons/20/solid/hand-thumb-up.svg +3 -0
  739. data/vendor/heroicons/20/solid/hashtag.svg +3 -0
  740. data/vendor/heroicons/20/solid/heart.svg +3 -0
  741. data/vendor/heroicons/20/solid/home-modern.svg +3 -0
  742. data/vendor/heroicons/20/solid/home.svg +3 -0
  743. data/vendor/heroicons/20/solid/identification.svg +3 -0
  744. data/vendor/heroicons/20/solid/inbox-arrow-down.svg +4 -0
  745. data/vendor/heroicons/20/solid/inbox-stack.svg +4 -0
  746. data/vendor/heroicons/20/solid/inbox.svg +3 -0
  747. data/vendor/heroicons/20/solid/information-circle.svg +3 -0
  748. data/vendor/heroicons/20/solid/italic.svg +3 -0
  749. data/vendor/heroicons/20/solid/key.svg +3 -0
  750. data/vendor/heroicons/20/solid/language.svg +4 -0
  751. data/vendor/heroicons/20/solid/lifebuoy.svg +3 -0
  752. data/vendor/heroicons/20/solid/light-bulb.svg +3 -0
  753. data/vendor/heroicons/20/solid/link-slash.svg +3 -0
  754. data/vendor/heroicons/20/solid/link.svg +4 -0
  755. data/vendor/heroicons/20/solid/list-bullet.svg +3 -0
  756. data/vendor/heroicons/20/solid/lock-closed.svg +3 -0
  757. data/vendor/heroicons/20/solid/lock-open.svg +3 -0
  758. data/vendor/heroicons/20/solid/magnifying-glass-circle.svg +4 -0
  759. data/vendor/heroicons/20/solid/magnifying-glass-minus.svg +4 -0
  760. data/vendor/heroicons/20/solid/magnifying-glass-plus.svg +4 -0
  761. data/vendor/heroicons/20/solid/magnifying-glass.svg +3 -0
  762. data/vendor/heroicons/20/solid/map-pin.svg +3 -0
  763. data/vendor/heroicons/20/solid/map.svg +3 -0
  764. data/vendor/heroicons/20/solid/megaphone.svg +3 -0
  765. data/vendor/heroicons/20/solid/microphone.svg +4 -0
  766. data/vendor/heroicons/20/solid/minus-circle.svg +3 -0
  767. data/vendor/heroicons/20/solid/minus-small.svg +3 -0
  768. data/vendor/heroicons/20/solid/minus.svg +3 -0
  769. data/vendor/heroicons/20/solid/moon.svg +3 -0
  770. data/vendor/heroicons/20/solid/musical-note.svg +3 -0
  771. data/vendor/heroicons/20/solid/newspaper.svg +4 -0
  772. data/vendor/heroicons/20/solid/no-symbol.svg +3 -0
  773. data/vendor/heroicons/20/solid/numbered-list.svg +3 -0
  774. data/vendor/heroicons/20/solid/paint-brush.svg +3 -0
  775. data/vendor/heroicons/20/solid/paper-airplane.svg +3 -0
  776. data/vendor/heroicons/20/solid/paper-clip.svg +3 -0
  777. data/vendor/heroicons/20/solid/pause-circle.svg +3 -0
  778. data/vendor/heroicons/20/solid/pause.svg +3 -0
  779. data/vendor/heroicons/20/solid/pencil-square.svg +4 -0
  780. data/vendor/heroicons/20/solid/pencil.svg +3 -0
  781. data/vendor/heroicons/20/solid/percent-badge.svg +3 -0
  782. data/vendor/heroicons/20/solid/phone-arrow-down-left.svg +3 -0
  783. data/vendor/heroicons/20/solid/phone-arrow-up-right.svg +3 -0
  784. data/vendor/heroicons/20/solid/phone-x-mark.svg +3 -0
  785. data/vendor/heroicons/20/solid/phone.svg +3 -0
  786. data/vendor/heroicons/20/solid/photo.svg +3 -0
  787. data/vendor/heroicons/20/solid/play-circle.svg +3 -0
  788. data/vendor/heroicons/20/solid/play-pause.svg +3 -0
  789. data/vendor/heroicons/20/solid/play.svg +3 -0
  790. data/vendor/heroicons/20/solid/plus-circle.svg +3 -0
  791. data/vendor/heroicons/20/solid/plus-small.svg +3 -0
  792. data/vendor/heroicons/20/solid/plus.svg +3 -0
  793. data/vendor/heroicons/20/solid/power.svg +3 -0
  794. data/vendor/heroicons/20/solid/presentation-chart-bar.svg +3 -0
  795. data/vendor/heroicons/20/solid/presentation-chart-line.svg +3 -0
  796. data/vendor/heroicons/20/solid/printer.svg +3 -0
  797. data/vendor/heroicons/20/solid/puzzle-piece.svg +3 -0
  798. data/vendor/heroicons/20/solid/qr-code.svg +3 -0
  799. data/vendor/heroicons/20/solid/question-mark-circle.svg +3 -0
  800. data/vendor/heroicons/20/solid/queue-list.svg +3 -0
  801. data/vendor/heroicons/20/solid/radio.svg +3 -0
  802. data/vendor/heroicons/20/solid/receipt-percent.svg +3 -0
  803. data/vendor/heroicons/20/solid/receipt-refund.svg +3 -0
  804. data/vendor/heroicons/20/solid/rectangle-group.svg +3 -0
  805. data/vendor/heroicons/20/solid/rectangle-stack.svg +3 -0
  806. data/vendor/heroicons/20/solid/rocket-launch.svg +4 -0
  807. data/vendor/heroicons/20/solid/rss.svg +4 -0
  808. data/vendor/heroicons/20/solid/scale.svg +3 -0
  809. data/vendor/heroicons/20/solid/scissors.svg +4 -0
  810. data/vendor/heroicons/20/solid/server-stack.svg +4 -0
  811. data/vendor/heroicons/20/solid/server.svg +4 -0
  812. data/vendor/heroicons/20/solid/share.svg +3 -0
  813. data/vendor/heroicons/20/solid/shield-check.svg +3 -0
  814. data/vendor/heroicons/20/solid/shield-exclamation.svg +3 -0
  815. data/vendor/heroicons/20/solid/shopping-bag.svg +3 -0
  816. data/vendor/heroicons/20/solid/shopping-cart.svg +3 -0
  817. data/vendor/heroicons/20/solid/signal-slash.svg +3 -0
  818. data/vendor/heroicons/20/solid/signal.svg +4 -0
  819. data/vendor/heroicons/20/solid/slash.svg +3 -0
  820. data/vendor/heroicons/20/solid/sparkles.svg +3 -0
  821. data/vendor/heroicons/20/solid/speaker-wave.svg +4 -0
  822. data/vendor/heroicons/20/solid/speaker-x-mark.svg +3 -0
  823. data/vendor/heroicons/20/solid/square-2-stack.svg +4 -0
  824. data/vendor/heroicons/20/solid/square-3-stack-3d.svg +5 -0
  825. data/vendor/heroicons/20/solid/squares-2x2.svg +3 -0
  826. data/vendor/heroicons/20/solid/squares-plus.svg +3 -0
  827. data/vendor/heroicons/20/solid/star.svg +3 -0
  828. data/vendor/heroicons/20/solid/stop-circle.svg +3 -0
  829. data/vendor/heroicons/20/solid/stop.svg +3 -0
  830. data/vendor/heroicons/20/solid/strikethrough.svg +3 -0
  831. data/vendor/heroicons/20/solid/sun.svg +3 -0
  832. data/vendor/heroicons/20/solid/swatch.svg +3 -0
  833. data/vendor/heroicons/20/solid/table-cells.svg +3 -0
  834. data/vendor/heroicons/20/solid/tag.svg +3 -0
  835. data/vendor/heroicons/20/solid/ticket.svg +3 -0
  836. data/vendor/heroicons/20/solid/trash.svg +3 -0
  837. data/vendor/heroicons/20/solid/trophy.svg +3 -0
  838. data/vendor/heroicons/20/solid/truck.svg +4 -0
  839. data/vendor/heroicons/20/solid/tv.svg +4 -0
  840. data/vendor/heroicons/20/solid/underline.svg +3 -0
  841. data/vendor/heroicons/20/solid/user-circle.svg +3 -0
  842. data/vendor/heroicons/20/solid/user-group.svg +3 -0
  843. data/vendor/heroicons/20/solid/user-minus.svg +3 -0
  844. data/vendor/heroicons/20/solid/user-plus.svg +3 -0
  845. data/vendor/heroicons/20/solid/user.svg +3 -0
  846. data/vendor/heroicons/20/solid/users.svg +3 -0
  847. data/vendor/heroicons/20/solid/variable.svg +3 -0
  848. data/vendor/heroicons/20/solid/video-camera-slash.svg +3 -0
  849. data/vendor/heroicons/20/solid/video-camera.svg +3 -0
  850. data/vendor/heroicons/20/solid/view-columns.svg +3 -0
  851. data/vendor/heroicons/20/solid/viewfinder-circle.svg +3 -0
  852. data/vendor/heroicons/20/solid/wallet.svg +3 -0
  853. data/vendor/heroicons/20/solid/wifi.svg +3 -0
  854. data/vendor/heroicons/20/solid/window.svg +3 -0
  855. data/vendor/heroicons/20/solid/wrench-screwdriver.svg +4 -0
  856. data/vendor/heroicons/20/solid/wrench.svg +3 -0
  857. data/vendor/heroicons/20/solid/x-circle.svg +3 -0
  858. data/vendor/heroicons/20/solid/x-mark.svg +3 -0
  859. data/vendor/heroicons/24/outline/academic-cap.svg +3 -0
  860. data/vendor/heroicons/24/outline/adjustments-horizontal.svg +3 -0
  861. data/vendor/heroicons/24/outline/adjustments-vertical.svg +3 -0
  862. data/vendor/heroicons/24/outline/archive-box-arrow-down.svg +3 -0
  863. data/vendor/heroicons/24/outline/archive-box-x-mark.svg +3 -0
  864. data/vendor/heroicons/24/outline/archive-box.svg +3 -0
  865. data/vendor/heroicons/24/outline/arrow-down-circle.svg +3 -0
  866. data/vendor/heroicons/24/outline/arrow-down-left.svg +3 -0
  867. data/vendor/heroicons/24/outline/arrow-down-on-square-stack.svg +3 -0
  868. data/vendor/heroicons/24/outline/arrow-down-on-square.svg +3 -0
  869. data/vendor/heroicons/24/outline/arrow-down-right.svg +3 -0
  870. data/vendor/heroicons/24/outline/arrow-down-tray.svg +3 -0
  871. data/vendor/heroicons/24/outline/arrow-down.svg +3 -0
  872. data/vendor/heroicons/24/outline/arrow-left-circle.svg +3 -0
  873. data/vendor/heroicons/24/outline/arrow-left-end-on-rectangle.svg +3 -0
  874. data/vendor/heroicons/24/outline/arrow-left-on-rectangle.svg +3 -0
  875. data/vendor/heroicons/24/outline/arrow-left-start-on-rectangle.svg +3 -0
  876. data/vendor/heroicons/24/outline/arrow-left.svg +3 -0
  877. data/vendor/heroicons/24/outline/arrow-long-down.svg +3 -0
  878. data/vendor/heroicons/24/outline/arrow-long-left.svg +3 -0
  879. data/vendor/heroicons/24/outline/arrow-long-right.svg +3 -0
  880. data/vendor/heroicons/24/outline/arrow-long-up.svg +3 -0
  881. data/vendor/heroicons/24/outline/arrow-path-rounded-square.svg +3 -0
  882. data/vendor/heroicons/24/outline/arrow-path.svg +3 -0
  883. data/vendor/heroicons/24/outline/arrow-right-circle.svg +3 -0
  884. data/vendor/heroicons/24/outline/arrow-right-end-on-rectangle.svg +3 -0
  885. data/vendor/heroicons/24/outline/arrow-right-on-rectangle.svg +3 -0
  886. data/vendor/heroicons/24/outline/arrow-right-start-on-rectangle.svg +3 -0
  887. data/vendor/heroicons/24/outline/arrow-right.svg +3 -0
  888. data/vendor/heroicons/24/outline/arrow-small-down.svg +3 -0
  889. data/vendor/heroicons/24/outline/arrow-small-left.svg +3 -0
  890. data/vendor/heroicons/24/outline/arrow-small-right.svg +3 -0
  891. data/vendor/heroicons/24/outline/arrow-small-up.svg +3 -0
  892. data/vendor/heroicons/24/outline/arrow-top-right-on-square.svg +3 -0
  893. data/vendor/heroicons/24/outline/arrow-trending-down.svg +3 -0
  894. data/vendor/heroicons/24/outline/arrow-trending-up.svg +3 -0
  895. data/vendor/heroicons/24/outline/arrow-turn-down-left.svg +3 -0
  896. data/vendor/heroicons/24/outline/arrow-turn-down-right.svg +3 -0
  897. data/vendor/heroicons/24/outline/arrow-turn-left-down.svg +3 -0
  898. data/vendor/heroicons/24/outline/arrow-turn-left-up.svg +3 -0
  899. data/vendor/heroicons/24/outline/arrow-turn-right-down.svg +3 -0
  900. data/vendor/heroicons/24/outline/arrow-turn-right-up.svg +3 -0
  901. data/vendor/heroicons/24/outline/arrow-turn-up-left.svg +3 -0
  902. data/vendor/heroicons/24/outline/arrow-turn-up-right.svg +3 -0
  903. data/vendor/heroicons/24/outline/arrow-up-circle.svg +3 -0
  904. data/vendor/heroicons/24/outline/arrow-up-left.svg +3 -0
  905. data/vendor/heroicons/24/outline/arrow-up-on-square-stack.svg +3 -0
  906. data/vendor/heroicons/24/outline/arrow-up-on-square.svg +3 -0
  907. data/vendor/heroicons/24/outline/arrow-up-right.svg +3 -0
  908. data/vendor/heroicons/24/outline/arrow-up-tray.svg +3 -0
  909. data/vendor/heroicons/24/outline/arrow-up.svg +3 -0
  910. data/vendor/heroicons/24/outline/arrow-uturn-down.svg +3 -0
  911. data/vendor/heroicons/24/outline/arrow-uturn-left.svg +3 -0
  912. data/vendor/heroicons/24/outline/arrow-uturn-right.svg +3 -0
  913. data/vendor/heroicons/24/outline/arrow-uturn-up.svg +3 -0
  914. data/vendor/heroicons/24/outline/arrows-pointing-in.svg +3 -0
  915. data/vendor/heroicons/24/outline/arrows-pointing-out.svg +3 -0
  916. data/vendor/heroicons/24/outline/arrows-right-left.svg +3 -0
  917. data/vendor/heroicons/24/outline/arrows-up-down.svg +3 -0
  918. data/vendor/heroicons/24/outline/at-symbol.svg +3 -0
  919. data/vendor/heroicons/24/outline/backspace.svg +3 -0
  920. data/vendor/heroicons/24/outline/backward.svg +3 -0
  921. data/vendor/heroicons/24/outline/banknotes.svg +3 -0
  922. data/vendor/heroicons/24/outline/bars-2.svg +3 -0
  923. data/vendor/heroicons/24/outline/bars-3-bottom-left.svg +3 -0
  924. data/vendor/heroicons/24/outline/bars-3-bottom-right.svg +3 -0
  925. data/vendor/heroicons/24/outline/bars-3-center-left.svg +3 -0
  926. data/vendor/heroicons/24/outline/bars-3.svg +3 -0
  927. data/vendor/heroicons/24/outline/bars-4.svg +3 -0
  928. data/vendor/heroicons/24/outline/bars-arrow-down.svg +3 -0
  929. data/vendor/heroicons/24/outline/bars-arrow-up.svg +3 -0
  930. data/vendor/heroicons/24/outline/battery-0.svg +3 -0
  931. data/vendor/heroicons/24/outline/battery-100.svg +3 -0
  932. data/vendor/heroicons/24/outline/battery-50.svg +3 -0
  933. data/vendor/heroicons/24/outline/beaker.svg +3 -0
  934. data/vendor/heroicons/24/outline/bell-alert.svg +3 -0
  935. data/vendor/heroicons/24/outline/bell-slash.svg +3 -0
  936. data/vendor/heroicons/24/outline/bell-snooze.svg +3 -0
  937. data/vendor/heroicons/24/outline/bell.svg +3 -0
  938. data/vendor/heroicons/24/outline/bold.svg +3 -0
  939. data/vendor/heroicons/24/outline/bolt-slash.svg +3 -0
  940. data/vendor/heroicons/24/outline/bolt.svg +3 -0
  941. data/vendor/heroicons/24/outline/book-open.svg +3 -0
  942. data/vendor/heroicons/24/outline/bookmark-slash.svg +3 -0
  943. data/vendor/heroicons/24/outline/bookmark-square.svg +3 -0
  944. data/vendor/heroicons/24/outline/bookmark.svg +3 -0
  945. data/vendor/heroicons/24/outline/briefcase.svg +3 -0
  946. data/vendor/heroicons/24/outline/bug-ant.svg +3 -0
  947. data/vendor/heroicons/24/outline/building-library.svg +3 -0
  948. data/vendor/heroicons/24/outline/building-office-2.svg +3 -0
  949. data/vendor/heroicons/24/outline/building-office.svg +3 -0
  950. data/vendor/heroicons/24/outline/building-storefront.svg +3 -0
  951. data/vendor/heroicons/24/outline/cake.svg +3 -0
  952. data/vendor/heroicons/24/outline/calculator.svg +3 -0
  953. data/vendor/heroicons/24/outline/calendar-date-range.svg +3 -0
  954. data/vendor/heroicons/24/outline/calendar-days.svg +3 -0
  955. data/vendor/heroicons/24/outline/calendar.svg +3 -0
  956. data/vendor/heroicons/24/outline/camera.svg +4 -0
  957. data/vendor/heroicons/24/outline/chart-bar-square.svg +3 -0
  958. data/vendor/heroicons/24/outline/chart-bar.svg +3 -0
  959. data/vendor/heroicons/24/outline/chart-pie.svg +4 -0
  960. data/vendor/heroicons/24/outline/chat-bubble-bottom-center-text.svg +3 -0
  961. data/vendor/heroicons/24/outline/chat-bubble-bottom-center.svg +3 -0
  962. data/vendor/heroicons/24/outline/chat-bubble-left-ellipsis.svg +3 -0
  963. data/vendor/heroicons/24/outline/chat-bubble-left-right.svg +3 -0
  964. data/vendor/heroicons/24/outline/chat-bubble-left.svg +3 -0
  965. data/vendor/heroicons/24/outline/chat-bubble-oval-left-ellipsis.svg +3 -0
  966. data/vendor/heroicons/24/outline/chat-bubble-oval-left.svg +3 -0
  967. data/vendor/heroicons/24/outline/check-badge.svg +3 -0
  968. data/vendor/heroicons/24/outline/check-circle.svg +3 -0
  969. data/vendor/heroicons/24/outline/check.svg +3 -0
  970. data/vendor/heroicons/24/outline/chevron-double-down.svg +3 -0
  971. data/vendor/heroicons/24/outline/chevron-double-left.svg +3 -0
  972. data/vendor/heroicons/24/outline/chevron-double-right.svg +3 -0
  973. data/vendor/heroicons/24/outline/chevron-double-up.svg +4 -0
  974. data/vendor/heroicons/24/outline/chevron-down.svg +3 -0
  975. data/vendor/heroicons/24/outline/chevron-left.svg +3 -0
  976. data/vendor/heroicons/24/outline/chevron-right.svg +3 -0
  977. data/vendor/heroicons/24/outline/chevron-up-down.svg +3 -0
  978. data/vendor/heroicons/24/outline/chevron-up.svg +3 -0
  979. data/vendor/heroicons/24/outline/circle-stack.svg +3 -0
  980. data/vendor/heroicons/24/outline/clipboard-document-check.svg +3 -0
  981. data/vendor/heroicons/24/outline/clipboard-document-list.svg +3 -0
  982. data/vendor/heroicons/24/outline/clipboard-document.svg +3 -0
  983. data/vendor/heroicons/24/outline/clipboard.svg +3 -0
  984. data/vendor/heroicons/24/outline/clock.svg +3 -0
  985. data/vendor/heroicons/24/outline/cloud-arrow-down.svg +3 -0
  986. data/vendor/heroicons/24/outline/cloud-arrow-up.svg +3 -0
  987. data/vendor/heroicons/24/outline/cloud.svg +3 -0
  988. data/vendor/heroicons/24/outline/code-bracket-square.svg +3 -0
  989. data/vendor/heroicons/24/outline/code-bracket.svg +3 -0
  990. data/vendor/heroicons/24/outline/cog-6-tooth.svg +4 -0
  991. data/vendor/heroicons/24/outline/cog-8-tooth.svg +4 -0
  992. data/vendor/heroicons/24/outline/cog.svg +3 -0
  993. data/vendor/heroicons/24/outline/command-line.svg +3 -0
  994. data/vendor/heroicons/24/outline/computer-desktop.svg +3 -0
  995. data/vendor/heroicons/24/outline/cpu-chip.svg +3 -0
  996. data/vendor/heroicons/24/outline/credit-card.svg +3 -0
  997. data/vendor/heroicons/24/outline/cube-transparent.svg +3 -0
  998. data/vendor/heroicons/24/outline/cube.svg +3 -0
  999. data/vendor/heroicons/24/outline/currency-bangladeshi.svg +3 -0
  1000. data/vendor/heroicons/24/outline/currency-dollar.svg +3 -0
  1001. data/vendor/heroicons/24/outline/currency-euro.svg +3 -0
  1002. data/vendor/heroicons/24/outline/currency-pound.svg +3 -0
  1003. data/vendor/heroicons/24/outline/currency-rupee.svg +3 -0
  1004. data/vendor/heroicons/24/outline/currency-yen.svg +3 -0
  1005. data/vendor/heroicons/24/outline/cursor-arrow-rays.svg +3 -0
  1006. data/vendor/heroicons/24/outline/cursor-arrow-ripple.svg +3 -0
  1007. data/vendor/heroicons/24/outline/device-phone-mobile.svg +3 -0
  1008. data/vendor/heroicons/24/outline/device-tablet.svg +3 -0
  1009. data/vendor/heroicons/24/outline/divide.svg +3 -0
  1010. data/vendor/heroicons/24/outline/document-arrow-down.svg +3 -0
  1011. data/vendor/heroicons/24/outline/document-arrow-up.svg +3 -0
  1012. data/vendor/heroicons/24/outline/document-chart-bar.svg +3 -0
  1013. data/vendor/heroicons/24/outline/document-check.svg +3 -0
  1014. data/vendor/heroicons/24/outline/document-currency-bangladeshi.svg +3 -0
  1015. data/vendor/heroicons/24/outline/document-currency-dollar.svg +3 -0
  1016. data/vendor/heroicons/24/outline/document-currency-euro.svg +3 -0
  1017. data/vendor/heroicons/24/outline/document-currency-pound.svg +3 -0
  1018. data/vendor/heroicons/24/outline/document-currency-rupee.svg +3 -0
  1019. data/vendor/heroicons/24/outline/document-currency-yen.svg +3 -0
  1020. data/vendor/heroicons/24/outline/document-duplicate.svg +3 -0
  1021. data/vendor/heroicons/24/outline/document-magnifying-glass.svg +3 -0
  1022. data/vendor/heroicons/24/outline/document-minus.svg +3 -0
  1023. data/vendor/heroicons/24/outline/document-plus.svg +3 -0
  1024. data/vendor/heroicons/24/outline/document-text.svg +3 -0
  1025. data/vendor/heroicons/24/outline/document.svg +3 -0
  1026. data/vendor/heroicons/24/outline/ellipsis-horizontal-circle.svg +3 -0
  1027. data/vendor/heroicons/24/outline/ellipsis-horizontal.svg +3 -0
  1028. data/vendor/heroicons/24/outline/ellipsis-vertical.svg +3 -0
  1029. data/vendor/heroicons/24/outline/envelope-open.svg +3 -0
  1030. data/vendor/heroicons/24/outline/envelope.svg +3 -0
  1031. data/vendor/heroicons/24/outline/equals.svg +3 -0
  1032. data/vendor/heroicons/24/outline/exclamation-circle.svg +3 -0
  1033. data/vendor/heroicons/24/outline/exclamation-triangle.svg +3 -0
  1034. data/vendor/heroicons/24/outline/eye-dropper.svg +3 -0
  1035. data/vendor/heroicons/24/outline/eye-slash.svg +3 -0
  1036. data/vendor/heroicons/24/outline/eye.svg +4 -0
  1037. data/vendor/heroicons/24/outline/face-frown.svg +3 -0
  1038. data/vendor/heroicons/24/outline/face-smile.svg +3 -0
  1039. data/vendor/heroicons/24/outline/film.svg +3 -0
  1040. data/vendor/heroicons/24/outline/finger-print.svg +3 -0
  1041. data/vendor/heroicons/24/outline/fire.svg +4 -0
  1042. data/vendor/heroicons/24/outline/flag.svg +3 -0
  1043. data/vendor/heroicons/24/outline/folder-arrow-down.svg +3 -0
  1044. data/vendor/heroicons/24/outline/folder-minus.svg +3 -0
  1045. data/vendor/heroicons/24/outline/folder-open.svg +3 -0
  1046. data/vendor/heroicons/24/outline/folder-plus.svg +3 -0
  1047. data/vendor/heroicons/24/outline/folder.svg +3 -0
  1048. data/vendor/heroicons/24/outline/forward.svg +3 -0
  1049. data/vendor/heroicons/24/outline/funnel.svg +3 -0
  1050. data/vendor/heroicons/24/outline/gif.svg +3 -0
  1051. data/vendor/heroicons/24/outline/gift-top.svg +3 -0
  1052. data/vendor/heroicons/24/outline/gift.svg +3 -0
  1053. data/vendor/heroicons/24/outline/globe-alt.svg +3 -0
  1054. data/vendor/heroicons/24/outline/globe-americas.svg +3 -0
  1055. data/vendor/heroicons/24/outline/globe-asia-australia.svg +3 -0
  1056. data/vendor/heroicons/24/outline/globe-europe-africa.svg +3 -0
  1057. data/vendor/heroicons/24/outline/h1.svg +3 -0
  1058. data/vendor/heroicons/24/outline/h2.svg +3 -0
  1059. data/vendor/heroicons/24/outline/h3.svg +3 -0
  1060. data/vendor/heroicons/24/outline/hand-raised.svg +3 -0
  1061. data/vendor/heroicons/24/outline/hand-thumb-down.svg +3 -0
  1062. data/vendor/heroicons/24/outline/hand-thumb-up.svg +3 -0
  1063. data/vendor/heroicons/24/outline/hashtag.svg +3 -0
  1064. data/vendor/heroicons/24/outline/heart.svg +3 -0
  1065. data/vendor/heroicons/24/outline/home-modern.svg +3 -0
  1066. data/vendor/heroicons/24/outline/home.svg +3 -0
  1067. data/vendor/heroicons/24/outline/identification.svg +3 -0
  1068. data/vendor/heroicons/24/outline/inbox-arrow-down.svg +3 -0
  1069. data/vendor/heroicons/24/outline/inbox-stack.svg +3 -0
  1070. data/vendor/heroicons/24/outline/inbox.svg +3 -0
  1071. data/vendor/heroicons/24/outline/information-circle.svg +3 -0
  1072. data/vendor/heroicons/24/outline/italic.svg +3 -0
  1073. data/vendor/heroicons/24/outline/key.svg +3 -0
  1074. data/vendor/heroicons/24/outline/language.svg +3 -0
  1075. data/vendor/heroicons/24/outline/lifebuoy.svg +3 -0
  1076. data/vendor/heroicons/24/outline/light-bulb.svg +3 -0
  1077. data/vendor/heroicons/24/outline/link-slash.svg +3 -0
  1078. data/vendor/heroicons/24/outline/link.svg +3 -0
  1079. data/vendor/heroicons/24/outline/list-bullet.svg +3 -0
  1080. data/vendor/heroicons/24/outline/lock-closed.svg +3 -0
  1081. data/vendor/heroicons/24/outline/lock-open.svg +3 -0
  1082. data/vendor/heroicons/24/outline/magnifying-glass-circle.svg +3 -0
  1083. data/vendor/heroicons/24/outline/magnifying-glass-minus.svg +3 -0
  1084. data/vendor/heroicons/24/outline/magnifying-glass-plus.svg +3 -0
  1085. data/vendor/heroicons/24/outline/magnifying-glass.svg +3 -0
  1086. data/vendor/heroicons/24/outline/map-pin.svg +4 -0
  1087. data/vendor/heroicons/24/outline/map.svg +3 -0
  1088. data/vendor/heroicons/24/outline/megaphone.svg +3 -0
  1089. data/vendor/heroicons/24/outline/microphone.svg +3 -0
  1090. data/vendor/heroicons/24/outline/minus-circle.svg +3 -0
  1091. data/vendor/heroicons/24/outline/minus-small.svg +3 -0
  1092. data/vendor/heroicons/24/outline/minus.svg +3 -0
  1093. data/vendor/heroicons/24/outline/moon.svg +3 -0
  1094. data/vendor/heroicons/24/outline/musical-note.svg +3 -0
  1095. data/vendor/heroicons/24/outline/newspaper.svg +3 -0
  1096. data/vendor/heroicons/24/outline/no-symbol.svg +3 -0
  1097. data/vendor/heroicons/24/outline/numbered-list.svg +3 -0
  1098. data/vendor/heroicons/24/outline/paint-brush.svg +3 -0
  1099. data/vendor/heroicons/24/outline/paper-airplane.svg +3 -0
  1100. data/vendor/heroicons/24/outline/paper-clip.svg +3 -0
  1101. data/vendor/heroicons/24/outline/pause-circle.svg +3 -0
  1102. data/vendor/heroicons/24/outline/pause.svg +3 -0
  1103. data/vendor/heroicons/24/outline/pencil-square.svg +3 -0
  1104. data/vendor/heroicons/24/outline/pencil.svg +3 -0
  1105. data/vendor/heroicons/24/outline/percent-badge.svg +3 -0
  1106. data/vendor/heroicons/24/outline/phone-arrow-down-left.svg +3 -0
  1107. data/vendor/heroicons/24/outline/phone-arrow-up-right.svg +3 -0
  1108. data/vendor/heroicons/24/outline/phone-x-mark.svg +3 -0
  1109. data/vendor/heroicons/24/outline/phone.svg +3 -0
  1110. data/vendor/heroicons/24/outline/photo.svg +3 -0
  1111. data/vendor/heroicons/24/outline/play-circle.svg +4 -0
  1112. data/vendor/heroicons/24/outline/play-pause.svg +3 -0
  1113. data/vendor/heroicons/24/outline/play.svg +3 -0
  1114. data/vendor/heroicons/24/outline/plus-circle.svg +3 -0
  1115. data/vendor/heroicons/24/outline/plus-small.svg +3 -0
  1116. data/vendor/heroicons/24/outline/plus.svg +3 -0
  1117. data/vendor/heroicons/24/outline/power.svg +3 -0
  1118. data/vendor/heroicons/24/outline/presentation-chart-bar.svg +3 -0
  1119. data/vendor/heroicons/24/outline/presentation-chart-line.svg +3 -0
  1120. data/vendor/heroicons/24/outline/printer.svg +3 -0
  1121. data/vendor/heroicons/24/outline/puzzle-piece.svg +3 -0
  1122. data/vendor/heroicons/24/outline/qr-code.svg +4 -0
  1123. data/vendor/heroicons/24/outline/question-mark-circle.svg +3 -0
  1124. data/vendor/heroicons/24/outline/queue-list.svg +3 -0
  1125. data/vendor/heroicons/24/outline/radio.svg +3 -0
  1126. data/vendor/heroicons/24/outline/receipt-percent.svg +3 -0
  1127. data/vendor/heroicons/24/outline/receipt-refund.svg +3 -0
  1128. data/vendor/heroicons/24/outline/rectangle-group.svg +3 -0
  1129. data/vendor/heroicons/24/outline/rectangle-stack.svg +3 -0
  1130. data/vendor/heroicons/24/outline/rocket-launch.svg +3 -0
  1131. data/vendor/heroicons/24/outline/rss.svg +3 -0
  1132. data/vendor/heroicons/24/outline/scale.svg +3 -0
  1133. data/vendor/heroicons/24/outline/scissors.svg +3 -0
  1134. data/vendor/heroicons/24/outline/server-stack.svg +3 -0
  1135. data/vendor/heroicons/24/outline/server.svg +3 -0
  1136. data/vendor/heroicons/24/outline/share.svg +3 -0
  1137. data/vendor/heroicons/24/outline/shield-check.svg +3 -0
  1138. data/vendor/heroicons/24/outline/shield-exclamation.svg +3 -0
  1139. data/vendor/heroicons/24/outline/shopping-bag.svg +3 -0
  1140. data/vendor/heroicons/24/outline/shopping-cart.svg +3 -0
  1141. data/vendor/heroicons/24/outline/signal-slash.svg +3 -0
  1142. data/vendor/heroicons/24/outline/signal.svg +3 -0
  1143. data/vendor/heroicons/24/outline/slash.svg +3 -0
  1144. data/vendor/heroicons/24/outline/sparkles.svg +3 -0
  1145. data/vendor/heroicons/24/outline/speaker-wave.svg +3 -0
  1146. data/vendor/heroicons/24/outline/speaker-x-mark.svg +3 -0
  1147. data/vendor/heroicons/24/outline/square-2-stack.svg +3 -0
  1148. data/vendor/heroicons/24/outline/square-3-stack-3d.svg +3 -0
  1149. data/vendor/heroicons/24/outline/squares-2x2.svg +3 -0
  1150. data/vendor/heroicons/24/outline/squares-plus.svg +3 -0
  1151. data/vendor/heroicons/24/outline/star.svg +3 -0
  1152. data/vendor/heroicons/24/outline/stop-circle.svg +4 -0
  1153. data/vendor/heroicons/24/outline/stop.svg +3 -0
  1154. data/vendor/heroicons/24/outline/strikethrough.svg +3 -0
  1155. data/vendor/heroicons/24/outline/sun.svg +3 -0
  1156. data/vendor/heroicons/24/outline/swatch.svg +3 -0
  1157. data/vendor/heroicons/24/outline/table-cells.svg +3 -0
  1158. data/vendor/heroicons/24/outline/tag.svg +4 -0
  1159. data/vendor/heroicons/24/outline/ticket.svg +3 -0
  1160. data/vendor/heroicons/24/outline/trash.svg +3 -0
  1161. data/vendor/heroicons/24/outline/trophy.svg +3 -0
  1162. data/vendor/heroicons/24/outline/truck.svg +3 -0
  1163. data/vendor/heroicons/24/outline/tv.svg +3 -0
  1164. data/vendor/heroicons/24/outline/underline.svg +3 -0
  1165. data/vendor/heroicons/24/outline/user-circle.svg +3 -0
  1166. data/vendor/heroicons/24/outline/user-group.svg +3 -0
  1167. data/vendor/heroicons/24/outline/user-minus.svg +3 -0
  1168. data/vendor/heroicons/24/outline/user-plus.svg +3 -0
  1169. data/vendor/heroicons/24/outline/user.svg +3 -0
  1170. data/vendor/heroicons/24/outline/users.svg +3 -0
  1171. data/vendor/heroicons/24/outline/variable.svg +3 -0
  1172. data/vendor/heroicons/24/outline/video-camera-slash.svg +3 -0
  1173. data/vendor/heroicons/24/outline/video-camera.svg +3 -0
  1174. data/vendor/heroicons/24/outline/view-columns.svg +3 -0
  1175. data/vendor/heroicons/24/outline/viewfinder-circle.svg +3 -0
  1176. data/vendor/heroicons/24/outline/wallet.svg +3 -0
  1177. data/vendor/heroicons/24/outline/wifi.svg +3 -0
  1178. data/vendor/heroicons/24/outline/window.svg +3 -0
  1179. data/vendor/heroicons/24/outline/wrench-screwdriver.svg +3 -0
  1180. data/vendor/heroicons/24/outline/wrench.svg +4 -0
  1181. data/vendor/heroicons/24/outline/x-circle.svg +3 -0
  1182. data/vendor/heroicons/24/outline/x-mark.svg +3 -0
  1183. data/vendor/heroicons/24/solid/academic-cap.svg +5 -0
  1184. data/vendor/heroicons/24/solid/adjustments-horizontal.svg +3 -0
  1185. data/vendor/heroicons/24/solid/adjustments-vertical.svg +3 -0
  1186. data/vendor/heroicons/24/solid/archive-box-arrow-down.svg +4 -0
  1187. data/vendor/heroicons/24/solid/archive-box-x-mark.svg +4 -0
  1188. data/vendor/heroicons/24/solid/archive-box.svg +4 -0
  1189. data/vendor/heroicons/24/solid/arrow-down-circle.svg +3 -0
  1190. data/vendor/heroicons/24/solid/arrow-down-left.svg +3 -0
  1191. data/vendor/heroicons/24/solid/arrow-down-on-square-stack.svg +4 -0
  1192. data/vendor/heroicons/24/solid/arrow-down-on-square.svg +3 -0
  1193. data/vendor/heroicons/24/solid/arrow-down-right.svg +3 -0
  1194. data/vendor/heroicons/24/solid/arrow-down-tray.svg +3 -0
  1195. data/vendor/heroicons/24/solid/arrow-down.svg +3 -0
  1196. data/vendor/heroicons/24/solid/arrow-left-circle.svg +3 -0
  1197. data/vendor/heroicons/24/solid/arrow-left-end-on-rectangle.svg +3 -0
  1198. data/vendor/heroicons/24/solid/arrow-left-on-rectangle.svg +3 -0
  1199. data/vendor/heroicons/24/solid/arrow-left-start-on-rectangle.svg +3 -0
  1200. data/vendor/heroicons/24/solid/arrow-left.svg +3 -0
  1201. data/vendor/heroicons/24/solid/arrow-long-down.svg +3 -0
  1202. data/vendor/heroicons/24/solid/arrow-long-left.svg +3 -0
  1203. data/vendor/heroicons/24/solid/arrow-long-right.svg +3 -0
  1204. data/vendor/heroicons/24/solid/arrow-long-up.svg +3 -0
  1205. data/vendor/heroicons/24/solid/arrow-path-rounded-square.svg +3 -0
  1206. data/vendor/heroicons/24/solid/arrow-path.svg +3 -0
  1207. data/vendor/heroicons/24/solid/arrow-right-circle.svg +3 -0
  1208. data/vendor/heroicons/24/solid/arrow-right-end-on-rectangle.svg +3 -0
  1209. data/vendor/heroicons/24/solid/arrow-right-on-rectangle.svg +3 -0
  1210. data/vendor/heroicons/24/solid/arrow-right-start-on-rectangle.svg +3 -0
  1211. data/vendor/heroicons/24/solid/arrow-right.svg +3 -0
  1212. data/vendor/heroicons/24/solid/arrow-small-down.svg +3 -0
  1213. data/vendor/heroicons/24/solid/arrow-small-left.svg +3 -0
  1214. data/vendor/heroicons/24/solid/arrow-small-right.svg +3 -0
  1215. data/vendor/heroicons/24/solid/arrow-small-up.svg +3 -0
  1216. data/vendor/heroicons/24/solid/arrow-top-right-on-square.svg +3 -0
  1217. data/vendor/heroicons/24/solid/arrow-trending-down.svg +3 -0
  1218. data/vendor/heroicons/24/solid/arrow-trending-up.svg +3 -0
  1219. data/vendor/heroicons/24/solid/arrow-turn-down-left.svg +3 -0
  1220. data/vendor/heroicons/24/solid/arrow-turn-down-right.svg +3 -0
  1221. data/vendor/heroicons/24/solid/arrow-turn-left-down.svg +3 -0
  1222. data/vendor/heroicons/24/solid/arrow-turn-left-up.svg +3 -0
  1223. data/vendor/heroicons/24/solid/arrow-turn-right-down.svg +3 -0
  1224. data/vendor/heroicons/24/solid/arrow-turn-right-up.svg +3 -0
  1225. data/vendor/heroicons/24/solid/arrow-turn-up-left.svg +3 -0
  1226. data/vendor/heroicons/24/solid/arrow-turn-up-right.svg +3 -0
  1227. data/vendor/heroicons/24/solid/arrow-up-circle.svg +3 -0
  1228. data/vendor/heroicons/24/solid/arrow-up-left.svg +3 -0
  1229. data/vendor/heroicons/24/solid/arrow-up-on-square-stack.svg +4 -0
  1230. data/vendor/heroicons/24/solid/arrow-up-on-square.svg +3 -0
  1231. data/vendor/heroicons/24/solid/arrow-up-right.svg +3 -0
  1232. data/vendor/heroicons/24/solid/arrow-up-tray.svg +3 -0
  1233. data/vendor/heroicons/24/solid/arrow-up.svg +3 -0
  1234. data/vendor/heroicons/24/solid/arrow-uturn-down.svg +3 -0
  1235. data/vendor/heroicons/24/solid/arrow-uturn-left.svg +3 -0
  1236. data/vendor/heroicons/24/solid/arrow-uturn-right.svg +3 -0
  1237. data/vendor/heroicons/24/solid/arrow-uturn-up.svg +3 -0
  1238. data/vendor/heroicons/24/solid/arrows-pointing-in.svg +3 -0
  1239. data/vendor/heroicons/24/solid/arrows-pointing-out.svg +3 -0
  1240. data/vendor/heroicons/24/solid/arrows-right-left.svg +3 -0
  1241. data/vendor/heroicons/24/solid/arrows-up-down.svg +3 -0
  1242. data/vendor/heroicons/24/solid/at-symbol.svg +3 -0
  1243. data/vendor/heroicons/24/solid/backspace.svg +3 -0
  1244. data/vendor/heroicons/24/solid/backward.svg +3 -0
  1245. data/vendor/heroicons/24/solid/banknotes.svg +5 -0
  1246. data/vendor/heroicons/24/solid/bars-2.svg +3 -0
  1247. data/vendor/heroicons/24/solid/bars-3-bottom-left.svg +3 -0
  1248. data/vendor/heroicons/24/solid/bars-3-bottom-right.svg +3 -0
  1249. data/vendor/heroicons/24/solid/bars-3-center-left.svg +3 -0
  1250. data/vendor/heroicons/24/solid/bars-3.svg +3 -0
  1251. data/vendor/heroicons/24/solid/bars-4.svg +3 -0
  1252. data/vendor/heroicons/24/solid/bars-arrow-down.svg +3 -0
  1253. data/vendor/heroicons/24/solid/bars-arrow-up.svg +3 -0
  1254. data/vendor/heroicons/24/solid/battery-0.svg +3 -0
  1255. data/vendor/heroicons/24/solid/battery-100.svg +3 -0
  1256. data/vendor/heroicons/24/solid/battery-50.svg +4 -0
  1257. data/vendor/heroicons/24/solid/beaker.svg +3 -0
  1258. data/vendor/heroicons/24/solid/bell-alert.svg +4 -0
  1259. data/vendor/heroicons/24/solid/bell-slash.svg +4 -0
  1260. data/vendor/heroicons/24/solid/bell-snooze.svg +3 -0
  1261. data/vendor/heroicons/24/solid/bell.svg +3 -0
  1262. data/vendor/heroicons/24/solid/bold.svg +3 -0
  1263. data/vendor/heroicons/24/solid/bolt-slash.svg +3 -0
  1264. data/vendor/heroicons/24/solid/bolt.svg +3 -0
  1265. data/vendor/heroicons/24/solid/book-open.svg +3 -0
  1266. data/vendor/heroicons/24/solid/bookmark-slash.svg +3 -0
  1267. data/vendor/heroicons/24/solid/bookmark-square.svg +3 -0
  1268. data/vendor/heroicons/24/solid/bookmark.svg +3 -0
  1269. data/vendor/heroicons/24/solid/briefcase.svg +4 -0
  1270. data/vendor/heroicons/24/solid/bug-ant.svg +3 -0
  1271. data/vendor/heroicons/24/solid/building-library.svg +5 -0
  1272. data/vendor/heroicons/24/solid/building-office-2.svg +3 -0
  1273. data/vendor/heroicons/24/solid/building-office.svg +3 -0
  1274. data/vendor/heroicons/24/solid/building-storefront.svg +4 -0
  1275. data/vendor/heroicons/24/solid/cake.svg +3 -0
  1276. data/vendor/heroicons/24/solid/calculator.svg +3 -0
  1277. data/vendor/heroicons/24/solid/calendar-date-range.svg +4 -0
  1278. data/vendor/heroicons/24/solid/calendar-days.svg +4 -0
  1279. data/vendor/heroicons/24/solid/calendar.svg +3 -0
  1280. data/vendor/heroicons/24/solid/camera.svg +4 -0
  1281. data/vendor/heroicons/24/solid/chart-bar-square.svg +3 -0
  1282. data/vendor/heroicons/24/solid/chart-bar.svg +3 -0
  1283. data/vendor/heroicons/24/solid/chart-pie.svg +4 -0
  1284. data/vendor/heroicons/24/solid/chat-bubble-bottom-center-text.svg +3 -0
  1285. data/vendor/heroicons/24/solid/chat-bubble-bottom-center.svg +3 -0
  1286. data/vendor/heroicons/24/solid/chat-bubble-left-ellipsis.svg +3 -0
  1287. data/vendor/heroicons/24/solid/chat-bubble-left-right.svg +4 -0
  1288. data/vendor/heroicons/24/solid/chat-bubble-left.svg +3 -0
  1289. data/vendor/heroicons/24/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
  1290. data/vendor/heroicons/24/solid/chat-bubble-oval-left.svg +3 -0
  1291. data/vendor/heroicons/24/solid/check-badge.svg +3 -0
  1292. data/vendor/heroicons/24/solid/check-circle.svg +3 -0
  1293. data/vendor/heroicons/24/solid/check.svg +3 -0
  1294. data/vendor/heroicons/24/solid/chevron-double-down.svg +4 -0
  1295. data/vendor/heroicons/24/solid/chevron-double-left.svg +4 -0
  1296. data/vendor/heroicons/24/solid/chevron-double-right.svg +4 -0
  1297. data/vendor/heroicons/24/solid/chevron-double-up.svg +4 -0
  1298. data/vendor/heroicons/24/solid/chevron-down.svg +3 -0
  1299. data/vendor/heroicons/24/solid/chevron-left.svg +3 -0
  1300. data/vendor/heroicons/24/solid/chevron-right.svg +3 -0
  1301. data/vendor/heroicons/24/solid/chevron-up-down.svg +3 -0
  1302. data/vendor/heroicons/24/solid/chevron-up.svg +3 -0
  1303. data/vendor/heroicons/24/solid/circle-stack.svg +6 -0
  1304. data/vendor/heroicons/24/solid/clipboard-document-check.svg +4 -0
  1305. data/vendor/heroicons/24/solid/clipboard-document-list.svg +4 -0
  1306. data/vendor/heroicons/24/solid/clipboard-document.svg +5 -0
  1307. data/vendor/heroicons/24/solid/clipboard.svg +3 -0
  1308. data/vendor/heroicons/24/solid/clock.svg +3 -0
  1309. data/vendor/heroicons/24/solid/cloud-arrow-down.svg +3 -0
  1310. data/vendor/heroicons/24/solid/cloud-arrow-up.svg +3 -0
  1311. data/vendor/heroicons/24/solid/cloud.svg +3 -0
  1312. data/vendor/heroicons/24/solid/code-bracket-square.svg +3 -0
  1313. data/vendor/heroicons/24/solid/code-bracket.svg +3 -0
  1314. data/vendor/heroicons/24/solid/cog-6-tooth.svg +3 -0
  1315. data/vendor/heroicons/24/solid/cog-8-tooth.svg +3 -0
  1316. data/vendor/heroicons/24/solid/cog.svg +4 -0
  1317. data/vendor/heroicons/24/solid/command-line.svg +3 -0
  1318. data/vendor/heroicons/24/solid/computer-desktop.svg +3 -0
  1319. data/vendor/heroicons/24/solid/cpu-chip.svg +4 -0
  1320. data/vendor/heroicons/24/solid/credit-card.svg +4 -0
  1321. data/vendor/heroicons/24/solid/cube-transparent.svg +3 -0
  1322. data/vendor/heroicons/24/solid/cube.svg +3 -0
  1323. data/vendor/heroicons/24/solid/currency-bangladeshi.svg +3 -0
  1324. data/vendor/heroicons/24/solid/currency-dollar.svg +4 -0
  1325. data/vendor/heroicons/24/solid/currency-euro.svg +3 -0
  1326. data/vendor/heroicons/24/solid/currency-pound.svg +3 -0
  1327. data/vendor/heroicons/24/solid/currency-rupee.svg +3 -0
  1328. data/vendor/heroicons/24/solid/currency-yen.svg +3 -0
  1329. data/vendor/heroicons/24/solid/cursor-arrow-rays.svg +3 -0
  1330. data/vendor/heroicons/24/solid/cursor-arrow-ripple.svg +3 -0
  1331. data/vendor/heroicons/24/solid/device-phone-mobile.svg +4 -0
  1332. data/vendor/heroicons/24/solid/device-tablet.svg +4 -0
  1333. data/vendor/heroicons/24/solid/divide.svg +3 -0
  1334. data/vendor/heroicons/24/solid/document-arrow-down.svg +4 -0
  1335. data/vendor/heroicons/24/solid/document-arrow-up.svg +4 -0
  1336. data/vendor/heroicons/24/solid/document-chart-bar.svg +4 -0
  1337. data/vendor/heroicons/24/solid/document-check.svg +4 -0
  1338. data/vendor/heroicons/24/solid/document-currency-bangladeshi.svg +3 -0
  1339. data/vendor/heroicons/24/solid/document-currency-dollar.svg +3 -0
  1340. data/vendor/heroicons/24/solid/document-currency-euro.svg +4 -0
  1341. data/vendor/heroicons/24/solid/document-currency-pound.svg +3 -0
  1342. data/vendor/heroicons/24/solid/document-currency-rupee.svg +3 -0
  1343. data/vendor/heroicons/24/solid/document-currency-yen.svg +3 -0
  1344. data/vendor/heroicons/24/solid/document-duplicate.svg +4 -0
  1345. data/vendor/heroicons/24/solid/document-magnifying-glass.svg +5 -0
  1346. data/vendor/heroicons/24/solid/document-minus.svg +4 -0
  1347. data/vendor/heroicons/24/solid/document-plus.svg +4 -0
  1348. data/vendor/heroicons/24/solid/document-text.svg +4 -0
  1349. data/vendor/heroicons/24/solid/document.svg +4 -0
  1350. data/vendor/heroicons/24/solid/ellipsis-horizontal-circle.svg +3 -0
  1351. data/vendor/heroicons/24/solid/ellipsis-horizontal.svg +3 -0
  1352. data/vendor/heroicons/24/solid/ellipsis-vertical.svg +3 -0
  1353. data/vendor/heroicons/24/solid/envelope-open.svg +4 -0
  1354. data/vendor/heroicons/24/solid/envelope.svg +4 -0
  1355. data/vendor/heroicons/24/solid/equals.svg +3 -0
  1356. data/vendor/heroicons/24/solid/exclamation-circle.svg +3 -0
  1357. data/vendor/heroicons/24/solid/exclamation-triangle.svg +3 -0
  1358. data/vendor/heroicons/24/solid/eye-dropper.svg +3 -0
  1359. data/vendor/heroicons/24/solid/eye-slash.svg +5 -0
  1360. data/vendor/heroicons/24/solid/eye.svg +4 -0
  1361. data/vendor/heroicons/24/solid/face-frown.svg +3 -0
  1362. data/vendor/heroicons/24/solid/face-smile.svg +3 -0
  1363. data/vendor/heroicons/24/solid/film.svg +3 -0
  1364. data/vendor/heroicons/24/solid/finger-print.svg +3 -0
  1365. data/vendor/heroicons/24/solid/fire.svg +3 -0
  1366. data/vendor/heroicons/24/solid/flag.svg +3 -0
  1367. data/vendor/heroicons/24/solid/folder-arrow-down.svg +3 -0
  1368. data/vendor/heroicons/24/solid/folder-minus.svg +3 -0
  1369. data/vendor/heroicons/24/solid/folder-open.svg +3 -0
  1370. data/vendor/heroicons/24/solid/folder-plus.svg +3 -0
  1371. data/vendor/heroicons/24/solid/folder.svg +3 -0
  1372. data/vendor/heroicons/24/solid/forward.svg +3 -0
  1373. data/vendor/heroicons/24/solid/funnel.svg +3 -0
  1374. data/vendor/heroicons/24/solid/gif.svg +3 -0
  1375. data/vendor/heroicons/24/solid/gift-top.svg +4 -0
  1376. data/vendor/heroicons/24/solid/gift.svg +3 -0
  1377. data/vendor/heroicons/24/solid/globe-alt.svg +3 -0
  1378. data/vendor/heroicons/24/solid/globe-americas.svg +3 -0
  1379. data/vendor/heroicons/24/solid/globe-asia-australia.svg +4 -0
  1380. data/vendor/heroicons/24/solid/globe-europe-africa.svg +3 -0
  1381. data/vendor/heroicons/24/solid/h1.svg +3 -0
  1382. data/vendor/heroicons/24/solid/h2.svg +3 -0
  1383. data/vendor/heroicons/24/solid/h3.svg +3 -0
  1384. data/vendor/heroicons/24/solid/hand-raised.svg +3 -0
  1385. data/vendor/heroicons/24/solid/hand-thumb-down.svg +3 -0
  1386. data/vendor/heroicons/24/solid/hand-thumb-up.svg +3 -0
  1387. data/vendor/heroicons/24/solid/hashtag.svg +3 -0
  1388. data/vendor/heroicons/24/solid/heart.svg +3 -0
  1389. data/vendor/heroicons/24/solid/home-modern.svg +4 -0
  1390. data/vendor/heroicons/24/solid/home.svg +4 -0
  1391. data/vendor/heroicons/24/solid/identification.svg +3 -0
  1392. data/vendor/heroicons/24/solid/inbox-arrow-down.svg +4 -0
  1393. data/vendor/heroicons/24/solid/inbox-stack.svg +4 -0
  1394. data/vendor/heroicons/24/solid/inbox.svg +3 -0
  1395. data/vendor/heroicons/24/solid/information-circle.svg +3 -0
  1396. data/vendor/heroicons/24/solid/italic.svg +3 -0
  1397. data/vendor/heroicons/24/solid/key.svg +3 -0
  1398. data/vendor/heroicons/24/solid/language.svg +3 -0
  1399. data/vendor/heroicons/24/solid/lifebuoy.svg +3 -0
  1400. data/vendor/heroicons/24/solid/light-bulb.svg +4 -0
  1401. data/vendor/heroicons/24/solid/link-slash.svg +3 -0
  1402. data/vendor/heroicons/24/solid/link.svg +3 -0
  1403. data/vendor/heroicons/24/solid/list-bullet.svg +3 -0
  1404. data/vendor/heroicons/24/solid/lock-closed.svg +3 -0
  1405. data/vendor/heroicons/24/solid/lock-open.svg +3 -0
  1406. data/vendor/heroicons/24/solid/magnifying-glass-circle.svg +4 -0
  1407. data/vendor/heroicons/24/solid/magnifying-glass-minus.svg +3 -0
  1408. data/vendor/heroicons/24/solid/magnifying-glass-plus.svg +3 -0
  1409. data/vendor/heroicons/24/solid/magnifying-glass.svg +3 -0
  1410. data/vendor/heroicons/24/solid/map-pin.svg +3 -0
  1411. data/vendor/heroicons/24/solid/map.svg +3 -0
  1412. data/vendor/heroicons/24/solid/megaphone.svg +3 -0
  1413. data/vendor/heroicons/24/solid/microphone.svg +4 -0
  1414. data/vendor/heroicons/24/solid/minus-circle.svg +3 -0
  1415. data/vendor/heroicons/24/solid/minus-small.svg +3 -0
  1416. data/vendor/heroicons/24/solid/minus.svg +3 -0
  1417. data/vendor/heroicons/24/solid/moon.svg +3 -0
  1418. data/vendor/heroicons/24/solid/musical-note.svg +3 -0
  1419. data/vendor/heroicons/24/solid/newspaper.svg +4 -0
  1420. data/vendor/heroicons/24/solid/no-symbol.svg +3 -0
  1421. data/vendor/heroicons/24/solid/numbered-list.svg +3 -0
  1422. data/vendor/heroicons/24/solid/paint-brush.svg +3 -0
  1423. data/vendor/heroicons/24/solid/paper-airplane.svg +3 -0
  1424. data/vendor/heroicons/24/solid/paper-clip.svg +3 -0
  1425. data/vendor/heroicons/24/solid/pause-circle.svg +3 -0
  1426. data/vendor/heroicons/24/solid/pause.svg +3 -0
  1427. data/vendor/heroicons/24/solid/pencil-square.svg +4 -0
  1428. data/vendor/heroicons/24/solid/pencil.svg +3 -0
  1429. data/vendor/heroicons/24/solid/percent-badge.svg +3 -0
  1430. data/vendor/heroicons/24/solid/phone-arrow-down-left.svg +4 -0
  1431. data/vendor/heroicons/24/solid/phone-arrow-up-right.svg +4 -0
  1432. data/vendor/heroicons/24/solid/phone-x-mark.svg +3 -0
  1433. data/vendor/heroicons/24/solid/phone.svg +3 -0
  1434. data/vendor/heroicons/24/solid/photo.svg +3 -0
  1435. data/vendor/heroicons/24/solid/play-circle.svg +3 -0
  1436. data/vendor/heroicons/24/solid/play-pause.svg +3 -0
  1437. data/vendor/heroicons/24/solid/play.svg +3 -0
  1438. data/vendor/heroicons/24/solid/plus-circle.svg +3 -0
  1439. data/vendor/heroicons/24/solid/plus-small.svg +3 -0
  1440. data/vendor/heroicons/24/solid/plus.svg +3 -0
  1441. data/vendor/heroicons/24/solid/power.svg +3 -0
  1442. data/vendor/heroicons/24/solid/presentation-chart-bar.svg +3 -0
  1443. data/vendor/heroicons/24/solid/presentation-chart-line.svg +3 -0
  1444. data/vendor/heroicons/24/solid/printer.svg +3 -0
  1445. data/vendor/heroicons/24/solid/puzzle-piece.svg +3 -0
  1446. data/vendor/heroicons/24/solid/qr-code.svg +3 -0
  1447. data/vendor/heroicons/24/solid/question-mark-circle.svg +3 -0
  1448. data/vendor/heroicons/24/solid/queue-list.svg +3 -0
  1449. data/vendor/heroicons/24/solid/radio.svg +3 -0
  1450. data/vendor/heroicons/24/solid/receipt-percent.svg +3 -0
  1451. data/vendor/heroicons/24/solid/receipt-refund.svg +3 -0
  1452. data/vendor/heroicons/24/solid/rectangle-group.svg +3 -0
  1453. data/vendor/heroicons/24/solid/rectangle-stack.svg +3 -0
  1454. data/vendor/heroicons/24/solid/rocket-launch.svg +4 -0
  1455. data/vendor/heroicons/24/solid/rss.svg +3 -0
  1456. data/vendor/heroicons/24/solid/scale.svg +3 -0
  1457. data/vendor/heroicons/24/solid/scissors.svg +4 -0
  1458. data/vendor/heroicons/24/solid/server-stack.svg +4 -0
  1459. data/vendor/heroicons/24/solid/server.svg +4 -0
  1460. data/vendor/heroicons/24/solid/share.svg +3 -0
  1461. data/vendor/heroicons/24/solid/shield-check.svg +3 -0
  1462. data/vendor/heroicons/24/solid/shield-exclamation.svg +3 -0
  1463. data/vendor/heroicons/24/solid/shopping-bag.svg +3 -0
  1464. data/vendor/heroicons/24/solid/shopping-cart.svg +3 -0
  1465. data/vendor/heroicons/24/solid/signal-slash.svg +3 -0
  1466. data/vendor/heroicons/24/solid/signal.svg +3 -0
  1467. data/vendor/heroicons/24/solid/slash.svg +3 -0
  1468. data/vendor/heroicons/24/solid/sparkles.svg +3 -0
  1469. data/vendor/heroicons/24/solid/speaker-wave.svg +4 -0
  1470. data/vendor/heroicons/24/solid/speaker-x-mark.svg +3 -0
  1471. data/vendor/heroicons/24/solid/square-2-stack.svg +4 -0
  1472. data/vendor/heroicons/24/solid/square-3-stack-3d.svg +5 -0
  1473. data/vendor/heroicons/24/solid/squares-2x2.svg +3 -0
  1474. data/vendor/heroicons/24/solid/squares-plus.svg +3 -0
  1475. data/vendor/heroicons/24/solid/star.svg +3 -0
  1476. data/vendor/heroicons/24/solid/stop-circle.svg +3 -0
  1477. data/vendor/heroicons/24/solid/stop.svg +3 -0
  1478. data/vendor/heroicons/24/solid/strikethrough.svg +3 -0
  1479. data/vendor/heroicons/24/solid/sun.svg +3 -0
  1480. data/vendor/heroicons/24/solid/swatch.svg +4 -0
  1481. data/vendor/heroicons/24/solid/table-cells.svg +3 -0
  1482. data/vendor/heroicons/24/solid/tag.svg +3 -0
  1483. data/vendor/heroicons/24/solid/ticket.svg +3 -0
  1484. data/vendor/heroicons/24/solid/trash.svg +3 -0
  1485. data/vendor/heroicons/24/solid/trophy.svg +3 -0
  1486. data/vendor/heroicons/24/solid/truck.svg +5 -0
  1487. data/vendor/heroicons/24/solid/tv.svg +4 -0
  1488. data/vendor/heroicons/24/solid/underline.svg +3 -0
  1489. data/vendor/heroicons/24/solid/user-circle.svg +3 -0
  1490. data/vendor/heroicons/24/solid/user-group.svg +4 -0
  1491. data/vendor/heroicons/24/solid/user-minus.svg +3 -0
  1492. data/vendor/heroicons/24/solid/user-plus.svg +3 -0
  1493. data/vendor/heroicons/24/solid/user.svg +3 -0
  1494. data/vendor/heroicons/24/solid/users.svg +3 -0
  1495. data/vendor/heroicons/24/solid/variable.svg +3 -0
  1496. data/vendor/heroicons/24/solid/video-camera-slash.svg +3 -0
  1497. data/vendor/heroicons/24/solid/video-camera.svg +3 -0
  1498. data/vendor/heroicons/24/solid/view-columns.svg +3 -0
  1499. data/vendor/heroicons/24/solid/viewfinder-circle.svg +3 -0
  1500. data/vendor/heroicons/24/solid/wallet.svg +3 -0
  1501. data/vendor/heroicons/24/solid/wifi.svg +3 -0
  1502. data/vendor/heroicons/24/solid/window.svg +3 -0
  1503. data/vendor/heroicons/24/solid/wrench-screwdriver.svg +5 -0
  1504. data/vendor/heroicons/24/solid/wrench.svg +3 -0
  1505. data/vendor/heroicons/24/solid/x-circle.svg +3 -0
  1506. data/vendor/heroicons/24/solid/x-mark.svg +3 -0
  1507. data/vendor/heroicons/LICENSE +21 -0
  1508. data/vendor/heroicons/VERSION +5 -0
  1509. metadata +1664 -0
@@ -0,0 +1,3125 @@
1
+ /* Abqari — _common.css ----------------------------------------------------
2
+ *
3
+ * Shared structural CSS loaded alongside every hand-written theme
4
+ * (minimal, magazine, notebook, sand). The theme file in
5
+ * themes/<name>/css/app.css provides the palette + typography + any
6
+ * per-theme aesthetic refinements; this file holds everything else
7
+ * — layout, components, page structure, banners, theme toggle.
8
+ *
9
+ * The bootstrap theme bundles its own CSS framework and skips this
10
+ * file (see the conditional in `app/views/partials/_head.html.erb`).
11
+ *
12
+ * Load order: this file loads BEFORE the theme's app.css, so themes
13
+ * win on cascade-equal specificity. Override anything below by
14
+ * re-declaring it in your theme's app.css.
15
+ *
16
+ * Sections:
17
+ * 1. Tokens — spacing, radii, fonts, shadows, palette
18
+ * 2. Reset — box-sizing, html
19
+ * 3. Layout — sticky-footer body, --content-max-width scaffold
20
+ * 4. Typography — body, headings, anchors, p, lists, hr, code
21
+ * 5. A11y primitives — skip-link, visually-hidden, reduced-motion
22
+ * 6. Header / nav — full-width header bar
23
+ * 7. Footer — full-width footer bar
24
+ * 8. Soft tints — placeholder colours for cover wrappers
25
+ * 9. Banners — draft + future-post indicators
26
+ * 10. Buttons — .btn-* + .folio-button-* component families
27
+ * 11. Cards + utilities — .card, .card-grid, .rounded-*, .shadow-*
28
+ * 12. Page lede + back link — index-page lede, slug-aware back link
29
+ * 13. Single-post detail — .post__meta, .post__hero, .story-image, etc.
30
+ * 14. Posts index — .post-list cards
31
+ * 15. Pagination — .pagination prev/next
32
+ * 16. Publication detail — cover-left + intro-right header layout
33
+ * 17. Publications index — list cards with 3D-tilt covers
34
+ * 18. Folio book grid — home-page card grid
35
+ * 19. Book cover — 3D-tilt cover wrapper
36
+ * 20. Testimonials — quote cards
37
+ * 21. Related books — sister-publications cards
38
+ * 22. Home modules — latest-post / -publication / -photo / contact
39
+ * 23. Theme toggle — sun/moon visibility logic
40
+ * 24. Photo single-page — image-centric post detail
41
+ * 25. Up next + Related — show-view follow-up blocks
42
+ * 26. Carousel — slideshow component
43
+ * 27. Gallery + grid — image-grid layouts
44
+ * 28. Workshops — show view + index for training offerings
45
+ * 29. Newsletter subscribe — provider-agnostic signup form
46
+ * 30. Visualisations — D3 viz pages
47
+ */
48
+
49
+
50
+ /* ============================================================
51
+ * 1. Tokens
52
+ * ============================================================ */
53
+
54
+ :root {
55
+ /* Tell the browser this site supports both light and dark — native
56
+ UI (scrollbars, form controls, autofill, default text-selection)
57
+ picks the right rendering automatically based on system pref or
58
+ [data-theme] toggle. Costs nothing, fixes "white scrollbar on
59
+ dark page" instantly. */
60
+ color-scheme: light dark;
61
+
62
+ /* Spacing scale — geometric, each step ~1.5–2x the previous. */
63
+ --space-xs: 0.25rem;
64
+ --space-sm: 0.5rem;
65
+ --space-md: 1rem;
66
+ --space-lg: 1.5rem;
67
+ --space-xl: 2rem;
68
+ --space-2xl: 3rem;
69
+
70
+ /* Container widths — themes choose one for `body { max-width }`. */
71
+ --container-narrow: 640px;
72
+ --container-default: 720px;
73
+ --container-wide: 880px;
74
+ --container-full: 1200px;
75
+
76
+ /* Border radii — six steps from sharp to pill. */
77
+ --radius-0: 0;
78
+ --radius-1: 0.25rem;
79
+ --radius-2: 0.375rem;
80
+ --radius-3: 0.5rem;
81
+ --radius-4: 1rem;
82
+ --radius-pill: 999px;
83
+ --radius-circle: 50%;
84
+
85
+ /* Legacy aliases (kept for back-compat). */
86
+ --radius-sm: var(--radius-1);
87
+ --radius-md: var(--radius-2);
88
+ --radius-lg: var(--radius-3);
89
+
90
+ /* Typography defaults.
91
+ --font-body — prose body
92
+ --font-heading — h1–h6
93
+ --font-meta — small metadata lines (timestamps, etc.)
94
+ --font-sans — buttons + other UI elements where a sans is
95
+ needed regardless of body/heading family
96
+ --font-mono — code, pre, and any theme that opts in to a
97
+ mono-typeface elsewhere (e.g. notebook's
98
+ `--font-heading: var(--font-mono)` trick)
99
+
100
+ Themes typically override `--font-body` and `--font-heading`; the
101
+ other three default to sensible values and only need overriding
102
+ when the theme wants a specific face. */
103
+ --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
104
+ --font-heading: var(--font-body);
105
+ --font-meta: var(--font-body);
106
+ --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
107
+ --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
108
+
109
+ /* Body density — `--font-size-body` is the prose body size,
110
+ `--line-height-body` controls its line-height. Themes can swing
111
+ between "prose vibe" (defaults: 1.0625rem / 1.7) and "docs vibe"
112
+ (e.g. notebook: 1rem / 1.55) entirely via these variables, so the
113
+ theme stylesheet stays nothing but token declarations + minor
114
+ decoration. */
115
+ --font-size-body: 1.0625rem;
116
+ --line-height-body: 1.7;
117
+
118
+ /* Shadow tokens — themes can override these tones if they want. */
119
+ --shadow-soft: 0 4px 16px rgba(0, 0, 0, 0.12);
120
+ --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.08);
121
+ --shadow-cover: 0 6px 20px rgba(0, 0, 0, 0.2);
122
+
123
+ /* Default colour palette — themes redefine these. The values below
124
+ are deliberately neutral; real palettes come from the theme file. */
125
+ --color-text: #1a1a1a;
126
+ --color-bg: #fafafa;
127
+ --color-muted: #6b6b6b;
128
+ --color-link: #0d6efd;
129
+ --color-rule: rgba(0, 0, 0, 0.12);
130
+ --color-card-bg: #fff;
131
+ --color-code-bg: rgba(0, 0, 0, 0.05);
132
+
133
+ /* Component palette — feeds .btn-*, .folio-button-* etc. */
134
+ --color-primary: #0d6efd;
135
+ --color-on-primary: #fff;
136
+ --color-secondary: #6c757d;
137
+ --color-on-secondary: #fff;
138
+ --color-success: #198754;
139
+ --color-on-success: #fff;
140
+ --color-danger: #dc3545;
141
+ --color-on-danger: #fff;
142
+ --color-warning: #ffc107;
143
+ --color-on-warning: #212529;
144
+ --color-info: #0dcaf0;
145
+ --color-on-info: #212529;
146
+ --color-light: #f8f9fa;
147
+ --color-on-light: #212529;
148
+ --color-dark: #212529;
149
+ --color-on-dark: #f8f9fa;
150
+
151
+ /* Price text on publication cards/headers. Defaults to the primary
152
+ accent; themes whose primary doubles as the link colour should
153
+ point it at `--color-text` instead, so prices don't read as
154
+ clickable (minimal does this). */
155
+ --color-price: var(--color-primary);
156
+
157
+ /* Responsive content max-width — col-12 / col-md-10 / col-lg-9 / col-xl-8. */
158
+ --content-max-width: 100%;
159
+ }
160
+
161
+ @media (min-width: 768px) { :root { --content-max-width: 83.333%; } }
162
+ @media (min-width: 992px) { :root { --content-max-width: 75%; } }
163
+ @media (min-width: 1200px) { :root { --content-max-width: 66.666%; } }
164
+
165
+
166
+ /* ============================================================
167
+ * 2. Reset
168
+ * ============================================================ */
169
+
170
+ *, *::before, *::after { box-sizing: border-box; }
171
+
172
+ html {
173
+ scroll-behavior: smooth;
174
+ /* Suppress iOS Safari's gray tap-flash on links and buttons. Focus
175
+ and active states still apply — this only removes the involuntary
176
+ highlight overlay. */
177
+ -webkit-tap-highlight-color: transparent;
178
+ }
179
+
180
+ /* Defensive media element rule — a markdown image wider than its
181
+ container would otherwise overflow horizontally on mobile and
182
+ break the layout. Applies to every replaced element so video,
183
+ svg, canvas, iframe all behave consistently. */
184
+ img, picture, video, svg, canvas, iframe {
185
+ max-width: 100%;
186
+ height: auto;
187
+ }
188
+
189
+
190
+ /* ============================================================
191
+ * 3. Layout — sticky-footer flex body + responsive content scaffold.
192
+ * ============================================================ */
193
+
194
+ body {
195
+ margin: 0;
196
+ display: flex;
197
+ flex-direction: column;
198
+ /* `100dvh` (dynamic viewport height) tracks the actual visible
199
+ area as mobile address bars expand/collapse — fixes the iOS
200
+ Safari issue where `100vh` is the *expanded* viewport, so
201
+ content can scroll under the address bar. `100vh` stays as a
202
+ fallback for browsers without dvh support. */
203
+ min-height: 100vh;
204
+ min-height: 100dvh;
205
+ font-family: var(--font-body);
206
+ /* Sizing routed through `--font-size-body` / `--line-height-body`
207
+ tokens so themes can express density choices declaratively in
208
+ their `:root` rather than overriding the `body` rule. Defaults
209
+ in `_common.css` are 1.0625rem / 1.7 (prose vibe). */
210
+ font-size: var(--font-size-body);
211
+ line-height: var(--line-height-body);
212
+ color: var(--color-text);
213
+ background-color: var(--color-bg);
214
+ -webkit-font-smoothing: antialiased;
215
+ }
216
+
217
+ main {
218
+ flex: 1 0 auto;
219
+ padding-top: var(--space-xl);
220
+ }
221
+
222
+ /* Single wrapper element used inside `<header>`, `<main>`, and
223
+ `<footer>` (see `application.html.erb` and `_footer.html.erb`).
224
+ The wrappers themselves stay full-width so borders / backgrounds
225
+ extend edge-to-edge; the `.container` inside is what's centred at
226
+ `--content-max-width`.
227
+
228
+ This replaces an older `* > *` scaffold rule that constrained
229
+ direct children of those wrappers — that approach silently broke
230
+ horizontal alignment whenever a component used shorthand `margin`
231
+ (which expanded to `margin-inline: 0`) and required every contributor
232
+ to remember the `margin-block` discipline. With a single wrapper,
233
+ children flow naturally — no margin gymnastics required. */
234
+ .container {
235
+ max-width: var(--content-max-width);
236
+ margin-inline: auto;
237
+ /* `max()` with safe-area-inset gives the container at least 1rem of
238
+ horizontal padding, and more if the device has a notch / curved
239
+ edges (landscape iPhone X+, foldables). On flat screens the
240
+ env() values evaluate to 0, so the rule falls through to 1rem. */
241
+ padding-inline: max(1rem, env(safe-area-inset-left)) max(1rem, env(safe-area-inset-right));
242
+ }
243
+
244
+
245
+ /* ============================================================
246
+ * 4. Typography
247
+ * ============================================================ */
248
+
249
+ h1, h2, h3, h4, h5, h6 {
250
+ font-family: var(--font-heading);
251
+ font-weight: 600;
252
+ line-height: 1.2;
253
+ color: var(--color-text);
254
+ margin: var(--space-2xl) 0 var(--space-md);
255
+ /* Pull lone words back from the end of a heading so the last line
256
+ is balanced with the lines above. Pure typography polish — no
257
+ fallback needed; browsers without support just wrap normally. */
258
+ text-wrap: balance;
259
+ }
260
+
261
+ /* Heading sizes use `clamp(min, fluid, max)` so they scale smoothly
262
+ from phone to desktop without manual breakpoints. `min` is the
263
+ small-phone floor, `max` is the desktop ceiling, and `vw` between
264
+ them lets the size respond to viewport width. Replaces the older
265
+ max-width@576/400 patches for h1 only. */
266
+ h1 { font-size: clamp(1.25rem, 4vw, 2.5rem); }
267
+ h2 { font-size: clamp(1.25rem, 3vw, 1.5rem); }
268
+ h3 { font-size: clamp(1.125rem, 2.5vw, 1.25rem); }
269
+ h4 { font-size: 1.125rem; }
270
+ h5 { font-size: 1rem; }
271
+ h6 { font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-muted); }
272
+
273
+ article > header > h1:first-child,
274
+ article > h1:first-child { margin-top: 0; }
275
+
276
+ a {
277
+ color: var(--color-link);
278
+ text-decoration: underline;
279
+ text-decoration-color: var(--color-rule);
280
+ text-underline-offset: 0.25em;
281
+ text-decoration-thickness: 1px;
282
+ }
283
+ a:hover {
284
+ color: var(--color-text);
285
+ text-decoration-color: currentColor;
286
+ }
287
+
288
+ /* `text-wrap: pretty` reshuffles paragraph wrapping to avoid orphans
289
+ (lone words on the last line) and unbalanced rivers. Modern, very
290
+ broadly supported, with graceful fallback to default wrap. */
291
+ p {
292
+ margin: 0 0 var(--space-md);
293
+ text-wrap: pretty;
294
+ }
295
+
296
+ ol, ul {
297
+ padding-left: 1.5rem;
298
+ margin: 0 0 var(--space-lg);
299
+ color: var(--color-muted);
300
+ }
301
+ ol li, ul li { margin-bottom: var(--space-sm); }
302
+
303
+ /* GFM task lists — kramdown emits the rendered list as a plain `<ul>`
304
+ with `<li><input type="checkbox" disabled></li>` for each row. With
305
+ no class hook on the list or items, the default disc marker shows
306
+ alongside the checkbox, giving a bullet + circle pair. Detect the
307
+ pattern with `:has()` and hide the marker (and the corresponding
308
+ indent) so only the checkbox carries the "this is a list item"
309
+ signal. `:has()` is supported in all evergreen browsers since
310
+ late 2023; older browsers fall back to the bullet + checkbox
311
+ double, which is ugly but readable. */
312
+ ul:has(> li > input[type="checkbox"]) {
313
+ list-style: none;
314
+ padding-left: 0;
315
+ }
316
+ ul > li:has(> input[type="checkbox"]) {
317
+ list-style: none;
318
+ }
319
+ ul > li > input[type="checkbox"] {
320
+ margin-right: 0.4em;
321
+ }
322
+
323
+ blockquote {
324
+ margin: var(--space-lg) 0;
325
+ padding-left: var(--space-md);
326
+ border-left: 3px solid var(--color-rule);
327
+ font-style: italic;
328
+ color: var(--color-muted);
329
+ }
330
+
331
+ hr {
332
+ border: 0;
333
+ border-top: 1px solid var(--color-rule);
334
+ margin: var(--space-2xl) 0;
335
+ }
336
+
337
+ /* ---- Type utilities --------------------------------------------------
338
+ A small Bootstrap-flavoured family for the one-off cases where a
339
+ BEM component class would be overkill. Use sparingly — the codebase
340
+ leans toward semantic component classes (.related__date, .post__meta)
341
+ for anything that recurs. Reach for these when you have a single span
342
+ or paragraph that needs a quick treatment and inventing a new class
343
+ would be heavier than the change deserves.
344
+ --------------------------------------------------------------------- */
345
+
346
+ /* `.small` and the semantic <small> element. Sized in `em` (relative
347
+ to parent), so a `.small` span inside an h2 reads at 87.5% of the
348
+ h2's size, not at an absolute 14px. */
349
+ small,
350
+ .small {
351
+ font-size: 0.875em;
352
+ }
353
+
354
+ /* De-emphasized text — captions, secondary metadata, fine print. */
355
+ .muted {
356
+ color: var(--color-muted);
357
+ }
358
+
359
+ /* Logical-property alignment. `text-end` mirrors automatically in RTL
360
+ contexts, where it becomes left-align — preferred over `text-right`
361
+ for locale-aware sites. */
362
+ .text-center { text-align: center; }
363
+ .text-end { text-align: end; }
364
+
365
+ /* Lede paragraph — the journalism term for the opening summary
366
+ that sits under a page title. Slightly larger size and tighter
367
+ line-height to set the lede apart from body copy. Pattern:
368
+ <h1>Page title</h1>
369
+ <p class="lede">Short standfirst paragraph…</p>
370
+ Used by every index / show layout as the description under the
371
+ H1, and also available inline anywhere in body content for one-off
372
+ prominent paragraphs. The extra-spacing rule for top-of-page
373
+ usage lives below. */
374
+ .lede {
375
+ font-size: 1.25rem;
376
+ line-height: 1.5;
377
+ }
378
+
379
+ code, pre {
380
+ /* Routes through `--font-mono` so a theme can swap in its own mono
381
+ face (e.g. notebook's JetBrains Mono) without overriding this
382
+ rule. Default mono stack is set in Section 1 (`--font-mono`). */
383
+ font-family: var(--font-mono);
384
+ font-size: 0.9em;
385
+ }
386
+ code {
387
+ padding: 0.125rem 0.375rem;
388
+ background: var(--color-code-bg);
389
+ border-radius: var(--radius-1);
390
+ }
391
+ pre {
392
+ padding: var(--space-md);
393
+ overflow-x: auto;
394
+ background: var(--color-code-bg);
395
+ border-radius: var(--radius-2);
396
+ }
397
+ pre code { padding: 0; background: transparent; }
398
+
399
+
400
+ /* ============================================================
401
+ * 5. Accessibility primitives
402
+ * ============================================================ */
403
+
404
+ .skip-link {
405
+ position: absolute;
406
+ top: 0;
407
+ left: 0;
408
+ padding: var(--space-sm) var(--space-md);
409
+ background: var(--color-text);
410
+ color: var(--color-bg);
411
+ text-decoration: none;
412
+ border-radius: 0 0 var(--radius-2) 0;
413
+ transform: translateY(-100%);
414
+ transition: transform 0.1s;
415
+ z-index: 100;
416
+ }
417
+ .skip-link:focus { transform: translateY(0); }
418
+
419
+ .visually-hidden {
420
+ position: absolute !important;
421
+ width: 1px;
422
+ height: 1px;
423
+ padding: 0;
424
+ margin: -1px;
425
+ overflow: hidden;
426
+ clip: rect(0, 0, 0, 0);
427
+ white-space: nowrap;
428
+ border: 0;
429
+ }
430
+
431
+ @media (prefers-reduced-motion: reduce) {
432
+ *, *::before, *::after {
433
+ animation-duration: 0.01ms !important;
434
+ animation-iteration-count: 1 !important;
435
+ transition-duration: 0.01ms !important;
436
+ }
437
+ }
438
+
439
+
440
+ /* ============================================================
441
+ * 6. Header / nav
442
+ * ============================================================ */
443
+
444
+ .site-header {
445
+ padding-block: var(--space-md);
446
+ border-bottom: 1px solid var(--color-rule);
447
+ /* Navigation reads as UI, not prose — uses the same sans face as
448
+ buttons and other controls. Themes that want a thematic sans
449
+ (sand → Merriweather Sans) override `--font-sans` once and the
450
+ header inherits automatically; the bare-default sans stack works
451
+ fine for themes that don't override. Footer mirrors this on the
452
+ same rationale — see Section 7. */
453
+ font-family: var(--font-sans);
454
+ }
455
+
456
+ nav[aria-label="Primary"] {
457
+ display: flex;
458
+ align-items: center;
459
+ flex-wrap: wrap;
460
+ gap: var(--space-md);
461
+ margin: 0;
462
+ }
463
+ .nav__brand {
464
+ font-family: var(--font-heading);
465
+ font-weight: 700;
466
+ text-decoration: none;
467
+ color: inherit;
468
+ }
469
+ .nav__brand:hover { opacity: 0.7; }
470
+ .nav__links { margin-left: auto; font-size: 0.9375rem; }
471
+ .nav__links a {
472
+ color: var(--color-muted);
473
+ text-decoration: none;
474
+ margin-left: 0.5rem;
475
+ }
476
+ .nav__links a:hover,
477
+ .nav__links a[aria-current="page"] { color: var(--color-primary); }
478
+
479
+ nav[aria-label="Primary"] [aria-current="page"] {
480
+ color: var(--color-text);
481
+ font-weight: 600;
482
+ }
483
+
484
+
485
+ /* ============================================================
486
+ * 7. Footer
487
+ * ============================================================ */
488
+
489
+ body > footer {
490
+ margin-top: var(--space-2xl);
491
+ padding-block: var(--space-lg);
492
+ border-top: 1px solid var(--color-rule);
493
+ font-size: 0.875rem;
494
+ color: var(--color-muted);
495
+ /* Mirror the header — footer reads as UI/meta, not prose. Themes
496
+ override `--font-sans` once and both regions follow. */
497
+ font-family: var(--font-sans);
498
+ }
499
+ .footer-bar {
500
+ display: flex;
501
+ justify-content: space-between;
502
+ align-items: center;
503
+ gap: var(--space-md);
504
+ flex-wrap: wrap;
505
+ }
506
+ .footer-bar > p { margin: 0; }
507
+ .footer-bar .footer-social { display: flex; gap: var(--space-sm); align-items: center; }
508
+ .footer-bar .footer-social a { display: inline-flex; align-items: center; color: var(--color-muted); }
509
+ .footer-bar .footer-social a:hover { color: var(--color-text); }
510
+ .footer-meta { margin: 0; }
511
+ .footer-social { margin: 0; }
512
+ .footer-links { margin: 0 0 var(--space-md); }
513
+
514
+
515
+ /* ============================================================
516
+ * 8. Soft-tint placeholder colours (CLS-safe cover wrappers)
517
+ * ============================================================ */
518
+
519
+ /* Diagonal linear gradients — same palette as the previous solid-
520
+ colour tints, but with ~20% light-to-dark depth across each tile
521
+ so empty covers don't feel flat. 135deg keeps the highlight in
522
+ the top-left corner consistently across all four tints, so a
523
+ gallery cycling through tints reads as a unified set rather than
524
+ four independent stickers. Used by photos / publications listings
525
+ and image-gallery placeholders. */
526
+
527
+ .gallery-index__cover--tint-1,
528
+ .image-gallery__placeholder--tint-1,
529
+ .publications-index__cover--tint-1 {
530
+ background: linear-gradient(135deg, #e6d4ad 0%, #c8b88f 100%); /* warm sand */
531
+ }
532
+
533
+ .gallery-index__cover--tint-2,
534
+ .image-gallery__placeholder--tint-2,
535
+ .publications-index__cover--tint-2 {
536
+ background: linear-gradient(135deg, #d5c5d8 0%, #b3a3b8 100%); /* dusty lavender */
537
+ }
538
+
539
+ .gallery-index__cover--tint-3,
540
+ .image-gallery__placeholder--tint-3,
541
+ .publications-index__cover--tint-3 {
542
+ background: linear-gradient(135deg, #c4d6c5 0%, #a3b8a6 100%); /* sage */
543
+ }
544
+
545
+ .gallery-index__cover--tint-4,
546
+ .image-gallery__placeholder--tint-4,
547
+ .publications-index__cover--tint-4 {
548
+ background: linear-gradient(135deg, #e2c4ad 0%, #c39d80 100%); /* terracotta */
549
+ }
550
+
551
+
552
+ /* ============================================================
553
+ * 9. Banners — draft + future-post indicators (theme-agnostic)
554
+ * ============================================================
555
+ *
556
+ * Banner colours are intentionally fixed warning palettes so authors
557
+ * can't miss the "this isn't shipped yet" signal regardless of theme.
558
+ */
559
+
560
+ .draft-banner,
561
+ .future-banner {
562
+ margin: var(--space-md) 0 var(--space-xl);
563
+ padding: 0.75rem 1rem;
564
+ border: 1px solid;
565
+ border-left-width: 4px;
566
+ border-radius: var(--radius-1);
567
+ font-size: 0.9375rem;
568
+ }
569
+ .draft-banner p,
570
+ .future-banner p { margin: 0; }
571
+ .draft-banner code,
572
+ .future-banner code { color: inherit; }
573
+ .future-banner time { font-variant-numeric: tabular-nums; }
574
+
575
+ .draft-banner { background: #fff4d6; color: #5c4400; border-color: #d9a900; }
576
+ .draft-banner code { background: rgba(217, 169, 0, 0.15); }
577
+ .future-banner { background: #e0eef9; color: #133757; border-color: #4a90c4; }
578
+
579
+ @media (prefers-color-scheme: dark) {
580
+ .draft-banner { background: #3a2e10; color: #ffe8a8; border-color: #b88800; }
581
+ .draft-banner code { background: rgba(184, 136, 0, 0.25); }
582
+ .future-banner { background: #142436; color: #b8d6f0; border-color: #3a78a8; }
583
+ }
584
+ [data-theme="dark"] .draft-banner { background: #3a2e10; color: #ffe8a8; border-color: #b88800; }
585
+ [data-theme="dark"] .draft-banner code { background: rgba(184, 136, 0, 0.25); }
586
+ [data-theme="dark"] .future-banner { background: #142436; color: #b8d6f0; border-color: #3a78a8; }
587
+ [data-theme="light"] .draft-banner { background: #fff4d6; color: #5c4400; border-color: #d9a900; }
588
+ [data-theme="light"] .draft-banner code { background: rgba(217, 169, 0, 0.15); }
589
+ [data-theme="light"] .future-banner { background: #e0eef9; color: #133757; border-color: #4a90c4; }
590
+
591
+
592
+ /* ============================================================
593
+ * 10. Buttons — .btn family + .folio-button family.
594
+ * ============================================================
595
+ *
596
+ * Two button systems coexist:
597
+ *
598
+ * .btn .btn-primary, .btn-outline-secondary, etc.
599
+ * The engine's general-purpose button family. Bootstrap-style
600
+ * naming. Use for site-specific CTAs.
601
+ *
602
+ * .folio-button .folio-button--buy / --cart / --outline
603
+ * Folio-compatible button family — matches the class names used
604
+ * by Folio's storefront pages, so users can paste Folio HTML
605
+ * and get a consistent look.
606
+ *
607
+ * Both pull colours from theme-defined CSS variables.
608
+ */
609
+
610
+ /* --- General buttons (.btn family) ------------------------------- */
611
+
612
+ .btn {
613
+ display: inline-block;
614
+ padding: 0.5rem 1rem;
615
+ font: inherit;
616
+ /* Always sans, never inherit body font — themes with a serif body
617
+ (e.g. magazine) still get crisp buttons. Themes with a thematic
618
+ sans set `--font-sans` once in `:root`. */
619
+ font-family: var(--font-sans);
620
+ font-size: 1rem;
621
+ line-height: 1.5;
622
+ border: 1px solid transparent;
623
+ border-radius: var(--radius-2);
624
+ background-color: transparent;
625
+ color: var(--color-text);
626
+ text-decoration: none;
627
+ text-align: center;
628
+ vertical-align: middle;
629
+ white-space: nowrap;
630
+ cursor: pointer;
631
+ user-select: none;
632
+ transition: background-color 0.15s ease, color 0.15s ease,
633
+ border-color 0.15s ease, box-shadow 0.15s ease;
634
+ }
635
+ .btn:focus-visible {
636
+ outline: 2px solid var(--color-primary);
637
+ outline-offset: 2px;
638
+ }
639
+ .btn:disabled,
640
+ .btn.disabled { opacity: 0.6; pointer-events: none; }
641
+
642
+ .btn-sm { padding: 0.25rem 0.5rem; font-size: 0.875rem; }
643
+ .btn-lg { padding: 0.75rem 1.5rem; font-size: 1.125rem; }
644
+
645
+ .btn-primary { background-color: var(--color-primary); color: var(--color-on-primary); border-color: var(--color-primary); }
646
+ .btn-secondary { background-color: var(--color-secondary); color: var(--color-on-secondary); border-color: var(--color-secondary); }
647
+ .btn-success { background-color: var(--color-success); color: var(--color-on-success); border-color: var(--color-success); }
648
+ .btn-danger { background-color: var(--color-danger); color: var(--color-on-danger); border-color: var(--color-danger); }
649
+ .btn-warning { background-color: var(--color-warning); color: var(--color-on-warning); border-color: var(--color-warning); }
650
+ .btn-info { background-color: var(--color-info); color: var(--color-on-info); border-color: var(--color-info); }
651
+ .btn-light { background-color: var(--color-light); color: var(--color-on-light); border-color: var(--color-light); }
652
+ .btn-dark { background-color: var(--color-dark); color: var(--color-on-dark); border-color: var(--color-dark); }
653
+
654
+ .btn-primary:hover { background-color: color-mix(in srgb, var(--color-primary) 85%, black); border-color: color-mix(in srgb, var(--color-primary) 85%, black); color: var(--color-on-primary); }
655
+ .btn-secondary:hover { background-color: color-mix(in srgb, var(--color-secondary) 85%, black); border-color: color-mix(in srgb, var(--color-secondary) 85%, black); color: var(--color-on-secondary); }
656
+ .btn-success:hover { background-color: color-mix(in srgb, var(--color-success) 85%, black); border-color: color-mix(in srgb, var(--color-success) 85%, black); color: var(--color-on-success); }
657
+ .btn-danger:hover { background-color: color-mix(in srgb, var(--color-danger) 85%, black); border-color: color-mix(in srgb, var(--color-danger) 85%, black); color: var(--color-on-danger); }
658
+ .btn-warning:hover { background-color: color-mix(in srgb, var(--color-warning) 85%, black); border-color: color-mix(in srgb, var(--color-warning) 85%, black); color: var(--color-on-warning); }
659
+ .btn-info:hover { background-color: color-mix(in srgb, var(--color-info) 85%, black); border-color: color-mix(in srgb, var(--color-info) 85%, black); color: var(--color-on-info); }
660
+ .btn-light:hover { background-color: color-mix(in srgb, var(--color-light) 85%, black); border-color: color-mix(in srgb, var(--color-light) 85%, black); color: var(--color-on-light); }
661
+ .btn-dark:hover { background-color: color-mix(in srgb, var(--color-dark) 85%, black); border-color: color-mix(in srgb, var(--color-dark) 85%, black); color: var(--color-on-dark); }
662
+
663
+ .btn-outline-primary { background-color: transparent; color: var(--color-primary); border-color: var(--color-primary); }
664
+ .btn-outline-secondary { background-color: transparent; color: var(--color-secondary); border-color: var(--color-secondary); }
665
+ .btn-outline-success { background-color: transparent; color: var(--color-success); border-color: var(--color-success); }
666
+ .btn-outline-danger { background-color: transparent; color: var(--color-danger); border-color: var(--color-danger); }
667
+ .btn-outline-warning { background-color: transparent; color: var(--color-warning); border-color: var(--color-warning); }
668
+ .btn-outline-info { background-color: transparent; color: var(--color-info); border-color: var(--color-info); }
669
+ .btn-outline-light { background-color: transparent; color: var(--color-light); border-color: var(--color-light); }
670
+ .btn-outline-dark { background-color: transparent; color: var(--color-dark); border-color: var(--color-dark); }
671
+
672
+ .btn-outline-primary:hover { background-color: var(--color-primary); color: var(--color-on-primary); }
673
+ .btn-outline-secondary:hover { background-color: var(--color-secondary); color: var(--color-on-secondary); }
674
+ .btn-outline-success:hover { background-color: var(--color-success); color: var(--color-on-success); }
675
+ .btn-outline-danger:hover { background-color: var(--color-danger); color: var(--color-on-danger); }
676
+ .btn-outline-warning:hover { background-color: var(--color-warning); color: var(--color-on-warning); }
677
+ .btn-outline-info:hover { background-color: var(--color-info); color: var(--color-on-info); }
678
+ .btn-outline-light:hover { background-color: var(--color-light); color: var(--color-on-light); }
679
+ .btn-outline-dark:hover { background-color: var(--color-dark); color: var(--color-on-dark); }
680
+
681
+
682
+ /* --- Folio-compatible buttons (.folio-button family) -------------
683
+ *
684
+ * Class names + structure mirror Folio's storefront output, so users
685
+ * can paste Folio HTML (Buy now, Add to cart) and get a consistent
686
+ * look without rewriting markup.
687
+ *
688
+ * Folio's button-theme generator (foliobooks.app) emits its own CSS
689
+ * — to use those styles instead of these defaults, paste the
690
+ * generator's CSS into your active theme's app.css. Theme CSS loads
691
+ * AFTER _common.css so your rules win on cascade order without
692
+ * !important. To zero out our defaults entirely:
693
+ *
694
+ * .folio-button { all: revert; }
695
+ * .folio-button--buy, .folio-button--cart, .folio-button--outline {
696
+ * all: revert;
697
+ * }
698
+ */
699
+
700
+ /* Standard layout for any row of buy / cart / outline buttons. The
701
+ five classes below all render `[Buy now] [Add to cart]` rows in
702
+ different contexts (generic, publication header, bundle show view,
703
+ bundle CTA on a publication page, series show view); a single
704
+ shared rule keeps the gap and wrap behaviour identical everywhere.
705
+ Per-context margins stay on each class individually, because each
706
+ context sits in a different flow (header vs body vs aside). */
707
+ .folio-buttons,
708
+ .publication__buttons,
709
+ .bundle__buttons,
710
+ .series__buttons,
711
+ .folio-bundle-cta__buttons {
712
+ display: flex;
713
+ flex-wrap: wrap;
714
+ gap: var(--space-sm);
715
+ }
716
+ .folio-buttons { margin: var(--space-md) 0; }
717
+
718
+ .folio-button {
719
+ display: inline-block;
720
+ font-family: var(--font-sans); /* see `.btn` above */
721
+ font-size: 1rem;
722
+ font-weight: 500;
723
+ line-height: 1.5;
724
+ padding: 0.6rem 1rem;
725
+ border-radius: var(--radius-3);
726
+ border: 1px solid transparent;
727
+ text-decoration: none;
728
+ text-align: center;
729
+ cursor: pointer;
730
+ user-select: none;
731
+ transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
732
+ }
733
+
734
+ .folio-button--buy {
735
+ background-color: var(--color-primary);
736
+ color: var(--color-on-primary);
737
+ border-color: var(--color-primary);
738
+ }
739
+ .folio-button--buy:hover,
740
+ .folio-button--buy:focus {
741
+ background-color: color-mix(in srgb, var(--color-primary) 85%, black);
742
+ border-color: color-mix(in srgb, var(--color-primary) 85%, black);
743
+ color: var(--color-on-primary);
744
+ text-decoration: none;
745
+ }
746
+
747
+ .folio-button--cart {
748
+ background-color: transparent;
749
+ color: var(--color-primary);
750
+ border-color: var(--color-primary);
751
+ }
752
+ .folio-button--cart:hover,
753
+ .folio-button--cart:focus {
754
+ background-color: var(--color-primary);
755
+ color: var(--color-on-primary);
756
+ text-decoration: none;
757
+ }
758
+
759
+ .folio-button--outline {
760
+ background-color: transparent;
761
+ color: var(--color-secondary);
762
+ border-color: var(--color-secondary);
763
+ }
764
+ .folio-button--outline:hover,
765
+ .folio-button--outline:focus {
766
+ background-color: var(--color-secondary);
767
+ color: var(--color-on-secondary);
768
+ text-decoration: none;
769
+ }
770
+
771
+ .folio-bundle-cta .folio-button {
772
+ font-size: 0.875rem;
773
+ padding: 0.35rem 0.75rem;
774
+ }
775
+
776
+ /* Touch-target sizing — Apple HIG / WCAG recommend a minimum 44×44
777
+ tap target on touch devices. The default button padding hits ~38–40px,
778
+ fine for mouse precision but cramped under a fingertip. `pointer:
779
+ coarse` matches touchscreens (phones, tablets, touch laptops) and
780
+ leaves precision-pointer devices on the tighter desktop sizing. */
781
+ @media (pointer: coarse) {
782
+ .btn,
783
+ .folio-button {
784
+ padding-block: 0.625rem;
785
+ }
786
+ }
787
+
788
+
789
+ /* ============================================================
790
+ * 11. Cards + radii + shadow utilities
791
+ * ============================================================ */
792
+
793
+ .rounded-0 { border-radius: var(--radius-0) !important; }
794
+ .rounded-1 { border-radius: var(--radius-1) !important; }
795
+ .rounded-2 { border-radius: var(--radius-2) !important; }
796
+ .rounded-3 { border-radius: var(--radius-3) !important; }
797
+ .rounded-4 { border-radius: var(--radius-4) !important; }
798
+ .rounded-pill { border-radius: var(--radius-pill) !important; }
799
+ .rounded-circle { border-radius: var(--radius-circle) !important; }
800
+
801
+ /* Shadow utilities — three depth tiers + an explicit-off class. Map
802
+ to the existing shadow tokens, so a theme that overrides any of
803
+ `--shadow-card / --shadow-soft / --shadow-cover` cascades through
804
+ these utilities AND the component CSS that uses the same tokens.
805
+ `!important` follows the `.rounded-*` precedent so utility classes
806
+ win over component-class shadow declarations on the same element. */
807
+ .shadow-sm { box-shadow: var(--shadow-card) !important; }
808
+ .shadow { box-shadow: var(--shadow-soft) !important; }
809
+ .shadow-lg { box-shadow: var(--shadow-cover) !important; }
810
+ .shadow-none { box-shadow: none !important; }
811
+
812
+ .card {
813
+ display: block;
814
+ padding: var(--space-lg);
815
+ background-color: var(--color-card-bg);
816
+ border: 1px solid var(--color-rule);
817
+ border-radius: var(--radius-3);
818
+ }
819
+ a.card { color: inherit; text-decoration: none; }
820
+ a.card:hover { border-color: var(--color-primary); }
821
+
822
+ .card-grid {
823
+ display: grid;
824
+ gap: var(--space-lg);
825
+ grid-template-columns: 1fr;
826
+ }
827
+ @media (min-width: 768px) {
828
+ .card-grid--2 { grid-template-columns: 1fr 1fr; }
829
+ .card-grid--3 { grid-template-columns: repeat(3, 1fr); }
830
+ }
831
+
832
+ .contact-button-wrapper { margin: var(--space-xl) 0; }
833
+
834
+
835
+ /* ============================================================
836
+ * 12. Page lede + back link
837
+ * ============================================================ */
838
+
839
+ /* When a `.lede` paragraph sits at the top of an `<article><header>`
840
+ (the index-page pattern: title, then short standfirst, then list of
841
+ items below), give it extra bottom margin so the lede stands apart
842
+ from the content that follows. Regular in-body `.lede` paragraphs
843
+ keep the default body-paragraph margin. */
844
+ article > header > .lede {
845
+ margin: 0 0 var(--space-2xl);
846
+ }
847
+
848
+ /* `.index-intro` — wraps the markdown body content on every collection
849
+ index layout (posts, photos, publications, workshops, bundles,
850
+ series, archives). The wrapper renders only when the page actually
851
+ has body content, so it never adds gap when an index is widget-only.
852
+ Sets a uniform bottom gap between the intro prose and the first
853
+ listing/widget below, so all collection landing pages share the same
854
+ visual rhythm. */
855
+ .index-intro {
856
+ margin-bottom: var(--space-2xl);
857
+ }
858
+
859
+ .back-link { margin: var(--space-lg) 0; }
860
+ .back-link a {
861
+ color: var(--color-muted);
862
+ text-decoration: none;
863
+ font-size: 0.875rem;
864
+ }
865
+ .back-link a:hover { color: var(--color-text); }
866
+
867
+
868
+ /* ============================================================
869
+ * 13. Single-post detail
870
+ * ============================================================
871
+ *
872
+ * Page hero (`.post__hero`, an <img>) renders at the image's
873
+ * natural aspect — author uploads vary (4:3, 3:2, square, 16:9,
874
+ * portrait), and the show view is where the full image gets to
875
+ * breathe. Index/listing views crop to 4:3 for grid consistency.
876
+ *
877
+ * Inline body figures (`.story-image`, a <figure>) DO crop to
878
+ * 16:9 since authors curate those within the body and a fixed
879
+ * banner crop reads better in flowing prose than a variable-
880
+ * height block.
881
+ */
882
+
883
+ .post__meta,
884
+ .story-meta {
885
+ font-family: var(--font-meta);
886
+ color: var(--color-muted);
887
+ margin: 0 0 var(--space-lg);
888
+ }
889
+
890
+ /* `.post__hero` renders at the image's NATURAL aspect — most user
891
+ uploads are 4:3 or 3:2, so forcing a wide 16:9 box would crop
892
+ the top + bottom of typical photographs. Same approach as the
893
+ photo show view (`.photo__image`): width fills the column, height
894
+ follows the image's intrinsic ratio. Index/list views still crop
895
+ to 4:3 (via `.post-list__cover`, `.posts-archive__cover`, etc.)
896
+ for grid consistency — the show view is where the full image
897
+ gets to breathe. */
898
+ .post__hero {
899
+ display: block;
900
+ width: 100%;
901
+ height: auto;
902
+ margin: 0 0 var(--space-xl);
903
+ border-radius: var(--radius-3);
904
+ box-shadow: var(--shadow-soft);
905
+ }
906
+
907
+ /* Workshop heroes and inline body figures keep the 16:9 banner
908
+ crop — workshops are typically event imagery (room photos,
909
+ flyers) that read best wide, and inline `.story-image` figures
910
+ are author-curated within the body so a fixed crop is fine. */
911
+ .workshop__hero,
912
+ .story-image {
913
+ display: block;
914
+ width: 100%;
915
+ margin: var(--space-xl) 0;
916
+ aspect-ratio: 16 / 9;
917
+ border-radius: var(--radius-3);
918
+ overflow: hidden;
919
+ box-shadow: var(--shadow-soft);
920
+ }
921
+ .workshop__hero {
922
+ object-fit: cover;
923
+ margin-top: 0;
924
+ }
925
+ .story-image img {
926
+ display: block;
927
+ width: 100%;
928
+ height: 100%;
929
+ object-fit: cover;
930
+ }
931
+
932
+ .post__tags-footer {
933
+ margin-top: var(--space-2xl);
934
+ padding-top: var(--space-md);
935
+ border-top: 1px solid var(--color-rule);
936
+ font-size: 0.875rem;
937
+ color: var(--color-muted);
938
+ }
939
+ .post__tags-footer a { color: var(--color-muted); text-decoration: none; }
940
+ .post__tags-footer a:hover { color: var(--color-text); }
941
+
942
+ /* IndieWeb webmentions — receives from webmention.io at build time,
943
+ renders as a "Replies & mentions" section below the post body.
944
+ Conversational mentions (in-reply-to, mention-of) get the full
945
+ author + body card; likes/reposts/bookmarks render facepile-style
946
+ (avatar grid) because the body text adds nothing the avatar +
947
+ count doesn't. Class hooks only — themes can override completely
948
+ via `themes/<name>/css/app.css`. */
949
+ .webmentions {
950
+ margin-top: var(--space-2xl);
951
+ padding-top: var(--space-lg);
952
+ border-top: 1px solid var(--color-rule);
953
+ }
954
+ .webmentions__heading {
955
+ font-size: 1.125rem;
956
+ margin: 0 0 var(--space-md);
957
+ }
958
+ .webmentions__list {
959
+ list-style: none;
960
+ padding: 0;
961
+ margin: 0;
962
+ display: flex;
963
+ flex-direction: column;
964
+ gap: var(--space-md);
965
+ }
966
+ .webmention {
967
+ display: flex;
968
+ gap: var(--space-md);
969
+ align-items: flex-start;
970
+ }
971
+ .webmention__avatar {
972
+ flex: none;
973
+ width: 48px;
974
+ height: 48px;
975
+ border-radius: 50%;
976
+ object-fit: cover;
977
+ }
978
+ .webmention__body { flex: 1; min-width: 0; }
979
+ .webmention__byline {
980
+ margin: 0 0 var(--space-xs);
981
+ font-size: 0.875rem;
982
+ color: var(--color-muted);
983
+ }
984
+ .webmention__author { color: var(--color-text); font-weight: 600; text-decoration: none; }
985
+ .webmention__author:hover { text-decoration: underline; }
986
+ .webmention__permalink { color: var(--color-muted); text-decoration: none; margin-left: var(--space-xs); }
987
+ .webmention__permalink:hover { color: var(--color-text); }
988
+ .webmention__text { margin: 0; }
989
+
990
+ .webmentions__facepile { margin-top: var(--space-lg); }
991
+ .webmentions__facepile-label {
992
+ margin: var(--space-md) 0 var(--space-xs);
993
+ font-size: 0.875rem;
994
+ color: var(--color-muted);
995
+ }
996
+ .webmentions__facepile-list {
997
+ list-style: none;
998
+ padding: 0;
999
+ margin: 0;
1000
+ display: flex;
1001
+ flex-wrap: wrap;
1002
+ gap: 4px;
1003
+ }
1004
+ .webmentions__facepile-list img {
1005
+ width: 32px;
1006
+ height: 32px;
1007
+ border-radius: 50%;
1008
+ object-fit: cover;
1009
+ display: block;
1010
+ }
1011
+
1012
+ /* Table of contents — auto-generated from h2/h3 headings via the
1013
+ `_toc` partial. Sits inline above the body when the layout
1014
+ renders it. Compact list with indented h3 entries (the `--h3`
1015
+ modifier class) so the hierarchy reads at a glance. */
1016
+ .toc {
1017
+ margin: var(--space-xl) 0;
1018
+ padding: var(--space-lg);
1019
+ background: var(--color-card-bg);
1020
+ border-radius: var(--radius-2);
1021
+ box-shadow: var(--shadow-soft);
1022
+ }
1023
+ /* `.toc__heading` typography is defined in the shared `__heading`
1024
+ rule. */
1025
+
1026
+ /* Native `<details>` collapse. The TOC starts expanded (the `open`
1027
+ attribute on the element) — the toggle is for readers who'd
1028
+ rather hide a long contents list while reading. Click or
1029
+ Enter/Space on the summary; chevron rotates to signal state.
1030
+ No JS, no ARIA polyfilling — browser handles all of it. */
1031
+ .toc__details { display: block; }
1032
+ .toc__summary {
1033
+ display: flex;
1034
+ align-items: center;
1035
+ justify-content: space-between;
1036
+ gap: var(--space-md);
1037
+ cursor: pointer;
1038
+ /* Strip the default disclosure triangle in every browser. The
1039
+ chevron we ship is positioned on the right and rotates with
1040
+ the open state. */
1041
+ list-style: none;
1042
+ }
1043
+ .toc__summary::-webkit-details-marker { display: none; }
1044
+ .toc__summary::marker { content: ''; }
1045
+ /* Zero the heading margin inside the summary — the gap between
1046
+ heading and list lives on the list (`margin-top` below) instead,
1047
+ so the gap only renders when the details is open (the list is
1048
+ hidden when closed, taking its margin with it). */
1049
+ .toc__summary .toc__heading { margin-bottom: 0; }
1050
+ .toc__chevron {
1051
+ flex: 0 0 auto;
1052
+ color: var(--color-muted);
1053
+ transition: transform 0.15s ease-out;
1054
+ /* Default (open) — chevron points down. Collapsed — rotated -90°
1055
+ so it points right. `prefers-reduced-motion` disables the
1056
+ transition via the global motion rule. */
1057
+ transform: rotate(0deg);
1058
+ }
1059
+ .toc__details:not([open]) .toc__chevron { transform: rotate(-90deg); }
1060
+
1061
+ .toc__list {
1062
+ list-style: none;
1063
+ margin: var(--space-md) 0 0;
1064
+ padding: 0;
1065
+ }
1066
+ .toc__item {
1067
+ margin: 0 0 var(--space-xs);
1068
+ }
1069
+ /* Indent + slight size step per heading level so the hierarchy reads
1070
+ at a glance. h2 (no modifier class beyond `.toc__item`) sits flush;
1071
+ h3 indents one step, h4 indents two. Deeper levels (h5/h6) fall
1072
+ through to the h4 style — almost no TOC realistically needs them,
1073
+ and adding more indent steps starts to look like a directory
1074
+ listing rather than a contents list. */
1075
+ .toc__item--h3 {
1076
+ padding-left: var(--space-md);
1077
+ font-size: 0.9375rem;
1078
+ }
1079
+ .toc__item--h4,
1080
+ .toc__item--h5,
1081
+ .toc__item--h6 {
1082
+ padding-left: calc(var(--space-md) * 2);
1083
+ font-size: 0.875rem;
1084
+ }
1085
+ .toc a {
1086
+ color: var(--color-text);
1087
+ text-decoration: none;
1088
+ }
1089
+ .toc a:hover { color: var(--color-primary); }
1090
+
1091
+ .story-break {
1092
+ border: 0;
1093
+ text-align: center;
1094
+ margin: var(--space-xl) 0;
1095
+ color: var(--color-muted);
1096
+ }
1097
+ .story-break::before {
1098
+ content: "* * *";
1099
+ letter-spacing: 0.5em;
1100
+ font-size: 1rem;
1101
+ }
1102
+
1103
+ /* Hero image on the publication detail page (legacy `.book__hero`). */
1104
+ .book__hero { margin: var(--space-xl) 0; }
1105
+ .book__hero img {
1106
+ width: 100%;
1107
+ height: auto;
1108
+ display: block;
1109
+ border-radius: var(--radius-2);
1110
+ }
1111
+
1112
+
1113
+ /* ============================================================
1114
+ * 14. Posts index — .post-list partial
1115
+ * ============================================================
1116
+ *
1117
+ * Each card is title + (optional) cover image + meta + description
1118
+ * + tags. Cover renders cover-left / body-right on >= 768px when
1119
+ * the post has `image:` frontmatter; text-only cards stay single-
1120
+ * column at every breakpoint.
1121
+ */
1122
+
1123
+ /* Zero the <ul>'s browser-default padding-inline-start: 40px (the
1124
+ bullet-space the user-agent reserves) so each `.post-list__item`
1125
+ aligns flush with the article's content edges. `list-style: none`
1126
+ removes the bullets; the padding zero removes their reserved gap. */
1127
+ .post-list {
1128
+ list-style: none;
1129
+ margin: 0;
1130
+ padding-inline: 0;
1131
+ }
1132
+
1133
+ /* "View all N posts →" link at the bottom of the front index when
1134
+ the archive is enabled. Same button-style treatment as the related
1135
+ "Show all N" CTA — pill-shaped, modest, centered. */
1136
+ /* `.posts-index__more`, `.photos-index__more`, and `.publications-index__more`
1137
+ share the same pill-button styling — the "View all N <items> →" link
1138
+ at the bottom of each landing page. Same shape, same hover. */
1139
+ .posts-index__more,
1140
+ .photos-index__more,
1141
+ .publications-index__more {
1142
+ margin: var(--space-2xl) 0 0;
1143
+ text-align: center;
1144
+ font-size: 0.9375rem;
1145
+ }
1146
+ .posts-index__more a,
1147
+ .photos-index__more a,
1148
+ .publications-index__more a {
1149
+ display: inline-block;
1150
+ padding: 0.375rem 1rem;
1151
+ border: 1px solid var(--color-rule);
1152
+ border-radius: var(--radius-pill);
1153
+ text-decoration: none;
1154
+ }
1155
+ .posts-index__more a:hover,
1156
+ .photos-index__more a:hover,
1157
+ .publications-index__more a:hover { border-color: var(--color-primary); }
1158
+
1159
+ /* Posts archive — each entry uses the same card shape as the home
1160
+ page's "Latest photo" / "Latest publication" modules: cover image
1161
+ on the left, body (title → meta → description) on the right at
1162
+ ≥ 600px; stacked on smaller screens. Posts without a hero fall
1163
+ back to a single column so the body fills the row. */
1164
+ .posts-archive {
1165
+ list-style: none;
1166
+ margin: var(--space-xl) 0 0;
1167
+ padding-inline: 0;
1168
+ }
1169
+ .posts-archive__item {
1170
+ display: grid;
1171
+ grid-template-columns: 1fr; /* mobile: stack */
1172
+ gap: var(--space-lg);
1173
+ padding: var(--space-lg) 0;
1174
+ border-top: 1px solid var(--color-rule);
1175
+ }
1176
+ .posts-archive__item:first-child {
1177
+ border-top: 0;
1178
+ padding-top: 0;
1179
+ }
1180
+ .posts-archive__item:last-child {
1181
+ padding-bottom: 0;
1182
+ }
1183
+ @media (min-width: 600px) {
1184
+ .posts-archive__item:has(.posts-archive__cover) {
1185
+ grid-template-columns: minmax(140px, 200px) 1fr;
1186
+ align-items: start;
1187
+ }
1188
+ }
1189
+ /* 4:3 in the archive (an index view) — post heroes are authored at
1190
+ 16:9 to suit the show view; `object-fit: cover` on the img crops
1191
+ to the archive's 4:3 thumbnail. Flat (no rounded corners, no
1192
+ shadow) to match `.post-list__cover` on the front posts index —
1193
+ the archive and the front index share visual treatment. */
1194
+ .posts-archive__cover {
1195
+ display: block;
1196
+ max-width: 200px;
1197
+ }
1198
+ .posts-archive__cover img {
1199
+ display: block;
1200
+ width: 100%;
1201
+ height: auto;
1202
+ aspect-ratio: 4 / 3;
1203
+ object-fit: cover;
1204
+ /* Same neutral surface the placeholder SVG paints, so a real `<img>`
1205
+ that's still on the wire fills its 4:3 box rather than flashing
1206
+ transparent — `object-fit: cover` paints over this entirely once
1207
+ the image arrives, so loaded thumbnails are unchanged. */
1208
+ background-color: var(--color-code-bg);
1209
+ }
1210
+ /* Placeholder rendered when a post has no hero. Matches the `<img>`
1211
+ shape so heroless rows keep the same grid alignment as their
1212
+ hero-bearing siblings. Flat (no shadow / no radius) so it reads
1213
+ the same as the front-index post-list placeholder. */
1214
+ .posts-archive__cover-placeholder {
1215
+ display: block;
1216
+ width: 100%;
1217
+ aspect-ratio: 4 / 3;
1218
+ color: var(--color-code-bg);
1219
+ }
1220
+ .posts-archive__body { min-width: 0; }
1221
+ .posts-archive__title {
1222
+ font-family: var(--font-heading);
1223
+ font-size: 1.25rem;
1224
+ font-weight: 600;
1225
+ margin: 0 0 var(--space-sm);
1226
+ }
1227
+ .posts-archive__title a {
1228
+ color: var(--color-text);
1229
+ text-decoration: none;
1230
+ }
1231
+ .posts-archive__meta {
1232
+ font-family: var(--font-meta);
1233
+ font-size: 0.875rem;
1234
+ color: var(--color-muted);
1235
+ margin: 0 0 var(--space-sm);
1236
+ }
1237
+ .posts-archive__description {
1238
+ margin: 0;
1239
+ color: var(--color-muted);
1240
+ }
1241
+ .post-list__item {
1242
+ display: grid;
1243
+ grid-template-columns: 1fr;
1244
+ gap: var(--space-lg);
1245
+ margin-bottom: var(--space-2xl);
1246
+ }
1247
+ .post-list__item:last-child { margin-bottom: 0; }
1248
+
1249
+ @media (min-width: 768px) {
1250
+ .post-list__item { grid-template-columns: 1fr 2fr; gap: var(--space-xl); }
1251
+ .post-list__item:not(:has(.post-list__cover)) { grid-template-columns: 1fr; }
1252
+ }
1253
+
1254
+ .post-list__cover {
1255
+ display: block;
1256
+ overflow: hidden;
1257
+ aspect-ratio: 4 / 3; /* default index aspect (vs. 16:9 on show views) */
1258
+ /* Same colour the placeholder SVG uses — so a real `<img>` that's
1259
+ still loading paints the same surface as a heroless card. Once
1260
+ the image arrives `object-fit: cover` paints over this entirely,
1261
+ so loaded cards are unchanged. */
1262
+ background-color: var(--color-code-bg);
1263
+ }
1264
+ .post-list__cover img {
1265
+ width: 100%;
1266
+ height: 100%;
1267
+ display: block;
1268
+ object-fit: cover;
1269
+ }
1270
+ /* Placeholder filler — rendered inside `.post-list__cover` when a
1271
+ post has no hero image, so the card keeps the same shape and the
1272
+ grid stays aligned across mixed has-hero / no-hero rows. The
1273
+ `<rect>` paints in `currentColor`, so the theme token sets the
1274
+ tint (same `--color-code-bg` used for workshop covers + inline
1275
+ code, so it reads as a neutral "no image here" surface rather
1276
+ than a real photo placeholder). */
1277
+ .post-list__cover-placeholder {
1278
+ display: block;
1279
+ width: 100%;
1280
+ height: 100%;
1281
+ color: var(--color-code-bg);
1282
+ }
1283
+
1284
+ /* Decorative initial-tile SVG variant of the cover. Inline SVG
1285
+ already carries its own gradient + text — the cover wrapper just
1286
+ needs the SVG to fill the slot. Generic `.cover-svg` class lets
1287
+ the same SVG render correctly inside any cover container (post
1288
+ list, workshop list, show-view heroes). */
1289
+ .cover-svg {
1290
+ display: block;
1291
+ width: 100%;
1292
+ height: 100%;
1293
+ }
1294
+ /* Tile titles follow the theme's heading face — a stylesheet rule
1295
+ outranks the SVG's presentational font-family attribute (which
1296
+ stays as the no-CSS fallback). Without this, every tile bakes in
1297
+ a generic sans and a post page can show two "titles" in two
1298
+ different typefaces (the h1 and the hero tile). */
1299
+ .cover-svg text {
1300
+ font-family: var(--font-heading);
1301
+ }
1302
+ .post-list__cover--svg .cover-svg,
1303
+ .workshops-index__cover--svg .cover-svg {
1304
+ aspect-ratio: 4 / 3;
1305
+ }
1306
+
1307
+ /* Decorative SVG hero on show views. Render as a wide banner with
1308
+ the same shape the photo-hero treatment uses (image-replacement
1309
+ shape), so theme styles that target `.post__hero` / `.workshop__hero`
1310
+ keep working. */
1311
+ .post__hero--svg,
1312
+ .workshop__hero--svg {
1313
+ display: block;
1314
+ width: 100%;
1315
+ aspect-ratio: 4 / 3;
1316
+ overflow: hidden;
1317
+ border-radius: var(--radius-2);
1318
+ }
1319
+ @media (min-width: 768px) {
1320
+ .post__hero--svg,
1321
+ .workshop__hero--svg { aspect-ratio: 16 / 9; }
1322
+ }
1323
+
1324
+ .post-list__body { min-width: 0; }
1325
+
1326
+ .post-list__title {
1327
+ margin: 0 0 0.25rem;
1328
+ font-family: var(--font-heading);
1329
+ font-size: 1.5rem;
1330
+ line-height: 1.3;
1331
+ }
1332
+ .post-list__title a { color: var(--color-text); text-decoration: none; }
1333
+ .post-list__title a:hover { color: var(--color-text); }
1334
+
1335
+ .post-list__meta {
1336
+ margin: 0 0 var(--space-sm);
1337
+ font-family: var(--font-meta);
1338
+ font-size: 0.9375rem;
1339
+ color: var(--color-muted);
1340
+ }
1341
+
1342
+ .post-list__description { margin: 0 0 0.75rem; color: var(--color-muted); }
1343
+
1344
+ .post-list__tags { margin: 0; font-size: 0.875rem; }
1345
+ /* Tag chip — themes customise via component tokens rather than
1346
+ re-declaring the rule. Defaults: plain inline link, no chrome, no
1347
+ prefix. Set these in a theme's `:root` to opt into chip styles:
1348
+ --tag-prefix — `"#"` to restore the hash, `""` to drop it
1349
+ --tag-padding — non-zero to add chrome (e.g. `0.125rem 0.5rem`)
1350
+ --tag-bg — chip background (typically `var(--color-code-bg)`)
1351
+ --tag-radius — corner shape (`var(--radius-pill)` for pills)
1352
+ --tag-font — override font-family (e.g. mono for terminal feel)
1353
+ --tag-font-size — override font-size for a smaller "label" look
1354
+ Notebook layers a `border` on top of the tokens for its outline
1355
+ variant — that's the only theme that still needs a rule of its own. */
1356
+ .post-list__tag {
1357
+ display: inline-block;
1358
+ margin-right: 0.5rem;
1359
+ padding: var(--tag-padding, 0);
1360
+ background: var(--tag-bg, transparent);
1361
+ border-radius: var(--tag-radius, 0);
1362
+ font-family: var(--tag-font, inherit);
1363
+ font-size: var(--tag-font-size, inherit);
1364
+ color: var(--color-muted);
1365
+ text-decoration: none;
1366
+ }
1367
+ .post-list__tag::before { content: var(--tag-prefix, ""); }
1368
+ .post-list__tag:hover { color: var(--color-text); }
1369
+
1370
+
1371
+ /* ============================================================
1372
+ * 15. Pagination
1373
+ * ============================================================ */
1374
+
1375
+ .pagination {
1376
+ margin: var(--space-2xl) 0;
1377
+ display: flex;
1378
+ justify-content: space-between;
1379
+ align-items: center;
1380
+ font-size: 0.9375rem;
1381
+ }
1382
+ .pagination a { color: var(--color-link); text-decoration: none; }
1383
+ .pagination a:hover { color: var(--color-primary); }
1384
+ .pagination__prev::before { content: "← "; }
1385
+ .pagination__next::after { content: " →"; }
1386
+
1387
+
1388
+ /* ============================================================
1389
+ * 16. Publication detail — cover-left + intro-right header
1390
+ * ============================================================ */
1391
+
1392
+ .publication__header {
1393
+ display: grid;
1394
+ grid-template-columns: 1fr;
1395
+ gap: var(--space-xl);
1396
+ align-items: start;
1397
+ margin: var(--space-md) 0 var(--space-2xl);
1398
+ }
1399
+ @media (min-width: 768px) {
1400
+ .publication__header {
1401
+ grid-template-columns: minmax(140px, 220px) 1fr;
1402
+ }
1403
+ }
1404
+
1405
+ .publication__cover {
1406
+ display: block;
1407
+ width: 100%;
1408
+ height: auto;
1409
+ max-width: 220px;
1410
+ margin: 0 auto;
1411
+ box-shadow: var(--shadow-cover);
1412
+ border-radius: var(--radius-1);
1413
+ }
1414
+ @media (min-width: 768px) {
1415
+ .publication__cover { margin: 0; }
1416
+ }
1417
+
1418
+ .publication__intro h1 {
1419
+ font-family: var(--font-heading);
1420
+ font-weight: 600;
1421
+ margin: 0 0 var(--space-sm);
1422
+ }
1423
+
1424
+ .publication__tagline {
1425
+ font-style: italic;
1426
+ color: var(--color-muted);
1427
+ font-size: 1.0625rem;
1428
+ margin: 0 0 var(--space-lg);
1429
+ }
1430
+
1431
+ .publication__isbn,
1432
+ .publication__pages,
1433
+ .publication__published {
1434
+ margin: 0 0 0.25rem;
1435
+ color: var(--color-muted);
1436
+ font-size: 0.9375rem;
1437
+ }
1438
+ .publication__published + .publication__price,
1439
+ .publication__pages + .publication__price,
1440
+ .publication__isbn + .publication__price {
1441
+ margin-top: var(--space-md);
1442
+ }
1443
+
1444
+ .publication__price {
1445
+ font-family: var(--font-heading);
1446
+ font-weight: 700;
1447
+ font-size: 1.25rem;
1448
+ color: var(--color-price);
1449
+ margin: 0 0 0.75rem;
1450
+ }
1451
+
1452
+ /* Layout (flex/wrap/gap) is in the shared rule above; this rule
1453
+ only specifies the no-margin override for the publication header
1454
+ context, where buttons sit directly below the price with no
1455
+ additional spacing wanted. */
1456
+ .publication__buttons { margin: 0; }
1457
+
1458
+ .publication__hero {
1459
+ display: block;
1460
+ width: 100%;
1461
+ margin: 0 0 var(--space-xl);
1462
+ aspect-ratio: 16 / 9; /* show-view default */
1463
+ border-radius: var(--radius-3);
1464
+ overflow: hidden;
1465
+ box-shadow: var(--shadow-soft);
1466
+ }
1467
+ .publication__hero img {
1468
+ display: block;
1469
+ width: 100%;
1470
+ height: 100%;
1471
+ object-fit: cover;
1472
+ }
1473
+
1474
+ /* Description renders as normal body text (inherits body font-size
1475
+ and color). Only the wrapper margin and the last-paragraph margin
1476
+ reset are component-specific. */
1477
+ .publication__description { margin: 0 0 var(--space-xl); }
1478
+ .publication__description p:last-child { margin-bottom: 0; }
1479
+
1480
+ /* On bundle / series pages the description sits directly above the
1481
+ markdown body (`page.content`). Let the description's paragraphs
1482
+ carry their natural `<p>` bottom margin so the description-to-
1483
+ content gap matches the paragraph-to-paragraph rhythm in the body
1484
+ — anything larger reads as a spacing bug because the two visually
1485
+ identical blocks of prose are pushed apart for no reason. */
1486
+ .bundle__description,
1487
+ .series__description { margin: 0; }
1488
+
1489
+ .publication__series {
1490
+ margin: var(--space-xl) 0;
1491
+ font-size: 0.9375rem;
1492
+ color: var(--color-muted);
1493
+ }
1494
+
1495
+ /* Bundle + series show-view header price. Prominent — heading font,
1496
+ bumped size — so the price reads clearly above the buy button on
1497
+ the landing page. Body text colour rather than the link/primary
1498
+ colour so it doesn't read as clickable. */
1499
+ .bundle__price,
1500
+ .series__price {
1501
+ font-family: var(--font-heading);
1502
+ font-weight: 700;
1503
+ font-size: 1.5rem;
1504
+ color: var(--color-text);
1505
+ margin: var(--space-md) 0 var(--space-sm);
1506
+ }
1507
+
1508
+ /* Bundle + series taglines use `.lede` for prominence (1.25rem,
1509
+ tightened line-height). The generic `article > header > .lede`
1510
+ rule adds 2xl bottom margin assuming the lede is the LAST item in
1511
+ the header — but here it's followed by price + buttons, so a
1512
+ smaller gap reads better. Same specificity as the generic rule,
1513
+ declared later so it wins. */
1514
+ article > header > .bundle__tagline,
1515
+ article > header > .series__tagline {
1516
+ margin: 0 0 var(--space-md);
1517
+ }
1518
+
1519
+
1520
+ /* ============================================================
1521
+ * 17. Publications index — list of cards with 3D-tilt covers,
1522
+ * plus Bundles + Series groupings (stack + row preview cards),
1523
+ * plus the optional showcase block at the top
1524
+ * ============================================================ */
1525
+
1526
+ /* Showcase — a single emphasized publication card at the top of the
1527
+ page when `collections.publications.index.display_showcase` is on
1528
+ and one of the books has `showcase: true` in its frontmatter. Cover
1529
+ is larger and the body has more room than the regular index card. */
1530
+ .publication-showcase {
1531
+ margin: var(--space-xl) 0 var(--space-2xl);
1532
+ padding: var(--space-xl);
1533
+ background: var(--color-card-bg);
1534
+ border-radius: var(--radius-3);
1535
+ box-shadow: var(--shadow-card);
1536
+ }
1537
+ .publication-showcase__link {
1538
+ display: grid;
1539
+ grid-template-columns: 1fr;
1540
+ gap: var(--space-lg);
1541
+ color: inherit;
1542
+ text-decoration: none;
1543
+ align-items: start;
1544
+ }
1545
+ @media (min-width: 600px) {
1546
+ .publication-showcase__link {
1547
+ grid-template-columns: 200px 1fr;
1548
+ gap: var(--space-xl);
1549
+ }
1550
+ }
1551
+ .publication-showcase__cover {
1552
+ width: 100%;
1553
+ max-width: 240px;
1554
+ aspect-ratio: 2 / 3;
1555
+ overflow: hidden;
1556
+ box-shadow: var(--shadow-cover);
1557
+ background: var(--color-code-bg);
1558
+ }
1559
+ .publication-showcase__cover img {
1560
+ width: 100%;
1561
+ height: 100%;
1562
+ display: block;
1563
+ object-fit: cover;
1564
+ }
1565
+ .publication-showcase__eyebrow {
1566
+ margin: 0 0 var(--space-sm);
1567
+ font-family: var(--font-meta);
1568
+ font-size: 0.75rem;
1569
+ text-transform: uppercase;
1570
+ letter-spacing: 0.08em;
1571
+ color: var(--color-muted);
1572
+ }
1573
+ .publication-showcase__title {
1574
+ margin: 0 0 var(--space-sm);
1575
+ font-family: var(--font-heading);
1576
+ font-size: 1.75rem;
1577
+ font-weight: 700;
1578
+ color: var(--color-text);
1579
+ }
1580
+ .publication-showcase__tagline {
1581
+ margin: 0 0 var(--space-md);
1582
+ font-style: italic;
1583
+ color: var(--color-muted);
1584
+ font-size: 1.125rem;
1585
+ }
1586
+ .publication-showcase__description {
1587
+ margin: 0 0 var(--space-md);
1588
+ }
1589
+ .publication-showcase__price {
1590
+ margin: 0;
1591
+ font-family: var(--font-heading);
1592
+ font-weight: 700;
1593
+ color: var(--color-price);
1594
+ }
1595
+
1596
+ /* Section heading shared by Bundles + Series. Styled to match
1597
+ `.home-module__heading` (small caps muted) so the publications
1598
+ landing's grouping headings read consistently with the home-page
1599
+ modules and the posts-landing Series row, which use the same
1600
+ typographic pattern. */
1601
+ .pubs-grouping {
1602
+ margin: var(--space-2xl) 0 0;
1603
+ }
1604
+ /* `.pubs-grouping__heading` typography is defined in the shared
1605
+ `__heading` rule. */
1606
+
1607
+ /* Bundle previews — a stack of 2-3 covers at slight angles, like a
1608
+ small deck of books on a desk. Each preview is a single link with
1609
+ the stack on top and a title + count below. On hover, the back/
1610
+ front covers fan out a little. Cap is 3 covers in the markup; if
1611
+ a bundle has more, additional ones aren't rendered in the stack
1612
+ (the link still leads to the bundle page, which shows them all). */
1613
+ .bundle-previews {
1614
+ list-style: none;
1615
+ padding: 0;
1616
+ margin: 0;
1617
+ display: grid;
1618
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
1619
+ gap: var(--space-2xl);
1620
+ }
1621
+ .bundle-preview__link {
1622
+ display: block;
1623
+ color: inherit;
1624
+ text-decoration: none;
1625
+ }
1626
+ .bundle-preview__stack {
1627
+ position: relative;
1628
+ display: block;
1629
+ width: 100%;
1630
+ /* Row sized to hug the cover stack with a deliberate gap below
1631
+ before the per-tile title. Cover height (76% × 1.5 = 1.14W) plus
1632
+ padding-top (6% W) plus ~8% W gap below the cover = 1.3W → row
1633
+ aspect-ratio 10/13. Using a tighter ratio than 2/3 keeps the
1634
+ section heading flush above the covers rather than leaving
1635
+ ~30% of row-width as empty space at the top. */
1636
+ aspect-ratio: 10 / 13;
1637
+ margin-bottom: 0;
1638
+ /* Inset so rotated covers don't get clipped by the column edge. */
1639
+ padding: 6% 12%;
1640
+ }
1641
+ .bundle-preview__cover {
1642
+ position: absolute;
1643
+ /* Top-anchored — keeps the section heading sitting just above the
1644
+ stack. The deliberate ~8% W gap *below* the stack (before the
1645
+ per-tile title) comes from the row's tighter aspect-ratio above,
1646
+ not from a bottom offset on the cover. */
1647
+ top: 6%;
1648
+ left: 50%;
1649
+ width: 76%;
1650
+ height: auto;
1651
+ aspect-ratio: 2 / 3;
1652
+ margin-left: -38%;
1653
+ display: block;
1654
+ border-radius: 2px;
1655
+ box-shadow: var(--shadow-cover);
1656
+ transition: transform 0.35s ease, box-shadow 0.35s ease;
1657
+ background: var(--color-card-bg);
1658
+ }
1659
+ /* Near-flat pile: all three covers sit at the same centered position
1660
+ (no translate), differentiated only by a shallow rotation. Front
1661
+ cover dominates; back + mid peek out as small wedges at the edges
1662
+ from beneath. The contrast with the series stack on the same
1663
+ landing is the splayed fan vs flat pile — see `.series-preview__cover`. */
1664
+ .bundle-preview__cover--back { transform: rotate(-5deg); z-index: 1; }
1665
+ .bundle-preview__cover--mid { transform: rotate(0deg); z-index: 2; }
1666
+ .bundle-preview__cover--front { transform: rotate(5deg); z-index: 3; }
1667
+ @media (hover: hover) {
1668
+ .bundle-preview__link:hover .bundle-preview__cover--back { transform: rotate(-8deg); }
1669
+ .bundle-preview__link:hover .bundle-preview__cover--front { transform: rotate(8deg); }
1670
+ }
1671
+ .bundle-preview__body {
1672
+ display: block;
1673
+ text-align: center;
1674
+ }
1675
+ .bundle-preview__title {
1676
+ display: block;
1677
+ font-family: var(--font-heading);
1678
+ font-weight: 700;
1679
+ font-size: 1.0625rem;
1680
+ margin-bottom: 0.25rem;
1681
+ }
1682
+ .bundle-preview__meta {
1683
+ display: block;
1684
+ color: var(--color-muted);
1685
+ font-size: 0.875rem;
1686
+ }
1687
+
1688
+ /* Series previews — structurally identical to `.bundle-preview__stack`
1689
+ / `.bundle-preview__cover`. Same tile, same cover size, same anchor
1690
+ point within the tile. The *only* difference is how the N covers
1691
+ stack: series fans out with continuous --i/--n rotation (±9°) plus
1692
+ translate (±12% X, ±2% Y), so the leftmost cover leans + slides
1693
+ left, the rightmost leans + slides right; bundles sit in a near-
1694
+ flat pile with shallow rotation only (see `.bundle-preview__cover`
1695
+ above). This is the intended visual contrast on the publications
1696
+ landing — same shape of "tile", different shape of "stack".
1697
+
1698
+ Posts series previews override below to keep their flex-row layout
1699
+ for landscape hero images. */
1700
+ .series-previews {
1701
+ list-style: none;
1702
+ padding: 0;
1703
+ margin: 0;
1704
+ display: grid;
1705
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
1706
+ gap: var(--space-2xl);
1707
+ }
1708
+ .series-preview__link {
1709
+ display: block;
1710
+ color: inherit;
1711
+ text-decoration: none;
1712
+ }
1713
+ .series-preview__row {
1714
+ position: relative;
1715
+ display: block;
1716
+ width: 100%;
1717
+ /* Match `.bundle-preview__stack`: tighter than 2/3 so the section
1718
+ heading sits just above the cover stack and a deliberate ~8% W
1719
+ gap is left below the stack before the per-tile title. See the
1720
+ bundle stack rule above for the breakdown of how 10/13 is
1721
+ derived from cover height + top padding + gap-below. */
1722
+ aspect-ratio: 10 / 13;
1723
+ margin-bottom: 0;
1724
+ /* Same inset as `.bundle-preview__stack` so the cover edges sit at
1725
+ the same tile coordinates as the bundle covers. */
1726
+ padding: 6% 12%;
1727
+ }
1728
+ .series-preview__cover {
1729
+ position: absolute;
1730
+ /* Top-anchored, matching `.bundle-preview__cover`. The gap below
1731
+ the stack comes from the row's tighter aspect-ratio (10/13). */
1732
+ top: 6%;
1733
+ left: 50%;
1734
+ width: 76%;
1735
+ height: auto;
1736
+ aspect-ratio: 2 / 3;
1737
+ margin-left: -38%;
1738
+ display: block;
1739
+ border-radius: 2px;
1740
+ box-shadow: var(--shadow-cover);
1741
+ background: var(--color-card-bg);
1742
+ transition: transform 0.35s ease, box-shadow 0.35s ease;
1743
+ /* Later-positioned covers (higher --i) stack on top. */
1744
+ z-index: calc(var(--i, 0) + 1);
1745
+ /* Splayed fan: rotation AND translate interpolate linearly across
1746
+ the row. For a 3-cover series the leftmost cover ends up at
1747
+ rotate(-9°) translate(-12%, -2%) and the rightmost at
1748
+ rotate(+9°) translate(+12%, +2%) — the same fanned silhouette
1749
+ the bundles partial used to carry, now reassigned to series to
1750
+ contrast with bundles' new flat pile. */
1751
+ --max-rot: 6deg;
1752
+ --max-tx: 8%;
1753
+ --max-ty: 1.5%;
1754
+ transform:
1755
+ translate(
1756
+ calc((var(--i, 0) / max(var(--n, 1) - 1, 1) - 0.5) * 2 * var(--max-tx)),
1757
+ calc((var(--i, 0) / max(var(--n, 1) - 1, 1) - 0.5) * 2 * var(--max-ty))
1758
+ )
1759
+ rotate(calc((var(--i, 0) / max(var(--n, 1) - 1, 1) - 0.5) * 2 * var(--max-rot)));
1760
+ }
1761
+ @media (hover: hover) {
1762
+ .series-preview__link:hover .series-preview__cover {
1763
+ --max-rot: 9deg;
1764
+ --max-tx: 11%;
1765
+ --max-ty: 2%;
1766
+ }
1767
+ }
1768
+
1769
+ /* Fan positioning inputs (`--i` = 0-based cover index, `--n` = cover
1770
+ count) used to be inline `style="--i:..;--n:.."` attributes. Those
1771
+ need `style-src 'unsafe-inline'`, which would weaken the shipped
1772
+ strict CSP for every site. Deriving them in CSS keeps `style-src
1773
+ 'self'` intact:
1774
+ - `--i` is the child's position, so `:nth-child()` supplies it.
1775
+ - `--n` rides a `data-n` attribute on the row and inherits down to
1776
+ the covers (custom properties inherit).
1777
+ Covered up to 8 covers per fan — preview stacks never show more, and
1778
+ a 9th+ cover simply falls back to the centred default (`--i:0;
1779
+ --n:1`), which degrades gracefully rather than breaking layout. */
1780
+ .series-preview__row[data-n="1"] { --n: 1; }
1781
+ .series-preview__row[data-n="2"] { --n: 2; }
1782
+ .series-preview__row[data-n="3"] { --n: 3; }
1783
+ .series-preview__row[data-n="4"] { --n: 4; }
1784
+ .series-preview__row[data-n="5"] { --n: 5; }
1785
+ .series-preview__row[data-n="6"] { --n: 6; }
1786
+ .series-preview__row[data-n="7"] { --n: 7; }
1787
+ .series-preview__row[data-n="8"] { --n: 8; }
1788
+ .series-preview__cover:nth-child(1) { --i: 0; }
1789
+ .series-preview__cover:nth-child(2) { --i: 1; }
1790
+ .series-preview__cover:nth-child(3) { --i: 2; }
1791
+ .series-preview__cover:nth-child(4) { --i: 3; }
1792
+ .series-preview__cover:nth-child(5) { --i: 4; }
1793
+ .series-preview__cover:nth-child(6) { --i: 5; }
1794
+ .series-preview__cover:nth-child(7) { --i: 6; }
1795
+ .series-preview__cover:nth-child(8) { --i: 7; }
1796
+
1797
+ /* Posts series preview — flex row of landscape hero images, with
1798
+ tight horizontal overlap. Different visual metaphor from the book
1799
+ stack above: heroes lined up side-by-side with overlap, not a
1800
+ pile of book covers. Override the absolute-positioned book stack
1801
+ structure inherited from the base rule. */
1802
+ .post-series-previews .series-previews {
1803
+ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
1804
+ }
1805
+ .series-preview--posts .series-preview__row {
1806
+ position: static;
1807
+ display: flex;
1808
+ /* Anchor the stack to the left edge of the partial so the leftmost
1809
+ cover lines up with the post-list cards above (which also sit
1810
+ against the partial's left edge). The overlap cascade runs to
1811
+ the right from there. */
1812
+ justify-content: flex-start;
1813
+ align-items: flex-end;
1814
+ aspect-ratio: auto;
1815
+ /* Drop the row's left padding to 0 so the first cover starts at
1816
+ the section edge; keep top/right/bottom so rotated covers don't
1817
+ get clipped and the row stays vertically inset. */
1818
+ padding: 4% 6% 6% 0;
1819
+ }
1820
+ /* Constrain the title/meta body to the stack's horizontal extent so
1821
+ `text-align: center` (inherited from the base `.series-preview__body`
1822
+ rule) lands at the stack's visual center rather than the tile's
1823
+ geometric center. With the stack left-anchored at 0% and ending
1824
+ near 86% of the tile width (cover width 58% + two cascading -44%
1825
+ margins), capping body width to match keeps title + post-count
1826
+ visually centred under the heroes above.
1827
+
1828
+ Adjacent tiles get 3rem of breathing room from the parent
1829
+ `.series-previews` grid `gap`, so a multi-series listing is
1830
+ already separated without further work. */
1831
+ .series-preview--posts .series-preview__body {
1832
+ width: 86%;
1833
+ }
1834
+ .series-preview--posts .series-preview__cover {
1835
+ position: static;
1836
+ /* Match the 4:3 aspect of `.post-list__cover` so the stacked heroes
1837
+ read as the same shape as the cards above. Post hero images are
1838
+ stored at 16:9; `object-fit: cover` crops top/bottom into the
1839
+ 4:3 box without distorting. */
1840
+ aspect-ratio: 4 / 3;
1841
+ object-fit: cover;
1842
+ width: 58%;
1843
+ /* Overlap only on the right edge so the first cover sits flush with
1844
+ the row's left edge. Each subsequent cover slides under the next
1845
+ by 44% of the row width — heavy overlap so only ~14% of each
1846
+ back cover peeks out from behind the front, reading as one
1847
+ tightly-grouped stack. */
1848
+ margin: 0 -44% 0 0;
1849
+ top: auto;
1850
+ bottom: auto;
1851
+ left: auto;
1852
+ --max-rot: 6deg;
1853
+ /* Posts use flex margin-based horizontal overlap, not transform
1854
+ translate — zero out the translate tokens inherited from the
1855
+ publications fan above. */
1856
+ --max-tx: 0%;
1857
+ --max-ty: 0%;
1858
+ }
1859
+ @media (hover: hover) {
1860
+ .series-preview--posts .series-preview__link:hover .series-preview__cover {
1861
+ --max-rot: 9deg;
1862
+ --max-tx: 0%;
1863
+ --max-ty: 0%;
1864
+ }
1865
+ }
1866
+
1867
+ /* `.post-series-previews` section sits beneath the post list on the
1868
+ posts landing. Borrows the home-module divider rule (1px line on
1869
+ top + breathing room) so the visual rhythm between the post list
1870
+ and this row matches the rhythm between home modules. */
1871
+ .post-series-previews {
1872
+ margin: var(--space-2xl) 0 0;
1873
+ padding-top: var(--space-xl);
1874
+ border-top: 1px solid var(--color-rule);
1875
+ }
1876
+
1877
+ .series-preview__body {
1878
+ display: block;
1879
+ text-align: center;
1880
+ }
1881
+ .series-preview__title {
1882
+ display: block;
1883
+ font-family: var(--font-heading);
1884
+ font-weight: 700;
1885
+ font-size: 1.0625rem;
1886
+ margin-bottom: 0.25rem;
1887
+ }
1888
+ .series-preview__meta {
1889
+ display: block;
1890
+ color: var(--color-muted);
1891
+ font-size: 0.875rem;
1892
+ }
1893
+
1894
+ .publications-index {
1895
+ list-style: none;
1896
+ padding: 0;
1897
+ margin: var(--space-xl) 0;
1898
+ }
1899
+ .publications-index__item {
1900
+ padding: var(--space-xl) 0;
1901
+ border-bottom: 1px solid var(--color-rule);
1902
+ }
1903
+ .publications-index__item:last-child { border-bottom: 0; }
1904
+
1905
+ /* Mobile-first: phone defaults are 110px cover + tighter gap. Above
1906
+ 480px the layout scales up to the larger 160px cover and wider
1907
+ gap. Matches the rest of the file's `min-width` breakpoint style. */
1908
+ .publications-index a {
1909
+ display: grid;
1910
+ grid-template-columns: 110px 1fr;
1911
+ gap: var(--space-md);
1912
+ align-items: start;
1913
+ color: inherit;
1914
+ text-decoration: none;
1915
+ }
1916
+
1917
+ .publications-index__cover {
1918
+ width: 110px;
1919
+ aspect-ratio: 2 / 3;
1920
+ background-color: #d8c8a0;
1921
+ box-shadow: var(--shadow-cover);
1922
+ overflow: hidden;
1923
+ transition: transform 0.4s ease, box-shadow 0.4s ease;
1924
+ }
1925
+ .publications-index__cover img {
1926
+ width: 100%;
1927
+ height: 100%;
1928
+ object-fit: cover;
1929
+ display: block;
1930
+ }
1931
+ /* Gate the 3D-tilt transform on hover-capable pointers — on touch
1932
+ devices the hover state sticks until the user taps elsewhere,
1933
+ leaving the cover stuck mid-rotation. `@media (hover: hover)`
1934
+ means "device has a real hover capability" (mouse, trackpad, pen).
1935
+ Colour-only hovers don't need this guard; transform-based ones do. */
1936
+ @media (hover: hover) {
1937
+ .publications-index a:hover .publications-index__cover {
1938
+ transform: perspective(900px) rotateY(-6deg);
1939
+ box-shadow: 8px 8px 24px rgba(0, 0, 0, 0.35);
1940
+ }
1941
+ }
1942
+
1943
+ .publications-index__body { min-width: 0; }
1944
+ .publications-index__title {
1945
+ margin: 0 0 var(--space-sm);
1946
+ font-family: var(--font-heading);
1947
+ font-weight: 700;
1948
+ font-size: 1.25rem;
1949
+ }
1950
+ /* Series-position prefix on a publication-card title (e.g. "#1") —
1951
+ muted so the title stays the primary read; only renders on cards
1952
+ passed a `:position` field (currently the series detail page). */
1953
+ .publications-index__position,
1954
+ .series-position {
1955
+ color: var(--color-muted);
1956
+ font-weight: 400;
1957
+ margin-right: 0.25ch;
1958
+ }
1959
+ .publications-index__tagline {
1960
+ margin: 0 0 0.75rem;
1961
+ font-style: italic;
1962
+ color: var(--color-muted);
1963
+ font-size: 1.0625rem;
1964
+ }
1965
+ .publications-index__description {
1966
+ margin: 0 0 0.75rem;
1967
+ color: var(--color-muted);
1968
+ font-size: 1rem;
1969
+ }
1970
+ .publications-index__price {
1971
+ margin: 0 0 var(--space-sm);
1972
+ font-family: var(--font-heading);
1973
+ font-weight: 700;
1974
+ color: var(--color-price);
1975
+ }
1976
+ .publications-index__isbn,
1977
+ .publications-index__pages,
1978
+ .publications-index__published {
1979
+ margin: 0 0 0.25rem;
1980
+ color: var(--color-muted);
1981
+ font-size: 0.875rem;
1982
+ }
1983
+
1984
+ /* Scale the publications-index card up above 480px — larger cover,
1985
+ more generous gap, full-size title. Below this width the defaults
1986
+ above keep the layout compact for phones. */
1987
+ @media (min-width: 480px) {
1988
+ .publications-index a { grid-template-columns: 160px 1fr; gap: var(--space-xl); }
1989
+ .publications-index__cover { width: 160px; }
1990
+ .publications-index__title { font-size: 1.5rem; }
1991
+ }
1992
+
1993
+
1994
+ /* ============================================================
1995
+ * 18. Folio book grid — home-page card grid
1996
+ * ============================================================ */
1997
+
1998
+ .folio-book-grid { margin: var(--space-2xl) 0; }
1999
+
2000
+ /* `.folio-book-grid__heading` typography is defined in the shared
2001
+ `__heading` rule below (small-caps muted, matching every other
2002
+ show-view section heading). */
2003
+
2004
+ .folio-book-grid__list {
2005
+ display: grid;
2006
+ grid-template-columns: 1fr;
2007
+ gap: var(--space-xl);
2008
+ }
2009
+ @media (min-width: 768px) {
2010
+ .folio-book-grid__list { grid-template-columns: 1fr 1fr; }
2011
+ }
2012
+
2013
+ .folio-book-grid__item {
2014
+ display: flex;
2015
+ flex-direction: column;
2016
+ background: var(--color-card-bg);
2017
+ border-radius: var(--radius-3);
2018
+ box-shadow: var(--shadow-card);
2019
+ padding: var(--space-xl);
2020
+ }
2021
+
2022
+ .folio-book-grid__cover-link {
2023
+ display: block;
2024
+ margin: 0 auto var(--space-lg);
2025
+ max-width: 220px;
2026
+ }
2027
+
2028
+ .folio-book-grid__title {
2029
+ font-family: var(--font-heading);
2030
+ font-size: 1.25rem;
2031
+ margin: 0 0 var(--space-sm);
2032
+ }
2033
+ .folio-book-grid__title a { color: var(--color-text); text-decoration: none; }
2034
+
2035
+ .folio-book-grid__tagline {
2036
+ font-style: italic;
2037
+ color: var(--color-muted);
2038
+ margin: 0 0 var(--space-md);
2039
+ }
2040
+
2041
+ .folio-book-grid__cta { margin: auto 0 0; }
2042
+
2043
+
2044
+ /* ============================================================
2045
+ * 19. Book cover — 3D-tilt hover + spine groove
2046
+ * ============================================================ */
2047
+
2048
+ .book-cover {
2049
+ position: relative;
2050
+ width: 100%;
2051
+ aspect-ratio: 2 / 3;
2052
+ margin: 20px auto;
2053
+ overflow: hidden;
2054
+ box-shadow: 3px 3px 15px rgba(0, 0, 0, 0.3);
2055
+ transition: transform 0.5s ease, box-shadow 0.5s ease;
2056
+ }
2057
+ .book-cover img {
2058
+ width: 100%;
2059
+ height: 100%;
2060
+ object-fit: cover;
2061
+ display: block;
2062
+ }
2063
+ .book-cover-link {
2064
+ display: block;
2065
+ margin: 0 auto;
2066
+ max-width: 220px;
2067
+ width: 100%;
2068
+ }
2069
+ .book-cover::before {
2070
+ content: '';
2071
+ position: absolute;
2072
+ top: 0;
2073
+ left: 2%;
2074
+ height: 100%;
2075
+ width: 6px;
2076
+ background: rgba(0, 0, 0, 0.10);
2077
+ box-shadow: inset 3px 0 3px -3px rgba(0, 0, 0, 0.5);
2078
+ pointer-events: none;
2079
+ z-index: 1;
2080
+ }
2081
+ /* Same hover-gate rationale as `.publications-index` above — the 3D
2082
+ tilt would stick mid-rotation on touch devices. Only apply the
2083
+ transform when the pointer can actually hover.
2084
+ The nested `prefers-reduced-motion` block keeps the no-motion
2085
+ behaviour for users who request it, on top of the hover guard. */
2086
+ @media (hover: hover) {
2087
+ .book-cover:hover {
2088
+ transform: perspective(1000px) rotateY(-10deg);
2089
+ box-shadow: 8px 8px 20px rgba(0, 0, 0, 0.5);
2090
+ }
2091
+ }
2092
+ @media (prefers-reduced-motion: reduce) {
2093
+ .book-cover { transition: none; }
2094
+ .book-cover:hover { transform: none; box-shadow: 3px 3px 15px rgba(0, 0, 0, 0.3); }
2095
+ }
2096
+
2097
+
2098
+ /* ============================================================
2099
+ * 20. Testimonials — quote cards
2100
+ * ============================================================ */
2101
+
2102
+ /* Section margin matches `.folio-book-grid` so testimonials sit at
2103
+ the same vertical rhythm as the other home-page sections. */
2104
+ .testimonials { margin: var(--space-2xl) 0; }
2105
+
2106
+ /* `.testimonials__heading` typography is defined in the shared
2107
+ `__heading` rule below. */
2108
+
2109
+ /* Card matches the article's content width — zero out the browser
2110
+ default <figure> margin (margin-inline: 40px) so the card extends
2111
+ to the article's content edges. Internal padding gives the quote
2112
+ breathing room from the card's coloured edge. */
2113
+ .testimonial {
2114
+ background: var(--color-card-bg);
2115
+ border-radius: var(--radius-3);
2116
+ box-shadow: var(--shadow-card);
2117
+ margin: 0;
2118
+ padding: var(--space-lg) var(--space-md);
2119
+ }
2120
+ .testimonial__quote {
2121
+ margin: 0 0 var(--space-md);
2122
+ font-size: 1.0625rem;
2123
+ line-height: 1.7;
2124
+ border-left: 0;
2125
+ padding-left: 0;
2126
+ font-style: normal;
2127
+ }
2128
+ .testimonial__cite {
2129
+ margin: 0;
2130
+ font-size: 0.9375rem;
2131
+ color: var(--color-muted);
2132
+ }
2133
+ .testimonial__cite strong {
2134
+ color: var(--color-text);
2135
+ font-weight: 600;
2136
+ }
2137
+ .testimonial__cite a {
2138
+ color: var(--color-muted);
2139
+ text-decoration: underline;
2140
+ }
2141
+
2142
+
2143
+ /* ============================================================
2144
+ * 21. Related books — sister-publications cards
2145
+ * ============================================================ */
2146
+
2147
+ .book-related { margin: var(--space-2xl) 0; }
2148
+ /* `.book-related__heading` typography is defined in the shared
2149
+ `__heading` rule below. */
2150
+ .book-related__item {
2151
+ background: var(--color-card-bg);
2152
+ border-radius: var(--radius-3);
2153
+ box-shadow: var(--shadow-card);
2154
+ padding: var(--space-xl);
2155
+ margin: 0 0 var(--space-lg);
2156
+ display: grid;
2157
+ grid-template-columns: 100px 1fr;
2158
+ gap: var(--space-xl);
2159
+ align-items: start;
2160
+ }
2161
+ @media (min-width: 768px) {
2162
+ .book-related__item { grid-template-columns: 140px 1fr; }
2163
+ }
2164
+ .book-related__cover img {
2165
+ width: 100%;
2166
+ height: auto;
2167
+ display: block;
2168
+ border-radius: var(--radius-1);
2169
+ box-shadow: var(--shadow-soft);
2170
+ }
2171
+ /* `.book-cover` (Section 19) carries a `margin: 20px auto` for the
2172
+ home-page book grid, where the cover stacks above the title and
2173
+ needs breathing room from the card's top padding. Inside the
2174
+ side-by-side `.book-related__item` grid, that margin pushes the
2175
+ cover down and breaks alignment with the title text. Zero it
2176
+ here so cover-top and title-top sit on the same line. */
2177
+ .book-related__cover .book-cover { margin: 0; }
2178
+ .book-related__title {
2179
+ font-family: var(--font-heading);
2180
+ font-size: 1.25rem;
2181
+ margin: 0 0 var(--space-sm);
2182
+ }
2183
+ .book-related__title a { color: var(--color-text); text-decoration: none; }
2184
+ .book-related__tagline {
2185
+ font-style: italic;
2186
+ color: var(--color-muted);
2187
+ margin: 0 0 var(--space-md);
2188
+ }
2189
+ .book-related__cta {
2190
+ display: inline-block;
2191
+ margin: 0;
2192
+ font-size: 0.9375rem;
2193
+ color: var(--color-muted);
2194
+ text-decoration: none;
2195
+ }
2196
+ .book-related__cta:hover { color: var(--color-primary); }
2197
+
2198
+
2199
+ /* ============================================================
2200
+ * 22. Home modules — latest-post / -publication / -photo / contact
2201
+ * ============================================================ */
2202
+
2203
+ .home-module {
2204
+ margin: var(--space-2xl) 0 0;
2205
+ padding-top: var(--space-xl);
2206
+ border-top: 1px solid var(--color-rule);
2207
+ }
2208
+
2209
+ /* `.home-module__heading` typography is defined in the shared
2210
+ `__heading` rule. The contextual override that zeros its margin
2211
+ when wrapped in `.home-module__header` lives below. */
2212
+
2213
+ /* `.home-module__header` wraps a heading + a "see all" link so they
2214
+ sit on one row with the heading on the left and the link aligned
2215
+ right. Used by the home page's modules (latest photo, latest post,
2216
+ etc.) AND by the photos landing's "Latest photos" row, plus the
2217
+ Series / Countries rows (via the `_taxonomy_row` partial). The
2218
+ class prefix is historical — the pattern is intentionally shared.
2219
+ When `__header` is present, it owns the bottom margin; the inner
2220
+ heading drops its own. */
2221
+ .home-module__header {
2222
+ display: flex;
2223
+ align-items: baseline;
2224
+ justify-content: space-between;
2225
+ gap: var(--space-md);
2226
+ margin: 0 0 var(--space-md);
2227
+ }
2228
+ .home-module__header .home-module__heading { margin: 0; }
2229
+ .home-module__see-all {
2230
+ font-family: var(--font-meta);
2231
+ font-size: 0.8125rem;
2232
+ color: var(--color-muted);
2233
+ text-decoration: none;
2234
+ white-space: nowrap;
2235
+ }
2236
+ .home-module__see-all:hover { color: var(--color-text); }
2237
+
2238
+ .home-module__item {
2239
+ display: grid;
2240
+ grid-template-columns: 1fr;
2241
+ gap: var(--space-lg);
2242
+ }
2243
+ /* The `display: grid` above overrides the user-agent's
2244
+ `[hidden] { display: none }`, so candidate cards in a random-pool
2245
+ would all show without this rule. Specificity 0,2,0 beats the
2246
+ `.home-module__item` rule above (0,1,0) cleanly — no !important
2247
+ needed. */
2248
+ .home-module__item[hidden] { display: none; }
2249
+ @media (min-width: 600px) {
2250
+ .home-module--latest-post .home-module__item,
2251
+ .home-module--random-post .home-module__item,
2252
+ .home-module--latest-publication .home-module__item,
2253
+ .home-module--featured-publication .home-module__item,
2254
+ .home-module--latest-photo .home-module__item,
2255
+ .home-module--random-photo .home-module__item,
2256
+ .home-module--next-workshop .home-module__item {
2257
+ grid-template-columns: minmax(140px, 200px) 1fr;
2258
+ align-items: start;
2259
+ }
2260
+ /* When a post has no hero image, fall back to single column so the
2261
+ body fills the card. The :has() match excludes items that lack
2262
+ `.home-module__cover` from the cover-left grid rule above. */
2263
+ .home-module--latest-post .home-module__item:not(:has(.home-module__cover)),
2264
+ .home-module--random-post .home-module__item:not(:has(.home-module__cover)) {
2265
+ grid-template-columns: 1fr;
2266
+ }
2267
+ }
2268
+
2269
+ .home-module__cover {
2270
+ display: block;
2271
+ max-width: 200px;
2272
+ }
2273
+ .home-module__cover img {
2274
+ display: block;
2275
+ width: 100%;
2276
+ height: auto;
2277
+ border-radius: var(--radius-1);
2278
+ box-shadow: var(--shadow-soft);
2279
+ }
2280
+
2281
+ /* Post home modules — force 4:3 cropping on the cover, since post
2282
+ heroes are authored at 16:9 (show-view ratio) and we want them
2283
+ to read as 4:3 thumbnails in the home module too. Same approach
2284
+ as `.home-module--latest-photo .home-module__cover`: the visual
2285
+ treatment (border-radius + shadow) stays on the img, the wrapper
2286
+ just sizes. `aspect-ratio` + `object-fit: cover` on the img
2287
+ handles the crop without needing `overflow: hidden` (which would
2288
+ clip the radius and shadow). Other modules keep natural aspect:
2289
+ publications are 2:3 (book-cover convention), photos are 4:3
2290
+ already in source, workshops render their 16:9 hero. */
2291
+ .home-module--latest-post .home-module__cover img,
2292
+ .home-module--random-post .home-module__cover img {
2293
+ aspect-ratio: 4 / 3;
2294
+ object-fit: cover;
2295
+ }
2296
+
2297
+ .home-module__title {
2298
+ font-family: var(--font-heading);
2299
+ font-size: 1.25rem;
2300
+ font-weight: 600;
2301
+ margin: 0 0 var(--space-sm);
2302
+ }
2303
+ .home-module__title a { color: var(--color-text); text-decoration: none; }
2304
+
2305
+ .home-module__tagline {
2306
+ font-style: italic;
2307
+ color: var(--color-muted);
2308
+ margin: 0 0 var(--space-sm);
2309
+ }
2310
+
2311
+ .home-module__meta {
2312
+ font-family: var(--font-meta);
2313
+ font-size: 0.875rem;
2314
+ color: var(--color-muted);
2315
+ margin: 0 0 var(--space-sm);
2316
+ }
2317
+
2318
+ .home-module__description { margin: 0; color: var(--color-muted); }
2319
+
2320
+
2321
+ /* ============================================================
2322
+ * 23. Theme toggle — sun/moon visibility
2323
+ * ============================================================
2324
+ *
2325
+ * Default (light) → moon visible, click → switch to dark.
2326
+ * Dark → sun visible, click → switch to light.
2327
+ * System dark preference behaves the same as explicit dark.
2328
+ * Explicit choice (data-theme) wins over system pref.
2329
+ */
2330
+
2331
+ .theme-toggle {
2332
+ background: transparent;
2333
+ border: 0;
2334
+ padding: 0.25rem;
2335
+ margin-left: 0.5rem;
2336
+ cursor: pointer;
2337
+ color: inherit;
2338
+ display: inline-flex;
2339
+ align-items: center;
2340
+ vertical-align: middle;
2341
+ }
2342
+ .theme-toggle:hover { opacity: 0.7; }
2343
+
2344
+ .theme-toggle__sun { display: none; }
2345
+ .theme-toggle__moon { display: inline-flex; }
2346
+
2347
+ @media (prefers-color-scheme: dark) {
2348
+ .theme-toggle__sun { display: inline-flex; }
2349
+ .theme-toggle__moon { display: none; }
2350
+ }
2351
+ [data-theme="dark"] .theme-toggle__sun { display: inline-flex; }
2352
+ [data-theme="dark"] .theme-toggle__moon { display: none; }
2353
+ [data-theme="light"] .theme-toggle__sun { display: none; }
2354
+ [data-theme="light"] .theme-toggle__moon { display: inline-flex; }
2355
+
2356
+
2357
+ /* ============================================================
2358
+ * 24. Photo single-page detail
2359
+ * ============================================================
2360
+ *
2361
+ * Layout for content/photos/<slug>/index.md — image-centric posts
2362
+ * with a hero photo, optional caption, equipment + location metadata,
2363
+ * and a "more from this series" related strip.
2364
+ */
2365
+
2366
+ .photo__image {
2367
+ width: 100%;
2368
+ height: auto;
2369
+ margin: 0 0 var(--space-xl);
2370
+ box-shadow: var(--shadow-soft);
2371
+ }
2372
+ .photo__title { margin-bottom: var(--space-sm); }
2373
+ .photo__caption {
2374
+ font-size: 1.125rem;
2375
+ color: var(--color-text);
2376
+ margin-bottom: var(--space-lg);
2377
+ }
2378
+ .photo__meta {
2379
+ display: grid;
2380
+ grid-template-columns: max-content 1fr;
2381
+ gap: 0.25rem var(--space-md);
2382
+ margin: var(--space-lg) 0;
2383
+ font-size: 0.9375rem;
2384
+ color: var(--color-muted);
2385
+ }
2386
+ /* Each `<dt>/<dd>` pair is wrapped in a `<div>` in the markup so the
2387
+ row reads as a single semantic unit. `display: contents` removes
2388
+ the div from the layout tree so the inner `<dt>` and `<dd>`
2389
+ participate directly in the parent grid — one pair per row with
2390
+ labels aligned in the first column. Without this, each `<div>` is
2391
+ a single grid item and two pairs land side-by-side per row. */
2392
+ .photo__meta > div { display: contents; }
2393
+ .photo__meta dt { font-weight: 600; }
2394
+ .photo__meta dd { margin: 0; }
2395
+ .photo__related {
2396
+ margin-top: var(--space-2xl);
2397
+ padding-top: var(--space-md);
2398
+ border-top: 1px solid var(--color-rule);
2399
+ }
2400
+ .photo__related-grid {
2401
+ display: grid;
2402
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
2403
+ gap: 0.75rem;
2404
+ list-style: none;
2405
+ padding: 0;
2406
+ }
2407
+ .photo__related-grid img {
2408
+ width: 100%;
2409
+ height: auto;
2410
+ aspect-ratio: 4 / 3; /* index default */
2411
+ object-fit: cover;
2412
+ }
2413
+ .photo__related-title {
2414
+ display: block;
2415
+ font-size: 0.875rem;
2416
+ margin-top: 0.25rem;
2417
+ }
2418
+
2419
+
2420
+ /* ============================================================
2421
+ * 25. "Up next" + series pager + Related items
2422
+ * ============================================================
2423
+ *
2424
+ * `.next-item` — single-card section below the post body linking to
2425
+ * the chronologically-newer post (or, with the `--series` modifier,
2426
+ * the next post by series position). Reuses `.post-list` so the
2427
+ * card reads exactly like a row from the posts index — there's only
2428
+ * ever one up-next post, so the full index treatment fits.
2429
+ *
2430
+ * `.series-pager` — the bidirectional alternative to `.next-item
2431
+ * --series` for ordered collections. Compact prev/next pair rather
2432
+ * than a card, because sequential readers use it constantly.
2433
+ *
2434
+ * `.related` — block below each show view (post, photo, publication)
2435
+ * listing items from the same collection ranked by tag/series
2436
+ * overlap. Compact multi-card grid, different shape from the
2437
+ * up-next card by design (the cases are different: one prominent
2438
+ * card vs. several thumbnails). `.related__list--full` is the
2439
+ * dedicated /<slug>/related/ index-page variant.
2440
+ *
2441
+ * The two sections share their heading style (small uppercase muted)
2442
+ * via the consolidated `__heading` rule below — so the show-view
2443
+ * tail reads as a coherent run of sections even though the card
2444
+ * shapes differ.
2445
+ */
2446
+
2447
+ .next-item {
2448
+ margin: var(--space-2xl) 0 0;
2449
+ padding-top: var(--space-lg);
2450
+ border-top: 1px solid var(--color-rule);
2451
+ }
2452
+ /* The lone post-list item is also the `:last-child`, so its bottom
2453
+ margin is already 0 from `.post-list__item:last-child`. Zero out
2454
+ the wrapping `.post-list` margin so the card sits flush against
2455
+ the heading. */
2456
+ .next-item .post-list { margin: 0; }
2457
+
2458
+ /* `.series-pager` — bidirectional prev/next nav for ordered
2459
+ collections (see `_series_pager.html.erb`). Deliberately lighter
2460
+ than `.next-item`: a course reader hits this control on every
2461
+ lesson, so it's a pair of compact link targets rather than two
2462
+ full index cards.
2463
+
2464
+ Two equal columns at every width. The columns don't collapse on
2465
+ mobile — "back" and "forward" side by side is the expected shape
2466
+ for sequential navigation, and the titles wrap rather than the
2467
+ layout reflowing. `--prev` / `--next` differ only in text
2468
+ alignment so the two links read as one control. */
2469
+ .series-pager {
2470
+ display: grid;
2471
+ grid-template-columns: 1fr 1fr;
2472
+ gap: var(--space-md);
2473
+ margin: var(--space-2xl) 0 0;
2474
+ padding-top: var(--space-lg);
2475
+ border-top: 1px solid var(--color-rule);
2476
+ }
2477
+
2478
+ .series-pager__link {
2479
+ display: flex;
2480
+ flex-direction: column;
2481
+ gap: var(--space-xs);
2482
+ padding: var(--space-md);
2483
+ border: 1px solid var(--color-rule);
2484
+ border-radius: var(--radius-2);
2485
+ text-decoration: none;
2486
+ color: var(--color-text);
2487
+ }
2488
+
2489
+ .series-pager__link:hover,
2490
+ .series-pager__link:focus-visible {
2491
+ border-color: var(--color-link);
2492
+ }
2493
+
2494
+ /* `--next` is the only cell in column 2, so aligning its text to the
2495
+ end puts the forward control hard against the right edge — the
2496
+ direction of travel it represents. */
2497
+ .series-pager__link--next {
2498
+ grid-column: 2;
2499
+ text-align: right;
2500
+ }
2501
+
2502
+ .series-pager__direction {
2503
+ font-family: var(--font-heading);
2504
+ font-size: 0.75rem;
2505
+ font-weight: 600;
2506
+ text-transform: uppercase;
2507
+ letter-spacing: 0.05em;
2508
+ color: var(--color-muted);
2509
+ }
2510
+
2511
+ .series-pager__title {
2512
+ font-family: var(--font-heading);
2513
+ line-height: 1.3;
2514
+ }
2515
+
2516
+ /* Section heading — ONE rule that owns the typography for every
2517
+ "small section heading" across the app. Show-view tails ("Related",
2518
+ "Up next", "Next in the series", "Other books in the series"),
2519
+ in-page groupings ("What's included" on bundles, "Books in this
2520
+ series" on series, "Testimonials"), home-page modules, the
2521
+ publications-landing Bundles / Series rows, the TOC, and the
2522
+ book grid all live here.
2523
+
2524
+ Centralised so a change to the section-heading style propagates
2525
+ to every show view at once — and so adding a new section type is
2526
+ one selector addition, not one new copy of the seven declarations.
2527
+
2528
+ The matching contextual override for `.home-module__header`
2529
+ children sits with the rest of the home-module rules above. */
2530
+ .toc__heading,
2531
+ .pubs-grouping__heading,
2532
+ .folio-book-grid__heading,
2533
+ .testimonials__heading,
2534
+ .book-related__heading,
2535
+ .home-module__heading,
2536
+ .next-item__heading,
2537
+ .related__heading,
2538
+ .bundle__contents-heading,
2539
+ .series__contents-heading {
2540
+ margin: 0 0 var(--space-md);
2541
+ font-family: var(--font-heading);
2542
+ font-size: 0.875rem;
2543
+ font-weight: 600;
2544
+ text-transform: uppercase;
2545
+ letter-spacing: 0.05em;
2546
+ color: var(--color-muted);
2547
+ }
2548
+
2549
+ .related {
2550
+ margin: var(--space-2xl) 0 0;
2551
+ padding-top: var(--space-lg);
2552
+ border-top: 1px solid var(--color-rule);
2553
+ }
2554
+ /* `.related__heading` typography is defined in the shared `__heading`
2555
+ rule above. */
2556
+ /* Grid track minimum drives the desktop card count. At 240px, the
2557
+ typical content max-width (~768px inner) fits 3 cards per row;
2558
+ smaller screens reflow to 2 or 1 automatically via auto-fill. */
2559
+ .related__list {
2560
+ list-style: none;
2561
+ padding: 0;
2562
+ margin: 0;
2563
+ display: grid;
2564
+ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
2565
+ gap: var(--space-md);
2566
+ }
2567
+ .related__item a {
2568
+ display: block;
2569
+ color: inherit;
2570
+ text-decoration: none;
2571
+ }
2572
+ .related__cover {
2573
+ width: 100%;
2574
+ aspect-ratio: 4 / 3; /* index default */
2575
+ overflow: hidden;
2576
+ border-radius: var(--radius-1);
2577
+ background-color: var(--color-code-bg);
2578
+ margin-bottom: var(--space-sm);
2579
+ }
2580
+ .related__cover img { width: 100%; height: 100%; display: block; object-fit: cover; }
2581
+
2582
+ /* Publications-context override — book covers are 2:3, not the 4:3
2583
+ landscape default. Without this, `object-fit: cover` crops the
2584
+ top + bottom of a book thumbnail. Also narrow the grid column so
2585
+ a 2:3 cover doesn't dominate the listing row (240px wide × 360px
2586
+ tall is too tall; 150 × 225 reads as a book thumbnail). The
2587
+ modifier is set on the `<section>` by `_related_items.html.erb`
2588
+ when `source_collection == 'publications'`. */
2589
+ .related--book .related__list {
2590
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
2591
+ }
2592
+ .related--book .related__cover {
2593
+ aspect-ratio: 2 / 3;
2594
+ }
2595
+ /* Title is a `<span>` (not an `<h*>`), so it doesn't pick up the
2596
+ browser's heading font-weight. Bump to 700 and pin to `--color-text`
2597
+ so it reads as substantial as the post-list/h2 titles elsewhere. */
2598
+ .related__title {
2599
+ display: block;
2600
+ font-weight: 700;
2601
+ color: var(--color-text);
2602
+ }
2603
+ .related__date,
2604
+ .related__location { display: block; color: var(--color-muted); font-size: 0.8125rem; }
2605
+ .related__more {
2606
+ margin: 1.25rem 0 0;
2607
+ text-align: center;
2608
+ font-size: 0.9375rem;
2609
+ }
2610
+ .related__more a {
2611
+ display: inline-block;
2612
+ padding: 0.375rem 1rem;
2613
+ border: 1px solid var(--color-rule);
2614
+ border-radius: var(--radius-pill);
2615
+ text-decoration: none;
2616
+ }
2617
+ .related__more a:hover { border-color: var(--color-primary); }
2618
+ .related__list--full {
2619
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
2620
+ gap: 1.25rem;
2621
+ }
2622
+ .related__back { margin-top: var(--space-xl); font-size: 0.9375rem; }
2623
+
2624
+
2625
+ /* ============================================================
2626
+ * 26. Carousel — slideshow used by the _carousel partial
2627
+ * ============================================================
2628
+ *
2629
+ * CSS-only show/hide via `.is-active`; navigation handled by carousel.js.
2630
+ */
2631
+
2632
+ .carousel { position: relative; margin: var(--space-lg) 0; }
2633
+ .carousel__track { position: relative; min-height: 200px; }
2634
+ .carousel__slide { display: none; margin: 0; }
2635
+ .carousel__slide.is-active { display: block; }
2636
+ .carousel__image {
2637
+ width: 100%;
2638
+ height: auto;
2639
+ display: block;
2640
+ box-shadow: var(--shadow-soft);
2641
+ }
2642
+ .carousel__caption { padding: 0.75rem 0; text-align: center; }
2643
+ .carousel__title { font-weight: 600; font-size: 1.125rem; }
2644
+ .carousel__quote { color: var(--color-muted); margin: 0.25rem 0; }
2645
+ .carousel__meta { font-size: 0.875rem; color: var(--color-muted); margin: 0.25rem 0; }
2646
+ .carousel__prev,
2647
+ .carousel__next {
2648
+ position: absolute;
2649
+ top: 50%;
2650
+ transform: translateY(-50%);
2651
+ background: rgba(0, 0, 0, 0.5);
2652
+ color: white;
2653
+ border: 0;
2654
+ padding: 0.5rem 0.75rem;
2655
+ font-size: 1.25rem;
2656
+ cursor: pointer;
2657
+ border-radius: var(--radius-1);
2658
+ }
2659
+ .carousel__prev { left: 0.5rem; }
2660
+ .carousel__next { right: 0.5rem; }
2661
+ .carousel__prev:hover,
2662
+ .carousel__next:hover { background: rgba(0, 0, 0, 0.75); }
2663
+ .carousel__counter { text-align: center; font-size: 0.875rem; color: var(--color-muted); }
2664
+
2665
+
2666
+ /* ============================================================
2667
+ * 27. Gallery index + image gallery + photo showcase
2668
+ * ============================================================
2669
+ *
2670
+ * `.gallery-index` — the grid of thumbnails on /photos/, /country/<x>/,
2671
+ * /series/<x>/. CLS-safe 1:1 wrappers with soft-tint placeholders
2672
+ * (defined in section 8) that show until image bytes load.
2673
+ *
2674
+ * `.image-gallery` — grid for the inline `_image_gallery` partial.
2675
+ * Default is auto-fill; override column count with
2676
+ * `.image-gallery--cols-{2,3,4}`.
2677
+ *
2678
+ * `.photo-showcase` — optional feature block at the top of the gallery
2679
+ * index when `collections.photos.index.display_showcase` is on and one
2680
+ * photo has `showcase: true` in its frontmatter. Renders the photo
2681
+ * full-width (same treatment as the show view), then a caption block
2682
+ * below with title + caption + location.
2683
+ */
2684
+
2685
+ .photo-showcase {
2686
+ margin: var(--space-xl) 0 var(--space-2xl);
2687
+ }
2688
+ /* Other photos_index widgets — `<section class="photos-section">` for
2689
+ the "latest photos" row, and `<section class="taxonomy-row">` for
2690
+ the series + countries rows — get a top margin so the vertical
2691
+ rhythm stays consistent regardless of which widget renders first
2692
+ (when the showcase is disabled, latest_photos becomes the first
2693
+ block below the page header; when latest_photos is also off,
2694
+ taxonomy_row is first; and so on).
2695
+ `<section>` has no default margin, so without this rule the gap
2696
+ between the header (or `.index-intro`) and the first widget would
2697
+ collapse to whatever the last header element carries on its own —
2698
+ typically smaller than we want. `.index-intro` carries its own
2699
+ `margin-bottom`, so when body content is present margin-collapse
2700
+ selects the larger of the two and the gap stays even either way. */
2701
+ .photos-section,
2702
+ .taxonomy-row {
2703
+ margin-top: var(--space-2xl);
2704
+ }
2705
+ .photo-showcase__link {
2706
+ display: block;
2707
+ }
2708
+ .photo-showcase__image {
2709
+ display: block;
2710
+ width: 100%;
2711
+ height: auto;
2712
+ box-shadow: var(--shadow-soft);
2713
+ }
2714
+ .photo-showcase__caption {
2715
+ margin-top: var(--space-md);
2716
+ }
2717
+ .photo-showcase__eyebrow {
2718
+ margin: 0;
2719
+ font-family: var(--font-meta);
2720
+ font-size: 0.75rem;
2721
+ text-transform: uppercase;
2722
+ letter-spacing: 0.08em;
2723
+ color: var(--color-muted);
2724
+ }
2725
+ .photo-showcase__title {
2726
+ margin: var(--space-sm) 0 var(--space-xs);
2727
+ font-family: var(--font-heading);
2728
+ font-size: 1.5rem;
2729
+ font-weight: 700;
2730
+ }
2731
+ .photo-showcase__text {
2732
+ margin: 0 0 var(--space-xs);
2733
+ font-size: 1.0625rem;
2734
+ }
2735
+ .photo-showcase__meta {
2736
+ margin: 0;
2737
+ color: var(--color-muted);
2738
+ font-size: 0.875rem;
2739
+ }
2740
+
2741
+ .gallery-index {
2742
+ display: grid;
2743
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
2744
+ gap: var(--space-md);
2745
+ list-style: none;
2746
+ padding: 0;
2747
+ margin: var(--space-lg) 0;
2748
+ }
2749
+ /* Explicit desktop column counts — opt in via `collections.photos.index.cols`
2750
+ in config/site.yml (one of 2, 3, 4). Desktop-only: below 768px the
2751
+ modifier has no effect and the grid falls back to the base auto-fill
2752
+ rule above, which already handles tablet/mobile reflow on its own. */
2753
+ @media (min-width: 768px) {
2754
+ .gallery-index--cols-2 { grid-template-columns: repeat(2, 1fr); }
2755
+ .gallery-index--cols-3 { grid-template-columns: repeat(3, 1fr); }
2756
+ .gallery-index--cols-4 { grid-template-columns: repeat(4, 1fr); }
2757
+ }
2758
+ .gallery-index a {
2759
+ display: block;
2760
+ color: inherit;
2761
+ text-decoration: none;
2762
+ }
2763
+ .gallery-index__cover {
2764
+ width: 100%;
2765
+ aspect-ratio: 4 / 3; /* index default */
2766
+ overflow: hidden;
2767
+ border-radius: var(--radius-1);
2768
+ margin-bottom: var(--space-sm);
2769
+ background-color: #d8c8a0;
2770
+ }
2771
+ .gallery-index__cover img {
2772
+ width: 100%;
2773
+ height: 100%;
2774
+ display: block;
2775
+ object-fit: cover;
2776
+ }
2777
+ .gallery-index__title { display: block; font-weight: 600; }
2778
+ .gallery-index__location { display: block; color: var(--color-muted); font-size: 0.875rem; }
2779
+ .gallery-index__date,
2780
+ .gallery-index__camera {
2781
+ display: block;
2782
+ color: var(--color-muted);
2783
+ font-size: 0.8125rem;
2784
+ }
2785
+ .gallery-index__caption {
2786
+ display: block;
2787
+ margin-top: 0.25rem;
2788
+ font-size: 0.8125rem;
2789
+ }
2790
+
2791
+ .image-gallery {
2792
+ display: grid;
2793
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
2794
+ gap: var(--space-sm);
2795
+ margin: var(--space-lg) 0;
2796
+ }
2797
+ .image-gallery--cols-2 { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
2798
+ .image-gallery--cols-3 { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
2799
+ .image-gallery--cols-4 { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
2800
+ .image-gallery__placeholder {
2801
+ width: 100%;
2802
+ aspect-ratio: 4 / 3; /* index default */
2803
+ overflow: hidden;
2804
+ border-radius: var(--radius-1);
2805
+ background-color: #d8c8a0;
2806
+ }
2807
+ .image-gallery__placeholder img {
2808
+ width: 100%;
2809
+ height: 100%;
2810
+ display: block;
2811
+ object-fit: cover;
2812
+ }
2813
+
2814
+
2815
+ /* ============================================================
2816
+ * 28. Workshops — show view + index
2817
+ * ============================================================ */
2818
+
2819
+ /* Workshop show-view metadata table — definition list with each
2820
+ `<dt>/<dd>` pair wrapped in a `<div>` for flex/grid-friendly
2821
+ row layout. Same pattern as `.photo__meta`. Above 480px the
2822
+ label/value sit side-by-side; below, they stack. */
2823
+ .workshop__meta {
2824
+ margin: var(--space-lg) 0 var(--space-xl);
2825
+ padding: var(--space-lg);
2826
+ background: var(--color-card-bg);
2827
+ border-radius: var(--radius-3);
2828
+ box-shadow: var(--shadow-card);
2829
+ }
2830
+ .workshop__meta div {
2831
+ display: grid;
2832
+ grid-template-columns: 1fr;
2833
+ gap: 0.125rem var(--space-md);
2834
+ padding: var(--space-sm) 0;
2835
+ border-bottom: 1px solid var(--color-rule);
2836
+ }
2837
+ .workshop__meta div:last-child { border-bottom: 0; }
2838
+ @media (min-width: 480px) {
2839
+ .workshop__meta div { grid-template-columns: 8em 1fr; }
2840
+ }
2841
+ .workshop__meta dt {
2842
+ font-weight: 600;
2843
+ color: var(--color-muted);
2844
+ font-size: 0.9375rem;
2845
+ }
2846
+ .workshop__meta dd {
2847
+ margin: 0;
2848
+ }
2849
+
2850
+ /* Registration CTA wrapper — typically renders directly after the
2851
+ meta block. Margin-top groups visually with meta; margin-bottom
2852
+ separates from the body content that follows. */
2853
+ .workshop__cta {
2854
+ margin: 0 0 var(--space-xl);
2855
+ }
2856
+
2857
+ /* Workshops index — flat list of cards. Each card is a link to the
2858
+ workshop detail page; the metadata line below the description
2859
+ gives quick scan-info (when / where / format / price) at the
2860
+ index level so visitors can skim without clicking through.
2861
+
2862
+ Optional cover image (driven by `image:` frontmatter + the
2863
+ `index.show_image` config toggle):
2864
+ - mobile: sits flush at the top of the card, body below
2865
+ - >= 768px: sits on the left at ~1/3 card width, body on the right
2866
+ Same `1fr 2fr` cover-left pattern as `.post-list__item`. `overflow:
2867
+ hidden` on the item card clips the cover to the card's rounded
2868
+ corners regardless of which side it's on. */
2869
+ .workshops-index {
2870
+ list-style: none;
2871
+ margin: var(--space-xl) 0;
2872
+ padding-inline: 0;
2873
+ display: grid;
2874
+ gap: var(--space-lg);
2875
+ }
2876
+ .workshops-index__item {
2877
+ background: var(--color-card-bg);
2878
+ border-radius: var(--radius-3);
2879
+ box-shadow: var(--shadow-card);
2880
+ overflow: hidden; /* clip cover to rounded corners */
2881
+ }
2882
+ .workshops-index__link {
2883
+ display: grid;
2884
+ grid-template-columns: 1fr; /* mobile + cards without a cover */
2885
+ color: inherit;
2886
+ text-decoration: none;
2887
+ }
2888
+ .workshops-index__link:hover {
2889
+ text-decoration: none;
2890
+ }
2891
+ @media (min-width: 768px) {
2892
+ /* When the card has a cover, switch to cover-left / body-right. Cards
2893
+ without a cover stay single-column at every breakpoint so the body
2894
+ fills the full card width. */
2895
+ .workshops-index__link:has(.workshops-index__cover) {
2896
+ grid-template-columns: 1fr 2fr;
2897
+ }
2898
+ }
2899
+ .workshops-index__cover {
2900
+ display: block;
2901
+ aspect-ratio: 4 / 3; /* mobile + no-body fallback */
2902
+ overflow: hidden;
2903
+ background-color: var(--color-code-bg);
2904
+ align-self: stretch; /* explicit — fill the grid row's
2905
+ height when side-by-side at
2906
+ ≥768px, even before the
2907
+ aspect-ratio override below
2908
+ drops the 4:3 constraint. */
2909
+ }
2910
+ .workshops-index__cover img {
2911
+ width: 100%;
2912
+ height: 100%;
2913
+ display: block;
2914
+ object-fit: cover;
2915
+ }
2916
+ @media (min-width: 768px) {
2917
+ /* In the side-by-side layout the cover lives in a `1fr 2fr` grid
2918
+ cell that stretches to match the body's height (title +
2919
+ description + three meta lines).
2920
+
2921
+ Release the 4:3 constraint AND switch the cover to a
2922
+ `position: relative` box whose img is absolutely positioned with
2923
+ `inset: 0`. The absolute-positioning pattern is the bulletproof
2924
+ "fill the parent" idiom — relying on `img { height: 100%; }`
2925
+ against a grid-stretched parent has a known resolution edge case
2926
+ where the img keeps its intrinsic aspect ratio instead of
2927
+ filling the cell, leaving a gap below the photo on cards whose
2928
+ body is taller than the cover's 4:3 natural height (e.g. when
2929
+ the description wraps to two lines). */
2930
+ .workshops-index__link:has(.workshops-index__cover) .workshops-index__cover {
2931
+ aspect-ratio: auto;
2932
+ position: relative;
2933
+ }
2934
+ .workshops-index__link:has(.workshops-index__cover) .workshops-index__cover > img,
2935
+ .workshops-index__link:has(.workshops-index__cover) .workshops-index__cover > svg {
2936
+ position: absolute;
2937
+ inset: 0;
2938
+ width: 100%;
2939
+ height: 100%;
2940
+ }
2941
+ }
2942
+ /* Flex column with `justify-content: center` so the title / description /
2943
+ meta block sits VERTICALLY CENTRED in the body cell. With the
2944
+ side-by-side grid (cover-left / body-right) the cover stretches to
2945
+ match the row height; centring the body content here keeps the
2946
+ text balanced top + bottom instead of hugging the top edge with
2947
+ surplus space below the price. The body retains symmetric `--space-lg`
2948
+ padding so the centred content has equal breathing room on all
2949
+ sides; nothing more is needed. */
2950
+ .workshops-index__body {
2951
+ display: flex;
2952
+ flex-direction: column;
2953
+ justify-content: center;
2954
+ padding: var(--space-lg);
2955
+ }
2956
+ .workshops-index__title {
2957
+ margin: 0 0 var(--space-sm);
2958
+ font-size: 1.25rem;
2959
+ }
2960
+ .workshops-index__description {
2961
+ margin: 0 0 var(--space-sm);
2962
+ color: var(--color-muted);
2963
+ }
2964
+ .workshops-index__meta {
2965
+ margin: 0;
2966
+ font-size: 0.9375rem;
2967
+ color: var(--color-muted);
2968
+ }
2969
+ /* Upcoming cards emit one meta line per fact (date / location+format
2970
+ / price) so each reads cleanly. This rule gives adjacent lines a
2971
+ small gap. Past-card meta is always a single line so this is a
2972
+ no-op there. */
2973
+ .workshops-index__meta + .workshops-index__meta {
2974
+ margin-top: 0.125rem;
2975
+ }
2976
+ /* Price gets a small contrast bump — halfway between muted and the
2977
+ body text colour — so it reads as the prominent fact on the card
2978
+ without going to full body weight/colour. */
2979
+ .workshops-index__meta--price {
2980
+ color: color-mix(in srgb, var(--color-muted) 50%, var(--color-text));
2981
+ }
2982
+
2983
+ /* Future + past sections share the same `.workshops-index__group`
2984
+ wrapper so they can stack with consistent vertical rhythm. The
2985
+ future section sits directly under the page header; the past
2986
+ section is separated by a rule + extra spacing as visual demotion. */
2987
+ .workshops-index__group {
2988
+ margin: var(--space-xl) 0 0;
2989
+ }
2990
+ .workshops-index__group--past {
2991
+ margin-top: var(--space-2xl);
2992
+ padding-top: var(--space-xl);
2993
+ border-top: 1px solid var(--color-rule);
2994
+ }
2995
+ .workshops-index__heading {
2996
+ margin: 0 0 var(--space-md);
2997
+ font-size: 1.25rem;
2998
+ }
2999
+ .workshops-index__heading--past {
3000
+ font-size: 1.125rem;
3001
+ color: var(--color-muted);
3002
+ }
3003
+ .workshops-index__empty {
3004
+ margin: 0;
3005
+ }
3006
+
3007
+ /* Past workshops — compact list-style treatment (no card background,
3008
+ no shadow). Each entry is a single divider-separated row showing
3009
+ title + date + location. Similar to the related partials' compact
3010
+ density: demotes past workshops visually without hiding them. */
3011
+ .workshops-index--past {
3012
+ gap: 0; /* rows abut, separated by border */
3013
+ margin: 0;
3014
+ }
3015
+ .workshops-index__item--past {
3016
+ background: transparent; /* no card chrome */
3017
+ box-shadow: none;
3018
+ border-radius: 0;
3019
+ border-top: 1px solid var(--color-rule);
3020
+ overflow: visible; /* no cover to clip; cancel the upcoming-card clip */
3021
+ }
3022
+ .workshops-index__item--past:first-child { border-top: 0; }
3023
+ .workshops-index__item--past .workshops-index__body {
3024
+ padding: var(--space-md) 0; /* tighter rows, no horizontal padding */
3025
+ }
3026
+ .workshops-index__item--past .workshops-index__title {
3027
+ margin: 0 0 0.125rem;
3028
+ font-size: 1rem;
3029
+ color: var(--color-text); /* full body color; only the size +
3030
+ meta-line muting demote past
3031
+ cards, not the title color */
3032
+ }
3033
+ .workshops-index__item--past .workshops-index__meta {
3034
+ font-size: 0.875rem;
3035
+ }
3036
+
3037
+
3038
+ /* ============================================================
3039
+ * 29. Newsletter subscribe — card-shaped form
3040
+ * ============================================================ */
3041
+
3042
+ /* The card itself — looks like a `.testimonial` / `.book-related__item`
3043
+ shape (background + radius + shadow + padding) so it sits naturally
3044
+ alongside other card-shaped content blocks. Renders via the
3045
+ `partials/_newsletter_subscribe` partial when `newsletter:` is
3046
+ configured in `config/site.yml`. */
3047
+ .newsletter-subscribe {
3048
+ background: var(--color-card-bg);
3049
+ border-radius: var(--radius-3);
3050
+ box-shadow: var(--shadow-card);
3051
+ padding: var(--space-xl);
3052
+ margin: var(--space-2xl) 0;
3053
+ }
3054
+ .newsletter-subscribe__title { margin: 0 0 var(--space-sm); font-size: 1.25rem; }
3055
+ .newsletter-subscribe__description { margin: 0 0 var(--space-md); color: var(--color-muted); }
3056
+
3057
+ /* Form layout — input + button on one row at ≥480px, stacked below. */
3058
+ .newsletter-subscribe__form {
3059
+ display: flex;
3060
+ flex-wrap: wrap;
3061
+ gap: var(--space-sm);
3062
+ align-items: stretch;
3063
+ }
3064
+ .newsletter-subscribe__input {
3065
+ flex: 1 1 18em; /* takes available width, drops to its own row on narrow viewports */
3066
+ min-width: 0;
3067
+ padding: 0.5rem 0.75rem;
3068
+ font: inherit;
3069
+ font-size: 1rem;
3070
+ line-height: 1.5;
3071
+ border: 1px solid var(--color-rule);
3072
+ border-radius: var(--radius-2);
3073
+ background: var(--color-bg);
3074
+ color: var(--color-text);
3075
+ }
3076
+ .newsletter-subscribe__input:focus-visible {
3077
+ outline: 2px solid var(--color-primary);
3078
+ outline-offset: 2px;
3079
+ }
3080
+ .newsletter-subscribe__button {
3081
+ flex: 0 0 auto; /* button keeps its natural width */
3082
+ }
3083
+
3084
+ .newsletter-subscribe__attribution {
3085
+ margin: var(--space-sm) 0 0;
3086
+ font-size: 0.8125rem;
3087
+ color: var(--color-muted);
3088
+ }
3089
+
3090
+
3091
+ /* ============================================================
3092
+ * 30. Visualisations
3093
+ * ============================================================ */
3094
+
3095
+ .viz { margin: var(--space-xl) 0; }
3096
+ .viz__title { margin: 0 0 var(--space-sm); }
3097
+ .viz__caption { color: var(--color-muted); font-size: 0.9375rem; }
3098
+
3099
+ /* D3-visualization scaffolding — moved here from inline `style=` on the
3100
+ visualization layout so the rendered HTML stays CSP-clean (no inline
3101
+ styles allowed under a strict CSP). */
3102
+ .viz-container {
3103
+ position: relative;
3104
+ min-height: 500px;
3105
+ }
3106
+ .viz-loading {
3107
+ position: absolute;
3108
+ top: 50%;
3109
+ left: 50%;
3110
+ transform: translate(-50%, -50%);
3111
+ opacity: 0.7;
3112
+ }
3113
+ .viz-tooltip {
3114
+ position: absolute;
3115
+ display: none;
3116
+ pointer-events: none;
3117
+ background: var(--color-bg);
3118
+ border: 1px solid currentColor;
3119
+ padding: var(--space-sm) 0.75rem;
3120
+ border-radius: var(--radius-2);
3121
+ font-size: 0.875rem;
3122
+ box-shadow: var(--shadow-card);
3123
+ z-index: 1000;
3124
+ max-width: 300px;
3125
+ }