@jant/core 0.6.12 → 0.6.14

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 (120) hide show
  1. package/bin/commands/import-site.js +2 -10
  2. package/bin/commands/migrate-text-attachments.js +1 -3
  3. package/bin/commands/site/export.js +1 -3
  4. package/bin/commands/telegram/register-webhooks.js +9 -3
  5. package/bin/lib/site-snapshot.js +1 -5
  6. package/dist/{app-D-zAhayc.js → app-2i7-WQHg.js} +426 -450
  7. package/dist/app-DZDlmh7C.js +6 -0
  8. package/dist/client/.vite/manifest.json +3 -3
  9. package/dist/client/_assets/{client-S1cdvulk.js → client-BvID5ucz.js} +1 -1
  10. package/dist/client/_assets/client-Cevfpm8H.css +2 -0
  11. package/dist/client/_assets/{client-auth-YW92ZH7u.js → client-auth-v3yvhbgZ.js} +596 -590
  12. package/dist/{export-Ckwh4BiE.js → export-DWn149b7.js} +24 -19
  13. package/dist/{github-sync-BMmK3JZ0.js → github-sync-C0zyF6XS.js} +2 -2
  14. package/dist/{github-sync-Dl9wQMar.js → github-sync-Ckk0sJxK.js} +1 -1
  15. package/dist/index.js +3 -3
  16. package/dist/node.js +4 -4
  17. package/package.json +1 -1
  18. package/src/__tests__/export-service.test.ts +1 -2
  19. package/src/__tests__/helpers/app.ts +3 -0
  20. package/src/__tests__/helpers/export-fixtures.ts +0 -1
  21. package/src/__tests__/import-site-command.test.ts +1 -2
  22. package/src/client/__tests__/site-header-nav.test.ts +36 -2
  23. package/src/client/components/__tests__/compose-title-from-heading.test.ts +57 -0
  24. package/src/client/components/__tests__/jant-command-palette.test.ts +137 -10
  25. package/src/client/components/__tests__/jant-compose-dialog.test.ts +3 -0
  26. package/src/client/components/__tests__/jant-compose-editor.test.ts +94 -2
  27. package/src/client/components/__tests__/jant-nav-manager.test.ts +107 -22
  28. package/src/client/components/__tests__/jant-settings-general.test.ts +1 -0
  29. package/src/client/components/compose-title-from-heading.ts +66 -0
  30. package/src/client/components/compose-types.ts +8 -0
  31. package/src/client/components/inline-image-issues.ts +17 -0
  32. package/src/client/components/jant-command-palette.ts +100 -70
  33. package/src/client/components/jant-compose-dialog.ts +3 -1
  34. package/src/client/components/jant-compose-editor.ts +78 -1
  35. package/src/client/components/jant-compose-fullscreen.ts +2 -0
  36. package/src/client/components/jant-nav-manager.ts +245 -155
  37. package/src/client/components/nav-manager-types.ts +0 -10
  38. package/src/client/site-header-nav.d.ts +1 -0
  39. package/src/client/site-header-nav.js +105 -47
  40. package/src/client/tiptap/__tests__/block-insertion.test.ts +35 -0
  41. package/src/client/tiptap/__tests__/footnotes.test.ts +284 -0
  42. package/src/client/tiptap/__tests__/image-input-rules.test.ts +117 -0
  43. package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +148 -1
  44. package/src/client/tiptap/bubble-menu.ts +3 -3
  45. package/src/client/tiptap/create-editor.ts +7 -0
  46. package/src/client/tiptap/extensions.ts +7 -2
  47. package/src/client/tiptap/footnotes.ts +156 -0
  48. package/src/client/tiptap/image-input-rules.ts +48 -0
  49. package/src/client/tiptap/image-node.ts +189 -7
  50. package/src/client/tiptap/markdown-clipboard.ts +7 -2
  51. package/src/client-auth.ts +0 -1
  52. package/src/i18n/locales/public/en.po +20 -4
  53. package/src/i18n/locales/public/en.ts +1 -1
  54. package/src/i18n/locales/public/zh-Hans.po +20 -4
  55. package/src/i18n/locales/public/zh-Hans.ts +1 -1
  56. package/src/i18n/locales/public/zh-Hant.po +20 -4
  57. package/src/i18n/locales/public/zh-Hant.ts +1 -1
  58. package/src/i18n/locales/settings/en.po +23 -20
  59. package/src/i18n/locales/settings/en.ts +1 -1
  60. package/src/i18n/locales/settings/zh-Hans.po +23 -20
  61. package/src/i18n/locales/settings/zh-Hans.ts +1 -1
  62. package/src/i18n/locales/settings/zh-Hant.po +23 -20
  63. package/src/i18n/locales/settings/zh-Hant.ts +1 -1
  64. package/src/lib/__tests__/markdown-to-tiptap.test.ts +4 -0
  65. package/src/lib/__tests__/navigation.test.ts +4 -37
  66. package/src/lib/__tests__/resolve-config.test.ts +6 -1
  67. package/src/lib/__tests__/view.test.ts +6 -30
  68. package/src/lib/github-sync-site-config.ts +0 -2
  69. package/src/lib/hugo-markdown.ts +1 -1
  70. package/src/lib/markdown-manager.ts +14 -5
  71. package/src/lib/navigation.ts +5 -22
  72. package/src/lib/resolve-config.ts +9 -2
  73. package/src/lib/site-header-fragment.tsx +37 -0
  74. package/src/lib/view.ts +2 -7
  75. package/src/node/__tests__/cli-site-snapshot.test.ts +45 -45
  76. package/src/routes/api/__tests__/nav-items.test.ts +26 -0
  77. package/src/routes/api/export.ts +0 -2
  78. package/src/routes/api/internal/__tests__/uploads.test.ts +9 -13
  79. package/src/routes/api/internal/sites.ts +5 -5
  80. package/src/routes/api/nav-items.ts +25 -4
  81. package/src/routes/dash/settings.tsx +8 -2
  82. package/src/routes/feed/__tests__/feed.test.ts +42 -0
  83. package/src/routes/feed/__tests__/sitemap.test.ts +2 -13
  84. package/src/routes/feed/feed.ts +1 -0
  85. package/src/routes/feed/sitemap.ts +2 -6
  86. package/src/routes/pages/archive.tsx +1 -0
  87. package/src/routes/pages/collection.tsx +1 -0
  88. package/src/routes/pages/featured.tsx +0 -4
  89. package/src/routes/pages/home.tsx +4 -51
  90. package/src/routes/pages/latest.tsx +2 -51
  91. package/src/services/__tests__/github-app-installations.test.ts +10 -10
  92. package/src/services/__tests__/navigation.test.ts +41 -0
  93. package/src/services/__tests__/post-timeline.test.ts +56 -0
  94. package/src/services/__tests__/post.test.ts +33 -0
  95. package/src/services/__tests__/settings.test.ts +5 -20
  96. package/src/services/export-theme/assets/client-site.js +10 -10
  97. package/src/services/export-theme/layouts/_default/rss.xml +5 -15
  98. package/src/services/export-theme/layouts/index.html +26 -39
  99. package/src/services/export.ts +5 -10
  100. package/src/services/github-app-installations.ts +1 -3
  101. package/src/services/navigation.ts +44 -13
  102. package/src/services/post.ts +80 -57
  103. package/src/services/settings.ts +0 -10
  104. package/src/services/site-admin.ts +0 -2
  105. package/src/services/upload-session.ts +4 -18
  106. package/src/styles/tokens.css +2 -2
  107. package/src/styles/ui.css +316 -34
  108. package/src/types/bindings.ts +0 -1
  109. package/src/types/config.ts +3 -7
  110. package/src/ui/compose/ComposeDialog.tsx +28 -0
  111. package/src/ui/dash/appearance/NavigationContent.tsx +1 -1
  112. package/src/ui/dash/settings/AccountMenuContent.tsx +2 -2
  113. package/src/ui/dash/settings/SettingsRootContent.tsx +3 -3
  114. package/src/ui/feed/__tests__/timeline-cards.test.ts +8 -3
  115. package/src/ui/layouts/BaseLayout.tsx +1 -1
  116. package/src/ui/layouts/SiteLayout.tsx +266 -227
  117. package/src/ui/layouts/__tests__/SiteLayout.test.tsx +48 -0
  118. package/dist/app-B5P1b4TF.js +0 -6
  119. package/dist/client/_assets/client-BUxR-E8O.css +0 -2
  120. package/src/client/nav-manager-bridge.ts +0 -54
@@ -2994,7 +2994,8 @@ function createMarkdownContentExtensions(options = {}) {
2994
2994
  openOnClick: false,
2995
2995
  autolink: false
2996
2996
  },
2997
- codeBlock: false
2997
+ codeBlock: false,
2998
+ trailingNode: { notAfter: ["footnoteDefinition"] }
2998
2999
  }),
2999
3000
  MarkdownCodeBlock,
