pandorga 1.2.1

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 (376) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +77 -0
  3. data/DESIGN.md +1434 -0
  4. data/LICENSE +21 -0
  5. data/README.md +81 -0
  6. data/_data/themes/dark.yml +97 -0
  7. data/_data/themes/light.yml +120 -0
  8. data/_data/themes/shared.yml +37 -0
  9. data/_data/translations.yml +85 -0
  10. data/_includes/chord-tab.html +38 -0
  11. data/_includes/content-runtime/00-config.html +22 -0
  12. data/_includes/content-runtime/10-utils.html +176 -0
  13. data/_includes/content-runtime/20-markdown.html +264 -0
  14. data/_includes/content-runtime/25-code-blocks.html +315 -0
  15. data/_includes/content-runtime/30-includes-bib.html +190 -0
  16. data/_includes/content-runtime/30-includes-xcite.html +122 -0
  17. data/_includes/content-runtime/30-includes.html +365 -0
  18. data/_includes/content-runtime/40-listing.html +225 -0
  19. data/_includes/content-runtime/41-listing-helpers.html +71 -0
  20. data/_includes/content-runtime/42-listing-filter.html +208 -0
  21. data/_includes/content-runtime/43-blocks.html +379 -0
  22. data/_includes/content-runtime/50-detail.html +861 -0
  23. data/_includes/content-runtime/55-toc.html +176 -0
  24. data/_includes/content-runtime/60-fragments.html +567 -0
  25. data/_includes/content-runtime/90-bootstrap.html +76 -0
  26. data/_includes/cut-in.html +10 -0
  27. data/_includes/cv/cv-box.html +18 -0
  28. data/_includes/dict-card.html +24 -0
  29. data/_includes/figure.html +36 -0
  30. data/_includes/home/band-index.html +43 -0
  31. data/_includes/home/band-listing.html +49 -0
  32. data/_includes/mathjax.html +10 -0
  33. data/_includes/ongoing-product.html +1 -0
  34. data/_includes/page/content-runtime.html +20 -0
  35. data/_includes/page/date_evolution.html +19 -0
  36. data/_includes/page/figure-lightbox.html +102 -0
  37. data/_includes/page/formatted_date.html +15 -0
  38. data/_includes/page/hero-default.html +18 -0
  39. data/_includes/page/listing-runtime-attrs.html +8 -0
  40. data/_includes/page/mermaid.html +101 -0
  41. data/_includes/page/network-graph.html +1253 -0
  42. data/_includes/page/page-header.html +41 -0
  43. data/_includes/page/professional-connections.html +2 -0
  44. data/_includes/page/site-footer.html +101 -0
  45. data/_includes/page/timeline-section.html +868 -0
  46. data/_includes/plotly.html +22 -0
  47. data/_includes/theme/dev-reexport.html +100 -0
  48. data/_includes/theme/favicons.html +4 -0
  49. data/_includes/theme/font-loader.html +55 -0
  50. data/_includes/theme/shell-theme-boot.html +115 -0
  51. data/_includes/theme/site-logo.html +6 -0
  52. data/_includes/theme/tailwind-theme-colors.json.liquid +65 -0
  53. data/_includes/theme/tailwind-theme-fonts.json.liquid +6 -0
  54. data/_includes/theme/theme-context.liquid +20 -0
  55. data/_includes/theme/theme-toggle.html +94 -0
  56. data/_includes/theme/theme-vars-block.liquid +161 -0
  57. data/_includes/theme/theme-vars.html +16 -0
  58. data/_includes/transcription.html +80 -0
  59. data/_includes/tweet.html +22 -0
  60. data/_includes/video.html +11 -0
  61. data/_includes/xcite.html +3 -0
  62. data/_includes/youtube-short.html +26 -0
  63. data/_includes/youtube.html +12 -0
  64. data/_layouts/article.html +27 -0
  65. data/_layouts/articles.html +534 -0
  66. data/_layouts/bibliography.html +417 -0
  67. data/_layouts/blog.html +544 -0
  68. data/_layouts/cv.html +393 -0
  69. data/_layouts/home.html +319 -0
  70. data/_layouts/network.html +9 -0
  71. data/_layouts/pandorga/articles.html +4 -0
  72. data/_layouts/pandorga/bibliography.html +4 -0
  73. data/_layouts/pandorga/blog.html +4 -0
  74. data/_layouts/pandorga/cv.html +4 -0
  75. data/_layouts/pandorga/media.html +4 -0
  76. data/_layouts/pandorga/network.html +4 -0
  77. data/_layouts/pandorga/portfolio.html +4 -0
  78. data/_layouts/post.html +7 -0
  79. data/_layouts/product.html +5 -0
  80. data/_layouts/project.html +27 -0
  81. data/_layouts/projects.html +534 -0
  82. data/_layouts/resources.html +387 -0
  83. data/_layouts/shell.html +203 -0
  84. data/_layouts/text.html +246 -0
  85. data/_plugins/bibliography_artifact.rb +57 -0
  86. data/_plugins/content_backend.rb +37 -0
  87. data/_plugins/content_collections.rb +51 -0
  88. data/_plugins/content_detail_paths.rb +58 -0
  89. data/_plugins/content_headers.rb +73 -0
  90. data/_plugins/content_keys.rb +310 -0
  91. data/_plugins/content_local_serve.rb +168 -0
  92. data/_plugins/content_site_adapter.rb +159 -0
  93. data/_plugins/content_validators_hook.rb +20 -0
  94. data/_plugins/content_writing_index.rb +52 -0
  95. data/_plugins/content_writing_paths.rb +55 -0
  96. data/_plugins/force_utf8_encoding.rb +13 -0
  97. data/_plugins/git_chronology.rb +211 -0
  98. data/_plugins/git_metadata.rb +43 -0
  99. data/_plugins/job_sections.rb +25 -0
  100. data/_plugins/lib/content_validators.rb +27 -0
  101. data/_plugins/lib/resource_validator.rb +56 -0
  102. data/_plugins/lib/tag_validator.rb +153 -0
  103. data/_plugins/lib/text_excerpt.rb +56 -0
  104. data/_plugins/lib/writing_entry.rb +107 -0
  105. data/_plugins/local_detail_rewrites.rb +194 -0
  106. data/_plugins/timeline.rb +507 -0
  107. data/_plugins/writing_slug_limits.rb +70 -0
  108. data/assets/css/article.css +1330 -0
  109. data/assets/css/base.css +1432 -0
  110. data/assets/css/cv.css +13 -0
  111. data/assets/css/global-link.css +94 -0
  112. data/assets/css/ledger/bibliography.css +307 -0
  113. data/assets/css/ledger/chrome.css +118 -0
  114. data/assets/css/ledger/cv.css +836 -0
  115. data/assets/css/ledger/detail.css +1270 -0
  116. data/assets/css/ledger/footer.css +298 -0
  117. data/assets/css/ledger/home.css +1490 -0
  118. data/assets/css/ledger/network.css +106 -0
  119. data/assets/css/ledger/projects.css +716 -0
  120. data/assets/css/ledger/rascunhos.css +379 -0
  121. data/assets/css/ledger/sources.css +327 -0
  122. data/assets/css/ledger/writing.css +754 -0
  123. data/assets/tailwind-play.js +15 -0
  124. data/examples/full/Gemfile +7 -0
  125. data/examples/full/_config.yml +92 -0
  126. data/examples/full/_redirects +3 -0
  127. data/examples/full/content/collections/articles/2026-01-01-welcome.md +9 -0
  128. data/examples/full/content/collections/data/contacts.yml +3 -0
  129. data/examples/full/content/collections/data/education.yml +4 -0
  130. data/examples/full/content/collections/jobs/research-fellow.md +12 -0
  131. data/examples/full/content/collections/posts/2026-01-02-note.md +9 -0
  132. data/examples/full/content/collections/products/ledger-tool.md +6 -0
  133. data/examples/full/content/collections/projects/demo-kit.md +10 -0
  134. data/examples/full/content/collections/resources/style-guide.md +7 -0
  135. data/examples/full/content/pages/cv/summary.md +1 -0
  136. data/examples/full/content/pages/headers.yml +20 -0
  137. data/examples/full/index.html +4 -0
  138. data/examples/minimal/Gemfile +7 -0
  139. data/examples/minimal/_config.yml +47 -0
  140. data/examples/minimal/_redirects +3 -0
  141. data/examples/minimal/content/collections/articles/2026-01-01-hello.md +10 -0
  142. data/examples/minimal/content/collections/articles/2026-01-02-second.md +9 -0
  143. data/examples/minimal/content/pages/headers.yml +6 -0
  144. data/examples/minimal/index.html +4 -0
  145. data/exe/pandorga +7 -0
  146. data/functions/api/studio/[[path]].js +562 -0
  147. data/functions/api/studio/_lib/auth.js +131 -0
  148. data/functions/api/studio/_lib/blocks.js +156 -0
  149. data/functions/api/studio/_lib/gemini.js +62 -0
  150. data/functions/api/studio/_lib/github.js +278 -0
  151. data/functions/api/studio/_lib/guidelines.js +143 -0
  152. data/functions/api/studio/_lib/paths.js +76 -0
  153. data/functions/api/studio/_lib/prompts.js +165 -0
  154. data/functions/api/studio/_lib/rate-limit.js +40 -0
  155. data/functions/api/studio/_lib/rewrite.js +136 -0
  156. data/functions/api/studio/_lib/sanitize.js +143 -0
  157. data/lib/pandorga/cli.rb +66 -0
  158. data/lib/pandorga/commands/doctor.rb +66 -0
  159. data/lib/pandorga/commands/export.rb +30 -0
  160. data/lib/pandorga/commands/install_functions.rb +41 -0
  161. data/lib/pandorga/commands/new.rb +113 -0
  162. data/lib/pandorga/commands/publish.rb +53 -0
  163. data/lib/pandorga/commands/serve.rb +34 -0
  164. data/lib/pandorga/commands/studio_schema.rb +309 -0
  165. data/lib/pandorga/jekyll/generator.rb +74 -0
  166. data/lib/pandorga/jekyll/plugins/bibliography_artifact.rb +57 -0
  167. data/lib/pandorga/jekyll/plugins/content_backend.rb +37 -0
  168. data/lib/pandorga/jekyll/plugins/content_collections.rb +51 -0
  169. data/lib/pandorga/jekyll/plugins/content_detail_paths.rb +58 -0
  170. data/lib/pandorga/jekyll/plugins/content_headers.rb +73 -0
  171. data/lib/pandorga/jekyll/plugins/content_keys.rb +310 -0
  172. data/lib/pandorga/jekyll/plugins/content_local_serve.rb +168 -0
  173. data/lib/pandorga/jekyll/plugins/content_site_adapter.rb +159 -0
  174. data/lib/pandorga/jekyll/plugins/content_validators_hook.rb +20 -0
  175. data/lib/pandorga/jekyll/plugins/content_writing_index.rb +52 -0
  176. data/lib/pandorga/jekyll/plugins/content_writing_paths.rb +55 -0
  177. data/lib/pandorga/jekyll/plugins/force_utf8_encoding.rb +13 -0
  178. data/lib/pandorga/jekyll/plugins/git_chronology.rb +211 -0
  179. data/lib/pandorga/jekyll/plugins/git_metadata.rb +43 -0
  180. data/lib/pandorga/jekyll/plugins/job_sections.rb +25 -0
  181. data/lib/pandorga/jekyll/plugins/lib/content_validators.rb +27 -0
  182. data/lib/pandorga/jekyll/plugins/lib/resource_validator.rb +56 -0
  183. data/lib/pandorga/jekyll/plugins/lib/tag_validator.rb +153 -0
  184. data/lib/pandorga/jekyll/plugins/lib/text_excerpt.rb +56 -0
  185. data/lib/pandorga/jekyll/plugins/lib/writing_entry.rb +107 -0
  186. data/lib/pandorga/jekyll/plugins/local_detail_rewrites.rb +194 -0
  187. data/lib/pandorga/jekyll/plugins/timeline.rb +507 -0
  188. data/lib/pandorga/jekyll/plugins/writing_slug_limits.rb +70 -0
  189. data/lib/pandorga/jekyll.rb +15 -0
  190. data/lib/pandorga/object_store_env.rb +51 -0
  191. data/lib/pandorga/registry/schema.yml +115 -0
  192. data/lib/pandorga/registry.rb +279 -0
  193. data/lib/pandorga/version.rb +5 -0
  194. data/lib/pandorga.rb +19 -0
  195. data/scripts/cdn-allowlist.json +19 -0
  196. data/scripts/content/backfill-content-keys.rb +99 -0
  197. data/scripts/content/band_art.rb +362 -0
  198. data/scripts/content/export-content-json.rb +741 -0
  199. data/scripts/content/flatten-ansi-capture.mjs +153 -0
  200. data/scripts/content/hero_portraits.rb +28 -0
  201. data/scripts/content/publish-content-to-object-store.sh +78 -0
  202. data/scripts/content/publish-content-to-r2.sh +5 -0
  203. data/scripts/content/sync-content-json-to-r2.rb +167 -0
  204. data/scripts/content/sync-content-redirects.rb +12 -0
  205. data/scripts/generate-configuration-doc.rb +127 -0
  206. data/scripts/lib/content_license.rb +50 -0
  207. data/scripts/lib/content_storage_config.rb +70 -0
  208. data/scripts/lib/normalize-display-math.mjs +52 -0
  209. data/scripts/lib/r2_json_sync.rb +76 -0
  210. data/scripts/lib/withdrawn_public_objects.rb +23 -0
  211. data/scripts/lib/writing_index_contract.rb +61 -0
  212. data/scripts/pdf/md-to-pdf.mjs +1400 -0
  213. data/scripts/pdf/md-to-pdf.sh +27 -0
  214. data/scripts/test/fixtures/dual-template/_config.yml +32 -0
  215. data/scripts/test/fixtures/dual-template/index.html +4 -0
  216. data/scripts/test/render-parity/article-note.json +5 -0
  217. data/scripts/test/render-parity/blockquote.json +5 -0
  218. data/scripts/test/render-parity/blocks/ansi-basic.json +7 -0
  219. data/scripts/test/render-parity/blocks/ansi-bold-is-bright.json +7 -0
  220. data/scripts/test/render-parity/blocks/ansi-drops-cursor-moves.json +7 -0
  221. data/scripts/test/render-parity/blocks/ansi-escapes-markup.json +7 -0
  222. data/scripts/test/render-parity/blocks/ansi-extended-colour.json +7 -0
  223. data/scripts/test/render-parity/blocks/ansi-real-control-byte.json +7 -0
  224. data/scripts/test/render-parity/blocks/archive-card-date-once.json +19 -0
  225. data/scripts/test/render-parity/blocks/archive-card-empty-foot.json +7 -0
  226. data/scripts/test/render-parity/blocks/archive-card-footer-dates.json +22 -0
  227. data/scripts/test/render-parity/blocks/archive-card-meta-parts.json +26 -0
  228. data/scripts/test/render-parity/blocks/archive-card.json +32 -0
  229. data/scripts/test/render-parity/blocks/cta-link.json +13 -0
  230. data/scripts/test/render-parity/blocks/lang-pill-pt.json +8 -0
  231. data/scripts/test/render-parity/blocks/lang-pill.json +8 -0
  232. data/scripts/test/render-parity/blocks/ledger-row-meta-parts.json +29 -0
  233. data/scripts/test/render-parity/blocks/ledger-row.json +35 -0
  234. data/scripts/test/render-parity/blocks/meta-strip.json +27 -0
  235. data/scripts/test/render-parity/blocks/poster-media-image.json +8 -0
  236. data/scripts/test/render-parity/blocks/poster-media-video.json +9 -0
  237. data/scripts/test/render-parity/blocks/section-banner.json +13 -0
  238. data/scripts/test/render-parity/blocks/system-card-custom-meta.json +22 -0
  239. data/scripts/test/render-parity/blocks/system-card.json +48 -0
  240. data/scripts/test/render-parity/blocks/tag-chips-links.json +12 -0
  241. data/scripts/test/render-parity/blocks/tag-chips.json +9 -0
  242. data/scripts/test/render-parity/cut-in-blank-line.json +9 -0
  243. data/scripts/test/render-parity/cut-in-right.json +9 -0
  244. data/scripts/test/render-parity/cut-in.json +8 -0
  245. data/scripts/test/render-parity/figure.json +5 -0
  246. data/scripts/test/render-parity/load-runtime.mjs +337 -0
  247. data/scripts/test/render-parity/ongoing-product.json +5 -0
  248. data/scripts/test/render-parity/plotly.json +5 -0
  249. data/scripts/test/render-parity/poem.json +5 -0
  250. data/scripts/test/render-parity/run-absent-field-checks.mjs +232 -0
  251. data/scripts/test/render-parity/run-block-fixture.mjs +86 -0
  252. data/scripts/test/render-parity/run-detail-parity-checks.mjs +123 -0
  253. data/scripts/test/render-parity/run-field-flow-checks.mjs +227 -0
  254. data/scripts/test/render-parity/run-fixture.mjs +159 -0
  255. data/scripts/test/render-parity/selectors.mjs +43 -0
  256. data/scripts/test/render-parity/video.json +5 -0
  257. data/scripts/test/render-parity/youtube-short.json +10 -0
  258. data/scripts/test/render-parity/youtube.json +8 -0
  259. data/scripts/test/test-absent-field-absent-element.rb +43 -0
  260. data/scripts/test/test-cdn-pins.rb +44 -0
  261. data/scripts/test/test-cloudflare-watch-paths-doc.rb +31 -0
  262. data/scripts/test/test-configuration-doc.rb +36 -0
  263. data/scripts/test/test-content-detail-urls.rb +346 -0
  264. data/scripts/test/test-content-keys.rb +110 -0
  265. data/scripts/test/test-content-license.rb +45 -0
  266. data/scripts/test/test-content-render-parity.rb +38 -0
  267. data/scripts/test/test-content-validators.rb +12 -0
  268. data/scripts/test/test-css-structure.rb +72 -0
  269. data/scripts/test/test-cv-export-contract.rb +158 -0
  270. data/scripts/test/test-detail-render-parity.rb +40 -0
  271. data/scripts/test/test-dev-reexport.rb +122 -0
  272. data/scripts/test/test-doctor.rb +39 -0
  273. data/scripts/test/test-dual-template-instances.rb +87 -0
  274. data/scripts/test/test-dual-template-runtime.rb +167 -0
  275. data/scripts/test/test-examples-build.rb +60 -0
  276. data/scripts/test/test-export-content-json-incremental.rb +138 -0
  277. data/scripts/test/test-export.rb +53 -0
  278. data/scripts/test/test-exported-fields-reach-the-view.rb +60 -0
  279. data/scripts/test/test-form-control-theming.rb +143 -0
  280. data/scripts/test/test-git-chronology.rb +414 -0
  281. data/scripts/test/test-hero-portraits.mjs +97 -0
  282. data/scripts/test/test-hero-portraits.rb +162 -0
  283. data/scripts/test/test-home-band-art.rb +135 -0
  284. data/scripts/test/test-install-functions.rb +39 -0
  285. data/scripts/test/test-language-export.rb +79 -0
  286. data/scripts/test/test-listing-filter-contract.rb +119 -0
  287. data/scripts/test/test-math-row-breaks.mjs +79 -0
  288. data/scripts/test/test-math-row-breaks.rb +18 -0
  289. data/scripts/test/test-new.rb +113 -0
  290. data/scripts/test/test-no-personal-data.rb +85 -0
  291. data/scripts/test/test-public-cv-export.rb +164 -0
  292. data/scripts/test/test-r2-config-consistency.rb +57 -0
  293. data/scripts/test/test-r2-json-sync.rb +193 -0
  294. data/scripts/test/test-registry-home.rb +34 -0
  295. data/scripts/test/test-runtime-js-syntax.rb +64 -0
  296. data/scripts/test/test-slim-writing-index.rb +126 -0
  297. data/scripts/test/test-studio-api-contract.rb +99 -0
  298. data/scripts/test/test-studio-content-files.rb +79 -0
  299. data/scripts/test/test-studio-liquid-roundtrip.mjs +179 -0
  300. data/scripts/test/test-studio-rate-limit.mjs +70 -0
  301. data/scripts/test/test-studio-rewrite-api-contract.rb +59 -0
  302. data/scripts/test/test-studio-rewrite-sanitize.mjs +210 -0
  303. data/scripts/test/test-studio-schema-composition.rb +126 -0
  304. data/scripts/test/test-studio-slug-config.rb +167 -0
  305. data/scripts/test/test-template-packages.rb +51 -0
  306. data/scripts/test/test-text-excerpt.rb +51 -0
  307. data/scripts/test/test-unwrap-media-src.mjs +39 -0
  308. data/scripts/test/test-unwrap-media-src.rb +19 -0
  309. data/scripts/test/test-withdrawn-content-export.rb +69 -0
  310. data/scripts/test/test-writing-index-export-slugs.rb +84 -0
  311. data/scripts/test/test-writing-slug-limits.rb +61 -0
  312. data/scripts/test/test-xcite-chronology.rb +106 -0
  313. data/scripts/validate.sh +74 -0
  314. data/scripts/visual/build-cv-pages-json.js +33 -0
  315. data/scripts/visual/build-site-pages-json.js +94 -0
  316. data/scripts/visual/publish-visual-inspection-to-r2.sh +42 -0
  317. data/scripts/visual/take-screenshots.js +88 -0
  318. data/scripts/visual/visual-inspection-pages.json +113 -0
  319. data/studio/assets/index-B_j0pMD5.css +1 -0
  320. data/studio/assets/index-Ch4YEv9g.js +285 -0
  321. data/studio/index.html +27 -0
  322. data/studio/schema.yml +869 -0
  323. data/studio-app/README.md +27 -0
  324. data/studio-app/index.html +26 -0
  325. data/studio-app/package-lock.json +2499 -0
  326. data/studio-app/package.json +26 -0
  327. data/studio-app/skills-lock.json +47 -0
  328. data/studio-app/src/api/client.js +71 -0
  329. data/studio-app/src/editor/body-editor.js +70 -0
  330. data/studio-app/src/editor/liquid-core.js +382 -0
  331. data/studio-app/src/editor/liquid.js +77 -0
  332. data/studio-app/src/lib/document.js +207 -0
  333. data/studio-app/src/lib/list-controls.js +317 -0
  334. data/studio-app/src/lib/schema.js +66 -0
  335. data/studio-app/src/lib/yaml-doc.js +100 -0
  336. data/studio-app/src/main.js +3693 -0
  337. data/studio-app/src/media/browser.js +578 -0
  338. data/studio-app/src/preview/render.js +430 -0
  339. data/studio-app/src/styles/studio.css +2826 -0
  340. data/studio-app/vite.config.js +25 -0
  341. data/templates/articles/README.md +40 -0
  342. data/templates/articles/fixtures/article.md +9 -0
  343. data/templates/articles/screenshots/README.md +6 -0
  344. data/templates/articles/studio.yml +73 -0
  345. data/templates/articles/template.yml +21 -0
  346. data/templates/bibliography/README.md +41 -0
  347. data/templates/bibliography/fixtures/references.json +9 -0
  348. data/templates/bibliography/screenshots/README.md +6 -0
  349. data/templates/bibliography/studio.yml +66 -0
  350. data/templates/bibliography/template.yml +18 -0
  351. data/templates/blog/README.md +38 -0
  352. data/templates/blog/fixtures/post.md +9 -0
  353. data/templates/blog/screenshots/README.md +6 -0
  354. data/templates/blog/studio.yml +69 -0
  355. data/templates/blog/template.yml +20 -0
  356. data/templates/cv/README.md +34 -0
  357. data/templates/cv/fixtures/job.md +12 -0
  358. data/templates/cv/screenshots/README.md +6 -0
  359. data/templates/cv/studio.yml +200 -0
  360. data/templates/cv/template.yml +25 -0
  361. data/templates/media/README.md +38 -0
  362. data/templates/media/fixtures/resource.md +7 -0
  363. data/templates/media/screenshots/README.md +6 -0
  364. data/templates/media/studio.yml +58 -0
  365. data/templates/media/template.yml +17 -0
  366. data/templates/network/README.md +34 -0
  367. data/templates/network/fixtures/sources.json +3 -0
  368. data/templates/network/screenshots/README.md +6 -0
  369. data/templates/network/studio.yml +28 -0
  370. data/templates/network/template.yml +10 -0
  371. data/templates/portfolio/README.md +39 -0
  372. data/templates/portfolio/fixtures/project.md +10 -0
  373. data/templates/portfolio/screenshots/README.md +6 -0
  374. data/templates/portfolio/studio.yml +89 -0
  375. data/templates/portfolio/template.yml +18 -0
  376. metadata +505 -0
