edgepress 2026.9.5 → 2026.9.8

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 (66) hide show
  1. package/README.md +5 -3
  2. package/config.yml +121 -69
  3. package/content/pages/home/en.md +15 -0
  4. package/content/pages/home/zh-cn.md +16 -1
  5. package/content/pages/plugin-development/en.md +5 -4
  6. package/content/pages/plugin-development/zh-cn.md +5 -4
  7. package/content/pages/privacy-policy/en.md +8 -5
  8. package/content/pages/privacy-policy/zh-cn.md +8 -5
  9. package/content/pages/theme-development/en.md +24 -0
  10. package/content/pages/theme-development/zh-cn.md +24 -0
  11. package/content/posts/2026-09-23-edgepress-on-the-edge/en.md +12 -2
  12. package/content/posts/2026-09-23-edgepress-on-the-edge/zh-cn.md +12 -2
  13. package/content/posts/2026-09-24-edgepress-release-2026-9-1/en.md +2 -0
  14. package/content/posts/2026-09-24-edgepress-release-2026-9-1/zh-cn.md +2 -0
  15. package/content/posts/2026-09-25-edgepress-release-2026-9-2/en.md +2 -0
  16. package/content/posts/2026-09-25-edgepress-release-2026-9-2/zh-cn.md +2 -0
  17. package/content/posts/2026-09-25-edgepress-release-2026-9-3/en.md +2 -0
  18. package/content/posts/2026-09-25-edgepress-release-2026-9-3/zh-cn.md +2 -0
  19. package/content/posts/2026-09-25-edgepress-release-2026-9-4/en.md +2 -0
  20. package/content/posts/2026-09-25-edgepress-release-2026-9-4/zh-cn.md +2 -0
  21. package/content/posts/2026-09-25-edgepress-release-2026-9-5/en.md +2 -0
  22. package/content/posts/2026-09-25-edgepress-release-2026-9-5/zh-cn.md +2 -0
  23. package/content/posts/2026-09-25-edgepress-release-2026-9-6/en.md +31 -0
  24. package/content/posts/2026-09-25-edgepress-release-2026-9-6/zh-cn.md +31 -0
  25. package/content/posts/2026-09-26-edgepress-release-2026-9-7/en.md +26 -0
  26. package/content/posts/2026-09-26-edgepress-release-2026-9-7/zh-cn.md +26 -0
  27. package/content/posts/2026-09-26-edgepress-release-2026-9-8/en.md +26 -0
  28. package/content/posts/2026-09-26-edgepress-release-2026-9-8/zh-cn.md +26 -0
  29. package/languages/base/en.json +9 -2
  30. package/languages/packs/zh-CN.json +9 -2
  31. package/package.json +2 -1
  32. package/plugins/consent/index.js +4 -2
  33. package/project-compatibility.json +26 -2
  34. package/src/build.js +5 -4
  35. package/src/cli.js +8 -13
  36. package/src/config.js +72 -14
  37. package/src/content.js +55 -1
  38. package/src/generators.js +125 -23
  39. package/src/i18n.js +6 -0
  40. package/src/icons.js +16 -0
  41. package/src/maintenance.js +0 -27
  42. package/src/markdown.js +88 -9
  43. package/src/page-blocks.js +84 -18
  44. package/src/page-check.js +79 -25
  45. package/src/report-visuals.js +111 -16
  46. package/src/theme.js +13 -2
  47. package/static/edgepress/brand/edgepress-mark.svg +7 -0
  48. package/static/edgepress/brand/mascot-209.webp +0 -0
  49. package/static/edgepress/brand/mascot-418.png +0 -0
  50. package/static/edgepress/brand/mascot-418.webp +0 -0
  51. package/static/edgepress/brand/mascot.png +0 -0
  52. package/static/edgepress/brand/og-image.png +0 -0
  53. package/static/edgepress/brand/og-image.svg +46 -0
  54. package/static/edgepress/code-copy.js +55 -0
  55. package/static/edgepress/icons.svg +24 -0
  56. package/static/edgepress/plugins/consent/manager.js +204 -71
  57. package/static/edgepress/plugins/statistics/cloudflare-web-analytics.js +1 -0
  58. package/themes/atelier/assets/style.css +98 -20
  59. package/themes/atelier/layouts/partials/head.html +5 -0
  60. package/themes/atelier/layouts/partials/header.html +1 -1
  61. package/themes/default/assets/style.css +99 -20
  62. package/themes/default/layouts/partials/head.html +3 -0
  63. package/themes/default/layouts/partials/header.html +1 -1
  64. package/themes/signal/assets/style.css +98 -20
  65. package/themes/signal/layouts/partials/head.html +5 -0
  66. package/themes/signal/layouts/partials/header.html +1 -1
@@ -18,25 +18,48 @@ main{flex:1;min-height:0}
18
18
  .ad-slot:empty{min-height:90px}.captcha-block{min-height:65px}
19
19
 
20
20
 