3000
3001
  Table.configure({
@@ -3013,9 +3014,16 @@ function createMarkdownContentExtensions(options = {}) {
3013
3014
  MarkdownFootnoteDefinition
3014
3015
  ];
3015
3016
  }
3016
- function normalizeMarkdownDoc(node) {
3017
+ /**
3018
+ * Normalizes Markdown parser output before it enters the editor schema.
3019
+ *
3020
+ * @param node - Parsed Tiptap document or descendant node
3021
+ * @returns A normalized copy safe to load into an editor
3022
+ * @example
3023
+ * const normalized = normalizeMarkdownDocument(markdownManager.parse(source));
3024
+ */ function normalizeMarkdownDocument(node) {
3017
3025
  const normalized = { ...node };
3018
- if (normalized.content) normalized.content = normalized.content.map(normalizeMarkdownDoc);
3026
+ if (normalized.content) normalized.content = normalized.content.map(normalizeMarkdownDocument);
3019
3027
  if (normalized.marks) normalized.marks = normalized.marks.map((mark) => {
3020
3028
  if (!mark || typeof mark !== "object") return mark;
3021
3029
  const nextMark = {
@@ -3040,8 +3048,8 @@ function normalizeMarkdownDoc(node) {
3040
3048
  for (let index = 0; index < normalized.content.length; index += 1) {
3041
3049
  const child = normalized.content[index];
3042
3050
  const nextChild = normalized.content[index + 1];
3043
- if (child?.type === "text" && typeof child.text === "string" && nextChild?.type === "footnoteReference" && child.text.endsWith("\n")) {
3044
- const trimmedText = child.text.replace(/\n$/, "");
3051
+ if (child?.type === "text" && typeof child.text === "string" && nextChild?.type === "footnoteReference" && /\n[ \t]*$/.test(child.text)) {
3052
+ const trimmedText = child.text.replace(/\n[ \t]*$/, "");
3045
3053
  if (trimmedText) nextContent.push({
3046
3054
  ...child,
3047
3055
  text: trimmedText
@@ -3069,7 +3077,7 @@ function getMarkdownManager() {
3069
3077
  return sharedMarkdownManager;
3070
3078
  }
3071
3079
  function parseMarkdownDocument(markdown) {
3072
- return normalizeMarkdownDoc(getMarkdownManager().parse(markdown));
3080
+ return normalizeMarkdownDocument(getMarkdownManager().parse(markdown));
3073
3081
  }
3074
3082
  function serializeMarkdownDocument(doc) {
3075
3083
  return expandCodeBlockFences(getMarkdownManager().serialize(normalizeFootnoteArtifacts(doc)));
@@ -3295,7 +3303,7 @@ function serializeMarkdownDocument(doc) {
3295
3303
  }
3296
3304
  //#endregion
3297
3305
  //#region src/styles/tokens.css?raw
3298
- var tokens_default = "/**\n * Design Tokens\n *\n * CSS custom properties for all visual aspects of the UI.\n * These are the stable customization API — override in custom CSS\n * to change typography, layout, surfaces, and element sizing.\n */\n\n:root {\n /* Typography — Font families */\n --font-cjk-serif-fallback:\n \"Songti SC\", STSong, SimSun, \"Songti TC\", PMingLiU, MingLiU,\n \"Noto Serif SC\", \"Noto Serif CJK SC\", \"Noto Serif TC\", \"Noto Serif CJK TC\";\n --font-body:\n system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n \"Helvetica Neue\", Helvetica, Arial, \"PingFang TC\", \"PingFang SC\",\n \"Hiragino Sans CNS\", \"Hiragino Sans GB\", \"Microsoft JhengHei\",\n \"Microsoft YaHei\", \"Noto Sans CJK TC\", \"Noto Sans CJK SC\", sans-serif;\n --font-heading:\n \"New York Small\", \"New York\", \"Iowan Old Style\", Charter,\n \"Bitstream Charter\", \"Source Serif 4\", Cambria, \"Sitka Text\", Georgia,\n var(--font-cjk-serif-fallback), ui-serif, serif;\n --font-site-title:\n \"New York Small\", \"New York\", \"Iowan Old Style\", Charter,\n \"Bitstream Charter\", \"Source Serif 4\", Cambria, \"Sitka Text\", Georgia,\n var(--font-cjk-serif-fallback), ui-serif, serif;\n --font-serif:\n var(--font-cjk-serif-fallback), ui-serif, \"New York Small\", \"New York\",\n \"Iowan Old Style\", Charter, Georgia, \"Times New Roman\", Times, serif;\n --font-ui:\n system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n \"Helvetica Neue\", Helvetica, Arial, \"PingFang TC\", \"PingFang SC\",\n \"Hiragino Sans CNS\", \"Hiragino Sans GB\", \"Microsoft JhengHei\",\n \"Microsoft YaHei\", \"Noto Sans CJK TC\", \"Noto Sans CJK SC\", sans-serif;\n --font-mono:\n ui-monospace, Menlo, Monaco, Consolas, \"Cascadia Code\", \"Courier New\",\n monospace;\n /*\n * Blockquote font family.\n *\n * Defaults to `inherit` so blockquotes follow the body font in sans-only\n * themes (Clean, Friendly, Bold) and serif-only themes (Tufte, Bookish).\n * Mixed themes that want a distinct blockquote voice — e.g. Classic, which\n * pairs a sans body with serif headings — override this token in their\n * `cssVariables` to point at a serif stack. This also restores a type-level\n * distinction for CJK, where italic is disabled.\n */\n --font-blockquote: inherit;\n\n /* Typography — Font weights */\n --fw-light: 300;\n --fw-regular: 400;\n --fw-medium: 500;\n --fw-semibold: 600;\n --fw-bold: 700;\n --fw-extrabold: 800;\n /*\n * Unified type scale.\n *\n * Every font-size in the system — reading content AND UI controls —\n * must reference one of these tokens. No raw rem/px values elsewhere.\n *\n * --type-display 2.7rem (40.5px) — page titles, h1\n * --type-title 2.1rem (31.5px) — h2, feed card titles\n * --type-subtitle 1.8rem (27px) — h3\n * --type-body 1.4rem (21px) — running text, form inputs\n * --type-secondary 1.1rem (16.5px) — meta, nav, sidenotes, UI labels\n * --type-base 1.0rem (15px) — UI buttons, controls\n * --type-sm 0.9rem (13.5px) — small UI text\n * --type-xs 0.8rem (12px) — captions, descriptions, chips\n * --type-2xs 0.65rem (9.75px) — tiny labels, file sizes, badges\n */\n --type-display: 2.7rem;\n --type-title: 2.1rem;\n --type-subtitle: 1.8rem;\n --type-body: 1.4rem;\n --type-secondary: 1.1rem;\n --type-base: 1rem;\n --type-sm: 0.9rem;\n --type-xs: 0.8rem;\n --type-2xs: 0.65rem;\n\n /* Content reading tokens — desktop maps to core scale,\n mobile overrides below cap sizes for small screens.\n --type-content-scale uniformly scales all content sizes\n without affecting UI controls. */\n --type-content-scale: 0.8;\n --type-content-display: calc(var(--type-display) * var(--type-content-scale));\n --type-content-title: calc(var(--type-title) * var(--type-content-scale));\n --type-content-subtitle: calc(\n var(--type-subtitle) * var(--type-content-scale)\n );\n --type-content-body: calc(var(--type-body) * var(--type-content-scale));\n --type-content-quote: calc(var(--type-content-body) * 1.16);\n --type-content-quote-leading: 1.4;\n\n /* Semantic aliases */\n --type-body-size: var(--type-content-body);\n --type-code: calc(var(--type-body-size) * 0.94);\n --type-code-block: calc(var(--type-body-size) * 0.9);\n --type-body-tracking: 0;\n --type-ui-title: var(--type-secondary);\n --type-ui-control: var(--type-base);\n --type-ui-meta: var(--type-base);\n --type-ui-hint: var(--type-sm);\n --type-ui-caption: var(--type-xs);\n --type-ui-micro: var(--type-2xs);\n --type-ui-input: var(--type-secondary);\n --type-thread-context: var(--type-base);\n --type-thread-context-title: var(--type-secondary);\n --type-thread-context-meta: var(--type-sm);\n --feed-note-title-size: calc(var(--type-content-body) * 1.36);\n --feed-note-title-leading: var(--type-heading-leading);\n --type-body-leading: 1.7;\n --type-display-leading: 1.15;\n --type-heading-leading: 1.15;\n --type-heading-weight: var(--fw-regular);\n --type-heading-tracking: 0;\n --type-display-weight: var(--fw-regular);\n --type-display-tracking: 0;\n --type-label-weight: var(--fw-medium);\n --type-label-tracking: 0.08em;\n\n /* Layout — Tufte proportional model */\n --content-max-width: 42rem;\n --form-max-width: 42rem;\n /* compose dialogs + feed content cap */\n --layout-body-max-width: 1088px;\n --layout-content-width: 55%;\n --layout-sidenote-width: 50%;\n --layout-sidenote-margin: -60%;\n --site-padding: 1.5rem;\n --content-gap: 1rem;\n --space-xl: 2rem;\n --space-2xl: 4rem;\n /*\n * Home timeline vertical rhythm — the single source of truth for the gaps\n * between stacked sections on the home page:\n *\n * site description → separator → first post → divider → post → ...\n *\n * where \"separator\" is the description hairline (logged out) or the compose\n * prompt (logged in). Every one of those gaps derives from this token, and\n * the individual pieces (compose prompt, description hairline, post cards)\n * carry no rhythm margin of their own — the structural wrappers\n * (.site-home-header, hr.feed-divider) own the spacing. Retune the whole\n * feed cadence by changing this one value.\n *\n * Note: per-format card padding (.feed-quote-post, thread previews) is the\n * card's own internal spacing and is intentionally NOT part of this rhythm.\n *\n * Kept as a free-standing value (not pinned to the --space-* scale) so the\n * feed cadence can be tuned independently.\n */\n --site-feed-rhythm: 4.4rem;\n /*\n * The post footer's action row (reply / menu buttons) is a taller tap\n * target than its visible content, leaving a few px of dead space below\n * the last visible element of every post (~5.9px logged out from the\n * footer min-height, ~6.8px logged in from the menu button). hr.feed-divider\n * subtracts this from its top margin so the VISIBLE gap between posts equals\n * --site-feed-rhythm — the same as the header spacing. Re-measure if the\n * footer button size or meta font changes.\n */\n --post-footer-overshoot: 6px;\n /*\n * The site intro (description) block is deliberately tighter than\n * --site-feed-rhythm so it reads as a compact header unit rather than a\n * full feed section. -top: gap from the header nav down to the intro.\n * -bottom: gap from the intro down to its separator — the hairline (logged\n * out) or the compose prompt text (logged in). Same values in both states.\n */\n --site-intro-gap-top: 24px;\n --site-intro-gap-bottom: 36px;\n\n /* Sidebar layout (admin + site sidebar pages) */\n --sidebar-width: 12rem;\n --sidebar-gap: 2rem;\n\n /* Surfaces */\n --card-bg: var(--card);\n --card-radius: 0;\n --card-padding: 1rem;\n --card-border-width: 0;\n --card-shadow: none;\n\n /* Elements */\n --avatar-size: 28px;\n --avatar-radius: 50%;\n --media-radius: 0.5rem;\n\n /* Icons */\n --icon-stroke: 2;\n --icon-stroke-fine: 1.5;\n\n /* Derived color tokens (from BaseCoat variables) */\n --site-accent: var(--primary);\n --site-accent-text: var(--primary-foreground);\n --site-column-outline: var(--border);\n --site-border-light: color-mix(\n in srgb,\n var(--site-column-outline) 52%,\n transparent\n );\n --site-threadline: var(--border);\n --site-page-bg: var(--background);\n --site-elevated-bg: var(--background);\n --site-nav-hover-bg: var(--accent);\n --site-text-primary: var(--foreground);\n --site-text-secondary: var(--muted-foreground);\n --site-reading-title: color-mix(\n in oklch,\n var(--site-text-primary) 81%,\n black\n );\n --site-reading-heading: color-mix(\n in oklch,\n var(--site-text-primary) 86%,\n black\n );\n --site-reading-body: color-mix(in oklch, var(--site-text-primary) 90%, black);\n --site-reading-quote: color-mix(\n in oklch,\n var(--site-text-primary) 95%,\n black\n );\n --site-reading-meta: color-mix(\n in srgb,\n var(--site-text-secondary) 72%,\n var(--site-text-primary)\n );\n --site-reading-caption: color-mix(\n in srgb,\n var(--site-text-secondary) 88%,\n var(--site-text-primary)\n );\n --site-content-link: inherit;\n --site-content-link-hover: var(--site-text-primary);\n --site-content-link-underline: color-mix(\n in srgb,\n var(--site-text-secondary) 58%,\n transparent\n );\n --site-reading-link: var(--site-reading-body);\n --site-reading-link-hover: var(--site-reading-heading);\n --site-reading-link-underline: color-mix(\n in srgb,\n var(--site-reading-meta) 58%,\n transparent\n );\n --site-text-placeholder: oklch(from var(--muted-foreground) l c h / 0.5);\n --site-media-outline: var(--border);\n --site-divider: var(--border);\n --site-feed-card-bg: color-mix(\n in srgb,\n var(--site-elevated-bg) 88%,\n var(--site-nav-hover-bg)\n );\n --site-feed-card-border: color-mix(\n in srgb,\n var(--site-divider) 78%,\n transparent\n );\n --site-feed-card-shadow: color-mix(\n in srgb,\n var(--site-text-primary) 12%,\n transparent\n );\n --site-code-text: color-mix(\n in srgb,\n var(--site-reading-heading) 86%,\n var(--site-reading-body)\n );\n --site-code-bg: color-mix(in srgb, var(--site-reading-meta) 12%, transparent);\n --site-code-block-bg: color-mix(\n in srgb,\n var(--site-elevated-bg) 94%,\n var(--site-nav-hover-bg)\n );\n --site-code-block-border: color-mix(\n in srgb,\n var(--site-divider) 62%,\n transparent\n );\n --site-feed-divider-color: color-mix(\n in srgb,\n var(--site-text-secondary) 30%,\n transparent\n );\n --site-feed-link-tint: color-mix(in srgb, var(--site-accent) 7%, transparent);\n --site-feed-quote-tint: color-mix(\n in srgb,\n var(--site-accent) 10%,\n transparent\n );\n --site-blockquote-rail: color-mix(\n in srgb,\n var(--site-accent) 22%,\n var(--site-divider)\n );\n --site-blockquote-bg: color-mix(\n in srgb,\n var(--site-feed-quote-tint) 62%,\n var(--site-page-bg)\n );\n --site-blockquote-text: color-mix(\n in oklch,\n var(--site-text-primary) 92%,\n black\n );\n --site-summary-blockquote-bg: color-mix(\n in srgb,\n var(--site-feed-quote-tint) 42%,\n var(--site-page-bg)\n );\n --site-reading-blockquote-rail: color-mix(\n in srgb,\n var(--site-reading-link) 18%,\n var(--site-reading-meta)\n );\n --site-reading-blockquote-bg: color-mix(\n in srgb,\n var(--site-accent) 6%,\n var(--site-page-bg)\n );\n --site-thread-context-bg: color-mix(\n in srgb,\n var(--site-nav-hover-bg) 58%,\n transparent\n );\n --site-thread-context-border: color-mix(\n in srgb,\n var(--site-divider) 74%,\n transparent\n );\n --site-thread-gap-bg: color-mix(\n in srgb,\n var(--site-nav-hover-bg) 42%,\n transparent\n );\n --site-thread-item-spacing: 32px;\n --site-thread-context-max-height: 160px;\n --site-thread-dot-ring: color-mix(\n in srgb,\n var(--site-accent) 16%,\n transparent\n );\n --compose-paper-bg: var(--site-page-bg);\n --compose-control-bg: color-mix(\n in srgb,\n var(--site-nav-hover-bg) 72%,\n var(--compose-paper-bg)\n );\n --compose-control-bg-strong: color-mix(\n in srgb,\n var(--site-nav-hover-bg) 88%,\n var(--compose-paper-bg)\n );\n --compose-control-border: color-mix(\n in srgb,\n var(--site-column-outline) 68%,\n transparent\n );\n --compose-blockquote-rail: color-mix(\n in srgb,\n var(--site-accent) 24%,\n var(--compose-control-border)\n );\n --compose-blockquote-bg: color-mix(\n in srgb,\n var(--compose-control-bg) 56%,\n var(--compose-paper-bg)\n );\n --compose-blockquote-bg-focus: color-mix(\n in srgb,\n var(--compose-control-bg-strong) 70%,\n var(--compose-paper-bg)\n );\n --compose-blockquote-text: color-mix(\n in srgb,\n var(--site-text-primary) 88%,\n var(--site-text-secondary)\n );\n --compose-floating-bg: color-mix(\n in srgb,\n var(--compose-paper-bg) 94%,\n var(--site-nav-hover-bg) 6%\n );\n\n /* Search highlight */\n --search-mark-bg: oklch(0.92 0.14 90 / 0.55);\n --search-mark-color: oklch(0.35 0.09 70);\n\n /* Admin */\n --dash-bg: oklch(0.97 0.005 80);\n --dash-card-radius: 10px;\n}\n\n@media (max-width: 760px) {\n :root {\n --site-padding: 1.875rem;\n }\n}\n\n/* Tufte two-column → single-column collapse.\n *\n * Below this width the post column is already narrowed to `min(100%, 35rem)`\n * (preset.css) and there is no room for a 45% sidenote gutter, so all content\n * goes full-width. Single images (MediaGallery getSingleVisualWidth) and link\n * previews (.link-preview) read this token directly, so they collapse here too.\n *\n * Keep this breakpoint in sync with the post-column collapse (preset.css /\n * ui.css feed-divider, both `max-width: 1024px`) and the sidenote float→inline\n * collapse (ui.css). They are one layout switch; do not let them drift apart. */\n@media (max-width: 1024px) {\n :root {\n --layout-content-width: 100%;\n }\n}\n\n/*\n * Dark-mode reading color overrides.\n *\n * These rules must beat the active color theme's light-mode block, which\n * uses `:root:root { ... }` (specificity 0,0,2,0) with no media query and\n * therefore applies in both light and dark modes. Most themes do not\n * redefine `--site-reading-*` in their dark block, so without higher\n * specificity here the light reading-body color would leak into dark mode\n * (resulting in near-invisible body text on a dark background).\n *\n * We repeat `:root:root` to reach specificity 0,0,3,0, which outranks the\n * theme's light `:root:root` (0,0,2,0). The theme's dark blocks use\n * `:root:root[data-theme-mode=\"dark\"]` or `:root:root:not([data-theme-mode=\"light\"])`\n * (also 0,0,3,0), so a theme that explicitly defines dark reading colors\n * still wins via source order.\n */\n@media (prefers-color-scheme: dark) {\n :root:root:not([data-theme-mode=\"light\"]) {\n --site-reading-title: var(--site-text-primary);\n --site-reading-heading: color-mix(\n in oklch,\n var(--site-text-primary) 94%,\n var(--site-text-secondary)\n );\n --site-reading-body: color-mix(\n in oklch,\n var(--site-text-primary) 96%,\n black\n );\n --site-reading-quote: color-mix(\n in oklch,\n var(--site-text-primary) 98%,\n black\n );\n --site-reading-meta: color-mix(\n in srgb,\n var(--site-text-secondary) 92%,\n var(--site-text-primary)\n );\n --site-reading-caption: color-mix(\n in srgb,\n var(--site-text-secondary) 96%,\n var(--site-text-primary)\n );\n --site-reading-link: var(--site-reading-body);\n --search-mark-bg: oklch(0.45 0.1 85 / 0.5);\n --search-mark-color: oklch(0.92 0.08 90);\n --dash-bg: oklch(0.2 0.005 80);\n }\n}\n\n:root:root[data-theme-mode=\"dark\"] {\n --site-reading-title: var(--site-text-primary);\n --site-reading-heading: color-mix(\n in oklch,\n var(--site-text-primary) 94%,\n var(--site-text-secondary)\n );\n --site-reading-body: color-mix(in oklch, var(--site-text-primary) 96%, black);\n --site-reading-quote: color-mix(\n in oklch,\n var(--site-text-primary) 98%,\n black\n );\n --site-reading-meta: color-mix(\n in srgb,\n var(--site-text-secondary) 92%,\n var(--site-text-primary)\n );\n --site-reading-caption: color-mix(\n in srgb,\n var(--site-text-secondary) 96%,\n var(--site-text-primary)\n );\n --site-reading-link: var(--site-reading-body);\n --search-mark-bg: oklch(0.45 0.1 85 / 0.5);\n --search-mark-color: oklch(0.92 0.08 90);\n --dash-bg: oklch(0.2 0.005 80);\n}\n\n@media (max-width: 760px), (hover: none) and (pointer: coarse) {\n :root {\n /* Content layer — tighter scale for mobile reading.\n Ratio ≈ 1.88 : 1.42 : 1.15 : 1 (display:title:subtitle:body).\n At 15px root × 0.8 content-scale: 29.4 / 22.2 / 18 / 15.6px.\n Body is floored to a 16px minimum below (max()) for readability;\n the floor still yields to calc() when the user zooms the root up. */\n --type-content-display: calc(2.45rem * var(--type-content-scale));\n --type-content-title: calc(1.85rem * var(--type-content-scale));\n --type-content-subtitle: calc(1.5rem * var(--type-content-scale));\n --type-content-body: max(16px, calc(1.3rem * var(--type-content-scale)));\n\n /* UI layer — pixel floors for touch targets */\n --type-ui-title: max(16px, var(--type-secondary));\n --type-ui-control: max(15px, var(--type-base));\n --type-ui-meta: max(15px, var(--type-secondary));\n --type-ui-hint: max(13px, var(--type-sm));\n --type-ui-caption: max(13px, var(--type-xs));\n --type-ui-micro: max(12px, var(--type-2xs));\n --type-ui-input: max(16px, var(--type-secondary));\n --type-thread-context: max(15px, var(--type-base));\n --type-thread-context-title: max(16px, var(--type-secondary));\n --type-thread-context-meta: max(14px, var(--type-sm));\n }\n}\n";
3306
+ var tokens_default = "/**\n * Design Tokens\n *\n * CSS custom properties for all visual aspects of the UI.\n * These are the stable customization API — override in custom CSS\n * to change typography, layout, surfaces, and element sizing.\n */\n\n:root {\n /* Typography — Font families */\n --font-cjk-serif-fallback:\n \"Songti SC\", STSong, SimSun, \"Songti TC\", PMingLiU, MingLiU,\n \"Noto Serif SC\", \"Noto Serif CJK SC\", \"Noto Serif TC\", \"Noto Serif CJK TC\";\n --font-body:\n system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n \"Helvetica Neue\", Helvetica, Arial, \"PingFang TC\", \"PingFang SC\",\n \"Hiragino Sans CNS\", \"Hiragino Sans GB\", \"Microsoft JhengHei\",\n \"Microsoft YaHei\", \"Noto Sans CJK TC\", \"Noto Sans CJK SC\", sans-serif;\n --font-heading:\n \"New York Small\", \"New York\", \"Iowan Old Style\", Charter,\n \"Bitstream Charter\", \"Source Serif 4\", Cambria, \"Sitka Text\", Georgia,\n var(--font-cjk-serif-fallback), ui-serif, serif;\n --font-site-title:\n \"New York Small\", \"New York\", \"Iowan Old Style\", Charter,\n \"Bitstream Charter\", \"Source Serif 4\", Cambria, \"Sitka Text\", Georgia,\n var(--font-cjk-serif-fallback), ui-serif, serif;\n --font-serif:\n var(--font-cjk-serif-fallback), ui-serif, \"New York Small\", \"New York\",\n \"Iowan Old Style\", Charter, Georgia, \"Times New Roman\", Times, serif;\n --font-ui:\n system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n \"Helvetica Neue\", Helvetica, Arial, \"PingFang TC\", \"PingFang SC\",\n \"Hiragino Sans CNS\", \"Hiragino Sans GB\", \"Microsoft JhengHei\",\n \"Microsoft YaHei\", \"Noto Sans CJK TC\", \"Noto Sans CJK SC\", sans-serif;\n --font-mono:\n ui-monospace, Menlo, Monaco, Consolas, \"Cascadia Code\", \"Courier New\",\n monospace;\n /*\n * Blockquote font family.\n *\n * Defaults to `inherit` so blockquotes follow the body font in sans-only\n * themes (Clean, Friendly, Bold) and serif-only themes (Tufte, Bookish).\n * Mixed themes that want a distinct blockquote voice — e.g. Classic, which\n * pairs a sans body with serif headings — override this token in their\n * `cssVariables` to point at a serif stack. This also restores a type-level\n * distinction for CJK, where italic is disabled.\n */\n --font-blockquote: inherit;\n\n /* Typography — Font weights */\n --fw-light: 300;\n --fw-regular: 400;\n --fw-medium: 500;\n --fw-semibold: 600;\n --fw-bold: 700;\n --fw-extrabold: 800;\n /*\n * Unified type scale.\n *\n * Every font-size in the system — reading content AND UI controls —\n * must reference one of these tokens. No raw rem/px values elsewhere.\n *\n * --type-display 2.7rem (40.5px) — page titles, h1\n * --type-title 2.1rem (31.5px) — h2, feed card titles\n * --type-subtitle 1.8rem (27px) — h3\n * --type-body 1.4rem (21px) — running text, form inputs\n * --type-secondary 1.1rem (16.5px) — meta, nav, sidenotes, UI labels\n * --type-base 1.0rem (15px) — UI buttons, controls\n * --type-sm 0.9rem (13.5px) — small UI text\n * --type-xs 0.8rem (12px) — captions, descriptions, chips\n * --type-2xs 0.65rem (9.75px) — tiny labels, file sizes, badges\n */\n --type-display: 2.7rem;\n --type-title: 2.1rem;\n --type-subtitle: 1.8rem;\n --type-body: 1.4rem;\n --type-secondary: 1.1rem;\n --type-base: 1rem;\n --type-sm: 0.9rem;\n --type-xs: 0.8rem;\n --type-2xs: 0.65rem;\n\n /* Content reading tokens — desktop maps to core scale,\n mobile overrides below cap sizes for small screens.\n --type-content-scale uniformly scales all content sizes\n without affecting UI controls. */\n --type-content-scale: 0.8;\n --type-content-display: calc(var(--type-display) * var(--type-content-scale));\n --type-content-title: calc(var(--type-title) * var(--type-content-scale));\n --type-content-subtitle: calc(\n var(--type-subtitle) * var(--type-content-scale)\n );\n --type-content-body: calc(var(--type-body) * var(--type-content-scale));\n --type-content-quote: calc(var(--type-content-body) * 1.16);\n --type-content-quote-leading: 1.4;\n\n /* Semantic aliases */\n --type-body-size: var(--type-content-body);\n --type-code: calc(var(--type-body-size) * 0.94);\n --type-code-block: calc(var(--type-body-size) * 0.9);\n --type-body-tracking: 0;\n --type-ui-title: var(--type-secondary);\n --type-ui-control: var(--type-base);\n --type-ui-meta: var(--type-base);\n --type-ui-hint: var(--type-sm);\n --type-ui-caption: var(--type-xs);\n --type-ui-micro: var(--type-2xs);\n --type-ui-input: var(--type-secondary);\n --type-thread-context: var(--type-base);\n --type-thread-context-title: var(--type-secondary);\n --type-thread-context-meta: var(--type-sm);\n --feed-note-title-size: calc(var(--type-content-body) * 1.36);\n --feed-note-title-leading: var(--type-heading-leading);\n --type-body-leading: 1.7;\n --type-display-leading: 1.15;\n --type-heading-leading: 1.15;\n --type-heading-weight: var(--fw-medium);\n --type-heading-tracking: 0;\n --type-display-weight: var(--fw-medium);\n --type-display-tracking: 0;\n --type-label-weight: var(--fw-medium);\n --type-label-tracking: 0.08em;\n\n /* Layout — Tufte proportional model */\n --content-max-width: 42rem;\n --form-max-width: 42rem;\n /* compose dialogs + feed content cap */\n --layout-body-max-width: 1088px;\n --layout-content-width: 55%;\n --layout-sidenote-width: 50%;\n --layout-sidenote-margin: -60%;\n --site-padding: 1.5rem;\n --content-gap: 1rem;\n --space-xl: 2rem;\n --space-2xl: 4rem;\n /*\n * Home timeline vertical rhythm — the single source of truth for the gaps\n * between stacked sections on the home page:\n *\n * site description → separator → first post → divider → post → ...\n *\n * where \"separator\" is the description hairline (logged out) or the compose\n * prompt (logged in). Every one of those gaps derives from this token, and\n * the individual pieces (compose prompt, description hairline, post cards)\n * carry no rhythm margin of their own — the structural wrappers\n * (.site-home-header, hr.feed-divider) own the spacing. Retune the whole\n * feed cadence by changing this one value.\n *\n * Note: per-format card padding (.feed-quote-post, thread previews) is the\n * card's own internal spacing and is intentionally NOT part of this rhythm.\n *\n * Kept as a free-standing value (not pinned to the --space-* scale) so the\n * feed cadence can be tuned independently.\n */\n --site-feed-rhythm: 4.4rem;\n /*\n * The post footer's action row (reply / menu buttons) is a taller tap\n * target than its visible content, leaving a few px of dead space below\n * the last visible element of every post (~5.9px logged out from the\n * footer min-height, ~6.8px logged in from the menu button). hr.feed-divider\n * subtracts this from its top margin so the VISIBLE gap between posts equals\n * --site-feed-rhythm — the same as the header spacing. Re-measure if the\n * footer button size or meta font changes.\n */\n --post-footer-overshoot: 6px;\n /*\n * The site intro (description) block is deliberately tighter than\n * --site-feed-rhythm so it reads as a compact header unit rather than a\n * full feed section. -top: gap from the header nav down to the intro.\n * -bottom: gap from the intro down to its separator — the hairline (logged\n * out) or the compose prompt text (logged in). Same values in both states.\n */\n --site-intro-gap-top: 24px;\n --site-intro-gap-bottom: 36px;\n\n /* Sidebar layout (admin + site sidebar pages) */\n --sidebar-width: 12rem;\n --sidebar-gap: 2rem;\n\n /* Surfaces */\n --card-bg: var(--card);\n --card-radius: 0;\n --card-padding: 1rem;\n --card-border-width: 0;\n --card-shadow: none;\n\n /* Elements */\n --avatar-size: 28px;\n --avatar-radius: 50%;\n --media-radius: 0.5rem;\n\n /* Icons */\n --icon-stroke: 2;\n --icon-stroke-fine: 1.5;\n\n /* Derived color tokens (from BaseCoat variables) */\n --site-accent: var(--primary);\n --site-accent-text: var(--primary-foreground);\n --site-column-outline: var(--border);\n --site-border-light: color-mix(\n in srgb,\n var(--site-column-outline) 52%,\n transparent\n );\n --site-threadline: var(--border);\n --site-page-bg: var(--background);\n --site-elevated-bg: var(--background);\n --site-nav-hover-bg: var(--accent);\n --site-text-primary: var(--foreground);\n --site-text-secondary: var(--muted-foreground);\n --site-reading-title: color-mix(\n in oklch,\n var(--site-text-primary) 81%,\n black\n );\n --site-reading-heading: color-mix(\n in oklch,\n var(--site-text-primary) 86%,\n black\n );\n --site-reading-body: color-mix(in oklch, var(--site-text-primary) 90%, black);\n --site-reading-quote: color-mix(\n in oklch,\n var(--site-text-primary) 95%,\n black\n );\n --site-reading-meta: color-mix(\n in srgb,\n var(--site-text-secondary) 72%,\n var(--site-text-primary)\n );\n --site-reading-caption: color-mix(\n in srgb,\n var(--site-text-secondary) 88%,\n var(--site-text-primary)\n );\n --site-content-link: inherit;\n --site-content-link-hover: var(--site-text-primary);\n --site-content-link-underline: color-mix(\n in srgb,\n var(--site-text-secondary) 58%,\n transparent\n );\n --site-reading-link: var(--site-reading-body);\n --site-reading-link-hover: var(--site-reading-heading);\n --site-reading-link-underline: color-mix(\n in srgb,\n var(--site-reading-meta) 58%,\n transparent\n );\n --site-text-placeholder: oklch(from var(--muted-foreground) l c h / 0.5);\n --site-media-outline: var(--border);\n --site-divider: var(--border);\n --site-feed-card-bg: color-mix(\n in srgb,\n var(--site-elevated-bg) 88%,\n var(--site-nav-hover-bg)\n );\n --site-feed-card-border: color-mix(\n in srgb,\n var(--site-divider) 78%,\n transparent\n );\n --site-feed-card-shadow: color-mix(\n in srgb,\n var(--site-text-primary) 12%,\n transparent\n );\n --site-code-text: color-mix(\n in srgb,\n var(--site-reading-heading) 86%,\n var(--site-reading-body)\n );\n --site-code-bg: color-mix(in srgb, var(--site-reading-meta) 12%, transparent);\n --site-code-block-bg: color-mix(\n in srgb,\n var(--site-elevated-bg) 94%,\n var(--site-nav-hover-bg)\n );\n --site-code-block-border: color-mix(\n in srgb,\n var(--site-divider) 62%,\n transparent\n );\n --site-feed-divider-color: color-mix(\n in srgb,\n var(--site-text-secondary) 30%,\n transparent\n );\n --site-feed-link-tint: color-mix(in srgb, var(--site-accent) 7%, transparent);\n --site-feed-quote-tint: color-mix(\n in srgb,\n var(--site-accent) 10%,\n transparent\n );\n --site-blockquote-rail: color-mix(\n in srgb,\n var(--site-accent) 22%,\n var(--site-divider)\n );\n --site-blockquote-bg: color-mix(\n in srgb,\n var(--site-feed-quote-tint) 62%,\n var(--site-page-bg)\n );\n --site-blockquote-text: color-mix(\n in oklch,\n var(--site-text-primary) 92%,\n black\n );\n --site-summary-blockquote-bg: color-mix(\n in srgb,\n var(--site-feed-quote-tint) 42%,\n var(--site-page-bg)\n );\n --site-reading-blockquote-rail: color-mix(\n in srgb,\n var(--site-reading-link) 18%,\n var(--site-reading-meta)\n );\n --site-reading-blockquote-bg: color-mix(\n in srgb,\n var(--site-accent) 6%,\n var(--site-page-bg)\n );\n --site-thread-context-bg: color-mix(\n in srgb,\n var(--site-nav-hover-bg) 58%,\n transparent\n );\n --site-thread-context-border: color-mix(\n in srgb,\n var(--site-divider) 74%,\n transparent\n );\n --site-thread-gap-bg: color-mix(\n in srgb,\n var(--site-nav-hover-bg) 42%,\n transparent\n );\n --site-thread-item-spacing: 32px;\n --site-thread-context-max-height: 160px;\n --site-thread-dot-ring: color-mix(\n in srgb,\n var(--site-accent) 16%,\n transparent\n );\n --compose-paper-bg: var(--site-page-bg);\n --compose-control-bg: color-mix(\n in srgb,\n var(--site-nav-hover-bg) 72%,\n var(--compose-paper-bg)\n );\n --compose-control-bg-strong: color-mix(\n in srgb,\n var(--site-nav-hover-bg) 88%,\n var(--compose-paper-bg)\n );\n --compose-control-border: color-mix(\n in srgb,\n var(--site-column-outline) 68%,\n transparent\n );\n --compose-blockquote-rail: color-mix(\n in srgb,\n var(--site-accent) 24%,\n var(--compose-control-border)\n );\n --compose-blockquote-bg: color-mix(\n in srgb,\n var(--compose-control-bg) 56%,\n var(--compose-paper-bg)\n );\n --compose-blockquote-bg-focus: color-mix(\n in srgb,\n var(--compose-control-bg-strong) 70%,\n var(--compose-paper-bg)\n );\n --compose-blockquote-text: color-mix(\n in srgb,\n var(--site-text-primary) 88%,\n var(--site-text-secondary)\n );\n --compose-floating-bg: color-mix(\n in srgb,\n var(--compose-paper-bg) 94%,\n var(--site-nav-hover-bg) 6%\n );\n\n /* Search highlight */\n --search-mark-bg: oklch(0.92 0.14 90 / 0.55);\n --search-mark-color: oklch(0.35 0.09 70);\n\n /* Admin */\n --dash-bg: oklch(0.97 0.005 80);\n --dash-card-radius: 10px;\n}\n\n@media (max-width: 760px) {\n :root {\n --site-padding: 1.875rem;\n }\n}\n\n/* Tufte two-column → single-column collapse.\n *\n * Below this width the post column is already narrowed to `min(100%, 35rem)`\n * (preset.css) and there is no room for a 45% sidenote gutter, so all content\n * goes full-width. Single images (MediaGallery getSingleVisualWidth) and link\n * previews (.link-preview) read this token directly, so they collapse here too.\n *\n * Keep this breakpoint in sync with the post-column collapse (preset.css /\n * ui.css feed-divider, both `max-width: 1024px`) and the sidenote float→inline\n * collapse (ui.css). They are one layout switch; do not let them drift apart. */\n@media (max-width: 1024px) {\n :root {\n --layout-content-width: 100%;\n }\n}\n\n/*\n * Dark-mode reading color overrides.\n *\n * These rules must beat the active color theme's light-mode block, which\n * uses `:root:root { ... }` (specificity 0,0,2,0) with no media query and\n * therefore applies in both light and dark modes. Most themes do not\n * redefine `--site-reading-*` in their dark block, so without higher\n * specificity here the light reading-body color would leak into dark mode\n * (resulting in near-invisible body text on a dark background).\n *\n * We repeat `:root:root` to reach specificity 0,0,3,0, which outranks the\n * theme's light `:root:root` (0,0,2,0). The theme's dark blocks use\n * `:root:root[data-theme-mode=\"dark\"]` or `:root:root:not([data-theme-mode=\"light\"])`\n * (also 0,0,3,0), so a theme that explicitly defines dark reading colors\n * still wins via source order.\n */\n@media (prefers-color-scheme: dark) {\n :root:root:not([data-theme-mode=\"light\"]) {\n --site-reading-title: var(--site-text-primary);\n --site-reading-heading: color-mix(\n in oklch,\n var(--site-text-primary) 94%,\n var(--site-text-secondary)\n );\n --site-reading-body: color-mix(\n in oklch,\n var(--site-text-primary) 96%,\n black\n );\n --site-reading-quote: color-mix(\n in oklch,\n var(--site-text-primary) 98%,\n black\n );\n --site-reading-meta: color-mix(\n in srgb,\n var(--site-text-secondary) 92%,\n var(--site-text-primary)\n );\n --site-reading-caption: color-mix(\n in srgb,\n var(--site-text-secondary) 96%,\n var(--site-text-primary)\n );\n --site-reading-link: var(--site-reading-body);\n --search-mark-bg: oklch(0.45 0.1 85 / 0.5);\n --search-mark-color: oklch(0.92 0.08 90);\n --dash-bg: oklch(0.2 0.005 80);\n }\n}\n\n:root:root[data-theme-mode=\"dark\"] {\n --site-reading-title: var(--site-text-primary);\n --site-reading-heading: color-mix(\n in oklch,\n var(--site-text-primary) 94%,\n var(--site-text-secondary)\n );\n --site-reading-body: color-mix(in oklch, var(--site-text-primary) 96%, black);\n --site-reading-quote: color-mix(\n in oklch,\n var(--site-text-primary) 98%,\n black\n );\n --site-reading-meta: color-mix(\n in srgb,\n var(--site-text-secondary) 92%,\n var(--site-text-primary)\n );\n --site-reading-caption: color-mix(\n in srgb,\n var(--site-text-secondary) 96%,\n var(--site-text-primary)\n );\n --site-reading-link: var(--site-reading-body);\n --search-mark-bg: oklch(0.45 0.1 85 / 0.5);\n --search-mark-color: oklch(0.92 0.08 90);\n --dash-bg: oklch(0.2 0.005 80);\n}\n\n@media (max-width: 760px), (hover: none) and (pointer: coarse) {\n :root {\n /* Content layer — tighter scale for mobile reading.\n Ratio ≈ 1.88 : 1.42 : 1.15 : 1 (display:title:subtitle:body).\n At 15px root × 0.8 content-scale: 29.4 / 22.2 / 18 / 15.6px.\n Body is floored to a 16px minimum below (max()) for readability;\n the floor still yields to calc() when the user zooms the root up. */\n --type-content-display: calc(2.45rem * var(--type-content-scale));\n --type-content-title: calc(1.85rem * var(--type-content-scale));\n --type-content-subtitle: calc(1.5rem * var(--type-content-scale));\n --type-content-body: max(16px, calc(1.3rem * var(--type-content-scale)));\n\n /* UI layer — pixel floors for touch targets */\n --type-ui-title: max(16px, var(--type-secondary));\n --type-ui-control: max(15px, var(--type-base));\n --type-ui-meta: max(15px, var(--type-secondary));\n --type-ui-hint: max(13px, var(--type-sm));\n --type-ui-caption: max(13px, var(--type-xs));\n --type-ui-micro: max(12px, var(--type-2xs));\n --type-ui-input: max(16px, var(--type-secondary));\n --type-thread-context: max(15px, var(--type-base));\n --type-thread-context-title: max(16px, var(--type-secondary));\n --type-thread-context-meta: max(14px, var(--type-sm));\n }\n}\n";
3299
3307
  //#endregion
3300
3308
  //#region src/services/export-theme/theme.toml?raw
3301
3309
  var theme_default = "name = \"jant\"\nlicense = \"MIT\"\nlicenselink = \"https://github.com/jant-me/jant/blob/main/LICENSE\"\ndescription = \"Default theme packaged with Jant exports.\"\nhomepage = \"https://jant.so\"\ntags = [\"blog\", \"microblog\", \"minimal\"]\nfeatures = [\"pagination\", \"aliases\"]\nmin_version = \"0.160.1\"\n\n[author]\n name = \"Jant\"\n homepage = \"https://jant.so\"\n";
@@ -3304,7 +3312,7 @@ var theme_default = "name = \"jant\"\nlicense = \"MIT\"\nlicenselink = \"https:/
3304
3312
  var main_default = "/*\n * Jant Hugo Export — main.css\n *\n * Fresh minimal text-first design. All colors, spacing, and type sizing\n * come from tokens.css (loaded first in the <head>). Color theme values\n * are supplied by theme.css; customizations live in custom.css.\n *\n * Load order in <head>: tokens.css → main.css → theme.css → custom.css\n *\n * This file intentionally avoids any hardcoded hex, rgb, or px color\n * values. Everything token-driven so the design evolves with the theme.\n */\n\n/* -------------------------------------------------------------------------\n * Reset + box model\n * ------------------------------------------------------------------------- */\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\nhtml {\n font-size: 15px;\n -webkit-text-size-adjust: 100%;\n text-size-adjust: 100%;\n}\n\nbody {\n margin: 0;\n font-family: var(--font-body);\n font-size: var(--type-body-size, var(--type-content-body));\n line-height: var(--type-body-leading);\n color: var(--site-reading-body);\n background-color: var(--site-page-bg);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nimg,\nvideo,\naudio,\niframe {\n max-width: 100%;\n height: auto;\n}\n\nfigure {\n margin: 0;\n}\n\nhr {\n border: 0;\n border-top: 1px solid var(--site-divider);\n margin: var(--space-xl) 0;\n}\n\n/* -------------------------------------------------------------------------\n * Typography\n * ------------------------------------------------------------------------- */\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-family: var(--font-heading);\n font-weight: var(--type-heading-weight);\n line-height: var(--type-heading-leading);\n letter-spacing: var(--type-heading-tracking);\n color: var(--site-reading-heading);\n margin: 1.6em 0 0.6em;\n}\n\nh1 {\n font-size: var(--type-content-display);\n line-height: var(--type-display-leading);\n font-weight: var(--type-display-weight);\n letter-spacing: var(--type-display-tracking);\n margin: 4rem 0 1.5rem;\n}\n\nh2 {\n font-size: var(--type-content-title);\n margin: 2.1rem 0 1.4rem;\n}\n\nh3 {\n font-size: var(--type-content-subtitle);\n margin: 2rem 0 1.4rem;\n}\n\nh4 {\n font-size: var(--type-content-body);\n font-weight: var(--fw-medium);\n}\n\nh5,\nh6 {\n font-size: var(--type-content-body);\n font-weight: var(--fw-medium);\n color: var(--site-reading-meta);\n}\n\np {\n margin: 1.4rem 0;\n}\n\nsmall {\n font-size: var(--type-sm);\n}\n\ncode,\nkbd,\nsamp {\n font-family: var(--font-mono);\n font-size: var(--type-code);\n line-height: 1.42;\n}\n\ncode {\n color: var(--site-code-text);\n overflow-wrap: break-word;\n}\n\npre {\n font-family: var(--font-mono);\n font-size: var(--type-code-block);\n line-height: 1.5;\n padding: 1rem;\n overflow-x: auto;\n color: var(--site-code-text);\n background-color: var(--site-code-block-bg);\n border: 1px solid var(--site-code-block-border);\n border-radius: 6px;\n}\n\npre code {\n padding: 0;\n background: transparent;\n border: 0;\n color: inherit;\n font-size: inherit;\n}\n\n:not(pre) > code {\n padding: 0.08em 0.28em;\n background-color: var(--site-code-bg);\n border-radius: 0.22em;\n box-decoration-break: clone;\n -webkit-box-decoration-break: clone;\n}\n\n/* Blockquotes — tinted background card with quote icon (matches main site). */\nblockquote {\n position: relative;\n margin: 1.4rem 0;\n padding: 1.4rem 1rem 0.75rem;\n border: none;\n background: var(--site-blockquote-bg);\n border-radius: 6px;\n color: var(--site-blockquote-text);\n font-family: var(--font-blockquote);\n font-style: italic;\n font-weight: inherit;\n quotes: none;\n text-wrap: pretty;\n}\n\nblockquote::before {\n content: \"\";\n display: block;\n width: 1.3rem;\n height: 1.3rem;\n margin-bottom: 0.35rem;\n background: var(--site-blockquote-rail);\n opacity: 0.6;\n mask-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 96 96' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M24.4 10.5C16.9 17.7 11.5 26.8 8.2 37.7C4.9 48.7 4.8 58.9 7.8 68.2C10.3 75.7 15.4 79.5 22.9 79.5C28 79.5 32.2 77.8 35.4 74.2C38.6 70.7 40.2 66.5 40.2 61.4C40.2 56.5 38.8 52.6 36 49.6C33.3 46.6 29.7 45.1 25.2 45.1C23.4 45.1 21.8 45.3 20.2 45.8C22.2 37.3 26.7 29.2 33.6 21.4L24.4 10.5Z'/%3E%3Cpath d='M60.8 10.5C53.3 17.7 47.9 26.8 44.6 37.7C41.3 48.7 41.2 58.9 44.2 68.2C46.7 75.7 51.8 79.5 59.3 79.5C64.4 79.5 68.6 77.8 71.8 74.2C75 70.7 76.6 66.5 76.6 61.4C76.6 56.5 75.2 52.6 72.4 49.6C69.7 46.6 66.1 45.1 61.6 45.1C59.8 45.1 58.2 45.3 56.6 45.8C58.6 37.3 63.1 29.2 70 21.4L60.8 10.5Z'/%3E%3C/svg%3E\");\n mask-size: contain;\n mask-repeat: no-repeat;\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 96 96' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M24.4 10.5C16.9 17.7 11.5 26.8 8.2 37.7C4.9 48.7 4.8 58.9 7.8 68.2C10.3 75.7 15.4 79.5 22.9 79.5C28 79.5 32.2 77.8 35.4 74.2C38.6 70.7 40.2 66.5 40.2 61.4C40.2 56.5 38.8 52.6 36 49.6C33.3 46.6 29.7 45.1 25.2 45.1C23.4 45.1 21.8 45.3 20.2 45.8C22.2 37.3 26.7 29.2 33.6 21.4L24.4 10.5Z'/%3E%3Cpath d='M60.8 10.5C53.3 17.7 47.9 26.8 44.6 37.7C41.3 48.7 41.2 58.9 44.2 68.2C46.7 75.7 51.8 79.5 59.3 79.5C64.4 79.5 68.6 77.8 71.8 74.2C75 70.7 76.6 66.5 76.6 61.4C76.6 56.5 75.2 52.6 72.4 49.6C69.7 46.6 66.1 45.1 61.6 45.1C59.8 45.1 58.2 45.3 56.6 45.8C58.6 37.3 63.1 29.2 70 21.4L60.8 10.5Z'/%3E%3C/svg%3E\");\n -webkit-mask-size: contain;\n -webkit-mask-repeat: no-repeat;\n}\n\nblockquote :where(p:first-of-type)::before,\nblockquote :where(p:last-of-type)::after {\n content: none;\n}\n\nblockquote > :first-child {\n margin-top: 0;\n}\n\nblockquote > :last-child {\n margin-bottom: 0;\n}\n\nblockquote p {\n margin: 0;\n}\n\nblockquote p + p,\nblockquote ul,\nblockquote ol,\nblockquote pre {\n margin-top: 0.6em;\n}\n\nblockquote cite {\n font-style: normal;\n color: var(--site-reading-meta);\n font-size: var(--type-sm);\n}\n\n/* CJK: no italic for blockquotes (no true italic glyph) */\n:lang(zh) blockquote,\n:lang(ja) blockquote,\n:lang(ko) blockquote {\n font-style: normal;\n}\n\nul,\nol {\n padding-left: 1.4em;\n margin: 1.25em 0;\n}\n\nli {\n margin-top: 0.65em;\n margin-bottom: 0.65em;\n}\n\n/* Normalize li > p so list spacing is controlled by li alone,\n regardless of whether the markdown renderer wraps li contents in <p>. */\nli > p:first-child {\n margin-top: 0;\n}\n\nli > p:last-child {\n margin-bottom: 0;\n}\n\na {\n color: var(--site-reading-link);\n text-decoration: underline;\n text-decoration-color: var(--site-reading-link-underline);\n text-underline-offset: 0.15em;\n transition:\n color 0.2s ease,\n text-decoration-color 0.2s ease;\n}\n\na:hover,\na:focus {\n color: var(--site-reading-link-hover);\n text-decoration-color: currentColor;\n}\n\na:focus-visible {\n outline: 2px solid var(--site-accent);\n outline-offset: 2px;\n border-radius: 2px;\n}\n\ntime {\n color: var(--site-reading-meta);\n font-size: var(--type-sm);\n font-variant-numeric: tabular-nums;\n}\n\n/* -------------------------------------------------------------------------\n * Page layout — Tufte horizontal frame\n *\n * Mirrors the main site's `.site-page > header/main/footer` rule. Every\n * top-level section gets the same asymmetric padding so the reading column\n * aligns with the rest of the site.\n *\n * 12.5% left + 4% right = 16.5% padding → content = 83.5% of the box.\n * max-width = body-max-width / 0.835 so the inner content area exactly\n * equals `--layout-body-max-width` on wide viewports. min() caps keep\n * padding from growing beyond 210px / 67px. Mobile widens to 5% / 5%\n * and the 55% content column collapses to 100% (via tokens.css).\n * ------------------------------------------------------------------------- */\n\n.site-page {\n min-height: 100vh;\n min-height: 100dvh;\n background-color: var(--site-page-bg);\n}\n\n.site-page > header,\n.site-page > main,\n.site-page > footer,\n.site-page > .home-branding-credit {\n width: 100%;\n max-width: calc(var(--layout-body-max-width) / 0.835);\n padding-left: min(12.5%, 210px);\n padding-right: min(4%, 67px);\n margin-left: auto;\n margin-right: auto;\n}\n\n@media (max-width: 760px) {\n .site-page > header,\n .site-page > main,\n .site-page > footer,\n .site-page > .home-branding-credit {\n padding-left: max(5%, 28px);\n padding-right: 5%;\n }\n}\n\n.site-main {\n padding-top: var(--space-xl);\n padding-bottom: var(--space-xl);\n}\n\n/* -------------------------------------------------------------------------\n * Header\n * ------------------------------------------------------------------------- */\n\n.site-header {\n padding-top: 24px;\n background-color: var(--site-page-bg);\n}\n\n@media (min-width: 700px) {\n .site-header {\n padding-top: 30px;\n }\n}\n\n.site-header-inner {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 0;\n}\n\n.site-header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: clamp(0.6rem, 2.2vw, 1rem);\n flex-wrap: nowrap;\n min-height: 2.75rem;\n width: 100%;\n}\n\n.site-header-top-bordered {\n padding-bottom: 15px;\n}\n\n@media (min-width: 700px) {\n .site-header-top-bordered {\n padding-bottom: 18px;\n }\n}\n\n.site-logo {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n gap: 10px;\n min-width: 0;\n padding: 0.15rem 0;\n font-family: var(--font-site-title);\n font-size: var(--type-subtitle);\n font-weight: var(--fw-regular);\n letter-spacing: -0.02em;\n line-height: 1.15;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--site-text-primary);\n text-decoration: none;\n}\n\n.site-logo:hover,\n.site-logo:focus {\n color: var(--site-text-primary);\n text-decoration: none;\n}\n\n.site-logo-avatar {\n box-sizing: border-box;\n width: calc(var(--avatar-size) + 4px);\n height: calc(var(--avatar-size) + 4px);\n border-radius: var(--avatar-radius);\n object-fit: cover;\n border: 1px solid color-mix(in srgb, var(--site-divider) 82%, transparent);\n flex: none;\n}\n\n.site-logo-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.site-header-nav {\n display: flex;\n align-items: center;\n flex-wrap: nowrap;\n justify-content: flex-end;\n gap: clamp(0.6rem, 2.2vw, 1rem);\n margin-left: auto;\n min-width: 0;\n font-family: var(--font-ui);\n}\n\n.site-header-link {\n display: inline-flex;\n flex: none;\n align-items: center;\n position: relative;\n min-height: 2rem;\n padding: 0.15rem 0;\n font-size: var(--type-ui-meta);\n font-weight: var(--fw-medium);\n letter-spacing: 0.01em;\n line-height: 1;\n white-space: nowrap;\n color: color-mix(in srgb, var(--site-text-secondary) 62%, transparent);\n text-decoration: none;\n transition: color 0.15s;\n}\n\n.site-header-link:hover,\n.site-header-link:focus {\n color: color-mix(\n in srgb,\n var(--site-text-primary) 84%,\n var(--site-text-secondary)\n );\n text-decoration: none;\n}\n\n.site-header-link-active {\n color: color-mix(\n in srgb,\n var(--site-text-primary) 84%,\n var(--site-text-secondary)\n );\n}\n\n/* --- \"More\" dropdown ---------------------------------------------------- */\n\n.site-header-more {\n position: relative;\n display: inline-flex;\n align-items: center;\n}\n\n.site-header-more-responsive-only {\n display: none;\n}\n\n.site-header-more-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.45rem;\n min-height: 2rem;\n padding: 0.15rem 0;\n border: none;\n background: transparent;\n cursor: pointer;\n font-family: var(--font-ui);\n font-size: var(--type-ui-meta);\n font-weight: var(--fw-medium);\n letter-spacing: 0.01em;\n line-height: 1;\n color: color-mix(in srgb, var(--site-text-secondary) 62%, transparent);\n transition: color 0.15s;\n}\n\n.site-header-more-btn svg {\n width: 0.82rem;\n height: 0.82rem;\n transition: transform 0.18s ease;\n}\n\n.site-header-more-btn:hover,\n.site-header-more-btn[aria-expanded=\"true\"] {\n color: color-mix(\n in srgb,\n var(--site-text-primary) 84%,\n var(--site-text-secondary)\n );\n}\n\n.site-header-more-btn[aria-expanded=\"true\"] svg {\n transform: rotate(180deg);\n}\n\n.site-header-more-popover {\n display: block;\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 0.6rem;\n min-width: 12.25rem;\n padding: 0.3rem 0;\n background: var(--site-page-bg);\n border: 0.5px solid color-mix(in srgb, var(--site-divider) 80%, transparent);\n border-radius: 0.4rem;\n box-shadow:\n 0 4px 20px -8px rgba(0, 0, 0, 0.12),\n 0 2px 6px -2px rgba(0, 0, 0, 0.06);\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n transform: translateY(-6px);\n transform-origin: top right;\n transition:\n opacity 0.18s ease,\n transform 0.18s ease,\n visibility 0s linear 0.18s;\n z-index: 50;\n}\n\n.site-header-more-popover[aria-hidden=\"false\"] {\n opacity: 1;\n visibility: visible;\n pointer-events: auto;\n transform: translateY(0);\n transition-delay: 0s;\n}\n\n.site-header-more-link {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.35rem;\n padding: 0.45rem 1rem;\n font-family: var(--font-ui);\n font-size: var(--type-ui-meta);\n color: var(--site-text-secondary);\n text-decoration: none;\n transition:\n color 0.15s,\n background-color 0.15s;\n}\n\n.site-header-more-link:hover,\n.site-header-more-link:focus {\n color: color-mix(\n in srgb,\n var(--site-text-primary) 84%,\n var(--site-text-secondary)\n );\n background: color-mix(in srgb, var(--site-nav-hover-bg) 58%, transparent);\n text-decoration: none;\n}\n\n.site-header-more-link-active {\n color: color-mix(\n in srgb,\n var(--site-text-primary) 84%,\n var(--site-text-secondary)\n );\n}\n\n.site-header-more-link-responsive,\n.site-header-more-divider-responsive {\n display: none;\n}\n\n.site-header-more-divider {\n height: 0;\n margin: 0.35rem 0.75rem;\n border-top: 0.5px solid\n color-mix(in srgb, var(--site-divider) 60%, transparent);\n}\n\n/* --- Tiered responsive collapse ---------------------------------------- *\n *\n * ≤960px — 5th+ inline link collapses into More (tier-lg)\n * ≤780px — also 4th collapses (tier-md)\n * ≤580px — also 3rd collapses (tier-sm)\n * The first two links always stay inline. No hamburger on static export —\n * at very narrow widths 2 inline links + More button is the floor.\n */\n\n@media (max-width: 960px) {\n .site-header-link-collapse-lg {\n display: none;\n }\n\n .site-header-more-responsive-only.site-header-more-tier-lg {\n display: inline-flex;\n }\n\n .site-header-more-link-show-lg {\n display: flex;\n }\n\n .site-header-more-divider-responsive {\n display: block;\n }\n}\n\n@media (max-width: 780px) {\n .site-header-link-collapse-md {\n display: none;\n }\n\n .site-header-more-responsive-only.site-header-more-tier-md {\n display: inline-flex;\n }\n\n .site-header-more-link-show-md {\n display: flex;\n }\n}\n\n@media (max-width: 580px) {\n .site-header-link-collapse-sm {\n display: none;\n }\n\n .site-header-more-responsive-only.site-header-more-tier-sm {\n display: inline-flex;\n }\n\n .site-header-more-link-show-sm {\n display: flex;\n }\n}\n\n/* -------------------------------------------------------------------------\n * Footer\n * ------------------------------------------------------------------------- */\n\n.site-footer {\n margin-top: var(--space-xl);\n padding-bottom: var(--space-xl);\n color: var(--site-text-secondary);\n font-size: var(--type-xs);\n background-color: var(--site-page-bg);\n}\n\n.site-footer-inner {\n border-top: 0.5px solid var(--site-divider);\n padding-top: var(--space-xl);\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.site-footer-content {\n color: var(--site-text-secondary);\n}\n\n.site-footer-content p {\n margin: 0 0 0.5em;\n}\n\n.site-footer-nav-list {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.home-branding-credit {\n margin-top: var(--space-xl);\n padding-bottom: var(--space-xl);\n text-align: center;\n color: var(--site-text-secondary);\n font-size: var(--type-base);\n}\n\n.home-branding-credit a {\n display: inline-flex;\n align-items: center;\n gap: 0.38rem;\n color: inherit;\n text-decoration: none;\n border-bottom: 0.5px solid\n color-mix(in srgb, var(--site-text-secondary) 45%, transparent);\n transition:\n color 160ms ease,\n border-color 160ms ease;\n}\n\n.home-branding-credit a:hover,\n.home-branding-credit a:focus-visible {\n color: var(--site-text-primary);\n border-color: currentColor;\n}\n\n/* -------------------------------------------------------------------------\n * Tufte content-width constraint\n *\n * Mirrors the main site's 55% rule: reading text occupies a narrow\n * column inside the Tufte frame, leaving a wide right margin that\n * would host sidenotes on the main site. Media (images, video, audio)\n * is NOT included — galleries intentionally span the full frame so\n * they can breathe.\n *\n * Mobile (<=760px): `--layout-content-width` collapses to 100% via\n * tokens.css. Tablet: cap at 35rem for readability.\n * ------------------------------------------------------------------------- */\n\n.section-header,\n.section-body,\n.post-card-title,\n.post-card-summary,\n.post-card-link-domain,\n.post-card-quote-content,\n.post-card-quote-attribution,\n.post-card-quote-commentary,\n.post-card-footer,\n.reply-title,\n.reply-body,\n.reply-link-domain,\n.reply-footer,\n.thread-title,\n.thread-body,\n.thread-link-domain,\n.thread-footer,\n.collection-directory,\n.pagination,\n.empty-state,\n.page-summary {\n width: var(--layout-content-width);\n max-width: 100%;\n}\n\n@media (min-width: 761px) and (max-width: 1024px) {\n .section-header,\n .section-body,\n .post-card-title,\n .post-card-summary,\n .post-card-link-domain,\n .post-card-quote-content,\n .post-card-quote-attribution,\n .post-card-quote-commentary,\n .post-card-footer,\n .reply-title,\n .reply-body,\n .reply-link-domain,\n .reply-footer,\n .thread-title,\n .thread-body,\n .thread-link-domain,\n .thread-footer,\n .collection-directory,\n .pagination,\n .empty-state,\n .page-summary {\n width: min(100%, 35rem);\n }\n}\n\n/* -------------------------------------------------------------------------\n * Section headers\n * ------------------------------------------------------------------------- */\n\n.section-header {\n margin-bottom: var(--space-xl);\n padding-bottom: 1rem;\n border-bottom: 1px solid var(--site-border-light);\n}\n\n.section-title {\n margin: 0 0 0.25em;\n}\n\n.section-summary {\n margin: 0;\n color: var(--site-reading-meta);\n font-size: var(--type-secondary);\n}\n\n.section-meta {\n margin: 0.5em 0 0;\n color: var(--site-reading-meta);\n font-size: var(--type-sm);\n}\n\n/* -------------------------------------------------------------------------\n * Post list + post cards\n * ------------------------------------------------------------------------- */\n\n.post-list {\n display: flex;\n flex-direction: column;\n gap: calc(var(--space-xl) * 1.25);\n}\n\n.post-list-pinned {\n margin-bottom: calc(var(--space-xl) * 1.25);\n padding-bottom: calc(var(--space-xl) * 1.25);\n border-bottom: 1px solid var(--site-border-light);\n}\n\n/* Decorative divider between posts in a timeline feed. Mirrors the main\n site's `hr.feed-divider`: a trio of small chevron marks masked from the\n current text color, so it picks up the theme automatically.\n `margin-left` centers the divider within the 55% reading column so it\n visually sits at the middle of the post-card text stack. */\nhr.feed-divider {\n border: none;\n width: 30px;\n height: 9px;\n margin: 0;\n margin-left: calc(var(--layout-content-width) / 2 - 15px);\n color: var(--site-feed-divider-color);\n background-color: currentColor;\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 45 13'%3E%3Cpath fill='black' transform='translate(0,0) rotate(90 6 6.5)' d='M6.765.5.177 6.093l2.61 5.966 8.39-3.17L6.765.5Z'/%3E%3Cpath fill='black' transform='translate(16,0) rotate(100 6 6.5)' d='M6.765.5.177 6.093l2.61 5.966 8.39-3.17L6.765.5Z'/%3E%3Cpath fill='black' transform='translate(32,0) rotate(80 6 6.5)' d='M6.765.5.177 6.093l2.61 5.966 8.39-3.17L6.765.5Z'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 45 13'%3E%3Cpath fill='black' transform='translate(0,0) rotate(90 6 6.5)' d='M6.765.5.177 6.093l2.61 5.966 8.39-3.17L6.765.5Z'/%3E%3Cpath fill='black' transform='translate(16,0) rotate(100 6 6.5)' d='M6.765.5.177 6.093l2.61 5.966 8.39-3.17L6.765.5Z'/%3E%3Cpath fill='black' transform='translate(32,0) rotate(80 6 6.5)' d='M6.765.5.177 6.093l2.61 5.966 8.39-3.17L6.765.5Z'/%3E%3C/svg%3E\");\n -webkit-mask-repeat: no-repeat;\n mask-repeat: no-repeat;\n -webkit-mask-position: center;\n mask-position: center;\n -webkit-mask-size: contain;\n mask-size: contain;\n}\n\n.post-card {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.post-card-title {\n font-family: var(--font-heading);\n font-size: var(--feed-note-title-size);\n font-weight: var(--type-heading-weight);\n line-height: var(--feed-note-title-leading);\n margin: 0;\n color: var(--site-reading-title);\n}\n\n.post-card-title a {\n color: inherit;\n text-decoration: none;\n}\n\n.post-card-title a:hover,\n.post-card-title a:focus {\n text-decoration: underline;\n text-underline-offset: 0.18em;\n}\n\n.post-card-summary {\n margin: 0;\n color: var(--site-reading-body);\n}\n\n.post-card > .post-card-summary :is(h1, h2),\n.post-card > .post-card-quote-commentary :is(h1, h2) {\n font-size: calc(var(--type-content-body) * 1.12);\n font-weight: var(--fw-medium);\n margin-top: 1.45rem;\n margin-bottom: 0.55rem;\n}\n\n.post-card > .post-card-summary :is(h3, h4),\n.post-card > .post-card-quote-commentary :is(h3, h4) {\n font-size: var(--type-content-body);\n font-weight: var(--fw-medium);\n margin-top: 1.2rem;\n margin-bottom: 0.45rem;\n}\n\n.post-card > .post-card-summary :is(h5, h6),\n.post-card > .post-card-quote-commentary :is(h5, h6) {\n font-size: var(--type-secondary);\n font-weight: var(--fw-medium);\n color: var(--site-text-secondary);\n margin-top: 1rem;\n margin-bottom: 0.35rem;\n}\n\n/* Link card domain row — shown ABOVE the title (matches main site's\n `.feed-link-domain` pattern). Inline flex with icon + host text. */\n.post-card-link-domain,\n.thread-link-domain,\n.reply-link-domain {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n max-width: 100%;\n margin: 0 0 0.4rem 0;\n font-family: var(--font-ui);\n font-size: var(--type-ui-meta);\n font-weight: var(--fw-regular);\n line-height: 1.3;\n color: var(--site-text-secondary);\n text-decoration: none;\n word-break: break-all;\n transition: color 0.18s ease;\n}\n\n.post-card-link-domain:hover,\n.post-card-link-domain:focus,\n.thread-link-domain:hover,\n.thread-link-domain:focus,\n.reply-link-domain:hover,\n.reply-link-domain:focus {\n color: var(--site-text-primary);\n}\n\n.post-card-link-domain-icon {\n width: 0.72rem;\n height: 0.72rem;\n flex-shrink: 0;\n}\n\n/* Slight extra breathing room below link-card titles to match main site. */\n.post-card-link-title,\n.thread-link-title,\n.reply-link-title {\n text-wrap: pretty;\n}\n\n.post-card-link-title a,\n.thread-link-title a,\n.reply-link-title a {\n text-decoration: none;\n}\n\n.post-card-link-title a:hover,\n.post-card-link-title a:focus,\n.thread-link-title a:hover,\n.thread-link-title a:focus,\n.reply-link-title a:hover,\n.reply-link-title a:focus {\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n\n.post-card-media,\n.reply-media,\n.thread-media {\n display: grid;\n grid-template-columns: 1fr;\n gap: 0.75rem;\n}\n\n.post-card-figure img,\n.reply-figure img,\n.thread-figure img {\n display: block;\n width: 100%;\n border-radius: var(--media-radius);\n border: 1px solid var(--site-media-outline);\n}\n\n.post-card-figure video,\n.reply-figure video,\n.thread-figure video {\n display: block;\n width: 100%;\n height: auto;\n border-radius: var(--media-radius);\n border: 1px solid var(--site-media-outline);\n background: #000;\n}\n\n.post-card-figure audio,\n.reply-figure audio,\n.thread-figure audio {\n display: block;\n width: 100%;\n}\n\n.post-card-figure-video a {\n position: relative;\n display: block;\n}\n\n.post-card-video-badge {\n position: absolute;\n left: 0.5rem;\n bottom: 0.5rem;\n padding: 0.125rem 0.5rem;\n font-size: var(--type-xs);\n color: #fff;\n background: rgba(0, 0, 0, 0.65);\n border-radius: 999px;\n pointer-events: none;\n}\n\n.thread-file a,\n.reply-file a {\n color: var(--site-link);\n text-decoration: underline;\n}\n\n/* -------------------------------------------------------------------------\n * Quote format — decorative mark, serif body, attribution line\n * ------------------------------------------------------------------------- */\n\n.post-card-quote {\n position: static;\n margin: 0;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: var(--site-reading-quote);\n font-family: inherit;\n font-style: normal;\n}\n\n/* Quote-format posts have their own decorative `.post-card-quote-mark`\n SVG inside the blockquote — suppress the global blockquote icon. */\n.post-card-quote::before {\n content: none;\n}\n\n.post-card-quote-mark {\n display: block;\n position: relative;\n width: 1.7rem;\n margin-bottom: -0.1rem;\n margin-left: -0.04rem;\n line-height: 0;\n pointer-events: none;\n color: color-mix(in srgb, var(--site-accent) 14%, var(--site-divider));\n opacity: 0.66;\n}\n\n.post-card-quote-mark svg {\n display: block;\n width: 100%;\n height: auto;\n}\n\n.post-card-quote-content {\n font-family: var(--font-serif);\n color: var(--site-text-primary);\n font-size: var(--type-content-quote);\n line-height: var(--type-content-quote-leading);\n white-space: pre-line;\n text-wrap: pretty;\n margin: 0;\n}\n\n.post-card-quote-attribution {\n display: flex;\n align-items: center;\n gap: 0.45rem;\n flex-wrap: wrap;\n margin-top: 0.95rem;\n color: var(--site-text-secondary);\n font-family: var(--font-ui);\n font-size: var(--type-ui-meta);\n font-style: normal;\n line-height: 1.3;\n}\n\n.post-card-quote-attribution::before {\n content: \"\";\n width: 0.9rem;\n height: 1px;\n background: color-mix(\n in srgb,\n var(--site-text-secondary) 38%,\n var(--site-divider)\n );\n}\n\n.post-card-quote-source {\n color: inherit;\n text-decoration: underline;\n text-decoration-color: color-mix(\n in srgb,\n var(--site-text-secondary) 55%,\n transparent\n );\n text-underline-offset: 3px;\n}\n\n.post-card-quote-source:hover,\n.post-card-quote-source:focus {\n color: var(--site-text-primary);\n text-decoration-color: currentColor;\n}\n\n.post-card-quote-commentary {\n position: relative;\n margin-top: 1.1rem;\n padding-top: 0.95rem;\n color: color-mix(\n in srgb,\n var(--site-text-secondary) 84%,\n var(--site-text-primary)\n );\n text-wrap: pretty;\n}\n\n.post-card-quote-commentary::before {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent 0%,\n color-mix(in srgb, var(--site-divider) 48%, transparent) 16%,\n color-mix(in srgb, var(--site-divider) 78%, transparent) 50%,\n color-mix(in srgb, var(--site-divider) 48%, transparent) 84%,\n transparent 100%\n );\n}\n\n.post-card-quote-commentary.prose > :first-child {\n margin-top: 0;\n}\n\n.post-card-quote-commentary.prose > :last-child {\n margin-bottom: 0;\n}\n\n.post-card-quote-commentary p {\n margin: 0;\n}\n\n.post-card-quote-commentary p + p,\n.post-card-quote-commentary ul,\n.post-card-quote-commentary ol,\n.post-card-quote-commentary blockquote,\n.post-card-quote-commentary pre {\n margin-top: 0.55rem;\n}\n\n/* Fade the post meta on quote cards so the quote body stays visually primary. */\n.post-card-quote ~ .post-card-footer,\n.post-card-quote-commentary + .post-card-footer {\n opacity: 0.72;\n}\n\n/* -------------------------------------------------------------------------\n * Post footer — meta (featured, time, external link, collections, pinned)\n * ------------------------------------------------------------------------- */\n\n.post-card-footer,\n.reply-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 10px;\n min-height: 2rem;\n font-size: var(--type-ui-hint);\n}\n\n.post-footer-detail {\n margin-top: 24px;\n /* Match the feed/reply footer size so the root post's footer doesn't\n visually dominate. Main site uses a larger size because every post\n on the detail page is rendered at detail size; here only the root\n post gets this class, which otherwise creates a mismatch with the\n replies below. */\n font-size: var(--type-ui-hint);\n color: var(--site-text-secondary);\n}\n\n.post-footer-meta {\n display: flex;\n flex: 1 1 auto;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n min-width: 0;\n font-family: var(--font-ui);\n line-height: 1.35;\n color: var(--site-text-secondary);\n}\n\n.post-footer-meta time {\n font-size: inherit;\n color: inherit;\n}\n\n.post-footer-featured {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: color-mix(\n in srgb,\n var(--search-mark-color) 72%,\n var(--site-text-secondary)\n );\n flex-shrink: 0;\n}\n\n.post-footer-featured svg {\n width: 1rem;\n height: 1rem;\n opacity: 0.9;\n}\n\n.post-footer-link {\n color: var(--site-text-secondary);\n text-decoration: none;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.post-footer-link:hover,\n.post-footer-link:focus {\n color: var(--site-text-primary);\n text-decoration: underline;\n}\n\n.post-footer-external-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 0.6rem;\n color: var(--site-text-secondary);\n text-decoration: none;\n transition:\n color 0.18s ease,\n background-color 0.16s ease;\n flex-shrink: 0;\n}\n\n.post-footer-external-link:hover,\n.post-footer-external-link:focus {\n color: var(--site-text-primary);\n}\n\n.post-footer-external-link svg {\n width: 1rem;\n height: 1rem;\n}\n\n.post-collection-tags {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n min-width: 0;\n max-width: 100%;\n color: var(--site-text-secondary);\n}\n\n.post-collection-tag {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n color: inherit;\n text-decoration: none;\n min-width: 0;\n max-width: min(100%, 22ch);\n}\n\n.post-collection-tag:hover,\n.post-collection-tag:focus {\n color: var(--site-text-primary);\n text-decoration: underline;\n text-underline-offset: 0.18em;\n}\n\n.post-collection-tag-text {\n display: block;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.post-card-pin {\n font-size: var(--type-2xs);\n text-transform: uppercase;\n letter-spacing: var(--type-label-tracking);\n color: var(--site-accent);\n border: 1px solid var(--site-accent);\n padding: 0.1em 0.5em;\n border-radius: 999px;\n flex-shrink: 0;\n}\n\n/* -------------------------------------------------------------------------\n * Thread preview (list pages: root context + hero latest reply)\n *\n * Mirrors the main site's `.thread-group.thread-group-preview` layout:\n * content sits flush-left inside the preview, and the vertical rail +\n * dot markers are positioned OUTSIDE the content (overflowing into the\n * container's left gutter) via a negative `left` on the rail/dots.\n * ------------------------------------------------------------------------- */\n\n.thread-preview {\n /* Rail position: negative = overflow outside content. Mirrors\n `--site-thread-rail-line-left` on the main site. */\n --thread-rail-left: -27px;\n --thread-rail-width: 1px;\n --thread-rail-indent: 0px;\n --thread-dot-size: 10px;\n --thread-dot-ring-width: 2px;\n --thread-dot-border-width: 2px;\n --thread-hero-dot-size: 14px;\n --thread-hero-dot-border-width: 3px;\n --thread-item-spacing: 0.35rem;\n\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 0.6rem;\n padding-left: var(--thread-rail-indent);\n}\n\n@media (max-width: 760px) {\n .thread-preview {\n --thread-rail-left: -11px;\n --thread-rail-indent: 8px;\n }\n}\n\n/* Continuous vertical rail — subtle gradient so the line fades into\n whitespace at the top and tail. Sits outside the content via negative\n `left`. */\n.thread-preview::before {\n content: \"\";\n position: absolute;\n left: var(--thread-rail-left);\n top: 0;\n bottom: 0;\n width: var(--thread-rail-width);\n background: linear-gradient(\n 180deg,\n transparent 0,\n color-mix(in srgb, var(--site-threadline) 85%, transparent) 8%,\n color-mix(in srgb, var(--site-threadline) 55%, transparent) 100%\n );\n pointer-events: none;\n}\n\n.thread-preview-context {\n position: relative;\n display: flex;\n flex-direction: column;\n /* Match runtime `.thread-group-preview .thread-item` which uses\n `padding: var(--site-thread-item-spacing) 0` — adjacent items have\n 2x the token between them, so the flex `gap` here is 2x to match. */\n gap: calc(var(--site-thread-item-spacing) * 2);\n margin: 0;\n padding: 0;\n border-left: 0;\n}\n\n/* Individual entry in a thread preview — wraps a full `.post-card` so\n the root, second, and penultimate replies render with their own\n title/body/footer. Dot marker sits on the rail at the card's\n vertical midpoint. */\n.thread-preview .thread-item {\n position: relative;\n min-width: 0;\n max-width: 100%;\n}\n\n.thread-preview .thread-item::before {\n content: \"\";\n position: absolute;\n left: calc(\n var(--thread-rail-left) + var(--thread-rail-width) / 2 -\n var(--thread-dot-size) / 2 - var(--thread-rail-indent)\n );\n top: 1.4rem;\n width: var(--thread-dot-size);\n height: var(--thread-dot-size);\n border-radius: 50%;\n background-color: var(--site-threadline);\n border: var(--thread-dot-border-width) solid var(--site-page-bg);\n box-shadow: 0 0 0 var(--thread-dot-ring-width) var(--site-thread-dot-ring);\n z-index: 1;\n}\n\n/* Gap \"N more posts\" row has no card so we place the marker at its\n vertical midpoint instead of the card's top area. Swap the single dot\n for a short column of small beads (a vertical \"⋮\") so the rail visibly\n \"skips\" a run of posts — mirrors the main site's `.thread-item-gap`. */\n.thread-preview .thread-item-gap {\n display: flex;\n align-items: center;\n padding: 0.15rem 0 0.35rem;\n}\n\n.thread-preview .thread-item-gap::before {\n top: 50%;\n transform: translateY(-50%);\n left: calc(\n var(--thread-rail-left) + var(--thread-rail-width) / 2 - 2px -\n var(--thread-rail-indent)\n );\n width: 4px;\n height: 24px;\n border: 0;\n border-radius: 0;\n background: radial-gradient(\n circle,\n var(--site-threadline) 1.75px,\n transparent 2px\n );\n background-size: 4px 8px;\n background-repeat: repeat-y;\n background-position: center top;\n box-shadow: none;\n}\n\n/* Hidden-posts count — a calm route into the thread, matching the main\n site's `.thread-gap-link`: styled like a sibling of the Show more toggle\n with a small right-pointing chevron rather than an underline, firming up\n to the primary text colour on hover. */\n.thread-preview-gap {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n align-self: flex-start;\n margin: 0.15rem 0;\n padding: 0.25rem 0;\n color: var(--site-text-secondary);\n font-size: var(--type-thread-context-meta);\n font-weight: 500;\n line-height: 1.2;\n text-decoration: none;\n transition: color 0.18s ease;\n}\n\n.thread-preview-gap::after {\n content: \"\";\n width: 0.36em;\n height: 0.36em;\n border: 1.5px solid currentColor;\n border-left: 0;\n border-bottom: 0;\n opacity: 0.65;\n transform: rotate(45deg);\n transition:\n transform 0.18s ease,\n opacity 0.18s ease;\n}\n\n.thread-preview-gap:hover,\n.thread-preview-gap:focus {\n color: var(--site-text-primary);\n}\n\n.thread-preview-gap:hover::after,\n.thread-preview-gap:focus::after {\n opacity: 1;\n transform: translateX(2px) rotate(45deg);\n}\n\n/* Hero (latest reply) row: spacing above and below matches the main\n site's `.thread-item-hero`, and the dot is larger + accent-colored. */\n.thread-preview-hero {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n padding-top: calc(var(--space-xl) * 1.1);\n margin-top: 0;\n}\n\n.thread-preview .thread-item-hero::before {\n left: calc(\n var(--thread-rail-left) + var(--thread-rail-width) / 2 -\n var(--thread-hero-dot-size) / 2 - var(--thread-rail-indent)\n );\n top: calc(var(--space-xl) * 1.1 + 1.4rem);\n width: var(--thread-hero-dot-size);\n height: var(--thread-hero-dot-size);\n background-color: var(--site-accent);\n border-width: var(--thread-hero-dot-border-width);\n}\n\n.thread-preview-thread-link {\n align-self: flex-start;\n font-size: var(--type-sm);\n color: var(--site-reading-meta);\n text-decoration: none;\n}\n\n.thread-preview-thread-link:hover,\n.thread-preview-thread-link:focus {\n color: var(--site-text-primary);\n text-decoration: underline;\n}\n\n/* -------------------------------------------------------------------------\n * Thread (single post page with inline replies)\n * ------------------------------------------------------------------------- */\n\n.thread {\n /* Rail variables match `.thread-preview` so the detail-page rail\n shares the same visual position. */\n --thread-rail-left: -27px;\n --thread-rail-width: 1px;\n --thread-rail-indent: 0px;\n --thread-dot-size: 10px;\n --thread-dot-ring-width: 2px;\n --thread-dot-border-width: 2px;\n --thread-hero-dot-size: 14px;\n --thread-hero-dot-border-width: 3px;\n\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 1.25rem;\n padding-left: var(--thread-rail-indent);\n}\n\n@media (max-width: 760px) {\n .thread {\n --thread-rail-left: -11px;\n --thread-rail-indent: 8px;\n }\n}\n\n/* Continuous vertical rail spanning the entire thread (root post + replies).\n Only shown when the root post actually has replies — a lone post should\n not have a rail or dot. Matches `.thread-preview`. */\n.thread-has-replies::before {\n content: \"\";\n position: absolute;\n left: var(--thread-rail-left);\n top: 0;\n bottom: 0;\n width: var(--thread-rail-width);\n background: linear-gradient(\n 180deg,\n transparent 0,\n color-mix(in srgb, var(--site-threadline) 85%, transparent) 8%,\n color-mix(in srgb, var(--site-threadline) 55%, transparent) 100%\n );\n pointer-events: none;\n}\n\n/* Dot marker for each post in the thread (root + replies). Shown only when\n there are replies so a solo post doesn't get an orphaned dot. */\n.thread .thread-item {\n position: relative;\n min-width: 0;\n max-width: 100%;\n}\n\n.thread-has-replies .thread-item::before {\n content: \"\";\n position: absolute;\n left: calc(\n var(--thread-rail-left) + var(--thread-rail-width) / 2 -\n var(--thread-dot-size) / 2 - var(--thread-rail-indent)\n );\n top: 1.4rem;\n width: var(--thread-dot-size);\n height: var(--thread-dot-size);\n border-radius: 50%;\n background-color: var(--site-threadline);\n border: var(--thread-dot-border-width) solid var(--site-page-bg);\n box-shadow: 0 0 0 var(--thread-dot-ring-width) var(--site-thread-dot-ring);\n z-index: 1;\n}\n\n.thread-item-root {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.thread-header {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.thread-title {\n font-family: var(--font-heading);\n font-size: var(--type-content-display);\n font-weight: var(--type-display-weight);\n line-height: var(--type-display-leading);\n margin: 0;\n color: var(--site-reading-title);\n}\n\n.thread-title a {\n color: inherit;\n text-decoration: none;\n}\n\n.thread-title a:hover,\n.thread-title a:focus {\n text-decoration: underline;\n text-underline-offset: 0.18em;\n}\n\n.thread-body {\n font-size: var(--type-content-body);\n line-height: var(--type-body-leading);\n color: var(--site-reading-body);\n}\n\n.thread-body > :first-child {\n margin-top: 0;\n}\n\n.thread-body > :last-child {\n margin-bottom: 0;\n}\n\n.thread-replies {\n /* Flex container for replies. The rail and dots are provided by\n `.thread::before` and `.thread-item::before` so replies stay visually\n connected to the root post. */\n display: flex;\n flex-direction: column;\n gap: var(--space-xl);\n}\n\n/* -------------------------------------------------------------------------\n * Replies\n * ------------------------------------------------------------------------- */\n\n.reply {\n scroll-margin-top: 1.5rem;\n display: flex;\n flex-direction: column;\n gap: 0.6rem;\n}\n\n.reply:target {\n background-color: var(--search-mark-bg);\n border-radius: 0.25rem;\n padding: 0.75rem 1rem;\n margin-left: -1rem;\n margin-right: -1rem;\n}\n\n.reply:target::before {\n background-color: var(--site-accent);\n}\n\n.reply-title {\n font-family: var(--font-heading);\n font-size: var(--type-content-subtitle);\n font-weight: var(--type-heading-weight);\n line-height: var(--type-heading-leading);\n margin: 0;\n color: var(--site-reading-heading);\n}\n\n.reply-body {\n color: var(--site-reading-body);\n}\n\n.reply-body > :first-child {\n margin-top: 0;\n}\n\n.reply-body > :last-child {\n margin-bottom: 0;\n}\n\n/* -------------------------------------------------------------------------\n * Collections page\n *\n * Mirrors the main site's authenticated-less collections view\n * (`ui/pages/CollectionsPage.tsx` + `ui/shared/CollectionDirectory.tsx`):\n * a page-intro block with count, then a two-column grid per row where a\n * monospace sequence label sits beside the collection title, description,\n * and entry/activity meta.\n * ------------------------------------------------------------------------- */\n\n.collections-page-shell {\n position: relative;\n display: flex;\n flex-direction: column;\n width: var(--layout-content-width);\n max-width: 100%;\n gap: clamp(1.25rem, 3vw, 1.75rem);\n}\n\n@media (min-width: 761px) and (max-width: 1024px) {\n .collections-page-shell {\n width: min(100%, 35rem);\n }\n}\n\n@media (max-width: 760px) {\n .collections-page-shell {\n width: 100%;\n }\n}\n\n.collections-page-header {\n position: relative;\n display: flex;\n align-items: flex-start;\n padding-bottom: 0.2rem;\n}\n\n.collections-page-heading {\n min-width: 0;\n flex: 1 1 18rem;\n}\n\n.page-intro {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding-bottom: 0.1rem;\n}\n\n.page-intro-title-row {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: 0.7rem;\n min-width: 0;\n}\n\n.page-intro-title {\n margin: 0;\n font-family: var(--font-heading);\n font-size: var(--type-title, 2rem);\n font-weight: var(--type-heading-weight);\n line-height: 1.15;\n letter-spacing: -0.01em;\n color: var(--site-text-primary);\n}\n\n.page-intro-meta-row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem 1rem;\n}\n\n.page-intro-meta,\n.page-intro-description {\n margin: 0;\n color: var(--site-text-secondary);\n font-family: var(--font-ui);\n font-size: var(--type-secondary);\n line-height: 1.3;\n}\n\n.collection-directory {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 0.15rem;\n list-style: none;\n padding: 0;\n margin: 0;\n}\n\n.collection-directory-item {\n position: relative;\n display: flex;\n align-items: flex-start;\n gap: 0.75rem;\n padding: 0.95rem 0;\n background: transparent;\n text-decoration: none;\n}\n\n.collection-directory-main {\n --collection-directory-sequence-width: 3.5ch;\n --collection-directory-title-line-height: 1.18;\n min-width: 0;\n flex: 1;\n display: grid;\n grid-template-columns: var(--collection-directory-sequence-width) minmax(\n 0,\n 1fr\n );\n align-items: start;\n column-gap: 0.8rem;\n row-gap: 0.25rem;\n}\n\n.collection-directory-sequence {\n grid-column: 1;\n grid-row: 1;\n display: block;\n width: var(--collection-directory-sequence-width);\n padding-top: 0.2rem;\n font-family: var(--font-mono);\n font-size: var(--type-xs);\n font-variant-numeric: tabular-nums;\n line-height: var(--collection-directory-title-line-height);\n letter-spacing: 0.14em;\n color: var(--site-text-secondary);\n}\n\n.collection-directory-title-row {\n grid-column: 2;\n grid-row: 1;\n min-width: 0;\n display: flex;\n align-items: flex-start;\n}\n\n.collection-directory-title-link {\n color: inherit;\n text-decoration: none;\n transition: color 0.15s ease;\n}\n\n.collection-directory-title-link:hover,\n.collection-directory-title-link:focus-visible {\n color: var(--site-text-primary);\n}\n\n.collection-directory-title-link:hover .collection-directory-title,\n.collection-directory-title-link:focus-visible .collection-directory-title {\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n\n.collection-directory-title {\n min-width: 0;\n display: inline-flex;\n align-items: center;\n gap: 0.45rem;\n font-family: var(--font-heading);\n font-size: var(--type-content-body);\n font-weight: var(--type-heading-weight);\n line-height: var(--collection-directory-title-line-height);\n letter-spacing: -0.02em;\n text-wrap: pretty;\n}\n\n.collection-directory-title-marker {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 0.95rem;\n min-width: 0.95rem;\n height: 0.95rem;\n color: var(--site-text-secondary);\n transition: color 0.15s ease;\n}\n\n.collection-directory-title-link:hover .collection-directory-title-marker,\n.collection-directory-title-link:focus-visible\n .collection-directory-title-marker {\n color: var(--site-text-primary);\n}\n\n.collection-directory-description {\n grid-column: 2;\n grid-row: 2;\n margin: 0;\n color: color-mix(in srgb, var(--site-text-secondary) 80%, transparent);\n font-family: var(--font-body);\n font-size: var(--type-sm);\n line-height: 1.45;\n}\n\n.collection-directory-description :where(p) {\n margin-top: 0.25em;\n margin-bottom: 0.25em;\n}\n\n/* Links inside the description inherit the description color so they sit in\n the same gray tone as the copy around them (matches the main site's\n `.prose { --tw-prose-links: var(--site-content-link); }` which resolves\n to `inherit`). The underline stays, drawn in currentColor. */\n.collection-directory-description :where(a) {\n color: inherit;\n text-decoration: underline;\n text-decoration-color: currentColor;\n text-underline-offset: 0.15em;\n}\n\n.collection-directory-description :where(a:hover),\n.collection-directory-description :where(a:focus-visible) {\n color: var(--site-text-primary);\n}\n\n.collection-directory-description :where(p:first-child) {\n margin-top: 0;\n}\n\n.collection-directory-description :where(p:last-child) {\n margin-bottom: 0;\n}\n\n.collection-directory-description + .collection-directory-summary {\n grid-row: 3;\n}\n\n.collection-directory-summary {\n grid-column: 2;\n grid-row: 2;\n display: flex;\n min-width: 0;\n overflow: hidden;\n align-items: center;\n gap: 0.2rem 0.5rem;\n margin: 0;\n color: var(--site-reading-meta);\n font-family: var(--font-ui);\n font-size: var(--type-sm);\n line-height: 1.3;\n white-space: nowrap;\n}\n\n.collection-directory-meta {\n flex: 0 0 auto;\n color: inherit;\n}\n\n.collection-directory-meta-separator {\n flex: 0 0 auto;\n color: color-mix(in srgb, var(--site-divider) 88%, transparent);\n}\n\n.collection-directory-updated {\n flex: 0 0 auto;\n color: inherit;\n white-space: nowrap;\n}\n\n.collection-directory-divider {\n padding: 1.5rem 0 0.85rem;\n}\n\n.collection-directory-divider-row {\n display: flex;\n align-items: center;\n gap: 0.95rem;\n}\n\n.collection-directory-divider-text {\n font-family: var(--font-heading);\n font-size: var(--type-secondary);\n letter-spacing: 0;\n font-style: normal;\n white-space: nowrap;\n color: var(--site-text-secondary);\n}\n\n.collection-directory-divider-line {\n flex: 1;\n height: 1px;\n border: none;\n margin: 0;\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, var(--site-divider) 100%, transparent),\n color-mix(in srgb, var(--site-divider) 54%, transparent) 34%,\n transparent 86%\n );\n}\n\n/* -------------------------------------------------------------------------\n * Pagination\n * ------------------------------------------------------------------------- */\n\n.pagination {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-wrap: wrap;\n gap: 1rem;\n padding: 1.5rem 0;\n font-size: var(--type-sm);\n font-variant-numeric: tabular-nums;\n}\n\n.pagination-link {\n color: var(--site-text-secondary);\n text-decoration: underline;\n text-underline-offset: 3px;\n transition: color 0.15s ease;\n}\n\n.pagination-link:hover,\n.pagination-link:focus {\n color: var(--site-text-primary);\n}\n\n.pagination-link.is-disabled {\n color: color-mix(in srgb, var(--site-text-secondary) 50%, transparent);\n cursor: default;\n text-decoration: none;\n}\n\n.pagination-current {\n color: var(--site-text-primary);\n font-weight: var(--fw-medium);\n}\n\n.pagination-ellipsis {\n color: var(--site-text-secondary);\n}\n\n/* -------------------------------------------------------------------------\n * Empty states + utility\n * ------------------------------------------------------------------------- */\n\n.empty-state {\n color: var(--site-reading-meta);\n font-style: italic;\n text-align: center;\n padding: var(--space-xl) 0;\n}\n\n.page,\n.section {\n display: block;\n}\n\n.page-summary,\n.section-summary {\n font-size: var(--type-secondary);\n color: var(--site-reading-meta);\n}\n\n/* -------------------------------------------------------------------------\n * Wider viewport refinements\n * ------------------------------------------------------------------------- */\n\n@media (min-width: 768px) {\n .site-main {\n padding-top: calc(var(--space-xl) * 1.5);\n padding-bottom: calc(var(--space-xl) * 1.5);\n }\n\n .post-card-media,\n .thread-media,\n .reply-media {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n\n .post-card-media:has(> :only-child),\n .thread-media:has(> :only-child),\n .reply-media:has(> :only-child) {\n grid-template-columns: 1fr;\n }\n}\n";
3305
3313
  //#endregion
3306
3314
  //#region src/services/export-theme/assets/client-site.js?raw
3307
- var client_site_default$1 = "var e=null,t=0,n=!1,r=null,i=null,a=0;function o(e){return!isFinite(e)||e<0?`0:00`:`${Math.floor(e/60)}:${String(Math.floor(e%60)).padStart(2,`0`)}`}function s(e){return e.querySelector(`audio.media-audio-el`)}function c(e){return e.querySelector(`[data-audio-range]`)}function l(e){return e.querySelector(`[data-audio-waveform]`)}function u(e,t){let n=`${(t*100).toFixed(1)}%`;e.style.background=`linear-gradient(to right, var(--site-text-primary) ${n}, transparent ${n})`}var d=new WeakMap,f=new WeakSet;async function p(e,t){let n=await(await fetch(e)).arrayBuffer(),r=new AudioContext;try{let e=(await r.decodeAudioData(n)).getChannelData(0),i=Math.max(1,Math.floor(e.length/t)),a=Array(t);for(let n=0;n<t;n++){let t=0,r=n*i,o=Math.min(r+i,e.length);for(let n=r;n<o;n++){let r=Math.abs(e[n]);r>t&&(t=r)}a[n]=t}let o=0;for(let e of a)e>o&&(o=e);if(o>0)for(let e=0;e<t;e++)a[e]/=o;return a}finally{await r.close()}}function m(e=document){let t=e.querySelectorAll(`[data-audio-peaks]`),n=[];for(let e of t){let t=e.dataset.audioPeaks;if(!t)continue;let r=e.closest(`.media-audio-card`);if(!(!r||d.has(r)))try{let e=JSON.parse(t);if(!Array.isArray(e))continue;d.set(r,e),r.classList.add(`has-waveform`),n.push(r)}catch{}}n.length>0&&requestAnimationFrame(()=>{for(let e of n)h(e,0)})}async function ee(e){if(d.has(e)||f.has(e))return;f.add(e);let t=e.querySelector(`audio.media-audio-el source`),n=l(e);if(!t?.src||!n)return;let r=n.getBoundingClientRect().width,i=Math.max(20,Math.floor(r/3));try{let n=await p(t.src,i);d.set(e,n),e.classList.add(`has-waveform`);let r=s(e),a=r?.duration??0;h(e,r&&isFinite(a)&&a>0?r.currentTime/a:0)}catch{}}function h(e,t){let n=d.get(e),r=l(e);if(!n||!r)return;let i=window.devicePixelRatio||1,a=r.getBoundingClientRect(),o=Math.round(a.width*i),s=Math.round(a.height*i);if(o===0||s===0)return;(r.width!==o||r.height!==s)&&(r.width=o,r.height=s);let c=r.getContext(`2d`);if(!c)return;c.clearRect(0,0,o,s);let u=n.length,f=o/u,p=Math.max(1,Math.round(f*.6)),m=Math.round(2*i),ee=s*.85,h=getComputedStyle(r).getPropertyValue(`--site-text-primary`).trim()||`#000`;for(let e=0;e<u;e++){let r=Math.round(e*f+(f-p)/2),a=Math.max(m,Math.round(n[e]*ee)),o=Math.round((s-a)/2);c.globalAlpha=(e+.5)/u<=t?.9:.2,c.fillStyle=h;let l=Math.min(p/2,i);c.beginPath(),c.roundRect(r,o,p,a,l),c.fill()}c.globalAlpha=1}function te(e,t){let{currentTime:r,duration:i}=t,a=isFinite(i)&&i>0,s=a?r/i:0;if(!n){let t=c(e);t&&a&&(t.value=String(Math.round(s*1e3)),u(t,s)),d.has(e)&&h(e,s);let n=e.querySelector(`[data-audio-time]`);n&&(n.textContent=a?`${o(r)} / ${o(i)}`:o(r))}}function ne(){if(!e)return;let n=s(e);!n||n.paused||(te(e,n),t=requestAnimationFrame(ne))}function re(){if(e){let t=s(e);t&&!t.paused&&t.pause(),e.classList.remove(`is-playing`),e=null}cancelAnimationFrame(t)}async function ie(n){let r=s(n);if(r)if(e&&e!==n&&re(),r.paused){e=n,n.classList.add(`is-playing`);try{await r.play()}catch{n.classList.remove(`is-playing`),e=null;return}t=requestAnimationFrame(ne),ee(n)}else r.pause(),n.classList.remove(`is-playing`),cancelAnimationFrame(t),e=null}function ae(e){let t=e.closest(`.media-audio-card`);if(!t)return;let n=s(t);if(!n)return;let r=Number(e.value)/1e3,i=n.duration;isFinite(i)&&i>0&&(n.currentTime=r*i)}function oe(e,t){let n=e.getBoundingClientRect();a=Math.max(0,Math.min(1,(t.clientX-n.left)/n.width));let r=e.closest(`.media-audio-card`);if(!r)return;h(r,a);let i=s(r),c=r.querySelector(`[data-audio-time]`);if(i&&c){let e=i.duration;isFinite(e)&&e>0&&(c.textContent=`${o(a*e)} / ${o(e)}`)}}async function se(n){let r=n.closest(`.media-audio-card`);if(!r)return;let i=s(r);if(i)if(i.paused){e&&e!==r&&re(),e=r,r.classList.add(`is-playing`);try{await i.play()}catch{r.classList.remove(`is-playing`),e=null;return}let n=i.duration;isFinite(n)&&n>0&&(i.currentTime=a*n),t=requestAnimationFrame(ne),ee(r)}else{let e=i.duration;isFinite(e)&&e>0&&(i.currentTime=a*e)}}document.addEventListener(`pointerdown`,e=>{let t=e.target;t.matches(`[data-audio-range]`)?(n=!0,r=t):t.matches(`[data-audio-waveform]`)&&(n=!0,i=t,oe(t,e))},!0),document.addEventListener(`pointermove`,e=>{n&&i&&oe(i,e)},!0),document.addEventListener(`pointerup`,()=>{n&&(r?(ae(r),r=null):i&&=(se(i),null)),n=!1},!0),document.addEventListener(`pointercancel`,()=>{r=null,i=null,n=!1},!0),document.addEventListener(`click`,e=>{let t=e.target.closest(`[data-audio-play]`);if(!t)return;e.preventDefault();let n=t.closest(`.media-audio-card`);n&&ie(n)}),document.addEventListener(`input`,e=>{let t=e.target;if(!t.matches(`[data-audio-range]`))return;let n=t.closest(`.media-audio-card`);if(!n)return;let r=s(n);if(!r)return;let i=Number(t.value)/1e3;u(t,i);let a=r.duration,c=n.querySelector(`[data-audio-time]`);c&&isFinite(a)&&a>0&&(c.textContent=`${o(i*a)} / ${o(a)}`)},!0),document.addEventListener(`ended`,n=>{let r=n.target;if(!r.closest)return;let i=r.closest(`.media-audio-card`);if(!i)return;i.classList.remove(`is-playing`),cancelAnimationFrame(t),e=null;let a=c(i);a&&(a.value=`0`,u(a,0)),d.has(i)&&h(i,0);let o=i.querySelector(`[data-audio-time]`);o&&(o.textContent=`0:00`)},!0),document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>m()):m();var g=`jant:media-lightbox-toggle`,ce=`75% 0px`,le=.6,_=.25,ue=160,v=new Set,de=new WeakMap,fe=new WeakSet,y=null,b=null,x=null,pe=!1,S=null,C=null,w=null;function me(e){return e.length===0?null:[...e].sort((e,t)=>t.visibleArea===e.visibleArea?e.centerDistance===t.centerDistance?t.intersectionRatio-e.intersectionRatio:e.centerDistance-t.centerDistance:t.visibleArea-e.visibleArea)[0]??null}function he(){return{x:(globalThis.innerWidth||document.documentElement.clientWidth||0)/2,y:(globalThis.innerHeight||document.documentElement.clientHeight||0)/2}}function ge(e){return de.get(e)}function _e(e){return e.closest(`.media-video-wrap`)?.querySelector(`[data-feed-video-mute-toggle]`)??null}function T(e){let t=_e(e);if(!t)return;let n=x!==e||e.muted;t.dataset.muted=n?`true`:`false`,t.setAttribute(`aria-label`,n?`Play with sound`:`Mute video`)}function ve(){for(let e of v)T(e)}function ye(e){if(fe.has(e))return;let t=e.dataset.videoSrc;t&&(e.getAttribute(`src`)!==t&&(e.src=t),e.load(),fe.add(e))}function E(e){e?.pause()}function be(e){ye(e),e.muted=x!==e,e.playsInline=!0,e.loop=!0,T(e),e.play().catch(()=>{})}function xe(){for(let e of v)e.isConnected||(C?.unobserve(e),w?.unobserve(e),v.delete(e),e===y&&(y=null),e===b&&(b=null),e===x&&(x=null))}function Se(){if(S=null,xe(),document.hidden||pe){E(y);return}let e=[];for(let t of v){let n=ge(t);n&&(n.intersectionRatio<le||e.push({video:t,...n}))}let t=null;if(b?.isConnected){let e=ge(b);e&&e.intersectionRatio>_?t=b:(!e||e.intersectionRatio<=_)&&(b=null)}if(t||=me(e)?.video??null,!t){let e=y?ge(y):void 0;if(y&&e&&e.intersectionRatio>_)return;E(y),y=null;return}t!==y&&(E(y),y=t),be(t);for(let e of v)e!==t&&(E(e),T(e))}function D(){S!==null&&globalThis.clearTimeout(S),S=globalThis.setTimeout(Se,ue)}function Ce(e){let t=he();for(let n of e){let e=n.target,r=n.boundingClientRect,i=r.left+r.width/2,a=r.top+r.height/2,o=n.intersectionRect.width*n.intersectionRect.height,s=Math.hypot(i-t.x,a-t.y);de.set(e,{intersectionRatio:n.intersectionRatio,visibleArea:o,centerDistance:s})}D()}function we(e){for(let t of e)t.isIntersecting&&ye(t.target)}function Te(){C&&w||globalThis.IntersectionObserver!==void 0&&(C=new globalThis.IntersectionObserver(Ce,{threshold:[0,_,le,1]}),w=new globalThis.IntersectionObserver(we,{rootMargin:ce,threshold:0}))}function Ee(e){v.has(e)||(Te(),!(!C||!w)&&(v.add(e),C.observe(e),w.observe(e),_e(e)?.addEventListener(`click`,De),T(e)))}function De(e){e.preventDefault(),e.stopPropagation();let t=e.currentTarget.closest(`.media-video-wrap`)?.querySelector(`[data-feed-short-video]`);t&&(b=t,x!==t||t.muted?(x&&x!==t&&(x.muted=!0),x=t,y!==t&&(E(y),y=t),be(t)):(x=null,t.muted=!0,T(t)),ve(),D())}function Oe(e=document){let t=e.querySelectorAll(`[data-feed-short-video]`);for(let e of t)Ee(e);D()}document.addEventListener(g,e=>{pe=e.detail?.open===!0,pe&&E(y),D()}),document.addEventListener(`visibilitychange`,()=>{document.hidden&&E(y),D()}),document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>Oe(),{once:!0}):queueMicrotask(()=>Oe());var ke=4;function Ae(e){return e.querySelector(`[data-post-media]`)}function je(e){let t=Ae(e);if(!t)return;let{scrollLeft:n,scrollWidth:r,clientWidth:i}=t;e.classList.toggle(`can-scroll-start`,n>ke),e.classList.toggle(`can-scroll-end`,n+i<r-ke)}function Me(e){return Math.max(160,Math.round(e.clientWidth*.85))}function O(e,t){e.scrollBy({left:t*Me(e),behavior:`smooth`})}function k(e){if(e.dataset.scrollHintReady===`1`)return;let t=Ae(e);t&&(e.dataset.scrollHintReady=`1`,je(e),t.addEventListener(`scroll`,()=>je(e),{passive:!0}),e.querySelector(`.media-gallery-nav-prev`)?.addEventListener(`click`,()=>O(t,-1)),e.querySelector(`.media-gallery-nav-next`)?.addEventListener(`click`,()=>O(t,1)),t.addEventListener(`keydown`,e=>{if(e.target===t)switch(e.key){case`ArrowRight`:e.preventDefault(),O(t,1);break;case`ArrowLeft`:e.preventDefault(),O(t,-1);break;case`Home`:e.preventDefault(),t.scrollTo({left:0,behavior:`smooth`});break;case`End`:e.preventDefault(),t.scrollTo({left:t.scrollWidth,behavior:`smooth`});break}}))}function Ne(){document.querySelectorAll(`.media-gallery-scroll-wrap`).forEach(k)}var Pe=new globalThis.MutationObserver(e=>{for(let t of e)for(let e of t.addedNodes)e instanceof HTMLElement&&(e.matches(`.media-gallery-scroll-wrap`)&&k(e),e.querySelectorAll(`.media-gallery-scroll-wrap`).forEach(k))});document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>{Ne(),Pe.observe(document.body,{childList:!0,subtree:!0})}):(Ne(),Pe.observe(document.body,{childList:!0,subtree:!0}));function Fe(e){let t=e.querySelector(`.site-header-more-btn`),n=e.querySelector(`.site-header-more-popover`);if(!t||!n||t.dataset.moreInitialized===`true`)return;t.dataset.moreInitialized=`true`;function r(){n.setAttribute(`aria-hidden`,`false`),t.setAttribute(`aria-expanded`,`true`),document.dispatchEvent(new CustomEvent(`basecoat:popover`,{detail:{source:t.parentElement}}))}function i(e=!1){n.setAttribute(`aria-hidden`,`true`),t.setAttribute(`aria-expanded`,`false`),e&&t.focus()}t.addEventListener(`click`,e=>{e.preventDefault(),e.stopPropagation(),t.getAttribute(`aria-expanded`)===`true`?i():r()}),document.addEventListener(`click`,e=>{e.target instanceof Node&&(t.parentElement?.contains(e.target)||i())}),document.addEventListener(`keydown`,e=>{e.key===`Escape`&&n.getAttribute(`aria-hidden`)===`false`&&i(!0)}),document.addEventListener(`basecoat:popover`,e=>{e.detail?.source!==t.parentElement&&i()})}var Ie=`jant:nav-fresh-visits`;function Le(){let e=document.createElement(`span`);return e.className=`site-header-link-fresh`,e.setAttribute(`aria-hidden`,`true`),e.textContent=`*`,e}function Re(e){try{let t=JSON.parse(localStorage.getItem(Ie)||`{}`),n=location.pathname,r=e.querySelectorAll(`[data-fresh-at]`);for(let e of r){let r=new URL(e.href).pathname,i=parseInt(e.dataset.freshAt,10);if(r===n)t[r]=Math.floor(Date.now()/1e3);else{let n=t[r];if(!n||n<i){let t=e.querySelector(`svg`);e.insertBefore(Le(),t)}}}localStorage.setItem(Ie,JSON.stringify(t))}catch{}}function ze(e=document){let t=e.querySelector(`.site-header-hamburger`),n=e.querySelector(`#site-nav-drawer`),r=e.querySelector(`.site-nav-drawer-backdrop`),i=n?.querySelector(`.site-nav-drawer-close`);if(Re(e),Fe(e),!t||!n||!r||t.dataset.drawerInitialized===`true`)return;t.dataset.drawerInitialized=`true`;function a(){n.setAttribute(`aria-hidden`,`false`),n.removeAttribute(`inert`),r.setAttribute(`aria-hidden`,`false`),t.setAttribute(`aria-expanded`,`true`),document.documentElement.classList.add(`drawer-open`);let e=n.querySelector(`.site-nav-drawer-close`)??n.querySelector(`a[href], button`);e&&e.focus()}function o(e=!0){n.setAttribute(`aria-hidden`,`true`),r.setAttribute(`aria-hidden`,`true`),t.setAttribute(`aria-expanded`,`false`),document.documentElement.classList.remove(`drawer-open`),n.addEventListener(`transitionend`,()=>{n.getAttribute(`aria-hidden`)===`true`&&n.setAttribute(`inert`,``)},{once:!0}),e&&t.focus()}t.addEventListener(`click`,()=>{t.getAttribute(`aria-expanded`)===`true`?o():a()}),i?.addEventListener(`click`,()=>o()),r.addEventListener(`click`,()=>o()),n.addEventListener(`click`,e=>{e.target instanceof Element&&e.target.closest(`a[href]`)&&o(!1)}),n.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),o())})}ze();var A=globalThis,j=A.ShadowRoot&&(A.ShadyCSS===void 0||A.ShadyCSS.nativeShadow)&&`adoptedStyleSheets`in Document.prototype&&`replace`in CSSStyleSheet.prototype,Be=Symbol(),Ve=new WeakMap,He=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==Be)throw Error(\"CSSResult is not constructable. Use `unsafeCSS` or `css` instead.\");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(j&&e===void 0){let n=t!==void 0&&t.length===1;n&&(e=Ve.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),n&&Ve.set(t,e))}return e}toString(){return this.cssText}},Ue=e=>new He(typeof e==`string`?e:e+``,void 0,Be),We=(e,t)=>{if(j)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let n of t){let t=document.createElement(`style`),r=A.litNonce;r!==void 0&&t.setAttribute(`nonce`,r),t.textContent=n.cssText,e.appendChild(t)}},Ge=j?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t=``;for(let n of e.cssRules)t+=n.cssText;return Ue(t)})(e):e,{is:Ke,defineProperty:qe,getOwnPropertyDescriptor:Je,getOwnPropertyNames:Ye,getOwnPropertySymbols:Xe,getPrototypeOf:Ze}=Object,M=globalThis,Qe=M.trustedTypes,$e=Qe?Qe.emptyScript:``,et=M.reactiveElementPolyfillSupport,N=(e,t)=>e,P={toAttribute(e,t){switch(t){case Boolean:e=e?$e:null;break;case Object:case Array:e=e==null?e:JSON.stringify(e)}return e},fromAttribute(e,t){let n=e;switch(t){case Boolean:n=e!==null;break;case Number:n=e===null?null:Number(e);break;case Object:case Array:try{n=JSON.parse(e)}catch{n=null}}return n}},tt=(e,t)=>!Ke(e,t),nt={attribute:!0,type:String,converter:P,reflect:!1,useDefault:!1,hasChanged:tt};Symbol.metadata??=Symbol(`metadata`),M.litPropertyMetadata??=new WeakMap;var F=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=nt){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let n=Symbol(),r=this.getPropertyDescriptor(e,n,t);r!==void 0&&qe(this.prototype,e,r)}}static getPropertyDescriptor(e,t,n){let{get:r,set:i}=Je(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:r,set(t){let a=r?.call(this);i?.call(this,t),this.requestUpdate(e,a,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??nt}static _$Ei(){if(this.hasOwnProperty(N(`elementProperties`)))return;let e=Ze(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(N(`finalized`)))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(N(`properties`))){let e=this.properties,t=[...Ye(e),...Xe(e)];for(let n of t)this.createProperty(n,e[n])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[e,n]of t)this.elementProperties.set(e,n)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let n=this._$Eu(e,t);n!==void 0&&this._$Eh.set(n,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let n=new Set(e.flat(1/0).reverse());for(let e of n)t.unshift(Ge(e))}else e!==void 0&&t.push(Ge(e));return t}static _$Eu(e,t){let n=t.attribute;return!1===n?void 0:typeof n==`string`?n:typeof e==`string`?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let n of t.keys())this.hasOwnProperty(n)&&(e.set(n,this[n]),delete this[n]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return We(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,n){this._$AK(e,n)}_$ET(e,t){let n=this.constructor.elementProperties.get(e),r=this.constructor._$Eu(e,n);if(r!==void 0&&!0===n.reflect){let i=(n.converter?.toAttribute===void 0?P:n.converter).toAttribute(t,n.type);this._$Em=e,i==null?this.removeAttribute(r):this.setAttribute(r,i),this._$Em=null}}_$AK(e,t){let n=this.constructor,r=n._$Eh.get(e);if(r!==void 0&&this._$Em!==r){let e=n.getPropertyOptions(r),i=typeof e.converter==`function`?{fromAttribute:e.converter}:e.converter?.fromAttribute===void 0?P:e.converter;this._$Em=r;let a=i.fromAttribute(t,e.type);this[r]=a??this._$Ej?.get(r)??a,this._$Em=null}}requestUpdate(e,t,n,r=!1,i){if(e!==void 0){let a=this.constructor;if(!1===r&&(i=this[e]),n??=a.getPropertyOptions(e),!((n.hasChanged??tt)(i,t)||n.useDefault&&n.reflect&&i===this._$Ej?.get(e)&&!this.hasAttribute(a._$Eu(e,n))))return;this.C(e,t,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:n,reflect:r,wrapped:i},a){n&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,a??t??this[e]),!0!==i||a!==void 0)||(this._$AL.has(e)||(this.hasUpdated||n||(t=void 0),this._$AL.set(e,t)),!0===r&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}let e=this.scheduleUpdate();return e!=null&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(let[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}let e=this.constructor.elementProperties;if(e.size>0)for(let[t,n]of e){let{wrapped:e}=n,r=this[t];!0!==e||this._$AL.has(t)||r===void 0||this.C(t,void 0,n,r)}}let e=!1,t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};F.elementStyles=[],F.shadowRootOptions={mode:`open`},F[N(`elementProperties`)]=new Map,F[N(`finalized`)]=new Map,et?.({ReactiveElement:F}),(M.reactiveElementVersions??=[]).push(`2.1.2`);var I=globalThis,rt=e=>e,L=I.trustedTypes,it=L?L.createPolicy(`lit-html`,{createHTML:e=>e}):void 0,at=`$lit$`,R=`lit$${Math.random().toFixed(9).slice(2)}$`,ot=`?`+R,st=`<${ot}>`,z=document,B=()=>z.createComment(``),V=e=>e===null||typeof e!=`object`&&typeof e!=`function`,ct=Array.isArray,lt=e=>ct(e)||typeof e?.[Symbol.iterator]==`function`,ut=`[ \n\\f\\r]`,H=/<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))/g,dt=/-->/g,ft=/>/g,U=RegExp(`>|${ut}(?:([^\\\\s\"'>=/]+)(${ut}*=${ut}*(?:[^ \\t\\n\\f\\r\"'\\`<>=]|(\"|')|))|$)`,`g`),pt=/'/g,mt=/\"/g,ht=/^(?:script|style|textarea|title)$/i,gt=e=>(t,...n)=>({_$litType$:e,strings:t,values:n}),W=gt(1),_t=gt(2),G=Symbol.for(`lit-noChange`),K=Symbol.for(`lit-nothing`),vt=new WeakMap,q=z.createTreeWalker(z,129);function yt(e,t){if(!ct(e)||!e.hasOwnProperty(`raw`))throw Error(`invalid template strings array`);return it===void 0?t:it.createHTML(t)}var bt=(e,t)=>{let n=e.length-1,r=[],i,a=t===2?`<svg>`:t===3?`<math>`:``,o=H;for(let t=0;t<n;t++){let n=e[t],s,c,l=-1,u=0;for(;u<n.length&&(o.lastIndex=u,c=o.exec(n),c!==null);)u=o.lastIndex,o===H?c[1]===`!--`?o=dt:c[1]===void 0?c[2]===void 0?c[3]!==void 0&&(o=U):(ht.test(c[2])&&(i=RegExp(`</`+c[2],`g`)),o=U):o=ft:o===U?c[0]===`>`?(o=i??H,l=-1):c[1]===void 0?l=-2:(l=o.lastIndex-c[2].length,s=c[1],o=c[3]===void 0?U:c[3]===`\"`?mt:pt):o===mt||o===pt?o=U:o===dt||o===ft?o=H:(o=U,i=void 0);let d=o===U&&e[t+1].startsWith(`/>`)?` `:``;a+=o===H?n+st:l>=0?(r.push(s),n.slice(0,l)+at+n.slice(l)+R+d):n+R+(l===-2?t:d)}return[yt(e,a+(e[n]||`<?>`)+(t===2?`</svg>`:t===3?`</math>`:``)),r]},xt=class e{constructor({strings:t,_$litType$:n},r){let i;this.parts=[];let a=0,o=0,s=t.length-1,c=this.parts,[l,u]=bt(t,n);if(this.el=e.createElement(l,r),q.currentNode=this.el.content,n===2||n===3){let e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;(i=q.nextNode())!==null&&c.length<s;){if(i.nodeType===1){if(i.hasAttributes())for(let e of i.getAttributeNames())if(e.endsWith(at)){let t=u[o++],n=i.getAttribute(e).split(R),r=/([.?@])?(.*)/.exec(t);c.push({type:1,index:a,name:r[2],strings:n,ctor:r[1]===`.`?Ct:r[1]===`?`?wt:r[1]===`@`?Tt:X}),i.removeAttribute(e)}else e.startsWith(R)&&(c.push({type:6,index:a}),i.removeAttribute(e));if(ht.test(i.tagName)){let e=i.textContent.split(R),t=e.length-1;if(t>0){i.textContent=L?L.emptyScript:``;for(let n=0;n<t;n++)i.append(e[n],B()),q.nextNode(),c.push({type:2,index:++a});i.append(e[t],B())}}}else if(i.nodeType===8)if(i.data===ot)c.push({type:2,index:a});else{let e=-1;for(;(e=i.data.indexOf(R,e+1))!==-1;)c.push({type:7,index:a}),e+=R.length-1}a++}}static createElement(e,t){let n=z.createElement(`template`);return n.innerHTML=e,n}};function J(e,t,n=e,r){if(t===G)return t;let i=r===void 0?n._$Cl:n._$Co?.[r],a=V(t)?void 0:t._$litDirective$;return i?.constructor!==a&&(i?._$AO?.(!1),a===void 0?i=void 0:(i=new a(e),i._$AT(e,n,r)),r===void 0?n._$Cl=i:(n._$Co??=[])[r]=i),i!==void 0&&(t=J(e,i._$AS(e,t.values),i,r)),t}var St=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:n}=this._$AD,r=(e?.creationScope??z).importNode(t,!0);q.currentNode=r;let i=q.nextNode(),a=0,o=0,s=n[0];for(;s!==void 0;){if(a===s.index){let t;s.type===2?t=new Y(i,i.nextSibling,this,e):s.type===1?t=new s.ctor(i,s.name,s.strings,this,e):s.type===6&&(t=new Et(i,this,e)),this._$AV.push(t),s=n[++o]}a!==s?.index&&(i=q.nextNode(),a++)}return q.currentNode=z,r}p(e){let t=0;for(let n of this._$AV)n!==void 0&&(n.strings===void 0?n._$AI(e[t]):(n._$AI(e,n,t),t+=n.strings.length-2)),t++}},Y=class e{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,n,r){this.type=2,this._$AH=K,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=n,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=J(this,e,t),V(e)?e===K||e==null||e===``?(this._$AH!==K&&this._$AR(),this._$AH=K):e!==this._$AH&&e!==G&&this._(e):e._$litType$===void 0?e.nodeType===void 0?lt(e)?this.k(e):this._(e):this.T(e):this.$(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==K&&V(this._$AH)?this._$AA.nextSibling.data=e:this.T(z.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:n}=e,r=typeof n==`number`?this._$AC(e):(n.el===void 0&&(n.el=xt.createElement(yt(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===r)this._$AH.p(t);else{let e=new St(r,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=vt.get(e.strings);return t===void 0&&vt.set(e.strings,t=new xt(e)),t}k(t){ct(this._$AH)||(this._$AH=[],this._$AR());let n=this._$AH,r,i=0;for(let a of t)i===n.length?n.push(r=new e(this.O(B()),this.O(B()),this,this.options)):r=n[i],r._$AI(a),i++;i<n.length&&(this._$AR(r&&r._$AB.nextSibling,i),n.length=i)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let t=rt(e).nextSibling;rt(e).remove(),e=t}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},X=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,n,r,i){this.type=1,this._$AH=K,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=i,n.length>2||n[0]!==``||n[1]!==``?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=K}_$AI(e,t=this,n,r){let i=this.strings,a=!1;if(i===void 0)e=J(this,e,t,0),a=!V(e)||e!==this._$AH&&e!==G,a&&(this._$AH=e);else{let r=e,o,s;for(e=i[0],o=0;o<i.length-1;o++)s=J(this,r[n+o],t,o),s===G&&(s=this._$AH[o]),a||=!V(s)||s!==this._$AH[o],s===K?e=K:e!==K&&(e+=(s??``)+i[o+1]),this._$AH[o]=s}a&&!r&&this.j(e)}j(e){e===K?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??``)}},Ct=class extends X{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===K?void 0:e}},wt=class extends X{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==K)}},Tt=class extends X{constructor(e,t,n,r,i){super(e,t,n,r,i),this.type=5}_$AI(e,t=this){if((e=J(this,e,t,0)??K)===G)return;let n=this._$AH,r=e===K&&n!==K||e.capture!==n.capture||e.once!==n.once||e.passive!==n.passive,i=e!==K&&(n===K||r);r&&this.element.removeEventListener(this.name,this,n),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH==`function`?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},Et=class{constructor(e,t,n){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=n}get _$AU(){return this._$AM._$AU}_$AI(e){J(this,e)}},Dt=I.litHtmlPolyfillSupport;Dt?.(xt,Y),(I.litHtmlVersions??=[]).push(`3.3.2`);var Ot=(e,t,n)=>{let r=n?.renderBefore??t,i=r._$litPart$;if(i===void 0){let e=n?.renderBefore??null;r._$litPart$=i=new Y(t.insertBefore(B(),e),e,void 0,n??{})}return i._$AI(e),i},Z=globalThis,Q=class extends F{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){let e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){let t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=Ot(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return G}};Q._$litElement$=!0,Q.finalized=!0,Z.litElementHydrateSupport?.({LitElement:Q});var kt=Z.litElementPolyfillSupport;kt?.({LitElement:Q}),(Z.litElementVersions??=[]).push(`4.2.2`);function At(e){if(!e.mimeType?.startsWith(`video/`)||!Number.isFinite(e.durationSeconds)||!e.durationSeconds||e.durationSeconds<=0||e.durationSeconds>15)return!1;let t=e.size;return!(typeof t==`number`&&t>12582912)}var jt=640,Mt=8,Nt=72,Pt=16,Ft=704,It=.9,Lt=.85;function $(e){if(!(!Number.isFinite(e)||!e||e<=0))return e}function Rt(){return{width:globalThis.innerWidth||document.documentElement.clientWidth||0,height:globalThis.innerHeight||document.documentElement.clientHeight||0}}function zt(e,t){let n=e<=jt?Mt:Nt;return{width:Math.max(0,e-n*2),height:Math.max(0,t-Pt*2)}}function Bt(e,t,n){let r=$(e?.width),i=$(e?.height);if(!r||!i)return null;let a=zt(t,n);if(a.width<=0||a.height<=0)return null;let o=Math.min(a.width/r,a.height/i);return{width:Math.max(1,Math.round(r*o)),height:Math.max(1,Math.round(i*o))}}function Vt(e,t,n){if(!e||e.mimeType?.startsWith(`video/`)||!$(e.width)||!$(e.height)||t<=0||n<=0)return!1;let r=$(e.width),i=$(e.height);if(!r||!i)return!1;let a=t<=jt,o=zt(t,n),s=o.width,c=o.height;if(s<=0||c<=0)return!1;let l=r/i,u=Math.min(s,c*l);return l<It&&u<(a?s:Math.min(s,Ft))*Lt}var Ht=class extends Q{static properties={_images:{state:!0},_currentIndex:{state:!0},_open:{state:!0},_viewportWidth:{state:!0},_viewportHeight:{state:!0},_videoCurrentTime:{state:!0},_videoDuration:{state:!0},_videoMuted:{state:!0},_imageZoomed:{state:!0}};createRenderRoot(){return this.innerHTML=``,this}constructor(){super();let e=Rt();this._images=[],this._currentIndex=0,this._open=!1,this._viewportWidth=e.width,this._viewportHeight=e.height,this._videoCurrentTime=0,this._videoDuration=0,this._videoMuted=!1,this._imageZoomed=!1}connectedCallback(){super.connectedCallback(),document.addEventListener(`click`,this.#e),window.addEventListener(`resize`,this.#l),this.#u()}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(`click`,this.#e),window.removeEventListener(`resize`,this.#l)}open(e,t){this.#u(),this.#d(),this._images=e,this._currentIndex=Math.max(0,Math.min(t,e.length-1)),this.#m(this._images[this._currentIndex]),this._imageZoomed=!1,this._open=!0,document.dispatchEvent(new CustomEvent(g,{detail:{open:!0}})),this.updateComplete.then(()=>{this.querySelector(`.media-lightbox`)?.showModal(),this.#f()})}close(){this.#d(),this.querySelector(`.media-lightbox`)?.close(),this._open=!1,document.dispatchEvent(new CustomEvent(g,{detail:{open:!1}}))}#e=e=>{let t=e.target,n=t.closest(`[data-post-media] a[data-lightbox-index]`);if(n){let t=n.closest(`[data-lightbox-group]`);if(!t)return;e.preventDefault();let r=parseInt(n.dataset.lightboxIndex??`0`,10);try{let e=JSON.parse(t.dataset.lightboxGroup??`[]`);e.length>0&&this.open(e,r)}catch{}return}let r=t.closest(`[data-post-body] img`);if(r){e.preventDefault();let t=r.closest(`[data-post-body]`);if(!t)return;let n=Array.from(t.querySelectorAll(`img`)),i=n.map(e=>({url:e.src,alt:e.alt||``,width:$(e.naturalWidth||Number(e.getAttribute(`width`))),height:$(e.naturalHeight||Number(e.getAttribute(`height`)))})),a=n.indexOf(r);i.length>0&&this.open(i,Math.max(0,a))}};#t(){this._images.length<=1||(this.#d(),this._imageZoomed=!1,this._currentIndex=(this._currentIndex-1+this._images.length)%this._images.length)}#n(){this._images.length<=1||(this.#d(),this._imageZoomed=!1,this._currentIndex=(this._currentIndex+1)%this._images.length)}#r=e=>{let t=this._images[this._currentIndex];Vt(t,this._viewportWidth,this._viewportHeight)&&(e.stopPropagation(),this._imageZoomed=!this._imageZoomed)};#i=e=>{let t=e,n=e.target;if(t.key===`Escape`){e.preventDefault(),this.close();return}if(n instanceof HTMLInputElement||n instanceof HTMLButtonElement||n instanceof HTMLVideoElement)return;if(!this._images[this._currentIndex]?.mimeType?.startsWith(`video/`)){t.key===`ArrowLeft`?(e.preventDefault(),this.#t()):t.key===`ArrowRight`&&(e.preventDefault(),this.#n());return}let r=this.querySelector(`.media-lightbox-video`);r&&this.#a(t,r)};#a(e,t){let n=Number.isFinite(t.duration)&&t.duration>0?t.duration:null,r=e=>{let r=n==null?Math.max(0,e):Math.max(0,Math.min(e,n));t.currentTime=r,this._videoCurrentTime=r},i=e.key,a=i.toLowerCase();if(i===` `||a===`k`)e.preventDefault(),t.paused?t.play().catch(()=>{}):t.pause();else if(i===`ArrowLeft`)e.preventDefault(),r(t.currentTime-2);else if(i===`ArrowRight`)e.preventDefault(),r(t.currentTime+2);else if(i===`Home`)e.preventDefault(),r(0);else if(i===`End`)n!=null&&(e.preventDefault(),r(n));else if(i.length===1&&i>=`0`&&i<=`9`)n!=null&&(e.preventDefault(),r(Number(i)/10*n));else if(i===`ArrowUp`)e.preventDefault(),t.volume=Math.min(1,t.volume+.05);else if(i===`ArrowDown`)e.preventDefault(),t.volume=Math.max(0,t.volume-.05);else if(a===`m`){e.preventDefault();let n=!t.muted;t.muted=n,this._videoMuted=n}else a===`f`&&(e.preventDefault(),this.#o(t))}#o(e){let t=document,n=e;if(document.fullscreenElement??t.webkitFullscreenElement){document.exitFullscreen?document.exitFullscreen().catch(()=>{}):t.webkitExitFullscreen?.();return}e.requestFullscreen?e.requestFullscreen().catch(()=>{}):n.webkitRequestFullscreen?n.webkitRequestFullscreen():n.webkitEnterFullscreen&&n.webkitEnterFullscreen()}#s=e=>{let t=e.target;(t===e.currentTarget||t.classList.contains(`media-lightbox-content`)||t.classList.contains(`media-lightbox-stage`))&&this.close()};#c=()=>{this.#d(),this._open&&document.dispatchEvent(new CustomEvent(g,{detail:{open:!1}})),this._open=!1};#l=()=>{this.#u()};#u(){let e=Rt();e.width===this._viewportWidth&&e.height===this._viewportHeight||(this._viewportWidth=e.width,this._viewportHeight=e.height)}#d(){this.querySelector(`.media-lightbox-video`)?.pause()}#f(){this.querySelector(`.media-lightbox-content`)?.focus()}#p=()=>{this.querySelector(`.media-lightbox-content`)?.focus({preventScroll:!0})};#m(e){this._videoCurrentTime=0,this._videoDuration=e?.durationSeconds&&e.durationSeconds>0?e.durationSeconds:0,this._videoMuted=!1}#h(){let e=this._images[this._currentIndex];if(!At(e)){this.#m(e);return}let t=this.querySelector(`.media-lightbox-video`);t&&(t.currentTime=0,t.muted=this._videoMuted,t.play().catch(()=>{}))}#g=e=>{let t=e.currentTarget;Number.isFinite(t.duration)&&t.duration>0&&(this._videoDuration=t.duration),this._videoCurrentTime=t.currentTime,t.muted=this._videoMuted};#_=e=>{let t=e.currentTarget;this._videoCurrentTime=t.currentTime,Number.isFinite(t.duration)&&t.duration>0&&(this._videoDuration=t.duration)};#v=e=>{let t=e.currentTarget,n=this.querySelector(`.media-lightbox-video`),r=Number.parseFloat(t.value);!n||!Number.isFinite(r)||r<0||(n.currentTime=r,this._videoCurrentTime=r)};#y=()=>{this._videoMuted=!this._videoMuted;let e=this.querySelector(`.media-lightbox-video`);e&&(e.muted=this._videoMuted)};updated(e){if(super.updated(e),!this._open||!e.has(`_currentIndex`)&&!e.has(`_open`)&&!e.has(`_imageZoomed`))return;let t=this.querySelector(`.media-lightbox-stage`);t&&(t.scrollTop=0,t.scrollLeft=0,(e.has(`_currentIndex`)||e.has(`_open`))&&(this.#h(),this.#f()))}render(){if(!this._open)return K;let e=this._images[this._currentIndex],t=this._images.length>1,n=e?.mimeType?.startsWith(`video/`),r=At(e),i=Vt(e,this._viewportWidth,this._viewportHeight),a=i&&this._imageZoomed,o=r?Bt(e,this._viewportWidth,this._viewportHeight):null,s=r&&!!o&&o.height>o.width,c=o?`width:${o.width}px;height:${o.height}px;`:K,l=this._videoDuration>0?this._videoDuration:e?.durationSeconds??1,u=Math.min(this._videoCurrentTime,l),d=l>0?u/l*100:0;return W`\n <dialog\n class=${`media-lightbox${r?` media-lightbox-short`:``}`}\n @keydown=${this.#i}\n @click=${this.#s}\n @close=${this.#c}\n >\n <div class=\"media-lightbox-content\" tabindex=\"-1\">\n <button\n type=\"button\"\n class=\"media-lightbox-close\"\n @click=${()=>this.close()}\n aria-label=\"Close\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n\n ${t?W`<div class=\"media-lightbox-counter\">\n ${this._currentIndex+1} / ${this._images.length}\n </div>`:K}\n <div\n class=${`media-lightbox-stage${a?` media-lightbox-stage-scroll`:``}`}\n >\n ${n?r?W`<div\n class=${`media-lightbox-short-frame${s?` media-lightbox-short-frame-portrait`:` media-lightbox-short-frame-landscape`}`}\n style=${c}\n >\n <video\n class=\"media-lightbox-video media-lightbox-video-short\"\n src=${e?.url??``}\n poster=${e?.posterUrl??``}\n autoplay\n playsinline\n loop\n ?muted=${this._videoMuted}\n @focus=${this.#p}\n @loadedmetadata=${this.#g}\n @timeupdate=${this.#_}\n ></video>\n <div\n class=${`media-lightbox-short-controls${s?` media-lightbox-short-controls-portrait`:``}`}\n >\n <input\n class=\"media-lightbox-short-progress\"\n type=\"range\"\n min=\"0\"\n max=${l}\n step=\"0.01\"\n .value=${String(u)}\n style=${`--media-progress:${d}%`}\n aria-label=\"Video progress\"\n @input=${this.#v}\n />\n <button\n type=\"button\"\n class=\"media-lightbox-short-mute\"\n @click=${this.#y}\n aria-label=${this._videoMuted?`Unmute video`:`Mute video`}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 48 48\"\n fill=\"currentColor\"\n color=\"#fff\"\n aria-hidden=\"true\"\n >\n ${this._videoMuted?_t`\n <path d=\"M1.5 13.3c-.8 0-1.5.7-1.5 1.5v18.4c0 .8.7 1.5 1.5 1.5h8.7l12.9 12.9c.9.9 2.5.3 2.5-1v-9.8c0-.4-.2-.8-.4-1.1l-22-22c-.3-.3-.7-.4-1.1-.4h-.6zm46.8 31.4-5.5-5.5C44.9 36.6 48 31.4 48 24c0-11.4-7.2-17.4-7.2-17.4-.6-.6-1.6-.6-2.2 0L37.2 8c-.6.6-.6 1.6 0 2.2 0 0 5.7 5 5.7 13.8 0 5.4-2.1 9.3-3.8 11.6L35.5 32c1.1-1.7 2.3-4.4 2.3-8 0-6.8-4.1-10.3-4.1-10.3-.6-.6-1.6-.6-2.2 0l-1.4 1.4c-.6.6-.6 1.6 0 2.2 0 0 2.6 2 2.6 6.7 0 1.8-.4 3.2-.9 4.3L25.5 22V1.4c0-1.3-1.6-1.9-2.5-1L13.5 10 3.3-.3c-.6-.6-1.5-.6-2.1 0L-.2 1.1c-.6.6-.6 1.5 0 2.1L4 7.6l26.8 26.8 13.9 13.9c.6.6 1.5.6 2.1 0l1.4-1.4c.7-.6.7-1.6.1-2.2z\" />\n `:_t`\n <path d=\"M1.5 13.3c-.8 0-1.5.7-1.5 1.5v18.4c0 .8.7 1.5 1.5 1.5h8.7l12.9 12.9c.9.9 2.5.3 2.5-1V1.4c0-1.3-1.6-1.9-2.5-1L10.2 13.3H1.5z\" />\n <path d=\"M30.1 15.9c-.6-.6-.6-1.6 0-2.2l1.4-1.4c.6-.6 1.6-.6 2.2 0 0 0 4.1 3.5 4.1 11.7s-4.1 11.7-4.1 11.7c-.6.6-1.6.6-2.2 0l-1.4-1.4c-.6-.6-.6-1.6 0-2.2 0 0 2.6-2 2.6-8.1s-2.6-8.1-2.6-8.1z\" />\n <path d=\"M37.2 8c-.6-.6-.6-1.6 0-2.2l1.4-1.4c.6-.6 1.6-.6 2.2 0 0 0 5.7 5.1 5.7 19.6s-5.7 19.6-5.7 19.6c-.6.6-1.6.6-2.2 0L37.2 42c-.6-.6-.6-1.6 0-2.2 0 0 4.3-4.4 4.3-15.8S37.2 8 37.2 8z\" />\n `}\n </svg>\n </button>\n </div>\n </div>`:W`<video\n class=\"media-lightbox-video\"\n src=${e?.url??``}\n poster=${e?.posterUrl??``}\n controls\n autoplay\n playsinline\n @focus=${this.#p}\n ></video>`:W`<img\n class=${`media-lightbox-img${i?` media-lightbox-img-zoomable`:``}${a?` media-lightbox-img-scroll`:``}`}\n src=${e?.url??``}\n alt=${e?.alt??``}\n @click=${this.#r}\n />`}\n </div>\n ${t?W`\n <button\n type=\"button\"\n class=\"media-lightbox-nav media-lightbox-nav-prev\"\n @click=${()=>this.#t()}\n aria-label=\"Previous\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"media-lightbox-nav media-lightbox-nav-next\"\n @click=${()=>this.#n()}\n aria-label=\"Next\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n `:K}\n </div>\n </dialog>\n `}};customElements.define(`jant-media-lightbox`,Ht);";
3315
+ var client_site_default$1 = "var e=null,t=0,n=!1,r=null,i=null,a=0;function o(e){return!isFinite(e)||e<0?`0:00`:`${Math.floor(e/60)}:${String(Math.floor(e%60)).padStart(2,`0`)}`}function s(e){return e.querySelector(`audio.media-audio-el`)}function c(e){return e.querySelector(`[data-audio-range]`)}function l(e){return e.querySelector(`[data-audio-waveform]`)}function u(e,t){let n=`${(t*100).toFixed(1)}%`;e.style.background=`linear-gradient(to right, var(--site-text-primary) ${n}, transparent ${n})`}var d=new WeakMap,f=new WeakSet;async function p(e,t){let n=await(await fetch(e)).arrayBuffer(),r=new AudioContext;try{let e=(await r.decodeAudioData(n)).getChannelData(0),i=Math.max(1,Math.floor(e.length/t)),a=Array(t);for(let n=0;n<t;n++){let t=0,r=n*i,o=Math.min(r+i,e.length);for(let n=r;n<o;n++){let r=Math.abs(e[n]);r>t&&(t=r)}a[n]=t}let o=0;for(let e of a)e>o&&(o=e);if(o>0)for(let e=0;e<t;e++)a[e]/=o;return a}finally{await r.close()}}function m(e=document){let t=e.querySelectorAll(`[data-audio-peaks]`),n=[];for(let e of t){let t=e.dataset.audioPeaks;if(!t)continue;let r=e.closest(`.media-audio-card`);if(!(!r||d.has(r)))try{let e=JSON.parse(t);if(!Array.isArray(e))continue;d.set(r,e),r.classList.add(`has-waveform`),n.push(r)}catch{}}n.length>0&&requestAnimationFrame(()=>{for(let e of n)g(e,0)})}async function h(e){if(d.has(e)||f.has(e))return;f.add(e);let t=e.querySelector(`audio.media-audio-el source`),n=l(e);if(!t?.src||!n)return;let r=n.getBoundingClientRect().width,i=Math.max(20,Math.floor(r/3));try{let n=await p(t.src,i);d.set(e,n),e.classList.add(`has-waveform`);let r=s(e),a=r?.duration??0;g(e,r&&isFinite(a)&&a>0?r.currentTime/a:0)}catch{}}function g(e,t){let n=d.get(e),r=l(e);if(!n||!r)return;let i=window.devicePixelRatio||1,a=r.getBoundingClientRect(),o=Math.round(a.width*i),s=Math.round(a.height*i);if(o===0||s===0)return;(r.width!==o||r.height!==s)&&(r.width=o,r.height=s);let c=r.getContext(`2d`);if(!c)return;c.clearRect(0,0,o,s);let u=n.length,f=o/u,p=Math.max(1,Math.round(f*.6)),m=Math.round(2*i),h=s*.85,g=getComputedStyle(r).getPropertyValue(`--site-text-primary`).trim()||`#000`;for(let e=0;e<u;e++){let r=Math.round(e*f+(f-p)/2),a=Math.max(m,Math.round(n[e]*h)),o=Math.round((s-a)/2);c.globalAlpha=(e+.5)/u<=t?.9:.2,c.fillStyle=g;let l=Math.min(p/2,i);c.beginPath(),c.roundRect(r,o,p,a,l),c.fill()}c.globalAlpha=1}function ee(e,t){let{currentTime:r,duration:i}=t,a=isFinite(i)&&i>0,s=a?r/i:0;if(!n){let t=c(e);t&&a&&(t.value=String(Math.round(s*1e3)),u(t,s)),d.has(e)&&g(e,s);let n=e.querySelector(`[data-audio-time]`);n&&(n.textContent=a?`${o(r)} / ${o(i)}`:o(r))}}function _(){if(!e)return;let n=s(e);!n||n.paused||(ee(e,n),t=requestAnimationFrame(_))}function te(){if(e){let t=s(e);t&&!t.paused&&t.pause(),e.classList.remove(`is-playing`),e=null}cancelAnimationFrame(t)}async function ne(n){let r=s(n);if(r)if(e&&e!==n&&te(),r.paused){e=n,n.classList.add(`is-playing`);try{await r.play()}catch{n.classList.remove(`is-playing`),e=null;return}t=requestAnimationFrame(_),h(n)}else r.pause(),n.classList.remove(`is-playing`),cancelAnimationFrame(t),e=null}function re(e){let t=e.closest(`.media-audio-card`);if(!t)return;let n=s(t);if(!n)return;let r=Number(e.value)/1e3,i=n.duration;isFinite(i)&&i>0&&(n.currentTime=r*i)}function ie(e,t){let n=e.getBoundingClientRect();a=Math.max(0,Math.min(1,(t.clientX-n.left)/n.width));let r=e.closest(`.media-audio-card`);if(!r)return;g(r,a);let i=s(r),c=r.querySelector(`[data-audio-time]`);if(i&&c){let e=i.duration;isFinite(e)&&e>0&&(c.textContent=`${o(a*e)} / ${o(e)}`)}}async function ae(n){let r=n.closest(`.media-audio-card`);if(!r)return;let i=s(r);if(i)if(i.paused){e&&e!==r&&te(),e=r,r.classList.add(`is-playing`);try{await i.play()}catch{r.classList.remove(`is-playing`),e=null;return}let n=i.duration;isFinite(n)&&n>0&&(i.currentTime=a*n),t=requestAnimationFrame(_),h(r)}else{let e=i.duration;isFinite(e)&&e>0&&(i.currentTime=a*e)}}document.addEventListener(`pointerdown`,e=>{let t=e.target;t.matches(`[data-audio-range]`)?(n=!0,r=t):t.matches(`[data-audio-waveform]`)&&(n=!0,i=t,ie(t,e))},!0),document.addEventListener(`pointermove`,e=>{n&&i&&ie(i,e)},!0),document.addEventListener(`pointerup`,()=>{n&&(r?(re(r),r=null):i&&=(ae(i),null)),n=!1},!0),document.addEventListener(`pointercancel`,()=>{r=null,i=null,n=!1},!0),document.addEventListener(`click`,e=>{let t=e.target.closest(`[data-audio-play]`);if(!t)return;e.preventDefault();let n=t.closest(`.media-audio-card`);n&&ne(n)}),document.addEventListener(`input`,e=>{let t=e.target;if(!t.matches(`[data-audio-range]`))return;let n=t.closest(`.media-audio-card`);if(!n)return;let r=s(n);if(!r)return;let i=Number(t.value)/1e3;u(t,i);let a=r.duration,c=n.querySelector(`[data-audio-time]`);c&&isFinite(a)&&a>0&&(c.textContent=`${o(i*a)} / ${o(a)}`)},!0),document.addEventListener(`ended`,n=>{let r=n.target;if(!r.closest)return;let i=r.closest(`.media-audio-card`);if(!i)return;i.classList.remove(`is-playing`),cancelAnimationFrame(t),e=null;let a=c(i);a&&(a.value=`0`,u(a,0)),d.has(i)&&g(i,0);let o=i.querySelector(`[data-audio-time]`);o&&(o.textContent=`0:00`)},!0),document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>m()):m();var v=`jant:media-lightbox-toggle`,oe=`75% 0px`,se=.6,y=.25,ce=160,b=new Set,le=new WeakMap,ue=new WeakSet,x=null,S=null,C=null,de=!1,w=null,T=null,E=null;function fe(e){return e.length===0?null:[...e].sort((e,t)=>t.visibleArea===e.visibleArea?e.centerDistance===t.centerDistance?t.intersectionRatio-e.intersectionRatio:e.centerDistance-t.centerDistance:t.visibleArea-e.visibleArea)[0]??null}function pe(){return{x:(globalThis.innerWidth||document.documentElement.clientWidth||0)/2,y:(globalThis.innerHeight||document.documentElement.clientHeight||0)/2}}function me(e){return le.get(e)}function he(e){return e.closest(`.media-video-wrap`)?.querySelector(`[data-feed-video-mute-toggle]`)??null}function D(e){let t=he(e);if(!t)return;let n=C!==e||e.muted;t.dataset.muted=n?`true`:`false`,t.setAttribute(`aria-label`,n?`Play with sound`:`Mute video`)}function ge(){for(let e of b)D(e)}function _e(e){if(ue.has(e))return;let t=e.dataset.videoSrc;t&&(e.getAttribute(`src`)!==t&&(e.src=t),e.load(),ue.add(e))}function O(e){e?.pause()}function ve(e){_e(e),e.muted=C!==e,e.playsInline=!0,e.loop=!0,D(e),e.play().catch(()=>{})}function ye(){for(let e of b)e.isConnected||(T?.unobserve(e),E?.unobserve(e),b.delete(e),e===x&&(x=null),e===S&&(S=null),e===C&&(C=null))}function be(){if(w=null,ye(),document.hidden||de){O(x);return}let e=[];for(let t of b){let n=me(t);n&&(n.intersectionRatio<se||e.push({video:t,...n}))}let t=null;if(S?.isConnected){let e=me(S);e&&e.intersectionRatio>y?t=S:(!e||e.intersectionRatio<=y)&&(S=null)}if(t||=fe(e)?.video??null,!t){let e=x?me(x):void 0;if(x&&e&&e.intersectionRatio>y)return;O(x),x=null;return}t!==x&&(O(x),x=t),ve(t);for(let e of b)e!==t&&(O(e),D(e))}function k(){w!==null&&globalThis.clearTimeout(w),w=globalThis.setTimeout(be,ce)}function xe(e){let t=pe();for(let n of e){let e=n.target,r=n.boundingClientRect,i=r.left+r.width/2,a=r.top+r.height/2,o=n.intersectionRect.width*n.intersectionRect.height,s=Math.hypot(i-t.x,a-t.y);le.set(e,{intersectionRatio:n.intersectionRatio,visibleArea:o,centerDistance:s})}k()}function Se(e){for(let t of e)t.isIntersecting&&_e(t.target)}function Ce(){T&&E||globalThis.IntersectionObserver!==void 0&&(T=new globalThis.IntersectionObserver(xe,{threshold:[0,y,se,1]}),E=new globalThis.IntersectionObserver(Se,{rootMargin:oe,threshold:0}))}function we(e){b.has(e)||(Ce(),!(!T||!E)&&(b.add(e),T.observe(e),E.observe(e),he(e)?.addEventListener(`click`,Te),D(e)))}function Te(e){e.preventDefault(),e.stopPropagation();let t=e.currentTarget.closest(`.media-video-wrap`)?.querySelector(`[data-feed-short-video]`);t&&(S=t,C!==t||t.muted?(C&&C!==t&&(C.muted=!0),C=t,x!==t&&(O(x),x=t),ve(t)):(C=null,t.muted=!0,D(t)),ge(),k())}function Ee(e=document){let t=e.querySelectorAll(`[data-feed-short-video]`);for(let e of t)we(e);k()}document.addEventListener(v,e=>{de=e.detail?.open===!0,de&&O(x),k()}),document.addEventListener(`visibilitychange`,()=>{document.hidden&&O(x),k()}),document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>Ee(),{once:!0}):queueMicrotask(()=>Ee());var De=4;function Oe(e){return e.querySelector(`[data-post-media]`)}function ke(e){let t=Oe(e);if(!t)return;let{scrollLeft:n,scrollWidth:r,clientWidth:i}=t;e.classList.toggle(`can-scroll-start`,n>De),e.classList.toggle(`can-scroll-end`,n+i<r-De)}function Ae(e){return Math.max(160,Math.round(e.clientWidth*.85))}function A(e,t){e.scrollBy({left:t*Ae(e),behavior:`smooth`})}function j(e){if(e.dataset.scrollHintReady===`1`)return;let t=Oe(e);t&&(e.dataset.scrollHintReady=`1`,ke(e),t.addEventListener(`scroll`,()=>ke(e),{passive:!0}),e.querySelector(`.media-gallery-nav-prev`)?.addEventListener(`click`,()=>A(t,-1)),e.querySelector(`.media-gallery-nav-next`)?.addEventListener(`click`,()=>A(t,1)),t.addEventListener(`keydown`,e=>{if(e.target===t)switch(e.key){case`ArrowRight`:e.preventDefault(),A(t,1);break;case`ArrowLeft`:e.preventDefault(),A(t,-1);break;case`Home`:e.preventDefault(),t.scrollTo({left:0,behavior:`smooth`});break;case`End`:e.preventDefault(),t.scrollTo({left:t.scrollWidth,behavior:`smooth`});break}}))}function je(){document.querySelectorAll(`.media-gallery-scroll-wrap`).forEach(j)}var Me=new globalThis.MutationObserver(e=>{for(let t of e)for(let e of t.addedNodes)e instanceof HTMLElement&&(e.matches(`.media-gallery-scroll-wrap`)&&j(e),e.querySelectorAll(`.media-gallery-scroll-wrap`).forEach(j))});document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>{je(),Me.observe(document.body,{childList:!0,subtree:!0})}):(je(),Me.observe(document.body,{childList:!0,subtree:!0}));var Ne=new WeakMap,Pe=new WeakMap;function Fe(e){let t=e.querySelector(`.site-header-more-btn`),n=e.querySelector(`.site-header-more-popover`);if(!t||!n||t.dataset.moreInitialized===`true`)return;t.dataset.moreInitialized=`true`;let r=new AbortController,i=r.signal;Ne.set(t,r);function a(){n.setAttribute(`aria-hidden`,`false`),t.setAttribute(`aria-expanded`,`true`),document.dispatchEvent(new CustomEvent(`basecoat:popover`,{detail:{source:t.parentElement}}))}function o(e=!1){n.setAttribute(`aria-hidden`,`true`),t.setAttribute(`aria-expanded`,`false`),e&&t.focus()}t.addEventListener(`click`,e=>{e.preventDefault(),e.stopPropagation(),t.getAttribute(`aria-expanded`)===`true`?o():a()},{signal:i}),document.addEventListener(`click`,e=>{e.target instanceof Node&&(t.parentElement?.contains(e.target)||o())},{signal:i}),document.addEventListener(`keydown`,e=>{e.key===`Escape`&&n.getAttribute(`aria-hidden`)===`false`&&o(!0)},{signal:i}),document.addEventListener(`basecoat:popover`,e=>{e.detail?.source!==t.parentElement&&o()},{signal:i})}var Ie=`jant:nav-fresh-visits`;function Le(){let e=document.createElement(`span`);return e.className=`site-header-link-fresh`,e.setAttribute(`aria-hidden`,`true`),e.textContent=`*`,e}function Re(e){try{let t=JSON.parse(localStorage.getItem(Ie)||`{}`),n=location.pathname,r=e.querySelectorAll(`[data-fresh-at]`);for(let e of r){let r=new URL(e.href).pathname,i=parseInt(e.dataset.freshAt,10);if(r===n)t[r]=Math.floor(Date.now()/1e3);else{let n=t[r];if(!n||n<i){let t=e.querySelector(`svg`);e.insertBefore(Le(),t)}}}localStorage.setItem(Ie,JSON.stringify(t))}catch{}}function ze(e=document){let t=e.querySelector(`.site-header-hamburger`),n=e.querySelector(`#site-nav-drawer`),r=e.querySelector(`.site-nav-drawer-backdrop`),i=n?.querySelector(`.site-nav-drawer-close`);if(Re(e),Fe(e),!t||!n||!r||t.dataset.drawerInitialized===`true`)return;t.dataset.drawerInitialized=`true`;let a=new AbortController,o=a.signal;Pe.set(t,a);function s(){n.setAttribute(`aria-hidden`,`false`),n.removeAttribute(`inert`),r.setAttribute(`aria-hidden`,`false`),t.setAttribute(`aria-expanded`,`true`),document.documentElement.classList.add(`drawer-open`);let e=n.querySelector(`.site-nav-drawer-close`)??n.querySelector(`a[href], button`);e&&e.focus()}function c(e=!0){n.setAttribute(`aria-hidden`,`true`),r.setAttribute(`aria-hidden`,`true`),t.setAttribute(`aria-expanded`,`false`),document.documentElement.classList.remove(`drawer-open`),n.addEventListener(`transitionend`,()=>{n.getAttribute(`aria-hidden`)===`true`&&n.setAttribute(`inert`,``)},{once:!0,signal:o}),e&&t.focus()}t.addEventListener(`click`,()=>{t.getAttribute(`aria-expanded`)===`true`?c():s()},{signal:o}),i?.addEventListener(`click`,()=>c(),{signal:o}),r.addEventListener(`click`,()=>c(),{signal:o}),n.addEventListener(`click`,e=>{e.target instanceof Element&&e.target.closest(`a[href]`)&&c(!1)},{signal:o}),n.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),c())},{signal:o})}ze();var M=globalThis,N=M.ShadowRoot&&(M.ShadyCSS===void 0||M.ShadyCSS.nativeShadow)&&`adoptedStyleSheets`in Document.prototype&&`replace`in CSSStyleSheet.prototype,Be=Symbol(),Ve=new WeakMap,He=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==Be)throw Error(\"CSSResult is not constructable. Use `unsafeCSS` or `css` instead.\");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(N&&e===void 0){let n=t!==void 0&&t.length===1;n&&(e=Ve.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),n&&Ve.set(t,e))}return e}toString(){return this.cssText}},Ue=e=>new He(typeof e==`string`?e:e+``,void 0,Be),We=(e,t)=>{if(N)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let n of t){let t=document.createElement(`style`),r=M.litNonce;r!==void 0&&t.setAttribute(`nonce`,r),t.textContent=n.cssText,e.appendChild(t)}},Ge=N?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t=``;for(let n of e.cssRules)t+=n.cssText;return Ue(t)})(e):e,{is:Ke,defineProperty:qe,getOwnPropertyDescriptor:Je,getOwnPropertyNames:Ye,getOwnPropertySymbols:Xe,getPrototypeOf:Ze}=Object,P=globalThis,Qe=P.trustedTypes,$e=Qe?Qe.emptyScript:``,et=P.reactiveElementPolyfillSupport,F=(e,t)=>e,I={toAttribute(e,t){switch(t){case Boolean:e=e?$e:null;break;case Object:case Array:e=e==null?e:JSON.stringify(e)}return e},fromAttribute(e,t){let n=e;switch(t){case Boolean:n=e!==null;break;case Number:n=e===null?null:Number(e);break;case Object:case Array:try{n=JSON.parse(e)}catch{n=null}}return n}},tt=(e,t)=>!Ke(e,t),nt={attribute:!0,type:String,converter:I,reflect:!1,useDefault:!1,hasChanged:tt};Symbol.metadata??=Symbol(`metadata`),P.litPropertyMetadata??=new WeakMap;var L=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=nt){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let n=Symbol(),r=this.getPropertyDescriptor(e,n,t);r!==void 0&&qe(this.prototype,e,r)}}static getPropertyDescriptor(e,t,n){let{get:r,set:i}=Je(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:r,set(t){let a=r?.call(this);i?.call(this,t),this.requestUpdate(e,a,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??nt}static _$Ei(){if(this.hasOwnProperty(F(`elementProperties`)))return;let e=Ze(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(F(`finalized`)))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(F(`properties`))){let e=this.properties,t=[...Ye(e),...Xe(e)];for(let n of t)this.createProperty(n,e[n])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[e,n]of t)this.elementProperties.set(e,n)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let n=this._$Eu(e,t);n!==void 0&&this._$Eh.set(n,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let n=new Set(e.flat(1/0).reverse());for(let e of n)t.unshift(Ge(e))}else e!==void 0&&t.push(Ge(e));return t}static _$Eu(e,t){let n=t.attribute;return!1===n?void 0:typeof n==`string`?n:typeof e==`string`?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let n of t.keys())this.hasOwnProperty(n)&&(e.set(n,this[n]),delete this[n]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return We(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,n){this._$AK(e,n)}_$ET(e,t){let n=this.constructor.elementProperties.get(e),r=this.constructor._$Eu(e,n);if(r!==void 0&&!0===n.reflect){let i=(n.converter?.toAttribute===void 0?I:n.converter).toAttribute(t,n.type);this._$Em=e,i==null?this.removeAttribute(r):this.setAttribute(r,i),this._$Em=null}}_$AK(e,t){let n=this.constructor,r=n._$Eh.get(e);if(r!==void 0&&this._$Em!==r){let e=n.getPropertyOptions(r),i=typeof e.converter==`function`?{fromAttribute:e.converter}:e.converter?.fromAttribute===void 0?I:e.converter;this._$Em=r;let a=i.fromAttribute(t,e.type);this[r]=a??this._$Ej?.get(r)??a,this._$Em=null}}requestUpdate(e,t,n,r=!1,i){if(e!==void 0){let a=this.constructor;if(!1===r&&(i=this[e]),n??=a.getPropertyOptions(e),!((n.hasChanged??tt)(i,t)||n.useDefault&&n.reflect&&i===this._$Ej?.get(e)&&!this.hasAttribute(a._$Eu(e,n))))return;this.C(e,t,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:n,reflect:r,wrapped:i},a){n&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,a??t??this[e]),!0!==i||a!==void 0)||(this._$AL.has(e)||(this.hasUpdated||n||(t=void 0),this._$AL.set(e,t)),!0===r&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}let e=this.scheduleUpdate();return e!=null&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(let[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}let e=this.constructor.elementProperties;if(e.size>0)for(let[t,n]of e){let{wrapped:e}=n,r=this[t];!0!==e||this._$AL.has(t)||r===void 0||this.C(t,void 0,n,r)}}let e=!1,t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};L.elementStyles=[],L.shadowRootOptions={mode:`open`},L[F(`elementProperties`)]=new Map,L[F(`finalized`)]=new Map,et?.({ReactiveElement:L}),(P.reactiveElementVersions??=[]).push(`2.1.2`);var R=globalThis,rt=e=>e,z=R.trustedTypes,it=z?z.createPolicy(`lit-html`,{createHTML:e=>e}):void 0,at=`$lit$`,B=`lit$${Math.random().toFixed(9).slice(2)}$`,ot=`?`+B,st=`<${ot}>`,V=document,H=()=>V.createComment(``),U=e=>e===null||typeof e!=`object`&&typeof e!=`function`,ct=Array.isArray,lt=e=>ct(e)||typeof e?.[Symbol.iterator]==`function`,ut=`[ \n\\f\\r]`,W=/<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))/g,dt=/-->/g,ft=/>/g,G=RegExp(`>|${ut}(?:([^\\\\s\"'>=/]+)(${ut}*=${ut}*(?:[^ \\t\\n\\f\\r\"'\\`<>=]|(\"|')|))|$)`,`g`),pt=/'/g,mt=/\"/g,ht=/^(?:script|style|textarea|title)$/i,gt=e=>(t,...n)=>({_$litType$:e,strings:t,values:n}),K=gt(1),_t=gt(2),q=Symbol.for(`lit-noChange`),J=Symbol.for(`lit-nothing`),vt=new WeakMap,Y=V.createTreeWalker(V,129);function yt(e,t){if(!ct(e)||!e.hasOwnProperty(`raw`))throw Error(`invalid template strings array`);return it===void 0?t:it.createHTML(t)}var bt=(e,t)=>{let n=e.length-1,r=[],i,a=t===2?`<svg>`:t===3?`<math>`:``,o=W;for(let t=0;t<n;t++){let n=e[t],s,c,l=-1,u=0;for(;u<n.length&&(o.lastIndex=u,c=o.exec(n),c!==null);)u=o.lastIndex,o===W?c[1]===`!--`?o=dt:c[1]===void 0?c[2]===void 0?c[3]!==void 0&&(o=G):(ht.test(c[2])&&(i=RegExp(`</`+c[2],`g`)),o=G):o=ft:o===G?c[0]===`>`?(o=i??W,l=-1):c[1]===void 0?l=-2:(l=o.lastIndex-c[2].length,s=c[1],o=c[3]===void 0?G:c[3]===`\"`?mt:pt):o===mt||o===pt?o=G:o===dt||o===ft?o=W:(o=G,i=void 0);let d=o===G&&e[t+1].startsWith(`/>`)?` `:``;a+=o===W?n+st:l>=0?(r.push(s),n.slice(0,l)+at+n.slice(l)+B+d):n+B+(l===-2?t:d)}return[yt(e,a+(e[n]||`<?>`)+(t===2?`</svg>`:t===3?`</math>`:``)),r]},xt=class e{constructor({strings:t,_$litType$:n},r){let i;this.parts=[];let a=0,o=0,s=t.length-1,c=this.parts,[l,u]=bt(t,n);if(this.el=e.createElement(l,r),Y.currentNode=this.el.content,n===2||n===3){let e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;(i=Y.nextNode())!==null&&c.length<s;){if(i.nodeType===1){if(i.hasAttributes())for(let e of i.getAttributeNames())if(e.endsWith(at)){let t=u[o++],n=i.getAttribute(e).split(B),r=/([.?@])?(.*)/.exec(t);c.push({type:1,index:a,name:r[2],strings:n,ctor:r[1]===`.`?wt:r[1]===`?`?Tt:r[1]===`@`?Et:Z}),i.removeAttribute(e)}else e.startsWith(B)&&(c.push({type:6,index:a}),i.removeAttribute(e));if(ht.test(i.tagName)){let e=i.textContent.split(B),t=e.length-1;if(t>0){i.textContent=z?z.emptyScript:``;for(let n=0;n<t;n++)i.append(e[n],H()),Y.nextNode(),c.push({type:2,index:++a});i.append(e[t],H())}}}else if(i.nodeType===8)if(i.data===ot)c.push({type:2,index:a});else{let e=-1;for(;(e=i.data.indexOf(B,e+1))!==-1;)c.push({type:7,index:a}),e+=B.length-1}a++}}static createElement(e,t){let n=V.createElement(`template`);return n.innerHTML=e,n}};function X(e,t,n=e,r){if(t===q)return t;let i=r===void 0?n._$Cl:n._$Co?.[r],a=U(t)?void 0:t._$litDirective$;return i?.constructor!==a&&(i?._$AO?.(!1),a===void 0?i=void 0:(i=new a(e),i._$AT(e,n,r)),r===void 0?n._$Cl=i:(n._$Co??=[])[r]=i),i!==void 0&&(t=X(e,i._$AS(e,t.values),i,r)),t}var St=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:n}=this._$AD,r=(e?.creationScope??V).importNode(t,!0);Y.currentNode=r;let i=Y.nextNode(),a=0,o=0,s=n[0];for(;s!==void 0;){if(a===s.index){let t;s.type===2?t=new Ct(i,i.nextSibling,this,e):s.type===1?t=new s.ctor(i,s.name,s.strings,this,e):s.type===6&&(t=new Dt(i,this,e)),this._$AV.push(t),s=n[++o]}a!==s?.index&&(i=Y.nextNode(),a++)}return Y.currentNode=V,r}p(e){let t=0;for(let n of this._$AV)n!==void 0&&(n.strings===void 0?n._$AI(e[t]):(n._$AI(e,n,t),t+=n.strings.length-2)),t++}},Ct=class e{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,n,r){this.type=2,this._$AH=J,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=n,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=X(this,e,t),U(e)?e===J||e==null||e===``?(this._$AH!==J&&this._$AR(),this._$AH=J):e!==this._$AH&&e!==q&&this._(e):e._$litType$===void 0?e.nodeType===void 0?lt(e)?this.k(e):this._(e):this.T(e):this.$(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==J&&U(this._$AH)?this._$AA.nextSibling.data=e:this.T(V.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:n}=e,r=typeof n==`number`?this._$AC(e):(n.el===void 0&&(n.el=xt.createElement(yt(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===r)this._$AH.p(t);else{let e=new St(r,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=vt.get(e.strings);return t===void 0&&vt.set(e.strings,t=new xt(e)),t}k(t){ct(this._$AH)||(this._$AH=[],this._$AR());let n=this._$AH,r,i=0;for(let a of t)i===n.length?n.push(r=new e(this.O(H()),this.O(H()),this,this.options)):r=n[i],r._$AI(a),i++;i<n.length&&(this._$AR(r&&r._$AB.nextSibling,i),n.length=i)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let t=rt(e).nextSibling;rt(e).remove(),e=t}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},Z=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,n,r,i){this.type=1,this._$AH=J,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=i,n.length>2||n[0]!==``||n[1]!==``?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=J}_$AI(e,t=this,n,r){let i=this.strings,a=!1;if(i===void 0)e=X(this,e,t,0),a=!U(e)||e!==this._$AH&&e!==q,a&&(this._$AH=e);else{let r=e,o,s;for(e=i[0],o=0;o<i.length-1;o++)s=X(this,r[n+o],t,o),s===q&&(s=this._$AH[o]),a||=!U(s)||s!==this._$AH[o],s===J?e=J:e!==J&&(e+=(s??``)+i[o+1]),this._$AH[o]=s}a&&!r&&this.j(e)}j(e){e===J?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??``)}},wt=class extends Z{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===J?void 0:e}},Tt=class extends Z{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==J)}},Et=class extends Z{constructor(e,t,n,r,i){super(e,t,n,r,i),this.type=5}_$AI(e,t=this){if((e=X(this,e,t,0)??J)===q)return;let n=this._$AH,r=e===J&&n!==J||e.capture!==n.capture||e.once!==n.once||e.passive!==n.passive,i=e!==J&&(n===J||r);r&&this.element.removeEventListener(this.name,this,n),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH==`function`?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},Dt=class{constructor(e,t,n){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=n}get _$AU(){return this._$AM._$AU}_$AI(e){X(this,e)}},Ot=R.litHtmlPolyfillSupport;Ot?.(xt,Ct),(R.litHtmlVersions??=[]).push(`3.3.2`);var kt=(e,t,n)=>{let r=n?.renderBefore??t,i=r._$litPart$;if(i===void 0){let e=n?.renderBefore??null;r._$litPart$=i=new Ct(t.insertBefore(H(),e),e,void 0,n??{})}return i._$AI(e),i},At=globalThis,Q=class extends L{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){let e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){let t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=kt(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return q}};Q._$litElement$=!0,Q.finalized=!0,At.litElementHydrateSupport?.({LitElement:Q});var jt=At.litElementPolyfillSupport;jt?.({LitElement:Q}),(At.litElementVersions??=[]).push(`4.2.2`);function Mt(e){if(!e.mimeType?.startsWith(`video/`)||!Number.isFinite(e.durationSeconds)||!e.durationSeconds||e.durationSeconds<=0||e.durationSeconds>15)return!1;let t=e.size;return!(typeof t==`number`&&t>12582912)}var Nt=640,Pt=8,Ft=72,It=16,Lt=704,Rt=.9,zt=.85;function $(e){if(!(!Number.isFinite(e)||!e||e<=0))return e}function Bt(){return{width:globalThis.innerWidth||document.documentElement.clientWidth||0,height:globalThis.innerHeight||document.documentElement.clientHeight||0}}function Vt(e,t){let n=e<=Nt?Pt:Ft;return{width:Math.max(0,e-n*2),height:Math.max(0,t-It*2)}}function Ht(e,t,n){let r=$(e?.width),i=$(e?.height);if(!r||!i)return null;let a=Vt(t,n);if(a.width<=0||a.height<=0)return null;let o=Math.min(a.width/r,a.height/i);return{width:Math.max(1,Math.round(r*o)),height:Math.max(1,Math.round(i*o))}}function Ut(e,t,n){if(!e||e.mimeType?.startsWith(`video/`)||!$(e.width)||!$(e.height)||t<=0||n<=0)return!1;let r=$(e.width),i=$(e.height);if(!r||!i)return!1;let a=t<=Nt,o=Vt(t,n),s=o.width,c=o.height;if(s<=0||c<=0)return!1;let l=r/i,u=Math.min(s,c*l);return l<Rt&&u<(a?s:Math.min(s,Lt))*zt}var Wt=class extends Q{static properties={_images:{state:!0},_currentIndex:{state:!0},_open:{state:!0},_viewportWidth:{state:!0},_viewportHeight:{state:!0},_videoCurrentTime:{state:!0},_videoDuration:{state:!0},_videoMuted:{state:!0},_imageZoomed:{state:!0}};createRenderRoot(){return this.innerHTML=``,this}constructor(){super();let e=Bt();this._images=[],this._currentIndex=0,this._open=!1,this._viewportWidth=e.width,this._viewportHeight=e.height,this._videoCurrentTime=0,this._videoDuration=0,this._videoMuted=!1,this._imageZoomed=!1}connectedCallback(){super.connectedCallback(),document.addEventListener(`click`,this.#e),window.addEventListener(`resize`,this.#l),this.#u()}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(`click`,this.#e),window.removeEventListener(`resize`,this.#l)}open(e,t){this.#u(),this.#d(),this._images=e,this._currentIndex=Math.max(0,Math.min(t,e.length-1)),this.#m(this._images[this._currentIndex]),this._imageZoomed=!1,this._open=!0,document.dispatchEvent(new CustomEvent(v,{detail:{open:!0}})),this.updateComplete.then(()=>{this.querySelector(`.media-lightbox`)?.showModal(),this.#f()})}close(){this.#d(),this.querySelector(`.media-lightbox`)?.close(),this._open=!1,document.dispatchEvent(new CustomEvent(v,{detail:{open:!1}}))}#e=e=>{let t=e.target,n=t.closest(`[data-post-media] a[data-lightbox-index]`);if(n){let t=n.closest(`[data-lightbox-group]`);if(!t)return;e.preventDefault();let r=parseInt(n.dataset.lightboxIndex??`0`,10);try{let e=JSON.parse(t.dataset.lightboxGroup??`[]`);e.length>0&&this.open(e,r)}catch{}return}let r=t.closest(`[data-post-body] img`);if(r){e.preventDefault();let t=r.closest(`[data-post-body]`);if(!t)return;let n=Array.from(t.querySelectorAll(`img`)),i=n.map(e=>({url:e.src,alt:e.alt||``,width:$(e.naturalWidth||Number(e.getAttribute(`width`))),height:$(e.naturalHeight||Number(e.getAttribute(`height`)))})),a=n.indexOf(r);i.length>0&&this.open(i,Math.max(0,a))}};#t(){this._images.length<=1||(this.#d(),this._imageZoomed=!1,this._currentIndex=(this._currentIndex-1+this._images.length)%this._images.length)}#n(){this._images.length<=1||(this.#d(),this._imageZoomed=!1,this._currentIndex=(this._currentIndex+1)%this._images.length)}#r=e=>{let t=this._images[this._currentIndex];Ut(t,this._viewportWidth,this._viewportHeight)&&(e.stopPropagation(),this._imageZoomed=!this._imageZoomed)};#i=e=>{let t=e,n=e.target;if(t.key===`Escape`){e.preventDefault(),this.close();return}if(n instanceof HTMLInputElement||n instanceof HTMLButtonElement||n instanceof HTMLVideoElement)return;if(!this._images[this._currentIndex]?.mimeType?.startsWith(`video/`)){t.key===`ArrowLeft`?(e.preventDefault(),this.#t()):t.key===`ArrowRight`&&(e.preventDefault(),this.#n());return}let r=this.querySelector(`.media-lightbox-video`);r&&this.#a(t,r)};#a(e,t){let n=Number.isFinite(t.duration)&&t.duration>0?t.duration:null,r=e=>{let r=n==null?Math.max(0,e):Math.max(0,Math.min(e,n));t.currentTime=r,this._videoCurrentTime=r},i=e.key,a=i.toLowerCase();if(i===` `||a===`k`)e.preventDefault(),t.paused?t.play().catch(()=>{}):t.pause();else if(i===`ArrowLeft`)e.preventDefault(),r(t.currentTime-2);else if(i===`ArrowRight`)e.preventDefault(),r(t.currentTime+2);else if(i===`Home`)e.preventDefault(),r(0);else if(i===`End`)n!=null&&(e.preventDefault(),r(n));else if(i.length===1&&i>=`0`&&i<=`9`)n!=null&&(e.preventDefault(),r(Number(i)/10*n));else if(i===`ArrowUp`)e.preventDefault(),t.volume=Math.min(1,t.volume+.05);else if(i===`ArrowDown`)e.preventDefault(),t.volume=Math.max(0,t.volume-.05);else if(a===`m`){e.preventDefault();let n=!t.muted;t.muted=n,this._videoMuted=n}else a===`f`&&(e.preventDefault(),this.#o(t))}#o(e){let t=document,n=e;if(document.fullscreenElement??t.webkitFullscreenElement){document.exitFullscreen?document.exitFullscreen().catch(()=>{}):t.webkitExitFullscreen?.();return}e.requestFullscreen?e.requestFullscreen().catch(()=>{}):n.webkitRequestFullscreen?n.webkitRequestFullscreen():n.webkitEnterFullscreen&&n.webkitEnterFullscreen()}#s=e=>{let t=e.target;(t===e.currentTarget||t.classList.contains(`media-lightbox-content`)||t.classList.contains(`media-lightbox-stage`))&&this.close()};#c=()=>{this.#d(),this._open&&document.dispatchEvent(new CustomEvent(v,{detail:{open:!1}})),this._open=!1};#l=()=>{this.#u()};#u(){let e=Bt();e.width===this._viewportWidth&&e.height===this._viewportHeight||(this._viewportWidth=e.width,this._viewportHeight=e.height)}#d(){this.querySelector(`.media-lightbox-video`)?.pause()}#f(){this.querySelector(`.media-lightbox-content`)?.focus()}#p=()=>{this.querySelector(`.media-lightbox-content`)?.focus({preventScroll:!0})};#m(e){this._videoCurrentTime=0,this._videoDuration=e?.durationSeconds&&e.durationSeconds>0?e.durationSeconds:0,this._videoMuted=!1}#h(){let e=this._images[this._currentIndex];if(!Mt(e)){this.#m(e);return}let t=this.querySelector(`.media-lightbox-video`);t&&(t.currentTime=0,t.muted=this._videoMuted,t.play().catch(()=>{}))}#g=e=>{let t=e.currentTarget;Number.isFinite(t.duration)&&t.duration>0&&(this._videoDuration=t.duration),this._videoCurrentTime=t.currentTime,t.muted=this._videoMuted};#_=e=>{let t=e.currentTarget;this._videoCurrentTime=t.currentTime,Number.isFinite(t.duration)&&t.duration>0&&(this._videoDuration=t.duration)};#v=e=>{let t=e.currentTarget,n=this.querySelector(`.media-lightbox-video`),r=Number.parseFloat(t.value);!n||!Number.isFinite(r)||r<0||(n.currentTime=r,this._videoCurrentTime=r)};#y=()=>{this._videoMuted=!this._videoMuted;let e=this.querySelector(`.media-lightbox-video`);e&&(e.muted=this._videoMuted)};updated(e){if(super.updated(e),!this._open||!e.has(`_currentIndex`)&&!e.has(`_open`)&&!e.has(`_imageZoomed`))return;let t=this.querySelector(`.media-lightbox-stage`);t&&(t.scrollTop=0,t.scrollLeft=0,(e.has(`_currentIndex`)||e.has(`_open`))&&(this.#h(),this.#f()))}render(){if(!this._open)return J;let e=this._images[this._currentIndex],t=this._images.length>1,n=e?.mimeType?.startsWith(`video/`),r=Mt(e),i=Ut(e,this._viewportWidth,this._viewportHeight),a=i&&this._imageZoomed,o=r?Ht(e,this._viewportWidth,this._viewportHeight):null,s=r&&!!o&&o.height>o.width,c=o?`width:${o.width}px;height:${o.height}px;`:J,l=this._videoDuration>0?this._videoDuration:e?.durationSeconds??1,u=Math.min(this._videoCurrentTime,l),d=l>0?u/l*100:0;return K`\n <dialog\n class=${`media-lightbox${r?` media-lightbox-short`:``}`}\n @keydown=${this.#i}\n @click=${this.#s}\n @close=${this.#c}\n >\n <div class=\"media-lightbox-content\" tabindex=\"-1\">\n <button\n type=\"button\"\n class=\"media-lightbox-close\"\n @click=${()=>this.close()}\n aria-label=\"Close\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n\n ${t?K`<div class=\"media-lightbox-counter\">\n ${this._currentIndex+1} / ${this._images.length}\n </div>`:J}\n <div\n class=${`media-lightbox-stage${a?` media-lightbox-stage-scroll`:``}`}\n >\n ${n?r?K`<div\n class=${`media-lightbox-short-frame${s?` media-lightbox-short-frame-portrait`:` media-lightbox-short-frame-landscape`}`}\n style=${c}\n >\n <video\n class=\"media-lightbox-video media-lightbox-video-short\"\n src=${e?.url??``}\n poster=${e?.posterUrl??``}\n autoplay\n playsinline\n loop\n ?muted=${this._videoMuted}\n @focus=${this.#p}\n @loadedmetadata=${this.#g}\n @timeupdate=${this.#_}\n ></video>\n <div\n class=${`media-lightbox-short-controls${s?` media-lightbox-short-controls-portrait`:``}`}\n >\n <input\n class=\"media-lightbox-short-progress\"\n type=\"range\"\n min=\"0\"\n max=${l}\n step=\"0.01\"\n .value=${String(u)}\n style=${`--media-progress:${d}%`}\n aria-label=\"Video progress\"\n @input=${this.#v}\n />\n <button\n type=\"button\"\n class=\"media-lightbox-short-mute\"\n @click=${this.#y}\n aria-label=${this._videoMuted?`Unmute video`:`Mute video`}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 48 48\"\n fill=\"currentColor\"\n color=\"#fff\"\n aria-hidden=\"true\"\n >\n ${this._videoMuted?_t`\n <path d=\"M1.5 13.3c-.8 0-1.5.7-1.5 1.5v18.4c0 .8.7 1.5 1.5 1.5h8.7l12.9 12.9c.9.9 2.5.3 2.5-1v-9.8c0-.4-.2-.8-.4-1.1l-22-22c-.3-.3-.7-.4-1.1-.4h-.6zm46.8 31.4-5.5-5.5C44.9 36.6 48 31.4 48 24c0-11.4-7.2-17.4-7.2-17.4-.6-.6-1.6-.6-2.2 0L37.2 8c-.6.6-.6 1.6 0 2.2 0 0 5.7 5 5.7 13.8 0 5.4-2.1 9.3-3.8 11.6L35.5 32c1.1-1.7 2.3-4.4 2.3-8 0-6.8-4.1-10.3-4.1-10.3-.6-.6-1.6-.6-2.2 0l-1.4 1.4c-.6.6-.6 1.6 0 2.2 0 0 2.6 2 2.6 6.7 0 1.8-.4 3.2-.9 4.3L25.5 22V1.4c0-1.3-1.6-1.9-2.5-1L13.5 10 3.3-.3c-.6-.6-1.5-.6-2.1 0L-.2 1.1c-.6.6-.6 1.5 0 2.1L4 7.6l26.8 26.8 13.9 13.9c.6.6 1.5.6 2.1 0l1.4-1.4c.7-.6.7-1.6.1-2.2z\" />\n `:_t`\n <path d=\"M1.5 13.3c-.8 0-1.5.7-1.5 1.5v18.4c0 .8.7 1.5 1.5 1.5h8.7l12.9 12.9c.9.9 2.5.3 2.5-1V1.4c0-1.3-1.6-1.9-2.5-1L10.2 13.3H1.5z\" />\n <path d=\"M30.1 15.9c-.6-.6-.6-1.6 0-2.2l1.4-1.4c.6-.6 1.6-.6 2.2 0 0 0 4.1 3.5 4.1 11.7s-4.1 11.7-4.1 11.7c-.6.6-1.6.6-2.2 0l-1.4-1.4c-.6-.6-.6-1.6 0-2.2 0 0 2.6-2 2.6-8.1s-2.6-8.1-2.6-8.1z\" />\n <path d=\"M37.2 8c-.6-.6-.6-1.6 0-2.2l1.4-1.4c.6-.6 1.6-.6 2.2 0 0 0 5.7 5.1 5.7 19.6s-5.7 19.6-5.7 19.6c-.6.6-1.6.6-2.2 0L37.2 42c-.6-.6-.6-1.6 0-2.2 0 0 4.3-4.4 4.3-15.8S37.2 8 37.2 8z\" />\n `}\n </svg>\n </button>\n </div>\n </div>`:K`<video\n class=\"media-lightbox-video\"\n src=${e?.url??``}\n poster=${e?.posterUrl??``}\n controls\n autoplay\n playsinline\n @focus=${this.#p}\n ></video>`:K`<img\n class=${`media-lightbox-img${i?` media-lightbox-img-zoomable`:``}${a?` media-lightbox-img-scroll`:``}`}\n src=${e?.url??``}\n alt=${e?.alt??``}\n @click=${this.#r}\n />`}\n </div>\n ${t?K`\n <button\n type=\"button\"\n class=\"media-lightbox-nav media-lightbox-nav-prev\"\n @click=${()=>this.#t()}\n aria-label=\"Previous\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"media-lightbox-nav media-lightbox-nav-next\"\n @click=${()=>this.#n()}\n aria-label=\"Next\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n `:J}\n </div>\n </dialog>\n `}};customElements.define(`jant-media-lightbox`,Wt);";
3308
3316
  //#endregion
3309
3317
  //#region src/services/export-theme/assets/client-site.css?raw
3310
3318
  var client_site_default = "@keyframes lightbox-fade-in{0%{opacity:0}to{opacity:1}}@keyframes lightbox-scale-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.media-lightbox{background:0 0;border:none;outline:none;width:100%;max-width:100%;height:100%;max-height:100%;padding:0}.media-lightbox[open]{animation:.2s both lightbox-fade-in}.media-lightbox::backdrop{background-color:#000}.media-lightbox-content{outline:none;width:100%;height:100dvh;position:relative}.media-lightbox-stage{box-sizing:border-box;justify-content:center;align-items:center;width:100%;height:100%;padding:64px 96px;display:flex;overflow:hidden}.media-lightbox-stage-scroll{overscroll-behavior:contain;scrollbar-gutter:stable both-edges;-webkit-overflow-scrolling:touch;align-items:flex-start;overflow:hidden auto}.media-lightbox-img{object-fit:contain;border-radius:4px;max-width:100%;max-height:100%;animation:.28s cubic-bezier(.22,1,.36,1) both lightbox-scale-in;display:block}.media-lightbox-img-zoomable{cursor:zoom-in}.media-lightbox-img-scroll{width:min(100%,44rem);max-width:none;height:auto;max-height:none;margin:0 auto}.media-lightbox-img-zoomable.media-lightbox-img-scroll{cursor:zoom-out}.media-lightbox-close{z-index:10;-webkit-backdrop-filter:blur(8px);color:#fff;cursor:pointer;background-color:#00000080;border:none;border-radius:50%;justify-content:center;align-items:center;width:40px;height:40px;transition:background-color .15s;display:flex;position:fixed;top:16px;left:16px}.media-lightbox-close:hover{background-color:#000000b3}.media-lightbox-nav{z-index:10;-webkit-backdrop-filter:blur(8px);color:#fff;cursor:pointer;background-color:#00000080;border:none;border-radius:50%;justify-content:center;align-items:center;width:44px;height:44px;transition:background-color .15s;display:flex;position:fixed;top:50%;transform:translateY(-50%)}.media-lightbox-nav:hover{background-color:#000000b3}.media-lightbox-nav-prev{left:16px}.media-lightbox-nav-next{right:16px}.media-lightbox-counter{z-index:10;font-size:var(--type-xs);color:#ffffffb3;font-variant-numeric:tabular-nums;-webkit-user-select:none;user-select:none;position:fixed;top:20px;left:50%;transform:translate(-50%)}.media-lightbox-short-frame{max-width:100%;max-height:100%;display:block;position:relative}.media-lightbox-short-controls{z-index:2;pointer-events:none;height:86px;position:absolute;bottom:0;left:0;right:0}.media-lightbox-short-progress{--media-progress:0%;z-index:1;appearance:none;pointer-events:auto;cursor:pointer;background:0 0;width:auto;height:34px;margin:0;padding:0;display:block;position:absolute;bottom:0;left:16px;right:16px}.media-lightbox-short-progress::-webkit-slider-runnable-track{background:linear-gradient(to right, #ffffffeb 0, #ffffffeb var(--media-progress), #ffffff2e var(--media-progress), #ffffff2e 100%);border-radius:999px;height:2px;transition:height .15s,background .15s}.media-lightbox-short-progress::-webkit-slider-thumb{appearance:none;opacity:.82;background-color:#fff;border:none;border-radius:999px;width:10px;height:10px;margin-top:-4px;transition:opacity .15s,transform .15s;box-shadow:0 1px 4px #00000052}.media-lightbox-short-progress::-moz-range-track{background:#ffffff2e;border:none;border-radius:999px;height:2px}.media-lightbox-short-progress::-moz-range-progress{background:#ffffffeb;border-radius:999px;height:2px}.media-lightbox-short-progress::-moz-range-thumb{opacity:.82;background-color:#fff;border:none;border-radius:999px;width:10px;height:10px;transition:opacity .15s,transform .15s;box-shadow:0 1px 4px #00000052}.media-lightbox-short-controls-portrait .media-lightbox-short-progress{width:calc(100% - 48px);right:auto}.media-lightbox-short-progress:hover::-webkit-slider-runnable-track{height:4px}.media-lightbox-short-progress:focus-visible::-webkit-slider-runnable-track{height:4px}.media-lightbox-short-progress:hover::-moz-range-track{height:4px}.media-lightbox-short-progress:focus-visible::-moz-range-track{height:4px}.media-lightbox-short-progress:hover::-moz-range-progress{height:4px}.media-lightbox-short-progress:focus-visible::-moz-range-progress{height:4px}.media-lightbox-short-progress:hover::-webkit-slider-thumb{opacity:1;transform:scale(1.05)}.media-lightbox-short-progress:focus-visible::-webkit-slider-thumb{opacity:1;transform:scale(1.05)}.media-lightbox-short-progress:hover::-moz-range-thumb{opacity:1;transform:scale(1.05)}.media-lightbox-short-progress:focus-visible::-moz-range-thumb{opacity:1;transform:scale(1.05)}.media-lightbox-short-mute{z-index:2;color:#fff;pointer-events:auto;cursor:pointer;background-color:#777;border:none;border-radius:999px;justify-content:center;align-items:center;width:44px;height:44px;transition:background-color .15s,transform .15s;display:inline-flex;position:absolute;bottom:30px;right:24px}.media-lightbox-short-mute svg{flex-shrink:0;width:16px;height:16px;display:block}.media-lightbox-short-mute:hover{background-color:#686868;transform:scale(1.03)}.media-lightbox-short-mute:focus-visible{outline:none;box-shadow:0 0 0 3px #fff3}@media (max-width:640px){.media-lightbox-stage{padding:48px 16px}.media-lightbox-img{border-radius:0}.media-lightbox-img-scroll{width:100%}.media-lightbox-close{width:36px;height:36px;top:12px;left:12px}.media-lightbox-nav{width:36px;height:36px}.media-lightbox-nav-prev{left:8px}.media-lightbox-nav-next{right:8px}.media-lightbox-short-mute{bottom:26px;right:24px}}.media-visual-frame{border-radius:var(--media-radius,.5rem);background-color:var(--color-muted);display:block;overflow:hidden}.media-visual{background-position:50%;background-repeat:no-repeat;display:block}.media-video-wrap{position:relative}.media-video-link{cursor:pointer;display:block}.media-video-wrap video{object-fit:contain;background-color:var(--color-muted);width:100%;max-height:24rem}.media-video-wrap-short video{background-color:#000}.media-feed-video-mute{z-index:1;color:#fff;cursor:pointer;background-color:#00000080;border:none;border-radius:999px;justify-content:center;align-items:center;width:28px;height:28px;transition:background-color .15s,transform .15s;display:inline-flex;position:absolute;bottom:16px;right:16px}.media-feed-video-mute svg{width:12px;height:12px}.media-feed-video-mute:hover{background-color:#0000009e;transform:scale(1.03)}.media-feed-video-mute:focus-visible{outline:none;box-shadow:0 0 0 3px #fff3}.media-feed-video-icon{transition:opacity .15s,transform .15s;position:absolute}.media-feed-video-mute[data-muted=true] .media-feed-video-icon-muted,.media-feed-video-mute[data-muted=false] .media-feed-video-icon-unmuted{opacity:1;transform:scale(1)}.media-feed-video-mute[data-muted=true] .media-feed-video-icon-unmuted,.media-feed-video-mute[data-muted=false] .media-feed-video-icon-muted{opacity:0;transform:scale(.92)}.media-video-play-overlay{pointer-events:none;justify-content:center;align-items:center;transition:opacity .15s;display:flex;position:absolute;inset:0}.media-video-play-overlay svg{filter:drop-shadow(0 2px 6px #0006);opacity:.85;width:48px;height:48px}.media-gallery-card.media-audio-card{flex-direction:column;display:flex}.media-audio-card .media-audio-el{opacity:0;pointer-events:none;width:0;height:0;position:absolute}.media-audio-card .media-audio-artwork{background:linear-gradient(160deg,#8080801f 0%,#80808008 100%);flex:1;justify-content:center;align-items:center;width:100%;min-height:0;display:flex}.media-audio-card .media-audio-artwork svg{width:32px;height:32px;color:var(--site-text-secondary);opacity:.3}.media-audio-card .media-audio-waveform{cursor:pointer;touch-action:none;width:100%;height:24px;display:none}.media-audio-card.has-waveform .media-audio-waveform{display:block}.media-audio-card.has-waveform .media-audio-range{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.media-audio-card .media-audio-controls{flex-direction:column;flex-shrink:0;padding:0 0 6px;display:flex}.media-audio-card .media-audio-range{appearance:none;cursor:pointer;touch-action:none;background:0 0;width:100%;height:20px;margin:0;padding:0}.media-audio-card .media-audio-range::-webkit-slider-runnable-track{background:#80808026;border-radius:1.5px;height:3px}.media-audio-card .media-audio-range::-moz-range-track{background:#80808026;border:none;border-radius:1.5px;height:3px}.media-audio-card .media-audio-range::-moz-range-progress{background:var(--site-text-primary);border-radius:1.5px;height:3px}.media-audio-card .media-audio-range::-webkit-slider-thumb{-webkit-appearance:none;background:var(--site-text-primary);opacity:0;border:none;border-radius:50%;width:10px;height:10px;margin-top:-3.5px;transition:opacity .15s}.media-audio-card .media-audio-range:hover::-webkit-slider-thumb{opacity:1}.media-audio-card.is-playing .media-audio-range::-webkit-slider-thumb{opacity:1}.media-audio-card .media-audio-range::-moz-range-thumb{background:var(--site-text-primary);opacity:0;border:none;border-radius:50%;width:10px;height:10px;transition:opacity .15s}.media-audio-card .media-audio-range:hover::-moz-range-thumb{opacity:1}.media-audio-card.is-playing .media-audio-range::-moz-range-thumb{opacity:1}.media-audio-card .media-audio-range:focus-visible{outline:2px solid var(--site-text-primary);outline-offset:2px;border-radius:2px}.media-audio-card .media-audio-row{align-items:center;gap:6px;min-width:0;padding:6px 8px 0;display:flex}.media-audio-card .media-audio-info{flex-direction:column;flex:1;gap:1px;min-width:0;display:flex}.media-audio-card .media-audio-title{font-size:var(--type-2xs);font-weight:var(--fw-medium,500);color:var(--site-text-primary);text-overflow:ellipsis;white-space:nowrap;line-height:1.3;overflow:hidden}.media-audio-card .media-audio-time{font-size:var(--type-2xs);color:var(--site-text-secondary);font-variant-numeric:tabular-nums;line-height:1}.media-audio-card .media-audio-play-btn{cursor:pointer;background:var(--site-text-primary);width:28px;height:28px;color:var(--background,#fff);border:none;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;transition:transform .12s;display:flex}.media-audio-card .media-audio-play-btn:hover{transform:scale(1.1)}.media-audio-card .media-audio-play-btn:active{transform:scale(.92)}.media-audio-card .media-audio-play-btn svg{width:14px;height:14px}.media-audio-card .media-audio-icon-play{margin-left:2px}.media-audio-card .media-audio-icon-pause,.media-audio-card.is-playing .media-audio-icon-play{display:none}.media-audio-card.is-playing .media-audio-icon-pause{display:block}.media-gallery-card{color:var(--site-text-primary);border-radius:var(--media-radius,.5rem);background-color:var(--site-nav-hover-bg);border:1px solid var(--site-divider);text-decoration:none;transition:background-color .15s;display:block;overflow:hidden}a.media-gallery-card:hover,button.media-gallery-card:hover{background-color:var(--site-divider)}button.media-gallery-card{cursor:pointer;font:inherit;text-align:inherit}.media-gallery-card-inner{text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:8px;width:100%;height:100%;padding:16px 12px;display:flex}.media-gallery-card-icon{color:var(--site-text-secondary);opacity:.6}.media-gallery-card-summary{font-size:var(--type-xs);color:var(--site-text-secondary);-webkit-line-clamp:2;word-break:break-word;-webkit-box-orient:vertical;line-height:1.4;display:-webkit-box;overflow:hidden}.media-gallery-card-meta{font-size:var(--type-xs);color:var(--site-text-secondary)}.media-lightbox-video{background-color:#000;border-radius:4px;outline:none;max-width:100%;max-height:100%;animation:.28s cubic-bezier(.22,1,.36,1) both lightbox-scale-in}.media-lightbox-video:focus,.media-lightbox-video:focus-visible{outline:none}.media-lightbox-video-short{object-fit:contain;width:100%;max-width:none;height:100%;max-height:none;display:block}@media (max-width:640px){.media-lightbox-video{border-radius:0}}[data-post-media] img{background:0 0}.media-gallery-scroll-wrap{position:relative}.media-gallery-nav{z-index:2;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#fff;cursor:pointer;opacity:0;pointer-events:none;background-color:#00000080;border:none;border-radius:50%;justify-content:center;align-items:center;width:34px;height:34px;padding:0;transition:opacity .15s,background-color .15s;display:flex;position:absolute;top:50%;transform:translateY(-50%)}.media-gallery-nav:hover{background-color:#000000b3}.media-gallery-nav svg{width:18px;height:18px;display:block}.media-gallery-nav-prev{left:8px}.media-gallery-nav-next{right:8px}@media (hover:hover) and (pointer:fine){.media-gallery-scroll-wrap.can-scroll-start:hover .media-gallery-nav-prev,.media-gallery-scroll-wrap.can-scroll-end:hover .media-gallery-nav-next{opacity:1;pointer-events:auto}}.media-gallery-scroll-wrap>[data-post-media]:focus-visible{outline:2px solid var(--site-text-primary);outline-offset:2px;border-radius:4px}\n/*$vite$:1*/";
@@ -3322,7 +3330,7 @@ var list_default$4 = "{{ define \"main\" }}\n {{- /*\n _default/list.html is
3322
3330
  var alias_default = "<!doctype html>\n<html lang=\"{{ .Site.LanguageCode | default \"en\" }}\">\n <head>\n <meta charset=\"utf-8\">\n <title>{{ .Site.Title }}</title>\n <meta name=\"robots\" content=\"noindex,follow\">\n <meta http-equiv=\"refresh\" content=\"0; url={{ .Permalink }}\">\n <link rel=\"canonical\" href=\"{{ .Permalink }}\">\n <script>\n (function () {\n var target = {{ .Permalink }};\n var rootAliases = {{ with .Params.root_aliases }}{{ . | jsonify }}{{ else }}[]{{ end }};\n try {\n var path = window.location.pathname || \"\";\n var normalized = \"/\" + path.replace(/^\\/+|\\/+$/g, \"\") + \"/\";\n var isHistoricalRootAlias = false;\n for (var i = 0; i < rootAliases.length; i++) {\n var alias = String(rootAliases[i]);\n var aliasNorm = \"/\" + alias.replace(/^\\/+|\\/+$/g, \"\") + \"/\";\n if (aliasNorm === normalized) {\n isHistoricalRootAlias = true;\n break;\n }\n }\n if (isHistoricalRootAlias) {\n // Historical root-slug alias — redirect to the post itself\n // without injecting an anchor.\n window.location.replace(target);\n return;\n }\n // Thread reply alias — append the reply slug as an anchor so\n // the thread page scrolls to the original reply.\n var parts = normalized.split(\"/\").filter(Boolean);\n var slug = parts.length > 0 ? parts[parts.length - 1] : \"\";\n if (slug) {\n window.location.replace(target + \"#\" + slug);\n } else {\n window.location.replace(target);\n }\n } catch (_err) {\n window.location.replace(target);\n }\n })();\n <\/script>\n </head>\n <body>\n <p>Redirecting to <a href=\"{{ .Permalink }}\">{{ .Permalink }}</a>&hellip;</p>\n </body>\n</html>\n";
3323
3331
  //#endregion
3324
3332
  //#region src/services/export-theme/layouts/index.html?raw
3325
- var layouts_default = "{{ define \"main\" }}\n {{- $homeDefaultView := .Site.Params.home_default_view | default \"latest\" -}}\n {{- $pageSize := .Site.Params.page_size | default 10 -}}\n {{- /* Root posts are branch bundles (kind=section), so we iterate .Site.Pages, not .Site.RegularPages. */ -}}\n {{- $allPosts := where .Site.Pages \"Type\" \"post\" -}}\n {{- $pinned := where $allPosts \"Params.pinned_at\" \"ne\" nil -}}\n {{- $pinned = $pinned.ByDate.Reverse -}}\n {{- $main := slice -}}\n {{- if eq $homeDefaultView \"featured\" -}}\n {{- $featured := where $allPosts \"Params.featured_at\" \"ne\" nil -}}\n {{- $main = sort $featured \"Params.featured_at\" \"desc\" -}}\n {{- else -}}\n {{- $public := where $allPosts \"Params.visibility\" \"public\" -}}\n {{- $public = where $public \"Params.pinned_at\" nil -}}\n {{- $main = $public.ByDate.Reverse -}}\n {{- end -}}\n {{- $paginator := .Paginate $main $pageSize -}}\n\n <section class=\"home\">\n {{- if and (eq $paginator.PageNumber 1) $pinned -}}\n <div class=\"post-list post-list-pinned\" aria-label=\"Pinned posts\">\n {{- range $i, $p := $pinned -}}\n {{- if gt $i 0 -}}<hr class=\"feed-divider\" aria-hidden=\"true\" />{{- end -}}\n {{ partial \"thread-preview.html\" $p }}\n {{- end -}}\n </div>\n {{- end -}}\n\n {{- if $paginator.Pages -}}\n <div class=\"post-list post-list-main\">\n {{- range $i, $p := $paginator.Pages -}}\n {{- if gt $i 0 -}}<hr class=\"feed-divider\" aria-hidden=\"true\" />{{- end -}}\n {{ partial \"thread-preview.html\" $p }}\n {{- end -}}\n </div>\n {{ partial \"pagination.html\" $paginator }}\n {{- else if not $pinned -}}\n <p class=\"empty-state\">Nothing published yet. Write your first post to get started.</p>\n {{- end -}}\n </section>\n{{ end }}\n";
3333
+ var layouts_default = "{{ define \"main\" }} {{- $pageSize := .Site.Params.page_size | default 10 -}} {{-\n/* Root posts are branch bundles (kind=section), so we iterate .Site.Pages, not\n.Site.RegularPages. */ -}} {{- $allPosts := where .Site.Pages \"Type\" \"post\" -}}\n{{- $pinned := where $allPosts \"Params.pinned_at\" \"ne\" nil -}} {{- $pinned =\n$pinned.ByDate.Reverse -}} {{- $public := where $allPosts \"Params.visibility\"\n\"public\" -}} {{- $public = where $public \"Params.pinned_at\" nil -}} {{- $main :=\n$public.ByDate.Reverse -}} {{- $paginator := .Paginate $main $pageSize -}}\n\n<section class=\"home\">\n {{- if and (eq $paginator.PageNumber 1) $pinned -}}\n <div class=\"post-list post-list-pinned\" aria-label=\"Pinned posts\">\n {{- range $i, $p := $pinned -}} {{- if gt $i 0 -}}\n <hr class=\"feed-divider\" aria-hidden=\"true\" />\n {{- end -}} {{ partial \"thread-preview.html\" $p }} {{- end -}}\n </div>\n {{- end -}} {{- if $paginator.Pages -}}\n <div class=\"post-list post-list-main\">\n {{- range $i, $p := $paginator.Pages -}} {{- if gt $i 0 -}}\n <hr class=\"feed-divider\" aria-hidden=\"true\" />\n {{- end -}} {{ partial \"thread-preview.html\" $p }} {{- end -}}\n </div>\n {{ partial \"pagination.html\" $paginator }} {{- else if not $pinned -}}\n <p class=\"empty-state\">\n Nothing published yet. Write your first post to get started.\n </p>\n {{- end -}}\n</section>\n{{ end }}\n";
3326
3334
  //#endregion
3327
3335
  //#region src/services/export-theme/layouts/post/list.html?raw
3328
3336
  var list_default$3 = "{{ define \"main\" }}\n {{- $root := . -}}\n {{- $format := $root.Params.format | default \"note\" -}}\n {{- $slug := $root.Params.slug | default $root.Slug -}}\n {{- $media := $root.Params.media | default slice -}}\n {{- $collections := $root.Params.collections | default slice -}}\n {{- $linkUrl := $root.Params.link_url -}}\n {{- $replies := $root.Pages.ByDate -}}\n {{- $hasReplies := gt (len $replies) 0 -}}\n <article class=\"thread thread-{{ $format }}{{ if $hasReplies }} thread-has-replies{{ end }}\" id=\"{{ $slug }}\" data-format=\"{{ $format }}\" data-slug=\"{{ $slug }}\"\n {{- if $root.Params.pinned_at }} data-post-pinned{{ end -}}\n {{- if $root.Params.featured_at }} data-post-featured{{ end -}}\n >\n <div class=\"thread-item thread-item-root\">\n <header class=\"thread-header\">\n {{- if eq $format \"link\" -}}\n {{- if $linkUrl -}}\n {{- $domain := \"\" -}}\n {{- with urls.Parse $linkUrl -}}{{- $domain = .Host -}}{{- end -}}\n {{- if $domain -}}\n <a href=\"{{ $linkUrl }}\" class=\"thread-link-domain\" rel=\"noopener noreferrer\" target=\"_blank\">\n <svg class=\"post-card-link-domain-icon\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"2\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25\" />\n </svg>\n <span>{{ $domain }}</span>\n </a>\n {{- end -}}\n {{- end -}}\n {{- if $root.Title -}}\n <h1 class=\"thread-title thread-link-title\">\n {{- if $linkUrl -}}\n <a href=\"{{ $linkUrl }}\" rel=\"noopener noreferrer\" target=\"_blank\">{{ $root.Title }}</a>\n {{- else -}}\n {{ $root.Title }}\n {{- end -}}\n </h1>\n {{- end -}}\n {{- else if eq $format \"quote\" -}}\n <blockquote class=\"thread-quote post-card-quote\">\n {{- with $root.Params.quote_text -}}\n <span class=\"post-card-quote-mark\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 96 96\" role=\"presentation\" focusable=\"false\">\n <path fill=\"currentColor\" d=\"M24.4 10.5C16.9 17.7 11.5 26.8 8.2 37.7C4.9 48.7 4.8 58.9 7.8 68.2C10.3 75.7 15.4 79.5 22.9 79.5C28 79.5 32.2 77.8 35.4 74.2C38.6 70.7 40.2 66.5 40.2 61.4C40.2 56.5 38.8 52.6 36 49.6C33.3 46.6 29.7 45.1 25.2 45.1C23.4 45.1 21.8 45.3 20.2 45.8C22.2 37.3 26.7 29.2 33.6 21.4L24.4 10.5Z\" />\n <path fill=\"currentColor\" d=\"M60.8 10.5C53.3 17.7 47.9 26.8 44.6 37.7C41.3 48.7 41.2 58.9 44.2 68.2C46.7 75.7 51.8 79.5 59.3 79.5C64.4 79.5 68.6 77.8 71.8 74.2C75 70.7 76.6 66.5 76.6 61.4C76.6 56.5 75.2 52.6 72.4 49.6C69.7 46.6 66.1 45.1 61.6 45.1C59.8 45.1 58.2 45.3 56.6 45.8C58.6 37.3 63.1 29.2 70 21.4L60.8 10.5Z\" />\n </svg>\n </span>\n <div class=\"post-card-quote-content\">{{ . }}</div>\n {{- end -}}\n {{- if or $root.Params.source_name $root.Params.source_url -}}\n <div class=\"post-card-quote-attribution\">\n {{- if and $root.Params.source_name $root.Params.source_url -}}\n <a href=\"{{ $root.Params.source_url }}\" class=\"post-card-quote-source\" rel=\"noopener noreferrer\" target=\"_blank\">{{ $root.Params.source_name }}</a>\n {{- else if $root.Params.source_name -}}\n <span class=\"post-card-quote-source\">{{ $root.Params.source_name }}</span>\n {{- else -}}\n {{- $sourceDomain := \"\" -}}\n {{- with urls.Parse $root.Params.source_url -}}\n {{- $sourceDomain = .Host | replaceRE \"^(?:www|m|mobile)\\\\.\" \"\" -}}\n {{- end -}}\n <a href=\"{{ $root.Params.source_url }}\" class=\"post-card-quote-source\" rel=\"noopener noreferrer\" target=\"_blank\">{{ or $sourceDomain $root.Params.source_url }}</a>\n {{- end -}}\n </div>\n {{- end -}}\n </blockquote>\n {{- else -}}\n {{- with $root.Title -}}<h1 class=\"thread-title\">{{ . }}</h1>{{- end -}}\n {{- end -}}\n </header>\n\n {{- if eq $format \"quote\" -}}\n {{- with $root.Content -}}\n <div class=\"thread-body post-card-quote-commentary prose\">{{ . }}</div>\n {{- end -}}\n {{- else -}}\n <div class=\"thread-body prose\">\n {{ $root.Content }}\n </div>\n {{- end -}}\n\n {{ partial \"media-gallery.html\" (dict \"media\" $media \"permalink\" $root.RelPermalink) }}\n\n <footer class=\"thread-footer post-menu-footer post-footer-detail\" data-post-meta>\n <div class=\"post-footer-meta\">\n {{- if $root.Params.featured_at -}}\n <span class=\"post-footer-featured\" aria-label=\"Featured\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M12 3 10.1 10.1 3 12l7.1 1.9L12 21l1.9-7.1L21 12l-7.1-1.9Z\" />\n </svg>\n </span>\n {{- end -}}\n <a class=\"post-footer-link\" href=\"{{ $root.RelPermalink }}\">\n <time datetime=\"{{ $root.Date.Format \"2006-01-02T15:04:05Z07:00\" }}\">\n {{ $root.Date.Format \"Jan 2, 2006 · 15:04\" }}\n </time>\n </a>\n {{- if and (eq $format \"link\") $linkUrl -}}\n <a href=\"{{ $linkUrl }}\" class=\"post-footer-external-link\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"Open external link\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M7 17 17 7\" />\n <path d=\"M9 7h8v8\" />\n </svg>\n </a>\n {{- end -}}\n {{- if $collections -}}\n <span class=\"post-collection-tags\">\n {{- range $i, $c := $collections -}}\n {{- if gt $i 0 -}}<span class=\"post-collection-sep\" aria-hidden=\"true\">, </span>{{- end -}}\n <a class=\"post-collection-tag\" href=\"{{ printf \"/%s/\" .slug | relURL }}\">\n <span class=\"post-collection-tag-text\">{{ .title }}</span>\n </a>\n {{- end -}}\n </span>\n {{- end -}}\n {{- if $root.Params.pinned_at -}}\n <span class=\"post-card-pin\" aria-label=\"Pinned\">Pinned</span>\n {{- end -}}\n </div>\n </footer>\n </div>\n\n {{- if $hasReplies -}}\n <section class=\"thread-replies\" aria-label=\"Replies\">\n {{- range $replies -}}\n {{ partial \"reply.html\" . }}\n {{- end -}}\n </section>\n {{- end -}}\n </article>\n{{ end }}\n";
@@ -3364,7 +3372,7 @@ var reply_default = "{{- $reply := . -}}\n{{- $format := $reply.Params.format |
3364
3372
  var thread_preview_default = "{{- /*\n Thread preview partial.\n\n Matches the main site's `ThreadPreview` component layout:\n root post (full card, as \"context\")\n second reply (full card, as \"context\") ← if distinct\n \"N more posts\" gap pill ← if there are hidden middle replies\n penultimate reply (full card, as \"context\") ← if distinct\n latest reply (full card, as \"hero\")\n\n Each entry is wrapped in a `.thread-item` so the rail dot markers\n line up the same way the main site does via `.thread-item::before`.\n\n When the root has no replies, falls through to a plain post-card.\n*/ -}}\n{{- $root := . -}}\n{{- $replies := where $root.Pages \"Params.visibility\" \"public\" -}}\n{{- $replies = $replies.ByDate -}}\n{{- $replyCount := len $replies -}}\n{{- if eq $replyCount 0 -}}\n {{ partial \"post-card.html\" $root }}\n{{- else -}}\n {{- /* First-in / last-in replies, with overlap handled below. */ -}}\n {{- $latest := index $replies (sub $replyCount 1) -}}\n {{- $second := index $replies 0 -}}\n {{- $penultimate := cond (gt $replyCount 2) (index $replies (sub $replyCount 2)) false -}}\n\n {{- $renderSecond := ne $second.File.UniqueID $latest.File.UniqueID -}}\n {{- $renderPenultimate := and $penultimate (ne $penultimate.File.UniqueID $latest.File.UniqueID) -}}\n {{- if $penultimate -}}\n {{- if eq $penultimate.File.UniqueID $second.File.UniqueID -}}\n {{- $renderPenultimate = false -}}\n {{- end -}}\n {{- end -}}\n\n {{- /* Count of context posts actually rendered above the hero (second\n + penultimate when distinct from latest and each other). The\n remainder of replies is the \"hidden middle\" count. Mirrors\n `getThreadPreviewState` in thread-preview-state.ts. */ -}}\n {{- $visibleContextReplies := 0 -}}\n {{- if $renderSecond -}}{{- $visibleContextReplies = add $visibleContextReplies 1 -}}{{- end -}}\n {{- if $renderPenultimate -}}{{- $visibleContextReplies = add $visibleContextReplies 1 -}}{{- end -}}\n {{- /* Total replies rendered = visibleContextReplies + 1 (hero). */ -}}\n {{- $hiddenCount := sub $replyCount (add $visibleContextReplies 1) -}}\n {{- if lt $hiddenCount 0 -}}{{- $hiddenCount = 0 -}}{{- end -}}\n\n {{- $slug := $root.Params.slug | default $root.Slug -}}\n <article class=\"thread-preview\" data-slug=\"{{ $slug }}\" data-reply-count=\"{{ $replyCount }}\">\n <div class=\"thread-preview-context\">\n <div class=\"thread-item thread-item-context thread-item-root\">\n {{ partial \"post-card.html\" $root }}\n </div>\n\n {{- if $renderSecond -}}\n <div class=\"thread-item thread-item-context\">\n {{ partial \"post-card.html\" $second }}\n </div>\n {{- end -}}\n\n {{- if gt $hiddenCount 0 -}}\n <div class=\"thread-item thread-item-gap\">\n <a class=\"thread-preview-gap\" href=\"{{ $root.RelPermalink }}\">\n {{ $hiddenCount }} more {{ if eq $hiddenCount 1 }}post{{ else }}posts{{ end }}\n </a>\n </div>\n {{- end -}}\n\n {{- if $renderPenultimate -}}\n <div class=\"thread-item thread-item-context\">\n {{ partial \"post-card.html\" $penultimate }}\n </div>\n {{- end -}}\n </div>\n\n <div class=\"thread-item thread-item-hero thread-preview-hero\">\n {{ partial \"post-card.html\" $latest }}\n <a class=\"thread-preview-thread-link\" href=\"{{ $root.RelPermalink }}\">\n View full thread &rarr;\n </a>\n </div>\n </article>\n{{- end -}}\n";
3365
3373
  //#endregion
3366
3374
  //#region src/services/export-theme/layouts/_default/rss.xml?raw
3367
- var rss_default = "{{- /*\n Atom 2005 feed template — mirrors the main site's `lib/feed.ts`.\n\n One template covers every page that opts into the custom `RSS` output\n format (home, featured, archive, and each collection section). Root-post\n sections do NOT opt in, so no `/{slug}/index.xml` gets emitted.\n\n Feed filter parity with the corresponding HTML list view:\n - home (`.Kind == \"home\"`): visibility == \"public\" (drops latest_hidden)\n - featured (`.Type == \"featured\"`): featured_at != nil\n - archive (`.Type == \"archive\"`): all published (includes latest_hidden)\n - collection (`.Type == \"collection\"`): Params.collections.slug match,\n pinned first then per `sort_order`\n\n Per-entry payload mirrors `buildSinglePostContent` + `buildFeedContent`:\n - Title: empty for quote posts, else .Title\n - Link rel=alternate: external URL for `link` format, else permalink;\n link-format posts also get a <link rel=\"related\"> back to the\n permalink\n - Content (CDATA):\n quote → <blockquote cite><p>{quote}</p></blockquote>\n + <p>— <a href=url>{source}</a></p>\n body → Hugo-rendered .Content (stripped of <script>/<style>)\n rating → <p>★★★★☆ 4/5</p>\n link → trailing <p><a href=permalink> ★ </a></p>\n replies → <hr/> + <p><small><time>{dt}</time></small></p>\n + inline title/link metadata + content\n\n Hugo's default RSS media-type override (`[outputFormats.RSS]`) makes this\n template produce application/atom+xml at /{section}/index.xml.\n*/ -}}\n{{- $page := . -}}\n{{- $limit := int (.Site.Params.rss_feed_limit | default 50) -}}\n{{- $allPosts := where .Site.Pages \"Type\" \"post\" -}}\n\n{{- /* ------------------------------------------------------------------\n Post selection per feed kind\n ------------------------------------------------------------------ */ -}}\n{{- $posts := slice -}}\n{{- $isFeatured := eq $page.Type \"featured\" -}}\n\n{{- if eq $page.Kind \"home\" -}}\n {{- $public := where $allPosts \"Params.visibility\" \"public\" -}}\n {{- $posts = $public.ByDate.Reverse -}}\n{{- else if $isFeatured -}}\n {{- $featured := where $allPosts \"Params.featured_at\" \"ne\" nil -}}\n {{- $posts = sort $featured \"Params.featured_at\" \"desc\" -}}\n{{- else if eq $page.Type \"archive\" -}}\n {{- $posts = $allPosts.ByDate.Reverse -}}\n{{- else if eq $page.Type \"collection\" -}}\n {{- $collectionSlug := $page.Params.slug | default $page.Slug -}}\n {{- $members := slice -}}\n {{- range $allPosts -}}\n {{- $post := . -}}\n {{- with $post.Params.collections -}}\n {{- range . -}}\n {{- if eq .slug $collectionSlug -}}\n {{- $members = $members | append (dict \"post\" $post \"entry\" .) -}}\n {{- end -}}\n {{- end -}}\n {{- end -}}\n {{- end -}}\n {{- $pinned := slice -}}\n {{- $unpinned := slice -}}\n {{- range $members -}}\n {{- if .entry.pinned_at -}}\n {{- $pinned = $pinned | append . -}}\n {{- else -}}\n {{- $unpinned = $unpinned | append . -}}\n {{- end -}}\n {{- end -}}\n {{- if $pinned -}}{{- $pinned = sort $pinned \"entry.pinned_at\" \"desc\" -}}{{- end -}}\n {{- $sortOrder := $page.Params.sort_order | default \"position\" -}}\n {{- if $unpinned -}}\n {{- if eq $sortOrder \"collected_at_desc\" -}}\n {{- $unpinned = sort $unpinned \"entry.collected_at\" \"desc\" -}}\n {{- else -}}\n {{- $unpinned = sort $unpinned \"entry.position\" \"asc\" -}}\n {{- end -}}\n {{- end -}}\n {{- $ordered := $pinned | append $unpinned -}}\n {{- range $ordered -}}{{- $posts = $posts | append .post -}}{{- end -}}\n{{- end -}}\n\n{{- if gt (len $posts) $limit -}}\n {{- $posts = first $limit $posts -}}\n{{- end -}}\n\n{{- /* ------------------------------------------------------------------\n Feed title (mirrors the main site's Atom feed titles)\n ------------------------------------------------------------------ */ -}}\n{{- $feedTitle := .Site.Title -}}\n{{- if eq $page.Kind \"home\" -}}\n {{- $feedTitle = printf \"%s - Latest posts\" .Site.Title -}}\n{{- else if $isFeatured -}}\n {{- $feedTitle = printf \"%s - Featured posts\" .Site.Title -}}\n{{- else if eq $page.Type \"archive\" -}}\n {{- $feedTitle = printf \"%s - Archive\" .Site.Title -}}\n{{- else if eq $page.Type \"collection\" -}}\n {{- $feedTitle = printf \"%s - %s\" .Site.Title $page.Title -}}\n{{- end -}}\n\n{{- $siteDescription := .Site.Params.description | default \"\" -}}\n{{- $siteBase := .Site.BaseURL -}}\n{{- $selfUrl := .Permalink -}}\n{{- $now := now.UTC.Format \"2006-01-02T15:04:05Z\" -}}\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\">\n <title>{{ $feedTitle | transform.XMLEscape }}</title>\n <subtitle>{{ $siteDescription | transform.XMLEscape }}</subtitle>\n <link href=\"{{ $siteBase | transform.XMLEscape }}\" rel=\"alternate\"/>\n <link href=\"{{ $selfUrl | transform.XMLEscape }}\" rel=\"self\"/>\n <id>{{ $selfUrl | transform.XMLEscape }}</id>\n <updated>{{ $now }}</updated>\n {{- range $posts }}\n {{- $post := . -}}\n {{- $format := .Params.format | default \"note\" -}}\n {{- $permalink := .Permalink -}}\n {{- $isLink := and (eq $format \"link\") .Params.link_url -}}\n {{- $alternate := cond $isLink (string .Params.link_url) $permalink -}}\n {{- /* Atom <title>: empty for quotes (matches main site's getAtomTitle). */ -}}\n {{- $entryTitle := cond (eq $format \"quote\") \"\" (.Title | default \"\") -}}\n {{- /* <published>: from `date` frontmatter (= publishedAt).\n <updated>: prefer `last_activity_at` (thread-bumped), then `updated`\n (root edit time), else `date`. For featured, take max with\n `featured_at` so featuring alone surfaces a post. */ -}}\n {{- $published := .Date.UTC.Format \"2006-01-02T15:04:05Z\" -}}\n {{- $updatedSrc := .Date -}}\n {{- with .Params.last_activity_at -}}{{- $updatedSrc = time . -}}\n {{- else -}}{{- with .Params.updated -}}{{- $updatedSrc = time . -}}{{- end -}}{{- end -}}\n {{- if $isFeatured -}}\n {{- with .Params.featured_at -}}\n {{- $featuredAt := time . -}}\n {{- if $featuredAt.After $updatedSrc -}}{{- $updatedSrc = $featuredAt -}}{{- end -}}\n {{- end -}}\n {{- end -}}\n {{- $updated := $updatedSrc.UTC.Format \"2006-01-02T15:04:05Z\" -}}\n {{- /* Plain-text summary fallback chain (mirrors getFeedSummaryText). */ -}}\n {{- $summaryText := \"\" -}}\n {{- if eq $format \"quote\" -}}\n {{- $summaryText = or (string (.Params.summary_text | default \"\")) (string (.Params.quote_text | default \"\")) (.Title | default \"\") (string (.Params.link_url | default \"\")) (string (.Params.source_url | default \"\")) -}}\n {{- else -}}\n {{- $summaryText = or (string (.Params.summary_text | default \"\")) (.Title | default \"\") (string (.Params.link_url | default \"\")) -}}\n {{- end -}}\n {{- if eq $summaryText \"\" -}}{{- $summaryText = printf \"Post %s\" (string (.Params.id | default \"\")) -}}{{- end -}}\n <entry>\n <title>{{ $entryTitle | transform.XMLEscape }}</title>\n <link href=\"{{ $alternate | transform.XMLEscape }}\" rel=\"alternate\"/>\n {{- if $isLink }}\n <link href=\"{{ $permalink | transform.XMLEscape }}\" rel=\"related\"/>\n {{- end }}\n <id>{{ $permalink | transform.XMLEscape }}</id>\n <published>{{ $published }}</published>\n <updated>{{ $updated }}</updated>\n <summary type=\"text\">{{ $summaryText | transform.XMLEscape }}</summary>\n <content type=\"html\"><![CDATA[\n{{- partial \"feed-post-content.xml\" (dict \"post\" $post \"permalink\" $permalink \"includeReplies\" true) -}}\n]]></content>\n </entry>\n {{- end }}\n</feed>\n";
3375
+ var rss_default = "{{- /*\n Atom 2005 feed template — mirrors the main site's `lib/feed.ts`.\n\n One template covers every page that opts into the custom `RSS` output\n format (home, featured, archive, and each collection section). Root-post\n sections do NOT opt in, so no `/{slug}/index.xml` gets emitted.\n\n Feed filter parity with the corresponding HTML list view:\n - home (`.Kind == \"home\"`): visibility == \"public\" (drops latest_hidden)\n - featured (`.Type == \"featured\"`): featured_at != nil\n - archive (`.Type == \"archive\"`): all published (includes latest_hidden)\n - collection (`.Type == \"collection\"`): Params.collections.slug match,\n ordered per `sort_order`; pinning is ignored for RSS\n\n Per-entry payload mirrors `buildSinglePostContent` + `buildFeedContent`:\n - Title: empty for quote posts, else .Title\n - Link rel=alternate: external URL for `link` format, else permalink;\n link-format posts also get a <link rel=\"related\"> back to the\n permalink\n - Content (CDATA):\n quote → <blockquote cite><p>{quote}</p></blockquote>\n + <p>— <a href=url>{source}</a></p>\n body → Hugo-rendered .Content (stripped of <script>/<style>)\n rating → <p>★★★★☆ 4/5</p>\n link → trailing <p><a href=permalink> ★ </a></p>\n replies → <hr/> + <p><small><time>{dt}</time></small></p>\n + inline title/link metadata + content\n\n Hugo's default RSS media-type override (`[outputFormats.RSS]`) makes this\n template produce application/atom+xml at /{section}/index.xml.\n*/ -}}\n{{- $page := . -}}\n{{- $limit := int (.Site.Params.rss_feed_limit | default 50) -}}\n{{- $allPosts := where .Site.Pages \"Type\" \"post\" -}}\n\n{{- /* ------------------------------------------------------------------\n Post selection per feed kind\n ------------------------------------------------------------------ */ -}}\n{{- $posts := slice -}}\n{{- $isFeatured := eq $page.Type \"featured\" -}}\n\n{{- if eq $page.Kind \"home\" -}}\n {{- $public := where $allPosts \"Params.visibility\" \"public\" -}}\n {{- $posts = $public.ByDate.Reverse -}}\n{{- else if $isFeatured -}}\n {{- $featured := where $allPosts \"Params.featured_at\" \"ne\" nil -}}\n {{- $posts = sort $featured \"Params.featured_at\" \"desc\" -}}\n{{- else if eq $page.Type \"archive\" -}}\n {{- $posts = $allPosts.ByDate.Reverse -}}\n{{- else if eq $page.Type \"collection\" -}}\n {{- $collectionSlug := $page.Params.slug | default $page.Slug -}}\n {{- $members := slice -}}\n {{- range $allPosts -}}\n {{- $post := . -}}\n {{- with $post.Params.collections -}}\n {{- range . -}}\n {{- if eq .slug $collectionSlug -}}\n {{- $members = $members | append (dict \"post\" $post \"entry\" .) -}}\n {{- end -}}\n {{- end -}}\n {{- end -}}\n {{- end -}}\n {{- $sortOrder := $page.Params.sort_order | default \"position\" -}}\n {{- $ordered := $members -}}\n {{- if $ordered -}}\n {{- if eq $sortOrder \"collected_at_desc\" -}}\n {{- $ordered = sort $ordered \"entry.collected_at\" \"desc\" -}}\n {{- else -}}\n {{- $ordered = sort $ordered \"entry.position\" \"asc\" -}}\n {{- end -}}\n {{- end -}}\n {{- range $ordered -}}{{- $posts = $posts | append .post -}}{{- end -}}\n{{- end -}}\n\n{{- if gt (len $posts) $limit -}}\n {{- $posts = first $limit $posts -}}\n{{- end -}}\n\n{{- /* ------------------------------------------------------------------\n Feed title (mirrors the main site's Atom feed titles)\n ------------------------------------------------------------------ */ -}}\n{{- $feedTitle := .Site.Title -}}\n{{- if eq $page.Kind \"home\" -}}\n {{- $feedTitle = printf \"%s - Latest posts\" .Site.Title -}}\n{{- else if $isFeatured -}}\n {{- $feedTitle = printf \"%s - Featured posts\" .Site.Title -}}\n{{- else if eq $page.Type \"archive\" -}}\n {{- $feedTitle = printf \"%s - Archive\" .Site.Title -}}\n{{- else if eq $page.Type \"collection\" -}}\n {{- $feedTitle = printf \"%s - %s\" .Site.Title $page.Title -}}\n{{- end -}}\n\n{{- $siteDescription := .Site.Params.description | default \"\" -}}\n{{- $siteBase := .Site.BaseURL -}}\n{{- $selfUrl := .Permalink -}}\n{{- $now := now.UTC.Format \"2006-01-02T15:04:05Z\" -}}\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\">\n <title>{{ $feedTitle | transform.XMLEscape }}</title>\n <subtitle>{{ $siteDescription | transform.XMLEscape }}</subtitle>\n <link href=\"{{ $siteBase | transform.XMLEscape }}\" rel=\"alternate\"/>\n <link href=\"{{ $selfUrl | transform.XMLEscape }}\" rel=\"self\"/>\n <id>{{ $selfUrl | transform.XMLEscape }}</id>\n <updated>{{ $now }}</updated>\n {{- range $posts }}\n {{- $post := . -}}\n {{- $format := .Params.format | default \"note\" -}}\n {{- $permalink := .Permalink -}}\n {{- $isLink := and (eq $format \"link\") .Params.link_url -}}\n {{- $alternate := cond $isLink (string .Params.link_url) $permalink -}}\n {{- /* Atom <title>: empty for quotes (matches main site's getAtomTitle). */ -}}\n {{- $entryTitle := cond (eq $format \"quote\") \"\" (.Title | default \"\") -}}\n {{- /* <published>: from `date` frontmatter (= publishedAt).\n <updated>: prefer `last_activity_at` (thread-bumped), then `updated`\n (root edit time), else `date`. For featured, take max with\n `featured_at` so featuring alone surfaces a post. */ -}}\n {{- $published := .Date.UTC.Format \"2006-01-02T15:04:05Z\" -}}\n {{- $updatedSrc := .Date -}}\n {{- with .Params.last_activity_at -}}{{- $updatedSrc = time . -}}\n {{- else -}}{{- with .Params.updated -}}{{- $updatedSrc = time . -}}{{- end -}}{{- end -}}\n {{- if $isFeatured -}}\n {{- with .Params.featured_at -}}\n {{- $featuredAt := time . -}}\n {{- if $featuredAt.After $updatedSrc -}}{{- $updatedSrc = $featuredAt -}}{{- end -}}\n {{- end -}}\n {{- end -}}\n {{- $updated := $updatedSrc.UTC.Format \"2006-01-02T15:04:05Z\" -}}\n {{- /* Plain-text summary fallback chain (mirrors getFeedSummaryText). */ -}}\n {{- $summaryText := \"\" -}}\n {{- if eq $format \"quote\" -}}\n {{- $summaryText = or (string (.Params.summary_text | default \"\")) (string (.Params.quote_text | default \"\")) (.Title | default \"\") (string (.Params.link_url | default \"\")) (string (.Params.source_url | default \"\")) -}}\n {{- else -}}\n {{- $summaryText = or (string (.Params.summary_text | default \"\")) (.Title | default \"\") (string (.Params.link_url | default \"\")) -}}\n {{- end -}}\n {{- if eq $summaryText \"\" -}}{{- $summaryText = printf \"Post %s\" (string (.Params.id | default \"\")) -}}{{- end -}}\n <entry>\n <title>{{ $entryTitle | transform.XMLEscape }}</title>\n <link href=\"{{ $alternate | transform.XMLEscape }}\" rel=\"alternate\"/>\n {{- if $isLink }}\n <link href=\"{{ $permalink | transform.XMLEscape }}\" rel=\"related\"/>\n {{- end }}\n <id>{{ $permalink | transform.XMLEscape }}</id>\n <published>{{ $published }}</published>\n <updated>{{ $updated }}</updated>\n <summary type=\"text\">{{ $summaryText | transform.XMLEscape }}</summary>\n <content type=\"html\"><![CDATA[\n{{- partial \"feed-post-content.xml\" (dict \"post\" $post \"permalink\" $permalink \"includeReplies\" true) -}}\n]]></content>\n </entry>\n {{- end }}\n</feed>\n";
3368
3376
  //#endregion
3369
3377
  //#region src/services/export-theme/layouts/partials/feed-post-content.xml?raw
3370
3378
  var feed_post_content_default = "{{- /*\n Feed entry content builder — mirrors `buildSinglePostContent` +\n `buildFeedContent` from `packages/core/src/lib/feed.ts`.\n\n Arguments (dict):\n post — the Hugo Page for this post\n permalink — absolute permalink to the blog post (used for the\n link-format \"★\" suffix)\n includeReplies — when true, appends each public reply separated by\n <hr/> + <small><time></time></small>\n inline — when true, renders title/link metadata that top-level\n Atom entries expose through their entry fields\n\n Output is raw HTML suitable for embedding inside Atom\n <content type=\"html\"><![CDATA[...]]></content>. Since CDATA ends at the\n first `]]>`, any such sequence in rendered bodies is split using\n `replace ... \"]]>\" \"]]]]><![CDATA[>\"` — the same trick the main site uses\n in `escapeCdata`.\n*/ -}}\n{{- $post := .post -}}\n{{- $permalink := .permalink -}}\n{{- $includeReplies := .includeReplies -}}\n{{- $inline := false -}}\n{{- with .inline -}}{{- $inline = . -}}{{- end -}}\n{{- $format := $post.Params.format | default \"note\" -}}\n{{- $parts := slice -}}\n\n{{- /* --- Inline title/link metadata for thread replies --- */ -}}\n{{- if and $inline (ne $format \"quote\") -}}\n {{- $title := $post.Title | default \"\" -}}\n {{- $linkUrl := string ($post.Params.link_url | default \"\") -}}\n {{- if eq $format \"link\" -}}\n {{- if ne $linkUrl \"\" -}}\n {{- $domain := $linkUrl -}}\n {{- with urls.Parse $linkUrl -}}{{- if .Host -}}{{- $domain = replaceRE `^(www|m|mobile)\\.` \"\" .Host -}}{{- end -}}{{- end -}}\n {{- $parts = $parts | append (printf `<p><a href=%q>%s</a></p>` $linkUrl (transform.XMLEscape $domain)) -}}\n {{- end -}}\n {{- if ne $title \"\" -}}\n {{- $titleHref := $permalink -}}\n {{- if ne $linkUrl \"\" -}}{{- $titleHref = $linkUrl -}}{{- end -}}\n {{- $parts = $parts | append (printf `<h2><a href=%q>%s</a></h2>` $titleHref (transform.XMLEscape $title)) -}}\n {{- end -}}\n {{- else if ne $title \"\" -}}\n {{- $parts = $parts | append (printf `<h2><a href=%q>%s</a></h2>` $permalink (transform.XMLEscape $title)) -}}\n {{- end -}}\n{{- end -}}\n\n{{- /* --- Quote block (format=quote) --- */ -}}\n{{- if eq $format \"quote\" -}}\n {{- $quoteText := string ($post.Params.quote_text | default \"\") -}}\n {{- if ne $quoteText \"\" -}}\n {{- $sourceName := string ($post.Params.source_name | default \"\") -}}\n {{- $sourceUrl := string ($post.Params.source_url | default \"\") -}}\n {{- $cite := \"\" -}}\n {{- if ne $sourceUrl \"\" -}}{{- $cite = printf ` cite=%q` $sourceUrl -}}{{- end -}}\n {{- $block := printf \"<blockquote%s><p>%s</p></blockquote>\" $cite (transform.XMLEscape $quoteText) -}}\n {{- $parts = $parts | append $block -}}\n {{- /* Attribution line — prefer name, fall back to URL host or the\n raw URL itself (mirrors main site's extractDisplayDomain fallback\n chain in `lib/url.ts`). */ -}}\n {{- $attribution := \"\" -}}\n {{- if and (ne $sourceName \"\") (ne $sourceUrl \"\") -}}\n {{- $attribution = printf `<a href=%q>%s</a>` $sourceUrl (transform.XMLEscape $sourceName) -}}\n {{- else if ne $sourceName \"\" -}}\n {{- $attribution = transform.XMLEscape $sourceName -}}\n {{- else if ne $sourceUrl \"\" -}}\n {{- $host := $sourceUrl -}}\n {{- with urls.Parse $sourceUrl -}}{{- if .Host -}}{{- $host = .Host -}}{{- end -}}{{- end -}}\n {{- $attribution = printf `<a href=%q>%s</a>` $sourceUrl (transform.XMLEscape $host) -}}\n {{- end -}}\n {{- if ne $attribution \"\" -}}\n {{- $parts = $parts | append (printf \"<p>— %s</p>\" $attribution) -}}\n {{- end -}}\n {{- end -}}\n{{- end -}}\n\n{{- /* --- Rendered body HTML (with <script>/<style> stripped) --- */ -}}\n{{- $body := $post.Content -}}\n{{- if ne (string $body) \"\" -}}\n {{- $bodyStr := string $body -}}\n {{- $bodyStr = replaceRE `(?is)<script\\b[^>]*>.*?<\/script>` \"\" $bodyStr -}}\n {{- $bodyStr = replaceRE `(?is)<style\\b[^>]*>.*?</style>` \"\" $bodyStr -}}\n {{- /* Split any CDATA-terminator sequences so the content can be safely\n wrapped in <![CDATA[...]]> by the caller. */ -}}\n {{- $bodyStr = replace $bodyStr \"]]>\" \"]]]]><![CDATA[>\" -}}\n {{- if ne (trim $bodyStr \" \\t\\n\\r\") \"\" -}}\n {{- $parts = $parts | append $bodyStr -}}\n {{- end -}}\n{{- end -}}\n\n{{- /* --- Star rating --- */ -}}\n{{- with $post.Params.rating -}}\n {{- $r := int . -}}\n {{- if gt $r 0 -}}\n {{- $filled := strings.Repeat $r \"★\" -}}\n {{- $empty := strings.Repeat (sub 5 $r) \"☆\" -}}\n {{- $parts = $parts | append (printf \"<p>%s%s %d/5</p>\" $filled $empty $r) -}}\n {{- end -}}\n{{- end -}}\n\n{{- /* --- Empty-body fallback (plain-text summary) --- */ -}}\n{{- if eq (len $parts) 0 -}}\n {{- $fallback := string ($post.Params.summary_text | default \"\") -}}\n {{- if eq $fallback \"\" -}}{{- $fallback = $post.Title | default (printf \"Post %s\" (string ($post.Params.id | default \"\"))) -}}{{- end -}}\n {{- $parts = $parts | append (printf \"<p>%s</p>\" (transform.XMLEscape $fallback)) -}}\n{{- end -}}\n\n{{- /* --- link-format permalink suffix (Daring Fireball ★) --- */ -}}\n{{- if and (eq $format \"link\") (ne $permalink \"\") -}}\n {{- $parts = $parts | append (printf `<p><a href=%q title=\"Permalink\">&nbsp;★&nbsp;</a></p>` $permalink) -}}\n{{- end -}}\n\n{{- /* --- Thread replies --- */ -}}\n{{- if $includeReplies -}}\n {{- $replies := where $post.Pages \"Params.visibility\" \"public\" -}}\n {{- $replies = $replies.ByDate -}}\n {{- range $replies -}}\n {{- $replyPermalink := .Permalink -}}\n {{- $replyDatetime := .Date.UTC.Format \"2006-01-02T15:04:05Z\" -}}\n {{- /* Human-readable timestamp; mirrors the main site's\n `publishedAtFormatted` in the feed — there it's locale-formatted\n by `lib/format-timestamp.ts`, but Hugo doesn't have that at\n export time, so use a simple ISO-style fallback. */ -}}\n {{- $replyLabel := .Date.Format \"Jan 2, 2006 15:04\" -}}\n {{- $parts = $parts | append \"<hr/>\" -}}\n {{- $parts = $parts | append (printf `<p><small><time datetime=%q>%s</time></small></p>` $replyDatetime (transform.XMLEscape $replyLabel)) -}}\n {{- $parts = $parts | append (partial \"feed-post-content.xml\" (dict \"post\" . \"permalink\" $replyPermalink \"includeReplies\" false \"inline\" true)) -}}\n {{- end -}}\n{{- end -}}\n\n{{- delimit $parts \"\\n\" | safeHTML -}}\n";
@@ -4087,17 +4095,16 @@ function resolveNavItemLabel(item) {
4087
4095
  * Resolve a nav item's final href for the Hugo export.
4088
4096
  *
4089
4097
  * Mirrors the runtime logic in `lib/view.ts:toNavItemView`. System URLs
4090
- * stored in the DB ("/latest", "/featured") are not real routes — they get
4091
- * rewritten to "/" when they match `homeDefaultView`, otherwise they
4092
- * resolve to the dedicated path.
4098
+ * stored in the DB are canonicalized during export so stale DB values do not
4099
+ * leak into the static site's navigation.
4093
4100
  *
4094
4101
  * The "rss" system nav item points at whichever Atom feed the site has
4095
4102
  * configured as its main feed: `mainRssFeed === "featured"` → the featured
4096
4103
  * section feed at `/featured/index.xml`, otherwise the home feed at
4097
4104
  * `/index.xml` (which mirrors the homepage's "latest" timeline).
4098
- */ function resolveNavItemUrl(item, homeDefaultView, mainRssFeed) {
4099
- if (item.systemKey === "latest") return homeDefaultView === "latest" ? "/" : "/latest/";
4100
- if (item.systemKey === "featured") return homeDefaultView === "featured" ? "/" : "/featured/";
4105
+ */ function resolveNavItemUrl(item, mainRssFeed) {
4106
+ if (item.systemKey === "latest") return "/";
4107
+ if (item.systemKey === "featured") return "/featured/";
4101
4108
  if (item.systemKey === "collections") return "/collections/";
4102
4109
  if (item.systemKey === "archive") return "/archive/";
4103
4110
  if (item.systemKey === "rss") return mainRssFeed === "featured" ? "/featured/index.xml" : "/index.xml";
@@ -4144,7 +4151,6 @@ function buildHugoToml(config) {
4144
4151
  "",
4145
4152
  "[params]",
4146
4153
  ` description = "${escapeTomlString(config.siteDescription)}"`,
4147
- ` home_default_view = "${escapeTomlString(config.homeDefaultView)}"`,
4148
4154
  ` main_rss_feed = "${escapeTomlString(config.mainRssFeed)}"`,
4149
4155
  ` show_jant_branding_on_home = ${config.showJantBrandingOnHome}`,
4150
4156
  ` show_header_avatar = ${config.showHeaderAvatar}`,
@@ -4170,7 +4176,6 @@ function buildJantDataToml(config, iconAssets, directoryItems) {
4170
4176
  `site_name = "${escapeTomlString(config.siteName)}"`,
4171
4177
  `site_description = "${escapeTomlString(config.siteDescription)}"`,
4172
4178
  `site_language = "${escapeTomlString(config.siteLanguage)}"`,
4173
- `home_default_view = "${escapeTomlString(config.homeDefaultView)}"`,
4174
4179
  `main_rss_feed = "${escapeTomlString(config.mainRssFeed)}"`,
4175
4180
  `show_jant_branding_on_home = ${config.showJantBrandingOnHome}`,
4176
4181
  `show_header_avatar = ${config.showHeaderAvatar}`,
@@ -4198,7 +4203,7 @@ function buildJantDataToml(config, iconAssets, directoryItems) {
4198
4203
  parts.push("[[nav]]");
4199
4204
  parts.push(`type = "${escapeTomlString(item.type)}"`);
4200
4205
  parts.push(`label = "${escapeTomlString(resolveNavItemLabel(item))}"`);
4201
- parts.push(`url = "${escapeTomlString(resolveNavItemUrl(item, config.homeDefaultView, config.mainRssFeed))}"`);
4206
+ parts.push(`url = "${escapeTomlString(resolveNavItemUrl(item, config.mainRssFeed))}"`);
4202
4207
  parts.push(`system_key = "${escapeTomlString(item.systemKey ?? "")}"`);
4203
4208
  parts.push(`placement = "${escapeTomlString(item.placement ?? "header")}"`);
4204
4209
  }