@@ -0,0 +1,754 @@
1
+ /* Ledger page styles: writing. Owned by the writing page; shared component rules
2
+ belong in assets/css/base.css under "Architectural Ledger blocks".
3
+
4
+ Every ledger stylesheet is loaded on every page, so each rule here is scoped
5
+ to markup only the writing listings emit: .writing-index for the articles
6
+ page, and the .writing-rail block at the foot of this file, which is the one
7
+ sidebar both writing listings wear. Colours come from the theme custom
8
+ properties only: a literal hex would be correct in one palette and wrong in
9
+ the other. */
10
+
11
+ /* Page accent: `.page-accent--green` is defined once in base.css and
12
+ applied on `<main class="writing-index page-accent--green">`. */
13
+
14
+ .writing-index .writing-masthead {
15
+ padding-bottom: var(--space-lg);
16
+ margin-bottom: var(--space-xl);
17
+ border-bottom: 1px solid var(--border-gentle-divider);
18
+ box-shadow: 0 3px 0 -2px var(--border-gentle-faint);
19
+ position: relative;
20
+ }
21
+
22
+ .writing-index .writing-masthead::after {
23
+ content: "";
24
+ position: absolute;
25
+ left: 0;
26
+ bottom: -1.5px;
27
+ width: 3rem;
28
+ height: 2px;
29
+ background: var(--color-primary);
30
+ }
31
+
32
+
33
+
34
+ .writing-index .writing-masthead-tags {
35
+ margin-top: var(--space-sm);
36
+ /* The page accent, not a fixed role: Articles happens to read green, but
37
+ the tag line should follow whatever `.page-accent--*` sets. */
38
+ color: var(--color-primary);
39
+ letter-spacing: 0.06em;
40
+ }
41
+
42
+ /* ══ Featured panel ══
43
+ The first entry of the current selection that carries a thumbnail, given
44
+ the panel step of the surface ladder and the full gutter. Two columns when
45
+ there is an image and one when there is not, so the panel never reserves
46
+ space for a plate that does not exist. */
47
+ .writing-index .writing-lead {
48
+ position: relative;
49
+ overflow: hidden;
50
+ margin-bottom: var(--space-xl);
51
+ padding: var(--space-lg);
52
+ background: var(--color-panel-contrast);
53
+ }
54
+
55
+ @media (min-width: 1024px) {
56
+ .writing-index .writing-lead {
57
+ padding: var(--space-lg) var(--space-xl);
58
+ }
59
+ }
60
+
61
+ /* The mockup filled the right of this panel with a fabricated proof figure.
62
+ A shard bleeding off the corner holds that weight instead.
63
+
64
+ This used to be a single 19rem wedge at the top right, stood down whenever
65
+ the entry carried a thumbnail — and the panel picks the first entry that
66
+ *has* a thumbnail, so the condition was always true and the shard never
67
+ rendered on a built page. It is a pair now, placed around the plate rather
68
+ than instead of it.
69
+
70
+ The alpha sits bottom left, under the foot of the copy, the one corner the
71
+ plate never reaches at any width. The beta is a true corner accent at the
72
+ top right: it is offset far enough up that its visible part is the triangle
73
+ above the plate's top edge, and it tucks beNewsreader the plate as it descends
74
+ rather than fighting it. Neither corner repeats the home panel's pair, and
75
+ the hues are the only two this page has — `.page-accent--green` rebinds
76
+ primary onto secondary, so green and ochre is the whole palette here. */
77
+ .writing-index .writing-lead-shard {
78
+ left: -3.5rem;
79
+ bottom: -4rem;
80
+ width: 12rem;
81
+ height: 12rem;
82
+ background: var(--color-primary);
83
+ }
84
+
85
+ .writing-index .writing-lead-shard--beta {
86
+ left: auto;
87
+ right: -4rem;
88
+ bottom: auto;
89
+ top: -5rem;
90
+ width: 10rem;
91
+ height: 10rem;
92
+ background: var(--color-tertiary);
93
+ }
94
+
95
+ .writing-index .writing-lead-inner {
96
+ position: relative;
97
+ z-index: 1;
98
+ display: grid;
99
+ gap: var(--space-lg);
100
+ }
101
+
102
+ /* On a phone the plate leads the panel, at a width that still leaves the title
103
+ on the first screen. From the tablet up it moves beside the prose and grows
104
+ with the column. */
105
+ @media (max-width: 719px) {
106
+ .writing-index .writing-lead--illustrated .writing-lead-media {
107
+ order: -1;
108
+ max-width: 100%;
109
+ height: 11rem;
110
+ }
111
+ }
112
+
113
+ @media (min-width: 720px) {
114
+ .writing-index .writing-lead--illustrated .writing-lead-inner {
115
+ grid-template-columns: minmax(0, 1fr) 11rem;
116
+ align-items: stretch;
117
+ }
118
+ }
119
+
120
+ /* The plate stretches to match the content height, so the panel's height is a
121
+ function of the prose beside it. */
122
+ @media (min-width: 900px) {
123
+ .writing-index .writing-lead--illustrated .writing-lead-inner {
124
+ grid-template-columns: minmax(0, 1fr) 13.5rem;
125
+ gap: var(--space-xl);
126
+ align-items: stretch;
127
+ }
128
+ }
129
+
130
+ @media (min-width: 1280px) {
131
+ .writing-index .writing-lead--illustrated .writing-lead-inner {
132
+ grid-template-columns: minmax(0, 1fr) 15rem;
133
+ align-items: stretch;
134
+ }
135
+ }
136
+
137
+ .writing-index .writing-lead-body {
138
+ display: flex;
139
+ flex-direction: column;
140
+ justify-content: space-between;
141
+ gap: var(--space-sm);
142
+ max-width: var(--reading-measure, 45rem);
143
+ }
144
+
145
+ /* Featured chip and the date strip share one ledger line when they fit. */
146
+ .writing-index .writing-lead-rail {
147
+ display: flex;
148
+ flex-wrap: wrap;
149
+ align-items: center;
150
+ gap: var(--space-sm) var(--space-md);
151
+ }
152
+
153
+ .writing-index .writing-lead-rail .ledger-meta {
154
+ margin: 0;
155
+ }
156
+
157
+ /* Thin accent rule under the meta strip — monograph category cue. */
158
+ .writing-index .writing-lead-category-bar {
159
+ width: 4rem;
160
+ height: 2px;
161
+ margin: var(--space-xs) 0 var(--space-sm);
162
+ background: var(--color-primary);
163
+ }
164
+
165
+ .writing-index .writing-lead-featured {
166
+ flex: 0 0 auto;
167
+ }
168
+
169
+ .writing-index .writing-lead-title {
170
+ font-family: var(--font-content-title);
171
+ font-weight: var(--weight-title);
172
+ font-synthesis: none;
173
+ margin: 0;
174
+ }
175
+
176
+ .writing-index .writing-lead-title a {
177
+ color: var(--color-on-surface);
178
+ text-decoration: none;
179
+ transition: color var(--motion-duration-fast) var(--motion-ease-default);
180
+ }
181
+
182
+ .writing-index .writing-lead:hover .writing-lead-title a,
183
+ .writing-index .writing-lead-title a:hover {
184
+ color: var(--color-primary);
185
+ }
186
+
187
+ .writing-index .writing-lead-copy {
188
+ margin: 0;
189
+ font-family: var(--font-body);
190
+ font-size: var(--type-body);
191
+ font-weight: var(--weight-body);
192
+ line-height: var(--leading-body);
193
+ color: var(--color-legend);
194
+ }
195
+
196
+ /* The foot spreads: tags on the left, action aligned to the right. */
197
+ .writing-index .writing-lead-foot {
198
+ display: flex;
199
+ flex-direction: row;
200
+ flex-wrap: wrap;
201
+ align-items: center;
202
+ justify-content: space-between;
203
+ gap: var(--space-sm);
204
+ margin-top: auto;
205
+ padding-top: var(--space-sm);
206
+ border-top: 1px solid var(--border-gentle-divider);
207
+ }
208
+
209
+ .writing-index .writing-lead-foot .writing-lead-cta {
210
+ margin-left: auto;
211
+ padding: 0.35rem var(--space-md);
212
+ background: var(--color-primary);
213
+ color: var(--color-on-primary);
214
+ font-weight: var(--weight-label);
215
+ }
216
+
217
+ .writing-index .writing-lead-cta:hover {
218
+ background: color-mix(in srgb, var(--color-primary) 85%, var(--color-on-surface));
219
+ color: var(--color-on-primary);
220
+ text-decoration: none;
221
+ }
222
+
223
+ .writing-index .writing-lead-cta>span:not(.ledger-cta-arrow):not(.ledger-cta-icon),
224
+ .writing-index .writing-lead-cta:hover>span:not(.ledger-cta-arrow):not(.ledger-cta-icon) {
225
+ text-decoration: none;
226
+ }
227
+
228
+ /* Portrait plate. The frame is square-cornered like everything else, sits one
229
+ step below the panel it is on, and crops rather than letterboxes: a plate
230
+ with bars around it would read as a mistake at this size. */
231
+ .writing-index .writing-lead-media {
232
+ display: flex;
233
+ height: 100%;
234
+ }
235
+
236
+ .writing-index .writing-lead-media .ledger-poster {
237
+ width: 100%;
238
+ height: 100%;
239
+ min-height: 8rem;
240
+ background: var(--color-surface-container-lowest);
241
+ /* Same plate dialect as home featured / hero portrait. */
242
+ border: 1.5px solid var(--border-ink);
243
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-on-surface) 10%, transparent);
244
+ }
245
+
246
+ :root:not([data-theme="dark"]) .writing-index .writing-lead-media .ledger-poster,
247
+ html[data-theme="light"] .writing-index .writing-lead-media .ledger-poster {
248
+ border-width: 1px;
249
+ }
250
+
251
+ .writing-index .writing-lead-media .ledger-poster::after {
252
+ inset: 0.4rem;
253
+ --frame-corner-size: 0.85rem;
254
+ }
255
+
256
+ .writing-index .writing-lead-media .ledger-poster img {
257
+ width: 100%;
258
+ height: 100%;
259
+ object-fit: cover;
260
+ filter: saturate(0.9) contrast(1.02);
261
+ transition: filter var(--motion-duration-base) var(--motion-ease-default), transform var(--motion-duration-slow) var(--motion-ease-default);
262
+ }
263
+
264
+ .writing-index .writing-lead:hover .ledger-poster img {
265
+ filter: saturate(1.02) contrast(1);
266
+ transform: scale(1.02);
267
+ }
268
+
269
+ @media (prefers-reduced-motion: reduce) {
270
+ .writing-index .writing-lead:hover .ledger-poster img {
271
+ transform: none;
272
+ }
273
+ }
274
+
275
+ /* The revision date is the quieter half of the ledger line: it explains the
276
+ default order without competing with the publication date. */
277
+ .writing-index .writing-revised {
278
+ color: color-mix(in srgb, var(--color-on-surface-variant) 78%, transparent);
279
+ }
280
+
281
+ /* ══ Archive and rail ══
282
+ The mockup's nine/three split, with the filter in the column it filled with
283
+ invented marginalia. */
284
+ .writing-index .writing-body {
285
+ display: block;
286
+ }
287
+
288
+ @media (min-width: 1024px) {
289
+ .writing-index .writing-body {
290
+ display: grid;
291
+ grid-template-columns: minmax(0, 1fr) 16rem;
292
+ gap: var(--space-2xl);
293
+ align-items: start;
294
+ }
295
+
296
+ .writing-index .writing-main {
297
+ grid-column: 1;
298
+ grid-row: 1;
299
+ min-width: 0;
300
+ }
301
+
302
+ .writing-index .writing-rail {
303
+ grid-column: 2;
304
+ grid-row: 1;
305
+ }
306
+ }
307
+
308
+ @media (min-width: 1280px) {
309
+ .writing-index .writing-body {
310
+ grid-template-columns: minmax(0, 1fr) 18rem;
311
+ }
312
+ }
313
+
314
+ /* Archive head: the ordering and the tally, both read off the live list. */
315
+ .writing-index .writing-archive-head {
316
+ display: flex;
317
+ flex-wrap: wrap;
318
+ align-items: baseline;
319
+ gap: var(--space-sm) var(--space-md);
320
+ padding-bottom: var(--space-sm);
321
+ margin-bottom: var(--space-lg);
322
+ border-bottom: 1px solid var(--border-gentle-subtle);
323
+ }
324
+
325
+ .writing-index .writing-archive-title {
326
+ margin: 0;
327
+ color: var(--color-on-surface);
328
+ font-weight: var(--weight-label);
329
+ letter-spacing: 0.08em;
330
+ font-size: var(--type-label-lg);
331
+ }
332
+
333
+ .writing-index .writing-archive-note,
334
+ .writing-index .writing-archive-tally {
335
+ color: var(--color-on-surface-variant);
336
+ letter-spacing: 0.04em;
337
+ font-size: var(--type-meta);
338
+ }
339
+
340
+ .writing-index .writing-archive-tally {
341
+ margin-left: auto;
342
+ }
343
+
344
+ .writing-index .writing-archive {
345
+ display: flex;
346
+ flex-direction: column;
347
+ gap: var(--space-md);
348
+ }
349
+
350
+ .writing-index .writing-archive-state {
351
+ max-width: var(--reading-measure, 45rem);
352
+ padding: var(--space-xl);
353
+ background: var(--color-surface-card);
354
+ border: 1.5px solid var(--border-ink);
355
+ border-radius: var(--radius-card);
356
+ }
357
+
358
+ .writing-index .writing-pagination {
359
+ display: flex;
360
+ align-items: center;
361
+ justify-content: center;
362
+ gap: var(--space-lg);
363
+ margin-top: var(--space-2xl);
364
+ }
365
+
366
+ .writing-index .writing-pagination.hidden {
367
+ display: none;
368
+ }
369
+
370
+ /* ── Rows ──
371
+ A hairline rule on the reading side turns the run of slabs into a ledger:
372
+ the entry the pointer is on gains the brand edge, the rest stay quiet. */
373
+ .writing-index .ledger-row {
374
+ border: 1.5px solid var(--border-ink);
375
+ border-left: 3px solid transparent;
376
+ border-radius: var(--radius-card);
377
+ transition: background-color var(--motion-duration-fast) var(--motion-ease-default), border-color var(--motion-duration-fast) var(--motion-ease-default);
378
+ }
379
+
380
+ .writing-index .ledger-row:hover {
381
+ border-color: var(--border-ink);
382
+ border-left-color: var(--color-secondary);
383
+ }
384
+
385
+ /* Archive row blurbs — same reading size as the featured lead copy. */
386
+ .writing-index .ledger-row-copy {
387
+ font-size: var(--type-body);
388
+ line-height: var(--leading-body);
389
+ }
390
+
391
+ .writing-index .ledger-row-foot {
392
+ margin-top: var(--space-xs);
393
+ padding-top: var(--space-md);
394
+ border-top: 1px solid var(--border-gentle-divider);
395
+ }
396
+
397
+ /* An entry that declares a thumbnail keeps its plate on the reading side's
398
+ right, so the titles of illustrated and plain entries stay on one edge. */
399
+ .writing-index .writing-row--illustrated {
400
+ display: grid;
401
+ grid-template-columns: minmax(0, 1fr) 6.5rem;
402
+ column-gap: var(--space-lg);
403
+ align-items: start;
404
+ }
405
+
406
+ .writing-index .writing-row-body {
407
+ display: flex;
408
+ flex-direction: column;
409
+ gap: var(--space-sm);
410
+ min-width: 0;
411
+ }
412
+
413
+ .writing-index .writing-row--illustrated>.ledger-poster {
414
+ aspect-ratio: 3 / 4;
415
+ background: var(--color-surface-container-lowest);
416
+ border: 1px solid var(--border-gentle-faint);
417
+ }
418
+
419
+ .writing-index .writing-row--illustrated .ledger-poster img {
420
+ filter: saturate(0.88) contrast(1.02);
421
+ transition: filter var(--motion-duration-base) var(--motion-ease-default);
422
+ }
423
+
424
+ .writing-index .writing-row--illustrated:hover .ledger-poster img {
425
+ filter: saturate(1.02) contrast(1);
426
+ }
427
+
428
+ /* Below the tablet breakpoint the plate would take a third of the title's
429
+ measure. Same call as the shards: decoration goes, the entry stays whole. */
430
+ @media (max-width: 639px) {
431
+ .writing-index .writing-row--illustrated {
432
+ display: flex;
433
+ flex-direction: column;
434
+ }
435
+
436
+ .writing-index .writing-row--illustrated>.ledger-poster {
437
+ display: none;
438
+ }
439
+ }
440
+
441
+ /* global-link.css underlines any <a> hovered inside an <article>, which would
442
+ fuzz the chips and the directional links inside a ledger row. */
443
+ .writing-index a.ledger-chip:hover,
444
+ .writing-index .ledger-cta:hover {
445
+ text-decoration: none;
446
+ }
447
+
448
+ /* ══ Filter rail ══
449
+ Above 1024px the panel is always open and the trigger is not rendered;
450
+ below it the same markup is the shared disclosure. */
451
+ .writing-rail {
452
+ margin-bottom: var(--space-xl);
453
+ }
454
+
455
+ .writing-rail[hidden] {
456
+ display: none;
457
+ }
458
+
459
+ .writing-rail-trigger {
460
+ margin-bottom: var(--space-sm);
461
+ }
462
+
463
+ .writing-rail-trigger-label {
464
+ font-size: var(--type-meta);
465
+ letter-spacing: 0.06em;
466
+ }
467
+
468
+ .writing-rail-panel {
469
+ padding: var(--space-md);
470
+ background: var(--color-surface-card);
471
+ border: 1.5px solid var(--border-ink);
472
+ border-radius: var(--radius-card);
473
+ }
474
+
475
+ @media (min-width: 1024px) {
476
+
477
+ /* Default listing pattern: filter rail stays under the site nav while the
478
+ archive scrolls. Cap height so long tag lists scroll inside the ribbon. */
479
+ .writing-rail {
480
+ --listing-sticky-top: 5.5rem;
481
+ position: sticky;
482
+ top: var(--listing-sticky-top);
483
+ margin-bottom: 0;
484
+ max-height: calc(100vh - var(--listing-sticky-top) - var(--space-xl));
485
+ overflow-y: auto;
486
+ overscroll-behavior: contain;
487
+ background: var(--color-surface-card);
488
+ padding: var(--space-lg);
489
+ border: 1.5px solid var(--border-ink);
490
+ border-radius: var(--radius-card);
491
+ }
492
+
493
+ .home-band--contrast .writing-rail,
494
+ .rascunhos-main .writing-rail {
495
+ background: var(--color-surface-card);
496
+ }
497
+
498
+ .writing-rail-trigger {
499
+ display: none;
500
+ }
501
+
502
+ /* The controller toggles [hidden] on the panel for the disclosure form of
503
+ this rail. In the rail form the panel is the rail. */
504
+ .writing-rail-panel,
505
+ .writing-rail-panel[hidden] {
506
+ display: block;
507
+ padding: 0;
508
+ background: none;
509
+ border: 0;
510
+ }
511
+ }
512
+
513
+ /* Keyword box: full width of the rail, with the search glyph inside it. Its
514
+ heading matches the facet headings below, so the rail reads as three
515
+ labelled groups rather than a box with two lists under it. */
516
+ .writing-rail-panel>.listing-filter-group-label {
517
+ margin: 0 0 var(--space-sm);
518
+ padding-bottom: var(--space-xs);
519
+ border-bottom: 1px solid var(--border-gentle-faint);
520
+ color: var(--color-on-surface-variant);
521
+ font-family: var(--font-label);
522
+ font-size: var(--type-label-lg);
523
+ font-weight: var(--weight-label);
524
+ letter-spacing: 0.04em;
525
+ }
526
+
527
+ .writing-rail-search {
528
+ position: relative;
529
+ display: flex;
530
+ align-items: center;
531
+ margin-bottom: var(--space-lg);
532
+ }
533
+
534
+ /* A query is words, not notation: whatever is typed here is the same prose
535
+ that is being searched for. Monospace is reserved for code and for figures
536
+ that have to line up in a column, so the field keeps the body face — which
537
+ is what the `font-body` class already on the input asks for, and what this
538
+ rule used to override. */
539
+ .writing-rail-search .writing-rail-input {
540
+ width: 100%;
541
+ padding: 0.45rem 2.1rem 0.45rem 0.7rem;
542
+ background: var(--color-background);
543
+ color: var(--color-on-surface);
544
+ border: 1px solid var(--border-gentle-subtle);
545
+ font-family: var(--font-body);
546
+ font-size: calc(var(--type-subtitle) - 1pt);
547
+ font-weight: var(--weight-body);
548
+ }
549
+
550
+ .writing-rail-search .writing-rail-input::placeholder {
551
+ font-family: var(--font-body);
552
+ font-size: calc(var(--type-subtitle) - 1pt);
553
+ font-weight: var(--weight-body);
554
+ }
555
+
556
+ .writing-rail-search-icon.material-symbols-outlined {
557
+ position: absolute;
558
+ right: 0.45rem;
559
+ font-size: var(--type-card);
560
+ color: var(--color-on-surface-variant);
561
+ pointer-events: none;
562
+ }
563
+
564
+ /* Facets read as a list, not as a row of tabs: one line per tag, the count
565
+ beside its name, and the active line marked on its left edge. */
566
+ .writing-rail .listing-filter-group+.listing-filter-group {
567
+ margin-top: var(--space-lg);
568
+ }
569
+
570
+ .writing-rail .listing-filter-group-label {
571
+ margin: 0 0 var(--space-sm);
572
+ padding-bottom: var(--space-xs);
573
+ border-bottom: 1px solid var(--border-gentle-faint);
574
+ color: var(--color-on-surface-variant);
575
+ font-family: var(--font-label);
576
+ font-size: var(--type-label-lg);
577
+ font-weight: var(--weight-label);
578
+ letter-spacing: 0.04em;
579
+ }
580
+
581
+ .writing-rail .listing-filter-chips {
582
+ flex-direction: column;
583
+ align-items: stretch;
584
+ gap: 0;
585
+ }
586
+
587
+ .writing-rail .listing-filter-chip {
588
+ justify-content: flex-start;
589
+ padding: 0.4rem 0.5rem;
590
+ background: none;
591
+ border: 0;
592
+ border-left: 2px solid transparent;
593
+ color: var(--color-on-surface-variant);
594
+ font-family: var(--font-label);
595
+ font-size: var(--type-label-lg);
596
+ font-weight: var(--weight-label);
597
+ letter-spacing: 0.03em;
598
+ line-height: 1.2;
599
+ text-align: left;
600
+ }
601
+
602
+ .writing-rail .listing-filter-chip:hover {
603
+ background: var(--color-surface-high);
604
+ border-left-color: var(--color-outline-variant);
605
+ color: var(--color-on-surface);
606
+ }
607
+
608
+ /* The active state is carried by the page accent, the tinted fill and the rule
609
+ on the left edge. Cabin (label role) can take real weight; colour still does
610
+ the selected cue so the rail stays quiet. `--color-primary` follows
611
+ `.page-accent--*` (green on Articles, ochre on Rascunhos), so the same rail
612
+ markup does not stay locked to secondary. */
613
+ .writing-rail .listing-filter-chip.is-active {
614
+ background: color-mix(in srgb, var(--color-primary) 8%, transparent);
615
+ border-left-color: var(--color-primary);
616
+ color: var(--color-primary);
617
+ }
618
+
619
+ /* ── Licence ──
620
+ The last group in the rail, and the only one that is not a control: the
621
+ terms the archive beside it is published under. Every word of it is the
622
+ exported licence record, so the block exists only when the manifest
623
+ declares one — the rail has three labelled groups with it and two without.
624
+ It is rendered flush with the facet headings above so the rail still reads
625
+ as one column of labelled groups rather than a filter with a note stuck
626
+ underneath. */
627
+ .writing-rail-licence {
628
+ margin-top: var(--space-xl);
629
+ }
630
+
631
+ .writing-rail-licence[hidden] {
632
+ display: none;
633
+ }
634
+
635
+ .writing-rail-licence-label {
636
+ display: block;
637
+ margin: 0 0 var(--space-sm);
638
+ padding-bottom: var(--space-xs);
639
+ border-bottom: 1px solid var(--border-gentle-faint);
640
+ color: var(--color-on-surface-variant);
641
+ font-family: var(--font-label);
642
+ font-size: var(--type-label);
643
+ font-weight: var(--weight-label);
644
+ letter-spacing: 0.04em;
645
+ }
646
+
647
+ .writing-rail-licence-copy {
648
+ margin: 0 0 var(--space-xs);
649
+ color: var(--color-on-surface-variant);
650
+ font-size: var(--type-meta);
651
+ line-height: 1.5;
652
+ }
653
+
654
+ .writing-rail-licence .ledger-cta {
655
+ margin-top: var(--space-sm);
656
+ font-size: var(--type-cta);
657
+ }
658
+
659
+ /* ── Licence, a colophon rather than a preamble ──
660
+ On the disclosure form the rail stacks above the archive, which put the
661
+ reuse terms between the reader and the writing they describe. Nothing about
662
+ a licence needs reading first, so below 1024px it goes where a colophon
663
+ belongs: after the entries and after the pager.
664
+
665
+ It cannot simply be reordered, because it is a child of the rail rather
666
+ than a sibling of the archive. So the rail's own box dissolves and its
667
+ three children become items of the stacked body — `display: contents`, the
668
+ same move the sources page makes on its chip rows. `:not([hidden])` keeps
669
+ the dissolve off the rail until the controller mounts it; without it a
670
+ higher-specificity `display: contents` would beat `.writing-rail[hidden]`
671
+ and leak the Filter button onto an unmounted page.
672
+
673
+ The licence stays a note either way: no card fill, no frame, nothing that
674
+ would read as a panel to get past. */
675
+ @media (max-width: 1023px) {
676
+
677
+ .writing-index .writing-body,
678
+ .rascunhos-body {
679
+ display: flex;
680
+ flex-direction: column;
681
+ }
682
+
683
+ .writing-index .writing-body>.writing-rail:not([hidden]),
684
+ .rascunhos-body>.writing-rail:not([hidden]) {
685
+ display: contents;
686
+ }
687
+
688
+ .writing-index .writing-main,
689
+ .rascunhos-body>.rascunhos-ledger {
690
+ order: 1;
691
+ }
692
+
693
+ .writing-rail-licence {
694
+ order: 2;
695
+ margin-top: var(--space-xl);
696
+ padding-top: var(--space-lg);
697
+ border-top: 1px solid var(--border-gentle-subtle);
698
+ }
699
+
700
+ /* The dissolved rail took its margin-bottom with it, so the space between
701
+ the filter and the archive passes to whichever child is last on screen:
702
+ the panel when the disclosure is open, the trigger when it is shut. */
703
+ .writing-rail-panel {
704
+ margin-bottom: var(--space-xl);
705
+ }
706
+
707
+ .writing-rail:has(> .writing-rail-panel[hidden]) .writing-rail-trigger {
708
+ margin-bottom: var(--space-xl);
709
+ }
710
+ }
711
+
712
+ @media (min-width: 1024px) {
713
+ .writing-rail-licence {
714
+ padding-left: 0;
715
+ border-left: 0;
716
+ }
717
+ }
718
+
719
+ /* Between the 640px shard cut-off and the desktop layout the panel is narrow
720
+ enough that a shard sized for the wide card reaches the middle of it: at
721
+ 768px the 19rem one this started as ran straight through the lead headline.
722
+ Back to corner accents. The CV dossier and the rascunhos masthead carry the
723
+ same correction. Both corners are restated, not just the size, because the
724
+ base rule sets one of `top`/`bottom` and `left`/`right` to `auto` on the
725
+ beta and a size-only override would leave the pair half-placed: the beta
726
+ carries both class names, so the alpha rule matches it too, and an element
727
+ left with all four offsets set resolves to top and left, which drops the
728
+ pair into a single corner. */
729
+ @media (max-width: 1023px) {
730
+ .writing-index .writing-lead-shard {
731
+ left: -2.5rem;
732
+ bottom: -3rem;
733
+ width: 8.5rem;
734
+ height: 8.5rem;
735
+ }
736
+
737
+ .writing-index .writing-lead-shard--beta {
738
+ left: auto;
739
+ bottom: auto;
740
+ right: -3rem;
741
+ top: -3.5rem;
742
+ width: 7.5rem;
743
+ height: 7.5rem;
744
+ }
745
+ }
746
+
747
+ /* Pagination count face/size live on `.pagination-count` in base.css. */
748
+
749
+ /* global-link.css underlines any <a> hovered inside an <article>, which would
750
+ fuzz the chips and the directional links inside a ledger row. */
751
+ .writing-index a.ledger-chip:hover,
752
+ .writing-index .ledger-cta:hover {
753
+ text-decoration: none;
754
+ }