21
- .privacy-manager{position:fixed;right:16px;bottom:16px;z-index:1000;color:var(--ink);font:14px/1.5 ui-sans-serif,system-ui,sans-serif}
22
- .privacy-settings-button,.privacy-panel button{font:inherit;font-weight:700;border:1px solid var(--line);border-radius:8px;padding:9px 13px;background:var(--panel,#fff);color:var(--ink);cursor:pointer}
23
- .privacy-settings-button{box-shadow:0 4px 18px #0002}
24
- .privacy-panel{width:min(28rem,calc(100vw - 32px));max-height:min(80vh,42rem);overflow:auto;padding:20px;margin-bottom:10px;border:1px solid var(--line);border-radius:12px;background:var(--paper,#fff);box-shadow:0 12px 40px #0003}
25
- .privacy-panel[hidden]{display:none}
26
- .privacy-panel h2{margin:8px 0;font-size:1.2rem}
27
- .privacy-panel p{margin:10px 0}
28
- .privacy-close{float:right}
29
- .privacy-details{display:grid;gap:8px;margin:16px 0}
30
- .privacy-service{display:flex;align-items:flex-start;gap:10px;padding:10px;border:1px solid var(--line);border-radius:8px}
31
- .privacy-service input{margin-top:4px;accent-color:var(--accent)}
32
- .privacy-service span span{display:inline}
33
- .privacy-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
34
- .privacy-actions button{flex:1 1 auto}
35
- .privacy-accept,.privacy-reject{font-weight:800!important}
36
- .privacy-controller,.privacy-policy-link{font-size:.9rem}
37
- .privacy-settings-button:focus-visible,.privacy-panel button:focus-visible,.privacy-panel a:focus-visible,.privacy-service input:focus-visible{outline:3px solid var(--accent);outline-offset:3px}
38
- @media(max-width:500px){.privacy-manager{left:12px;right:12px;bottom:12px}.privacy-settings-button{float:right}.privacy-panel{width:100%}.privacy-actions button{flex:1 1 100%}}
39
-
21
+ .privacy-manager{position:fixed;inset-inline-end:max(12px,env(safe-area-inset-right));inset-block-end:max(12px,env(safe-area-inset-bottom));z-index:1000;display:grid;align-content:end;gap:8px;box-sizing:border-box;width:min(30rem,calc(100vw - 24px));max-height:calc(100vh - 24px);max-height:calc(100dvh - 24px);color:var(--ink,#1d2824);font:14px/1.45 ui-sans-serif,system-ui,sans-serif;pointer-events:none;isolation:isolate}
22
+ .privacy-manager *{box-sizing:border-box}
23
+ .privacy-manager>*{min-width:0;pointer-events:auto}
24
+ .privacy-manager .privacy-settings-button,.privacy-manager .privacy-panel button{display:inline-flex;justify-content:center;align-items:center;gap:8px;min-width:0;min-height:46px;max-width:100%;padding:10px 12px;border:1px solid var(--line,#c7d0c9);border-radius:10px;background:var(--panel,#fff);color:var(--ink,#1d2824);font:inherit;font-weight:700;line-height:1.25;text-align:center;overflow-wrap:anywhere;cursor:pointer}
25
+ .privacy-manager .privacy-settings-button{order:1;justify-self:end;box-shadow:0 4px 18px #0002}
26
+ .privacy-manager .privacy-panel{position:relative;order:0;display:grid;gap:12px;width:100%;max-height:min(68vh,40rem);max-height:min(68dvh,40rem);overflow:auto;overscroll-behavior:contain;padding:18px;border:1px solid var(--line,#c7d0c9);border-radius:14px;background:var(--paper,#fff);color:var(--ink,#1d2824);box-shadow:0 12px 40px #0003}
27
+ .privacy-manager .privacy-panel[hidden]{display:none}
28
+ .privacy-manager .privacy-panel h2{margin:0;padding-inline-end:44px;font-size:1.15rem;line-height:1.3}
29
+ .privacy-manager .privacy-panel p{margin:0;overflow-wrap:anywhere}
30
+ .privacy-manager .privacy-panel .privacy-close{position:absolute;inset-block-start:8px;inset-inline-end:8px;width:44px;min-width:44px;min-height:44px;padding:8px}
31
+ .privacy-manager .privacy-panel .privacy-close svg{width:20px;height:20px}
32
+ .privacy-manager svg{width:18px;height:18px;flex:none}
33
+ .privacy-manager .privacy-intro,.privacy-manager .privacy-essential,.privacy-manager .privacy-controller{color:var(--muted,#536159)}
34
+ .privacy-manager .privacy-service-preview,.privacy-manager .privacy-service-settings{display:grid;gap:8px;min-width:0}
35
+ .privacy-manager .privacy-preview-item,.privacy-manager .privacy-service-setting{display:grid;gap:7px;min-width:0;padding:11px;border:1px solid var(--line,#c7d0c9);border-radius:10px;background:var(--panel,#fff)}
36
+ .privacy-manager .privacy-preview-item{grid-template-columns:minmax(0,1fr) auto;align-items:start}
37
+ .privacy-manager .privacy-preview-item h3{min-width:0;margin:0;font-size:.96rem;overflow-wrap:anywhere}
38
+ .privacy-manager .privacy-preview-item p{grid-column:1/-1;color:var(--muted,#536159)}
39
+ .privacy-manager .privacy-category{justify-self:start;max-width:100%;padding:2px 7px;border-radius:999px;background:color-mix(in srgb,var(--accent,#315e49) 12%,transparent);color:var(--ink,#1d2824);font-size:.78rem;overflow-wrap:anywhere}
40
+ .privacy-manager .privacy-details{min-width:0;margin:0;border-block:1px solid var(--line,#c7d0c9)}
41
+ .privacy-manager .privacy-details>summary{padding:10px 2px;font-weight:750;cursor:pointer}
42
+ .privacy-manager .privacy-details>summary:focus-visible{outline:3px solid var(--accent,#315e49);outline-offset:3px}
43
+ .privacy-manager .privacy-service-settings{padding-block-end:10px}
44
+ .privacy-manager .privacy-service-toggle{display:flex;align-items:center;gap:11px;min-width:0;cursor:pointer}
45
+ .privacy-manager .privacy-service-toggle input{position:relative;flex:none;width:42px;height:24px;margin:0;appearance:none;border:1px solid var(--line,#748079);border-radius:999px;background:var(--line,#748079);cursor:pointer}
46
+ .privacy-manager .privacy-service-toggle input::before{position:absolute;inset-block-start:2px;inset-inline-start:2px;width:18px;height:18px;border-radius:50%;background:var(--paper,#fff);content:"";transition:transform .16s ease}
47
+ .privacy-manager .privacy-service-toggle input:checked{border-color:var(--accent,#315e49);background:var(--accent,#315e49)}
48
+ .privacy-manager .privacy-service-toggle input:checked::before{transform:translateX(18px)}
49
+ .privacy-manager .privacy-service-toggle input:focus-visible{outline:3px solid var(--accent,#315e49);outline-offset:3px}
50
+ .privacy-manager .privacy-service-toggle-text{display:grid;gap:3px;min-width:0;overflow-wrap:anywhere}
51
+ .privacy-manager .privacy-service-toggle-text strong{font-size:.96rem}
52
+ .privacy-manager .privacy-service-disclosures{display:grid;gap:6px;margin:0}
53
+ .privacy-manager .privacy-service-disclosures>div{display:grid;grid-template-columns:minmax(5.5rem,.34fr) minmax(0,1fr);gap:8px;min-width:0}
54
+ .privacy-manager .privacy-service-disclosures dt{color:var(--muted,#536159);font-weight:650}
55
+ .privacy-manager .privacy-service-disclosures dd{min-width:0;margin:0;overflow-wrap:anywhere}
56
+ .privacy-manager .privacy-actions{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
57
+ .privacy-manager .privacy-panel .privacy-accept,.privacy-manager .privacy-panel .privacy-reject{border-color:var(--accent,#315e49);background:var(--accent,#315e49);color:var(--paper,#fff)}
58
+ .privacy-manager .privacy-panel .privacy-save,.privacy-manager .privacy-panel .privacy-manage{background:transparent}
59
+ .privacy-manager .privacy-panel button:disabled{opacity:.55;cursor:not-allowed}
60
+ .privacy-manager .privacy-policy-link{width:fit-content;max-width:100%;font-size:.9rem;overflow-wrap:anywhere}
61
+ .privacy-manager .privacy-policy-link:focus-visible,.privacy-manager .privacy-settings-button:focus-visible,.privacy-manager .privacy-panel button:focus-visible{outline:3px solid var(--accent,#315e49);outline-offset:3px}
62
+ @media(max-width:560px){.privacy-manager{inset-inline-start:max(12px,env(safe-area-inset-left));width:auto;max-width:none}.privacy-manager .privacy-panel{max-height:min(68vh,40rem);max-height:min(68dvh,40rem);padding:15px}.privacy-manager .privacy-actions{grid-template-columns:repeat(2,minmax(0,1fr));gap:7px}.privacy-manager .privacy-actions .privacy-manage{grid-column:1/-1;grid-row:1}.privacy-manager .privacy-actions .privacy-reject{grid-column:1;grid-row:2}.privacy-manager .privacy-actions .privacy-accept{grid-column:2;grid-row:2}.privacy-manager .privacy-panel .privacy-save{width:100%}}
40
63
  /* Page blocks follow a section-and-widget layout, while articles keep their own reading column. */
41
64
  body{max-width:none;padding:0 clamp(18px,4vw,56px)}
42
65
  .site-header,main,.site-footer{width:min(100%,1240px);margin-inline:auto}
@@ -154,4 +177,60 @@ main,.page-builder,.page-builder-row,.page-builder-cell,.post,.post-content,.pos
154
177
  @media(max-width:620px){.local-search-controls{align-items:stretch;flex-direction:column}.local-search-controls button{min-height:44px}.post-content pre,.code-widget pre,.steps-widget pre{padding:12px}}
155
178
  .locale-nav select{max-width:min(100%,13rem);padding:7px 30px 7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--paper);color:var(--ink);font:inherit;cursor:pointer}
156
179
  .locale-nav select:focus-visible{outline:3px solid #cb774d;outline-offset:3px}
157
- @media(max-width:620px){.locale-nav select{min-height:42px;max-width:100%}}
180
+ @media(max-width:620px){.locale-nav select{min-height:42px;max-width:100%}}
181
+
182
+ /* Article contents and code tools use theme styling and wrap on narrow screens. */
183
+ .post-toc{max-width:760px;margin:24px auto;padding:18px 22px;border:1px solid var(--line);border-radius:12px;background:var(--paper)}
184
+ .post-toc h2{margin:0 0 8px;font-size:1.05rem;letter-spacing:0}
185
+ .post-toc ol{margin:0;padding-inline-start:1.35rem}
186
+ .post-toc li{padding:2px 0}
187
+ .post-toc .post-toc-level-3{padding-inline-start:1rem}
188
+ .post-toc .post-toc-level-4,.post-toc .post-toc-level-5,.post-toc .post-toc-level-6{padding-inline-start:2rem}
189
+ .post-content h2[id],.post-content h3[id],.post-content h4[id],.post-content h5[id],.post-content h6[id]{scroll-margin-top:1rem}
190
+ .code-copy-block{max-width:100%;margin:1.25em 0;border-radius:10px;overflow:hidden;background:#edf0ea}
191
+ .code-copy-block pre{margin:0;border-radius:0}
192
+ .code-copy-toolbar{display:flex;justify-content:flex-end;padding:7px 10px;background:var(--ink)}
193
+ .code-copy-button{min-height:36px;padding:5px 12px;border:1px solid currentColor;border-radius:7px;background:transparent;color:var(--paper);font:600 .88rem/1.3 ui-sans-serif,system-ui,sans-serif;cursor:pointer}
194
+ .code-copy-button:hover{background:var(--accent)}
195
+ .code-copy-button:focus-visible{outline:3px solid #cb774d;outline-offset:2px}
196
+ .code-copy-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
197
+ .post-content pre,.code-widget pre,.steps-widget pre{max-width:100%;overflow-x:hidden;overflow-y:visible;white-space:pre-wrap;overflow-wrap:anywhere;word-break:normal;overscroll-behavior-inline:auto}
198
+ .post-content pre code,.code-widget pre code,.steps-widget pre code{white-space:inherit;overflow-wrap:inherit;word-break:inherit}
199
+ .pagination{flex-wrap:wrap;gap:12px}
200
+ @media(max-width:620px){.post-toc{padding:14px}.code-copy-button{min-height:44px}.post-content pre,.code-widget pre,.steps-widget pre{padding:12px}}
201
+
202
+ /* A sharper editorial palette: cobalt ink, lilac surfaces, and citrus highlights. */
203
+ :root{--paper:#f7f8ff;--panel:#fff;--ink:#171a35;--muted:#5e6480;--line:#dce0f2;--accent:#3945c6;--warm:#d94d3f}
204
+ body{background:radial-gradient(ellipse at 92% 0%,#e9e9ff 0,transparent 33%),var(--paper)}
205
+ .hero-block,.cta-block{background:linear-gradient(118deg,#e5e7ff 0%,#fff0dc 100%)}
206
+ .page-section--soft,.error-page{background:#f0f1ff}
207
+ .page-section--accent{background:#ffefd7}
208
+ .page-section--dark{background:#211d49}
209
+ .hero-highlights li{background:#ffffffd9;border-color:#ffffff}
210
+ .steps-widget pre,.code-widget pre,.code-copy-block{background:#211d49}
211
+ .table-widget th{background:#ededff}
212
+ .notice-widget{background:#f0f1ff}
213
+ .notice-widget--warning{background:#fff0dc}
214
+ .notice-widget--success{background:#e7f7ef}
215
+ .code-copy-block pre{background:#211d49;color:#f7f8ff}
216
+ .code-copy-button:focus-visible,.local-search-form :focus-visible{outline-color:var(--warm)}
217
+
218
+ /* Shared EdgePress marks and SVG icons keep common navigation recognizable across themes. */
219
+ .brand{display:inline-flex;align-items:center;gap:10px}
220
+ .brand-mark{display:block;width:36px;height:36px;flex:0 0 auto;object-fit:contain}
221
+ .primary-navigation a,.site-header nav a,.footer-navigation a{display:inline-flex;align-items:center;gap:.42em}
222
+ .navigation-icon{display:block;width:1.05em;height:1.05em;flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
223
+ .hero-aside{display:grid;align-content:center;justify-items:center;gap:16px;min-width:0}
224
+ .hero-mascot{display:block;width:min(100%,230px);height:auto;max-height:220px;object-fit:contain;filter:drop-shadow(0 9px 13px #315e4922)}
225
+ .hero-aside .hero-highlights{width:100%;align-self:stretch}
226
+ .feature-icon{display:block;width:34px;height:34px;margin:0 0 10px;color:var(--accent);fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
227
+ .latest-posts-pagination{justify-content:flex-start;gap:16px;margin-top:18px}
228
+ .latest-posts-pagination a:last-child{margin-left:auto}
229
+ .hero-mascot-picture{display:block;width:min(100%,230px)}
230
+ .post-excerpt{max-width:72ch;color:var(--muted);font-size:.95rem;line-height:1.6}
231
+ .post-excerpt p{margin:.35rem 0 0}
232
+ .post-excerpt p:first-child{margin-top:0}
233
+ .post-excerpt a{color:inherit}
234
+ .post-content .markdown-video{margin:1.5rem 0}
235
+ .post-content .markdown-video video{display:block;width:100%;max-width:100%;height:auto;border-radius:10px;background:#101410}
236
+ .post-content .markdown-video figcaption{margin-top:.5rem;color:var(--muted);font-size:.9rem}
@@ -5,6 +5,8 @@
5
5
  <meta name="keywords" content="{{page.keywords}}">
6
6
  <meta name="author" content="{{site.seo.author}}">
7
7
  <title>{{page.title}}</title>
8
+ <meta name="theme-color" content="#315e49">
9
+ <link rel="icon" type="image/svg+xml" href="/edgepress/brand/edgepress-mark.svg">
8
10
  <link rel="canonical" href="{{page.canonical}}">
9
11
  <meta property="og:type" content="website">
10
12
  <meta property="og:title" content="{{page.title}}">
@@ -14,6 +16,7 @@
14
16
  <meta name="twitter:card" content="summary_large_image">
15
17
  <meta name="twitter:title" content="{{page.title}}">
16
18
  <meta name="twitter:description" content="{{page.description}}">
19
+ <meta name="twitter:image" content="{{page.image}}">
17
20
  <link rel="alternate" type="application/atom+xml" href="{{site.feedPath}}" title="{{site.feedLabel}}">
18
21
  <link rel="stylesheet" href="{{site.stylesheet}}">
19
22
  <script type="application/ld+json">{{{page.jsonLd}}}</script>
@@ -1,5 +1,5 @@
1
1
  <header class="site-header {{site.headerClass}}">
2
- <a class="brand {{site.brandClass}}" href="{{site.homePath}}">{{site.headerBrand}}</a>
2
+ <a class="brand {{site.brandClass}}" href="{{site.homePath}}"><img class="brand-mark" src="/edgepress/brand/edgepress-mark.svg" alt="" aria-hidden="true" width="36" height="36">{{site.headerBrand}}</a>
3
3
  <nav class="primary-navigation {{site.primaryNavigationClass}}" aria-label="{{site.mainNavigationLabel}}">{{{site.primaryNavigationHtml}}}</nav>
4
4
  <div class="locale-nav {{site.languageNavigationClass}}" role="group" aria-label="{{site.languageLabel}}">{{{site.localeLinksHtml}}}</div>
5
5
  </header>
@@ -18,25 +18,48 @@ main{flex:1;min-height:0}
18
18
  .ad-slot:empty{min-height:90px}.captcha-block{min-height:65px}
19
19
 
20
20
 
21
- .privacy-manager{position:fixed;right:16px;bottom:16px;z-index:1000;color:var(--ink);font:14px/1.5 ui-sans-serif,system-ui,sans-serif}
22
- .privacy-settings-button,.privacy-panel button{font:inherit;font-weight:700;border:1px solid var(--line);border-radius:8px;padding:9px 13px;background:var(--panel,#fff);color:var(--ink);cursor:pointer}
23
- .privacy-settings-button{box-shadow:0 4px 18px #0002}
24
- .privacy-panel{width:min(28rem,calc(100vw - 32px));max-height:min(80vh,42rem);overflow:auto;padding:20px;margin-bottom:10px;border:1px solid var(--line);border-radius:12px;background:var(--paper,#fff);box-shadow:0 12px 40px #0003}
25
- .privacy-panel[hidden]{display:none}
26
- .privacy-panel h2{margin:8px 0;font-size:1.2rem}
27
- .privacy-panel p{margin:10px 0}
28
- .privacy-close{float:right}
29
- .privacy-details{display:grid;gap:8px;margin:16px 0}
30
- .privacy-service{display:flex;align-items:flex-start;gap:10px;padding:10px;border:1px solid var(--line);border-radius:8px}
31
- .privacy-service input{margin-top:4px;accent-color:var(--accent)}
32
- .privacy-service span span{display:inline}
33
- .privacy-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
34
- .privacy-actions button{flex:1 1 auto}
35
- .privacy-accept,.privacy-reject{font-weight:800!important}
36
- .privacy-controller,.privacy-policy-link{font-size:.9rem}
37
- .privacy-settings-button:focus-visible,.privacy-panel button:focus-visible,.privacy-panel a:focus-visible,.privacy-service input:focus-visible{outline:3px solid var(--accent);outline-offset:3px}
38
- @media(max-width:500px){.privacy-manager{left:12px;right:12px;bottom:12px}.privacy-settings-button{float:right}.privacy-panel{width:100%}.privacy-actions button{flex:1 1 100%}}
39
-
21
+ .privacy-manager{position:fixed;inset-inline-end:max(12px,env(safe-area-inset-right));inset-block-end:max(12px,env(safe-area-inset-bottom));z-index:1000;display:grid;align-content:end;gap:8px;box-sizing:border-box;width:min(30rem,calc(100vw - 24px));max-height:calc(100vh - 24px);max-height:calc(100dvh - 24px);color:var(--ink,#1d2824);font:14px/1.45 ui-sans-serif,system-ui,sans-serif;pointer-events:none;isolation:isolate}
22
+ .privacy-manager *{box-sizing:border-box}
23
+ .privacy-manager>*{min-width:0;pointer-events:auto}
24
+ .privacy-manager .privacy-settings-button,.privacy-manager .privacy-panel button{display:inline-flex;justify-content:center;align-items:center;gap:8px;min-width:0;min-height:46px;max-width:100%;padding:10px 12px;border:1px solid var(--line,#c7d0c9);border-radius:10px;background:var(--panel,#fff);color:var(--ink,#1d2824);font:inherit;font-weight:700;line-height:1.25;text-align:center;overflow-wrap:anywhere;cursor:pointer}
25
+ .privacy-manager .privacy-settings-button{order:1;justify-self:end;box-shadow:0 4px 18px #0002}
26
+ .privacy-manager .privacy-panel{position:relative;order:0;display:grid;gap:12px;width:100%;max-height:min(68vh,40rem);max-height:min(68dvh,40rem);overflow:auto;overscroll-behavior:contain;padding:18px;border:1px solid var(--line,#c7d0c9);border-radius:14px;background:var(--paper,#fff);color:var(--ink,#1d2824);box-shadow:0 12px 40px #0003}
27
+ .privacy-manager .privacy-panel[hidden]{display:none}
28
+ .privacy-manager .privacy-panel h2{margin:0;padding-inline-end:44px;font-size:1.15rem;line-height:1.3}
29
+ .privacy-manager .privacy-panel p{margin:0;overflow-wrap:anywhere}
30
+ .privacy-manager .privacy-panel .privacy-close{position:absolute;inset-block-start:8px;inset-inline-end:8px;width:44px;min-width:44px;min-height:44px;padding:8px}
31
+ .privacy-manager .privacy-panel .privacy-close svg{width:20px;height:20px}
32
+ .privacy-manager svg{width:18px;height:18px;flex:none}
33
+ .privacy-manager .privacy-intro,.privacy-manager .privacy-essential,.privacy-manager .privacy-controller{color:var(--muted,#536159)}
34
+ .privacy-manager .privacy-service-preview,.privacy-manager .privacy-service-settings{display:grid;gap:8px;min-width:0}
35
+ .privacy-manager .privacy-preview-item,.privacy-manager .privacy-service-setting{display:grid;gap:7px;min-width:0;padding:11px;border:1px solid var(--line,#c7d0c9);border-radius:10px;background:var(--panel,#fff)}
36
+ .privacy-manager .privacy-preview-item{grid-template-columns:minmax(0,1fr) auto;align-items:start}
37
+ .privacy-manager .privacy-preview-item h3{min-width:0;margin:0;font-size:.96rem;overflow-wrap:anywhere}
38
+ .privacy-manager .privacy-preview-item p{grid-column:1/-1;color:var(--muted,#536159)}
39
+ .privacy-manager .privacy-category{justify-self:start;max-width:100%;padding:2px 7px;border-radius:999px;background:color-mix(in srgb,var(--accent,#315e49) 12%,transparent);color:var(--ink,#1d2824);font-size:.78rem;overflow-wrap:anywhere}
40
+ .privacy-manager .privacy-details{min-width:0;margin:0;border-block:1px solid var(--line,#c7d0c9)}
41
+ .privacy-manager .privacy-details>summary{padding:10px 2px;font-weight:750;cursor:pointer}
42
+ .privacy-manager .privacy-details>summary:focus-visible{outline:3px solid var(--accent,#315e49);outline-offset:3px}
43
+ .privacy-manager .privacy-service-settings{padding-block-end:10px}
44
+ .privacy-manager .privacy-service-toggle{display:flex;align-items:center;gap:11px;min-width:0;cursor:pointer}
45
+ .privacy-manager .privacy-service-toggle input{position:relative;flex:none;width:42px;height:24px;margin:0;appearance:none;border:1px solid var(--line,#748079);border-radius:999px;background:var(--line,#748079);cursor:pointer}
46
+ .privacy-manager .privacy-service-toggle input::before{position:absolute;inset-block-start:2px;inset-inline-start:2px;width:18px;height:18px;border-radius:50%;background:var(--paper,#fff);content:"";transition:transform .16s ease}
47
+ .privacy-manager .privacy-service-toggle input:checked{border-color:var(--accent,#315e49);background:var(--accent,#315e49)}
48
+ .privacy-manager .privacy-service-toggle input:checked::before{transform:translateX(18px)}
49
+ .privacy-manager .privacy-service-toggle input:focus-visible{outline:3px solid var(--accent,#315e49);outline-offset:3px}
50
+ .privacy-manager .privacy-service-toggle-text{display:grid;gap:3px;min-width:0;overflow-wrap:anywhere}
51
+ .privacy-manager .privacy-service-toggle-text strong{font-size:.96rem}
52
+ .privacy-manager .privacy-service-disclosures{display:grid;gap:6px;margin:0}
53
+ .privacy-manager .privacy-service-disclosures>div{display:grid;grid-template-columns:minmax(5.5rem,.34fr) minmax(0,1fr);gap:8px;min-width:0}
54
+ .privacy-manager .privacy-service-disclosures dt{color:var(--muted,#536159);font-weight:650}
55
+ .privacy-manager .privacy-service-disclosures dd{min-width:0;margin:0;overflow-wrap:anywhere}
56
+ .privacy-manager .privacy-actions{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
57
+ .privacy-manager .privacy-panel .privacy-accept,.privacy-manager .privacy-panel .privacy-reject{border-color:var(--accent,#315e49);background:var(--accent,#315e49);color:var(--paper,#fff)}
58
+ .privacy-manager .privacy-panel .privacy-save,.privacy-manager .privacy-panel .privacy-manage{background:transparent}
59
+ .privacy-manager .privacy-panel button:disabled{opacity:.55;cursor:not-allowed}
60
+ .privacy-manager .privacy-policy-link{width:fit-content;max-width:100%;font-size:.9rem;overflow-wrap:anywhere}
61
+ .privacy-manager .privacy-policy-link:focus-visible,.privacy-manager .privacy-settings-button:focus-visible,.privacy-manager .privacy-panel button:focus-visible{outline:3px solid var(--accent,#315e49);outline-offset:3px}
62
+ @media(max-width:560px){.privacy-manager{inset-inline-start:max(12px,env(safe-area-inset-left));width:auto;max-width:none}.privacy-manager .privacy-panel{max-height:min(68vh,40rem);max-height:min(68dvh,40rem);padding:15px}.privacy-manager .privacy-actions{grid-template-columns:repeat(2,minmax(0,1fr));gap:7px}.privacy-manager .privacy-actions .privacy-manage{grid-column:1/-1;grid-row:1}.privacy-manager .privacy-actions .privacy-reject{grid-column:1;grid-row:2}.privacy-manager .privacy-actions .privacy-accept{grid-column:2;grid-row:2}.privacy-manager .privacy-panel .privacy-save{width:100%}}
40
63
  .page-builder{display:grid;gap:22px}.page-title h1{font-size:clamp(2rem,5vw,3.5rem);line-height:1.08;letter-spacing:-.04em}
41
64
  .hero-block{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(190px,.8fr);align-items:center;gap:28px;padding:clamp(28px,6vw,70px);background:linear-gradient(145deg,#202a48,#171e35);border:1px solid var(--line);border-radius:18px;margin:0}
42
65
  .hero-block:not(.hero-block--split){display:block}.hero-highlights{display:grid;gap:10px;list-style:none;padding:0}.hero-highlights li,.feature-card,.steps-widget li,.privacy-service-list li,.link-list li{padding:18px;background:var(--panel);border:1px solid var(--line);border-radius:12px}
@@ -110,4 +133,59 @@ main,.page-builder,.page-builder-row,.page-builder-cell,.post,.post-content,.pos
110
133
  @media(max-width:620px){.local-search-controls{align-items:stretch;flex-direction:column}.local-search-controls button{min-height:44px}.post-content pre,.code-widget pre,.steps-widget pre{padding:12px}}
111
134
  .locale-nav select{max-width:min(100%,13rem);padding:7px 30px 7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--paper);color:var(--ink);font:inherit;cursor:pointer}
112
135
  .locale-nav select:focus-visible{outline:3px solid #cb774d;outline-offset:3px}
113
- @media(max-width:620px){.locale-nav select{min-height:42px;max-width:100%}}
136
+ @media(max-width:620px){.locale-nav select{min-height:42px;max-width:100%}}
137
+
138
+ /* Article contents and code tools use theme styling and wrap on narrow screens. */
139
+ .post-toc{display:block;max-width:760px;margin:24px 0;padding:18px 22px;border:1px solid var(--line);border-radius:12px;background:var(--panel)}
140
+ .post-toc h2{margin:0 0 8px;font-size:1.05rem;letter-spacing:0}
141
+ .post-toc ol{margin:0;padding-inline-start:1.35rem}
142
+ .post-toc li{padding:2px 0}
143
+ .post-toc .post-toc-level-3{padding-inline-start:1rem}
144
+ .post-toc .post-toc-level-4,.post-toc .post-toc-level-5,.post-toc .post-toc-level-6{padding-inline-start:2rem}
145
+ .post-content h2[id],.post-content h3[id],.post-content h4[id],.post-content h5[id],.post-content h6[id]{scroll-margin-top:1rem}
146
+ .code-copy-block{max-width:100%;margin:1.25em 0;border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#20253a}
147
+ .code-copy-block pre{margin:0;border-radius:0}
148
+ .code-copy-toolbar{display:flex;justify-content:flex-end;padding:7px 10px;background:var(--ink)}
149
+ .code-copy-button{min-height:36px;padding:5px 12px;border:1px solid currentColor;border-radius:7px;background:transparent;color:var(--paper);font:600 .88rem/1.3 ui-sans-serif,system-ui,sans-serif;cursor:pointer}
150
+ .code-copy-button:hover{background:var(--accent)}
151
+ .code-copy-button:focus-visible{outline:3px solid var(--accent);outline-offset:2px}
152
+ .code-copy-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
153
+ .post-content pre,.code-widget pre,.steps-widget pre{max-width:100%;overflow-x:hidden;overflow-y:visible;white-space:pre-wrap;overflow-wrap:anywhere;word-break:normal;overscroll-behavior-inline:auto}
154
+ .post-content pre code,.code-widget pre code,.steps-widget pre code{white-space:inherit;overflow-wrap:inherit;word-break:inherit}
155
+ .pagination{flex-wrap:wrap;gap:12px}
156
+ @media(max-width:620px){.post-toc{padding:14px}.code-copy-button{min-height:44px}.post-content pre,.code-widget pre,.steps-widget pre{padding:12px}}
157
+
158
+ /* A vivid night palette: ink blue, ultraviolet panels, and electric lime. */
159
+ :root{--night:#101426;--panel:#1d223a;--ink:#f2f4ff;--muted:#aeb5ce;--line:#363d5b;--accent:#b7f36b;--warm:#ff9873}
160
+ body{background:radial-gradient(ellipse at 14% 0%,#302052 0,transparent 38%),var(--night)}
161
+ .post-card,.hero-block,.cta-block,.error-page{background:linear-gradient(140deg,#28203f,#1a2035)}
162
+ .page-section--soft{background:#1d2740}
163
+ .page-section--accent{background:#292942}
164
+ .page-section--dark{background:#0b1020}
165
+ .steps-widget pre,.code-widget pre,.code-copy-block{background:#0b1020}
166
+ .table-widget th{background:#292d49}
167
+ .notice-widget--warning{background:#332a35}
168
+ .notice-widget--success{background:#1c342e}
169
+ .code-copy-block pre{background:#0b1020;color:#f2f4ff}
170
+ .local-search-controls button{color:var(--night)}
171
+ .code-copy-button:focus-visible{outline-color:var(--warm)}
172
+
173
+ /* Shared EdgePress marks and SVG icons keep common navigation recognizable across themes. */
174
+ .brand{display:inline-flex;align-items:center;gap:10px}
175
+ .brand-mark{display:block;width:36px;height:36px;flex:0 0 auto;object-fit:contain}
176
+ .primary-navigation a,.site-header nav a,.footer-navigation a{display:inline-flex;align-items:center;gap:.42em}
177
+ .navigation-icon{display:block;width:1.05em;height:1.05em;flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
178
+ .hero-aside{display:grid;align-content:center;justify-items:center;gap:16px;min-width:0}
179
+ .hero-mascot{display:block;width:min(100%,230px);height:auto;max-height:220px;object-fit:contain;filter:drop-shadow(0 9px 13px #315e4922)}
180
+ .hero-aside .hero-highlights{width:100%;align-self:stretch}
181
+ .feature-icon{display:block;width:34px;height:34px;margin:0 0 10px;color:var(--accent);fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
182
+ .latest-posts-pagination{justify-content:flex-start;gap:16px;margin-top:18px}
183
+ .latest-posts-pagination a:last-child{margin-left:auto}
184
+ .hero-mascot-picture{display:block;width:min(100%,230px)}
185
+ .post-excerpt{max-width:72ch;color:var(--muted);font-size:.95rem;line-height:1.6}
186
+ .post-excerpt p{margin:.35rem 0 0}
187
+ .post-excerpt p:first-child{margin-top:0}
188
+ .post-excerpt a{color:inherit}
189
+ .post-content .markdown-video{margin:1.5rem 0}
190
+ .post-content .markdown-video video{display:block;width:100%;max-width:100%;height:auto;border-radius:10px;background:#101410}
191
+ .post-content .markdown-video figcaption{margin-top:.5rem;color:var(--muted);font-size:.9rem}
@@ -5,6 +5,8 @@
5
5
  <meta name="keywords" content="{{page.keywords}}">
6
6
  <meta name="author" content="{{site.seo.author}}">
7
7
  <title>{{page.title}}</title>
8
+ <meta name="theme-color" content="#315e49">
9
+ <link rel="icon" type="image/svg+xml" href="/edgepress/brand/edgepress-mark.svg">
8
10
  <link rel="canonical" href="{{page.canonical}}">
9
11
  <meta property="og:type" content="website">
10
12
  <meta property="og:title" content="{{page.title}}">
@@ -12,6 +14,9 @@
12
14
  <meta property="og:url" content="{{page.canonical}}">
13
15
  <meta property="og:image" content="{{page.image}}">
14
16
  <meta name="twitter:card" content="summary_large_image">
17
+ <meta name="twitter:title" content="{{page.title}}">
18
+ <meta name="twitter:description" content="{{page.description}}">
19
+ <meta name="twitter:image" content="{{page.image}}">
15
20
  <link rel="alternate" type="application/atom+xml" href="{{site.feedPath}}" title="{{site.feedLabel}}">
16
21
  <link rel="stylesheet" href="{{site.stylesheet}}">
17
22
  <script type="application/ld+json">{{{page.jsonLd}}}</script>
@@ -1,5 +1,5 @@
1
1
  <header class="signal-header site-header {{site.headerClass}}">
2
- <a class="brand {{site.brandClass}}" href="{{site.homePath}}"><span class="signal-mark" aria-hidden="true"></span>{{site.headerBrand}}</a>
2
+ <a class="brand {{site.brandClass}}" href="{{site.homePath}}"><img class="brand-mark" src="/edgepress/brand/edgepress-mark.svg" alt="" aria-hidden="true" width="36" height="36">{{site.headerBrand}}</a>
3
3
  <nav class="primary-navigation {{site.primaryNavigationClass}}" aria-label="{{site.mainNavigationLabel}}">{{{site.primaryNavigationHtml}}}</nav>
4
4
  <div class="locale-nav {{site.languageNavigationClass}}" role="group" aria-label="{{site.languageLabel}}">{{{site.localeLinksHtml}}}</div>
5
5
  </header>