jekyll-theme-zer0 1.31.1 → 1.31.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e606d7c2cacf7b4ceb9b974a7a23454a0a258f6a349aef34c39a02f3af7b515
4
- data.tar.gz: aec18fe69d6addfeaec4bb530e31d529c5df469a57a9a776c67f5949ea05d74c
3
+ metadata.gz: 816ebacaa328a7680e39d49a7e2b8e05defcf855b78e45f4c6389f0aa3d20215
4
+ data.tar.gz: cf16d9cbfd9f909a7164ce66ccc6ce4fab4ec3c788922b38b93dfc3243e3e4ff
5
5
  SHA512:
6
- metadata.gz: d03269b1e5c2f1ae7d0b4d09b97e1467cdc0ad2f0a3df8f7029ded9ab8f1b5263252f72e3cf7846b6f169c8baea3accd02221977003a149e4d7f20f13dee53be
7
- data.tar.gz: 1d5bc750fda06eb0288c96dd2720c7782828d9b24fbdc7f79140e2eae16f4f1af1d7110a6bad4575a4188fc4dc1a00ea294697dfdce8dca3187518a79fbf07a7
6
+ metadata.gz: 90b19505b5d0946020b8ea49e8440ccc61697f56181902a72ffba7dd860ac82555d1f33ab71f2b28e0c9627ec311a155d9f652b4f04367f1f095a05ab3084f3f
7
+ data.tar.gz: 4d59a4d83ec78332e125dc5d45c09b747de729bf16d6c77c365ffc89074c7c9db5deeb3def0d27c8dc91d779dd932e8e3a2f2c3970ac9be231627a4dad5bbeae
data/CHANGELOG.md CHANGED
@@ -12,6 +12,30 @@ hand-written prose covering the same releases in more depth; they sit below
12
12
  their version because release-please inserts each new release at the top of the
13
13
  file. Only `## [Unreleased]` describes work that has not shipped yet.
14
14
 
15
+ ## [1.31.3](https://github.com/bamr87/zer0-mistakes/compare/v1.31.2...v1.31.3) (2026-10-20)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **a11y:** cookie banner reserves its space, skip link above navbar, back-to-top focus ring ([#540](https://github.com/bamr87/zer0-mistakes/issues/540)) ([7012568](https://github.com/bamr87/zer0-mistakes/commit/70125682a7df9ee533cb0440aa07b89697045238))
21
+ * **analytics:** load GA and PostHog only after analytics consent ([#539](https://github.com/bamr87/zer0-mistakes/issues/539)) ([caa349b](https://github.com/bamr87/zer0-mistakes/commit/caa349b43019de37c27ae429ea15c497f637dc5b))
22
+ * **ci:** visual-evidence autogen starts Jekyll without LiveReload; re-renders evidence for edited generators ([#547](https://github.com/bamr87/zer0-mistakes/issues/547)) ([2dbeff1](https://github.com/bamr87/zer0-mistakes/commit/2dbeff1a3274bda845622af99ffb98732769ba6c))
23
+ * **includes:** print the footer copyright notice once ([#558](https://github.com/bamr87/zer0-mistakes/issues/558)) ([388745f](https://github.com/bamr87/zer0-mistakes/commit/388745f19b74be06b600f54af621db07786735d6))
24
+ * **includes:** stop favicon and tag badges linking missing paths ([#549](https://github.com/bamr87/zer0-mistakes/issues/549)) ([ec28e80](https://github.com/bamr87/zer0-mistakes/commit/ec28e803b060b8aec282db0e2b4db77b8f55f56d))
25
+
26
+
27
+ ### Performance Improvements
28
+
29
+ * **navigation:** yield between start-up steps; scroll spy measures in idle time ([#542](https://github.com/bamr87/zer0-mistakes/issues/542)) ([b1a9e3e](https://github.com/bamr87/zer0-mistakes/commit/b1a9e3efbc692e2989e0ccd7bca041e12e8a12c2))
30
+ * **sitemap:** render only the first page of index rows; build the rest from compact JSON ([#541](https://github.com/bamr87/zer0-mistakes/issues/541)) ([9838e8e](https://github.com/bamr87/zer0-mistakes/commit/9838e8e2a0f03dc358531242e79d4475d5f32fa2))
31
+
32
+ ## [1.31.2](https://github.com/bamr87/zer0-mistakes/compare/v1.31.1...v1.31.2) (2026-10-18)
33
+
34
+
35
+ ### Bug Fixes
36
+
37
+ * **ci:** give ui-audit's Jekyll serve 240s to become ready, not 90s ([#524](https://github.com/bamr87/zer0-mistakes/issues/524)) ([209a0e6](https://github.com/bamr87/zer0-mistakes/commit/209a0e6e394c162817aa11ad6bd2d803aa410842))
38
+
15
39
  ## [1.31.1](https://github.com/bamr87/zer0-mistakes/compare/v1.31.0...v1.31.1) (2026-10-17)
16
40
 
17
41
 
@@ -421,6 +445,17 @@ feature docs with captured screenshots of both the broken widget and the giscus.
421
445
 
422
446
  ### Changed
423
447
 
448
+ - **Navigation start-up no longer runs as one long task.**
449
+ `assets/js/modules/navigation/index.js` now wires sidebar state, keyboard
450
+ shortcuts, focus management and the navbar first, then yields to the main
451
+ thread before each step that reads styles or layout (breakpoint sync,
452
+ gestures, sidebar and TOC visibility, scroll spy). `navigation:ready` still
453
+ fires once every module exists. One step that throws no longer stops the
454
+ rest. ScrollSpy defers its first heading measurement to idle time
455
+ (`requestIdleCallback`, 1.5 s timeout), so it no longer forces a full
456
+ synchronous layout while the page is loading. On it-journey.dev quest
457
+ pages Lighthouse reported that task, attributed to `navigation/config.js`,
458
+ at about 1 s.
424
459
  - **Navbar label tiers reduced from three to two** ([#405](https://github.com/bamr87/zer0-mistakes/issues/405)).
425
460
  Top-level nav items now render as icon + full label above 51rem of centre
426
461
  track and icon-only below it; `text-overflow: ellipsis` is gone, so a label
@@ -429,6 +464,14 @@ feature docs with captured screenshots of both the broken widget and the giscus.
429
464
  change:** centre-track widths between 41rem and 51rem (roughly 992–1200px
430
465
  viewports) previously showed bare labels and now show icons, with the
431
466
  existing `.nav-tooltip` carrying the name on hover.
467
+ - **The sitemap index (`content/sitemap.html`) renders only its first page
468
+ of rows as HTML.** Every row is also in a compact `#sitemapData` JSON array
469
+ (title, description, collection, dates, categories, tags, URL), and the
470
+ script builds the other rows from it when "Show more", sorting or a search
471
+ needs them. Search, filters, `?q=`, stats and card view behave as before.
472
+ Without JavaScript, visitors get the first 50 rows and a pointer to
473
+ `/sitemap.xml` (when `jekyll-sitemap` is enabled). it-journey.dev's
474
+ `/search/` (431 rows) drops from 2.25 MB of HTML to 0.69 MB.
432
475
  - **Dropdown chevrons merged into their parent row** ([#405](https://github.com/bamr87/zer0-mistakes/issues/405)).
433
476
  The split toggle is now absolutely positioned inside padding the parent link
434
477
  reserves, and hover applies to the whole row, so there is no dead zone
@@ -884,6 +927,8 @@ feature docs with captured screenshots of both the broken widget and the giscus.
884
927
 
885
928
  ### Fixed
886
929
 
930
+ - **`require_consent` now means no analytics until the visitor accepts.** With `posthog.privacy.require_consent: true`, PostHog used to load opted-out on a first visit: the browser still fetched `array.js`, `config.js` and `surveys.js` and stored `ph_<key>_posthog` before any banner choice, and Google Analytics ignored consent entirely. `_includes/analytics/posthog.html` now boots PostHog only once analytics consent exists, and `_includes/analytics/google-analytics.html` follows the same flag (override per site with `google_analytics_require_consent`). Both load as soon as the visitor clicks Accept All or saves preferences with Analytics on, through the banner's `cookieConsentChanged` event, so no reload is needed. Reject All keeps them off. Sites without the flag load exactly as before. Regression test: `test/visual/features/analytics-consent.spec.js`.
931
+
887
932
  - **Color-mode toggle exposes the selected mode** ([#521](https://github.com/bamr87/zer0-mistakes/issues/521)).
888
933
  `_includes/components/halfmoon.html` server-rendered Light/Dark/Auto all
889
934
  `aria-pressed="false"`, and on load `assets/js/halfmoon.js` marked the
@@ -1565,6 +1610,20 @@ off the `data-repo` attribute, not the page origin, so the iframe renders and re
1565
1610
  `jekyll-remote-theme` + `webrick`, and both the Gemfile and the remote
1566
1611
  `_config.yml` template add `jekyll-include-cache` (required by the theme's
1567
1612
  layouts).
1613
+ - **The cookie banner covered page content and controls.** While the banner is
1614
+ showing, `cookie-consent.html` now publishes its height as
1615
+ `--zer0-cookie-banner-inset` (kept current with a ResizeObserver). The page
1616
+ reserves that much bottom padding and scroll padding, and the floating
1617
+ buttons (back to top, AI chat, graph, TOC/sidebar FABs) move up above it.
1618
+ Hero CTAs and keyboard focus no longer end up underneath. All of it is
1619
+ removed as soon as a choice is made.
1620
+ - **The skip link opened underneath the fixed navbar.** When focused it is now
1621
+ `position: fixed` at `--zer0-layer-skip-link` (1100, above the navbar's
1622
+ 1030). On `default.html` (docs) pages it now targets `#page-content` (the
1623
+ article column), not `#main-content`, which starts with the docs sidebar and
1624
+ TOC. Layouts and pages can set `skip_link_target` in front matter.
1625
+ - **Back to top had no visible keyboard focus.** It now draws a 2px
1626
+ primary-color `:focus-visible` outline.
1568
1627
 
1569
1628
  ## [1.31.0](https://github.com/bamr87/zer0-mistakes/compare/v1.30.0...v1.31.0) (2026-10-07)
1570
1629
 
data/_data/ai.yml CHANGED
@@ -8,5 +8,5 @@
8
8
  # CLAUDE_CODE_OAUTH_TOKEN (preferred) or ANTHROPIC_API_KEY secret.
9
9
  # =============================================================================
10
10
  provider: anthropic
11
- model: claude-opus-4-8
11
+ model: claude-opus-5-5
12
12
  max_tokens: 8000
data/_data/backlog.yml CHANGED
@@ -62,8 +62,8 @@
62
62
 
63
63
  meta:
64
64
  title: "zer0-mistakes Backlog"
65
- updated: 2026-09-05
66
- next_id: 52
65
+ updated: 2026-10-19
66
+ next_id: 55
67
67
 
68
68
  tasks:
69
69
  # --- Housekeeping (seeded so the loop has work on day one) ------------------
@@ -1444,3 +1444,55 @@ tasks:
1444
1444
  links: { issue: null, pr: null, roadmap: null }
1445
1445
  created: 2026-09-07
1446
1446
  updated: 2026-09-07
1447
+
1448
+ - id: T-054
1449
+ title: "Footer prints the copyright notice twice"
1450
+ status: done
1451
+ priority: P3
1452
+ area: feat
1453
+ risk: standard
1454
+ effort: S
1455
+ source: user
1456
+ route: theme-ui
1457
+ summary: "`_includes/core/footer.html` printed `© <year> <site.name>` above the Powered-by row and again as `© <year> <site.title>. All Rights Reserved.` in the bottom bar, so every page (and every consumer site, e.g. bamr87.github.io) showed two copyright lines. Reported by the bamr87.github.io audit at b1a9e3e. T-052/T-053 are taken by PR #549, so this starts at T-054."
1458
+ acceptance:
1459
+ - "Every page renders exactly one © notice in the footer (the bottom-bar line)."
1460
+ - "A test/visual spec asserts a single © in the footer."
1461
+ links: { issue: null, pr: null, roadmap: null }
1462
+ created: 2026-10-19
1463
+ updated: 2026-10-19
1464
+ - id: T-052
1465
+ title: "favicon.html emits /favicon.ico unconditionally — 404 on every page for consumers without that file"
1466
+ status: done
1467
+ priority: P2
1468
+ area: feat
1469
+ risk: standard
1470
+ effort: S
1471
+ source: issue
1472
+ route: theme-ui
1473
+ summary: "`_includes/core/favicon.html` always linked `/favicon.ico` when no `favicon.ico` was configured. A remote_theme consumer does not get this repo's root favicon.ico, so sites without one (e.g. bamr87.github.io, which ships favicon.png) requested a missing file on every page (#536). Instance of the T-027 class."
1474
+ acceptance:
1475
+ - "With no `favicon.ico` configured, the default icon link is emitted only for a root /favicon.ico, /favicon.png or /favicon.svg that exists in site.static_files (in that order); none present -> no icon link."
1476
+ - "A configured `favicon.ico` is still emitted as-is, and baseurl sites resolve through relative_url."
1477
+ - "test/test_consumer_404_gates.rb (run by test_core.sh) builds consumer sites with and without each file and asserts the rendered links."
1478
+ links: { issue: 536, pr: 549, roadmap: null }
1479
+ created: 2026-10-18
1480
+ updated: 2026-10-18
1481
+
1482
+ - id: T-053
1483
+ title: "intro.html links tag/category badges to /tags/ without an existence gate (404 for remote-theme consumers)"
1484
+ status: done
1485
+ priority: P1
1486
+ area: feat
1487
+ risk: standard
1488
+ effort: S
1489
+ source: issue
1490
+ route: theme-ui
1491
+ summary: "`_includes/content/intro.html` linked every page's category badge and tag badges to `/tags/#<slug>` without checking that a tags index exists, so remote-theme consumers got 404 links on every tagged page (#537). #204 / #218 (T-029) already gated the same link in article.html and section-sidebar.html; intro.html was missed. Instance of the T-027 class."
1492
+ acceptance:
1493
+ - "Tag and non-docs category badges link to the tags index only when `site.tags_page` is set or a page at /tags/ exists in site.html_pages; otherwise they render as plain `<span>` badges."
1494
+ - "This site (which has /tags/) still renders linked badges; the Jekyll build stays green."
1495
+ - "test/test_consumer_404_gates.rb asserts the linked, unlinked and `tags_page` variants."
1496
+ links: { issue: 537, pr: 549, roadmap: null }
1497
+ created: 2026-10-18
1498
+ updated: 2026-10-18
data/_data/features.yml CHANGED
@@ -227,6 +227,7 @@ features:
227
227
  tests:
228
228
  - "test/test_quality.sh"
229
229
  - "test/visual/core/security.spec.js"
230
+ - "test/visual/features/analytics-consent.spec.js"
230
231
  references:
231
232
  include: "_includes/analytics/posthog.html"
232
233
  config: "_config.yml"
@@ -257,6 +258,7 @@ features:
257
258
  issue: null
258
259
  tests:
259
260
  - "test/test_quality.sh"
261
+ - "test/visual/features/banner-inset-skip-link.spec.js"
260
262
  references:
261
263
  include: "_includes/components/cookie-consent.html"
262
264
  config: "_config.yml"
@@ -288,6 +290,7 @@ features:
288
290
  issue: null
289
291
  tests:
290
292
  - "test/visual/features/sidebar-navigation.spec.js"
293
+ - "test/visual/features/scroll-spy.spec.js"
291
294
  references:
292
295
  javascript:
293
296
  - "assets/js/modules/navigation/sidebar-state.js"
@@ -389,6 +392,7 @@ features:
389
392
  issue: null
390
393
  tests:
391
394
  - "test/visual/core/accessibility.spec.js"
395
+ - "test/visual/features/banner-inset-skip-link.spec.js"
392
396
  references:
393
397
  include: "_includes/core/header.html"
394
398
  styles: "_sass/custom.scss"
@@ -945,6 +949,7 @@ features:
945
949
  issue: null
946
950
  tests:
947
951
  - "test/visual/features/content-enhancements.spec.js"
952
+ - "test/visual/features/banner-inset-skip-link.spec.js"
948
953
  references:
949
954
  scripts:
950
955
  - "assets/js/back-to-top.js"
@@ -1208,6 +1213,7 @@ features:
1208
1213
  issue: null
1209
1214
  tests:
1210
1215
  - "test/test_quality.sh"
1216
+ - "test/visual/features/analytics-consent.spec.js"
1211
1217
  references:
1212
1218
  includes:
1213
1219
  - "_includes/analytics/google-analytics.html"
@@ -1322,6 +1328,7 @@ features:
1322
1328
  tests:
1323
1329
  - "test/test_core.sh"
1324
1330
  - "test/test_deployment.sh"
1331
+ - "test/visual/features/sitemap-pagination.spec.js"
1325
1332
  references:
1326
1333
  includes:
1327
1334
  - "_includes/content/sitemap.html"
@@ -2202,7 +2209,7 @@ features:
2202
2209
 
2203
2210
  - id: ZER0-079
2204
2211
  title: "Config-Driven Favicon and Browser Identity"
2205
- description: "Head include emitting favicon, SVG icon, Apple touch icon, web manifest, and theme-color tags from an optional favicon config block, with an explicit /favicon.ico fallback that works on baseurl deployments"
2212
+ description: "Head include emitting favicon, SVG icon, Apple touch icon, web manifest, and theme-color tags from an optional favicon config block, with an existence-gated root favicon fallback (.ico, .png, .svg) that works on baseurl deployments and never links a missing file"
2206
2213
  implemented: true
2207
2214
  version: "1.28.0"
2208
2215
  link: "/"
@@ -2222,7 +2229,7 @@ features:
2222
2229
  - "_includes/core/head.html"
2223
2230
  docs: "pages/_docs/features/favicon.md"
2224
2231
  features:
2225
- - "Zero-config default: explicit /favicon.ico link on every page (fixes silent 404s and baseurl project sites)"
2232
+ - "Zero-config default: explicit link to the root /favicon.ico (else /favicon.png, else /favicon.svg) only when that file exists in site.static_files — no 404 for remote-theme consumers without one (#536)"
2226
2233
  - "Optional SVG favicon, PNG sizes, apple-touch-icon, and web manifest links"
2227
2234
  - "scheme-aware theme-color metas tracking --bs-body-bg (light #ffffff / dark #212529), emitted even with no config; favicon.theme_color pins a single value"
2228
2235
 
@@ -103,7 +103,7 @@ providers:
103
103
  token_hint: "Mint one with `claude setup-token`, or create an API key at console.anthropic.com."
104
104
  console: "https://console.anthropic.com/"
105
105
  env: "CLAUDE_CODE_OAUTH_TOKEN"
106
- models: [claude-opus-4-8, claude-opus-5, claude-sonnet-5, claude-haiku-4-5]
106
+ models: [claude-opus-5-5, claude-sonnet-5-5, claude-haiku-5-5]
107
107
  - id: xai
108
108
  label: "Grok"
109
109
  vendor: "xAI"
@@ -3,8 +3,8 @@
3
3
  # Regenerated automatically during each release (scripts/bin/release).
4
4
  # Consumers use this file via scripts/bin/audit-consumer to detect drift.
5
5
 
6
- version: "1.31.1"
7
- generated_at: "2026-10-17T18:15:21Z"
6
+ version: "1.31.3"
7
+ generated_at: "2026-10-20T03:56:33Z"
8
8
 
9
9
  # Directories owned by this theme. A consumer file in any of these paths
10
10
  # that is not declared in the consumer's .theme-overrides.yml is flagged
@@ -68,7 +68,7 @@ file_checksums:
68
68
  _layouts/book.html: "ab256dbdf36e7e1ec07f06870f20dc47805de3b905747a453625642404540b0a"
69
69
  _layouts/collection.html: "9da7ac3209eb2e3e0980cbc934878e31a01fc1fd4be3871fdf4880a2f68b02ff"
70
70
  _layouts/cookbook.html: "f0ae3fcb1f07f3355fb5c876f2305873fb4a8cd457335dfd8f22e1856bc6bf56"
71
- _layouts/default.html: "4292cd641057a70d654407eb67eef8d6921692f1cf40b237f364f8f237c26c13"
71
+ _layouts/default.html: "94cd7db2a889e33bffd25cc254cb48514f0947df3a580aa0c347f386cb1bc7a7"
72
72
  _layouts/home.html: "a67e0219abef4c78513c088004c39980e574d898c9dfeb5ad1522fd5edc292f8"
73
73
  _layouts/index.html: "82b543be5a911a0d48bccb25be1ee514eed6e8299dc4ae20d7ce7e08778d4bc0"
74
74
  _layouts/landing.html: "fbec896f0e75339a746bdb1a9a176ed66742d517c041a2bb89c3fd1f61512007"
@@ -84,14 +84,14 @@ file_checksums:
84
84
  _layouts/stats.html: "df42629997836865139ba79467d481dce042a40a51e4c9966631f5f97dba76c4"
85
85
  _layouts/tag.html: "e642bfed8f3c79401e72532d46b4874e9f25bca3ea3b7abfc40c504b496829db"
86
86
  _layouts/welcome.html: "85c129e313a37b6c720b319bb8c5aab12234e617d78b02cf9b8e45bde53e1f30"
87
- _includes/analytics/google-analytics.html: "d67b99397df941b9bee165866c97f92c3cf6f247f76281e2126638ae3dc8647f"
87
+ _includes/analytics/google-analytics.html: "de14702cbee862f531c47f17a98bf151f875dfa482894d133314f246bdda1d0c"
88
88
  _includes/analytics/google-tag-manager-body.html: "7e37766982dc0b21d14683fa1f64f12c2f2eb500423edf6fa6184b1617788236"
89
89
  _includes/analytics/google-tag-manager-head.html: "4f52a13ff60a5eb099d3cbdeb756e44d2eac3bed214a7293f755f9f5aaa7ad20"
90
- _includes/analytics/posthog.html: "869d09e36185a9dbbff68214fc800fa62e0a5c6100dff8619381cbce15017af6"
90
+ _includes/analytics/posthog.html: "4c206d128f311cd9f872c683a377213f05d09a2eb836431cf480405eb01da4c0"
91
91
  _includes/components/abc-letter.html: "2a7765f39e0263ddb8ce7438dc159f25c6da6745c484a99c0b04b2a991dd8700"
92
92
  _includes/components/admin-links.html: "71fba67a292265f4074d254e7a8d90daab39f7a510ee3530f42681bb6c41981a"
93
93
  _includes/components/admin-tabs.html: "b75590a4c987440e35afeb96a62d569dc4f4c4ce5e91f966eacdef14ed28ddb0"
94
- _includes/components/ai-chat.html: "8f47af244d1b846228d195b671605249835113a12c3db16194fae4ab7e7cc46a"
94
+ _includes/components/ai-chat.html: "90c6241ede95bc58851345234a0a35d32fe07670bc61df408ee8929f3e6bfd75"
95
95
  _includes/components/analytics-dashboard.html: "511d20bff9cc2c22e92b2a5e6f71292f9397dcb1180fa33f559f085de8a2a66c"
96
96
  _includes/components/author-avatar-url.html: "7c9499d7623c9f8eb478fee3028fcc0a29de51f4f10eea87a1db4f67cccb65c3"
97
97
  _includes/components/author-bio.html: "6da96d8b4ddfc798e1fd350199e14e31d18649aa6cdde7351b8a629fc8c29abc"
@@ -111,7 +111,7 @@ file_checksums:
111
111
  _includes/components/component-showcase.html: "d36a006832bf0991d0a2540829bc9bad68b0af6aab13cf6e283d8f19e9e71b31"
112
112
  _includes/components/config-editor.html: "61c96ec4891966983839e4fcc68c77e5989dbc9d72c806706091b378b7f48b84"
113
113
  _includes/components/config-viewer.html: "dd88d0e8a311370c2a8c9605230940223db44c129b1d1adebc81915ef565b957"
114
- _includes/components/cookie-consent.html: "e8ea786e3420bd796da666b6d9aed5ec6c98aff13879f017b700ca23e557e103"
114
+ _includes/components/cookie-consent.html: "c20c1f82429af38ca5730114da559e7d84545674bc94b91da8acd1f72a1845d0"
115
115
  _includes/components/cta-button.html: "a4352d9d4b43e0cb3c8fcf2c70569ec1a46029ab733a063a3e16be8bdc6c7501"
116
116
  _includes/components/data-card.html: "c46604f61bffab476bb943f4a631320077cb47b6a58a12e14aea7bc5118f80ac"
117
117
  _includes/components/dev-shortcuts.html: "32d430d109474d6136969b7f9ea1dc8b07386856e14a5829e22ac2c9102aa6f2"
@@ -128,7 +128,7 @@ file_checksums:
128
128
  _includes/components/nav-editor.html: "51dde98e848c44cf464ea16308d965a3424706008119fab14fd181ddbf5067c0"
129
129
  _includes/components/nav-export.html: "11d56e16f29a6d51ce6816e87de348019eb56bb820fa23a184c4e1639da3fac0"
130
130
  _includes/components/nav-overview.html: "8625169918a8e43fd3a5dc2b8c08e9cbaa78fc5e6be6a9b1ca418f7084ccadfb"
131
- _includes/components/page-feedback.html: "93476492d278da6e403a2231dd5054dced94d1a0a2ec0eed30f5e94e09bdc862"
131
+ _includes/components/page-feedback.html: "3fd048cef6b26bbdd83c9b0fbeb9ca7c0a58c91c92046fa3b7b63cf8e73e15b4"
132
132
  _includes/components/page-views-init.html: "07495e4c3343e5dbfb84ebfd04d25ac7340de34f41f8dce8394a6db2d157afee"
133
133
  _includes/components/page-views.html: "b5654482c7ecffc95f9d0afad1b707a402e0e82f8ee474d39c108894175b7d9b"
134
134
  _includes/components/post-card.html: "d93a021a9c2e979bf3d7d741281ce4a15ec115c2b8b6a5a1bcc40e9a187959c2"
@@ -165,21 +165,21 @@ file_checksums:
165
165
  _includes/components/zer0-env-var.html: "d11f3a578319f48f763b0e8639230e71b9a6e9301453c73c9907814f086fc03e"
166
166
  _includes/content/backlinks.html: "6b18741876a3923606b60f60b3f366c3f60d49924d03a2b86c80df41f2e8130a"
167
167
  _includes/content/giscus.html: "8c49d8a22caef89a3132ba9da5434ddecf33b615f051eee1af7441df0bfef686"
168
- _includes/content/intro.html: "3afe3f3154fae6a3e4c8f96f818226ab9a41448fadee76d172e1019fdd1cf63c"
168
+ _includes/content/intro.html: "8580a875177b360f721c8715997608087437bfd668ee63070cf2904e2d35b2f3"
169
169
  _includes/content/jsonld-faq.html: "9e4001c9ccebb91ac1b2e51a8a7833e611bd70ae59fee7c599a88597b079a55c"
170
170
  _includes/content/jsonld-software.html: "41624ca1a61687a91878e4147cb6e1fc172ace09bf2d9688e5f1da16cdaecf06"
171
171
  _includes/content/seo.html: "05a6c4bb5aa9357facd041b85eb3ffc3b1ab0c4fabe7cbfa87f9905618718d5f"
172
- _includes/content/sitemap.html: "d2504f4573d1978134d54751f63939f13a10efe0b5996267ccf2a6e3d13df589"
172
+ _includes/content/sitemap.html: "5add1a394ba57979eaf88b84586803a2485b4db5e07a4117e333709c59616ebb"
173
173
  _includes/content/toc.html: "b42a00a641db03b4936d4d754a2e14fcf9517c2b8e0257ceba8a6fe2e2003e40"
174
174
  _includes/content/transclude.html: "da0714fb23034e1499920fa7fe7f6ef58c4b98eeea40319d6f10361db99ea754"
175
175
  _includes/core/branding.html: "3e5d00bc427eb12585f77f98990e59f6dae8643eddfa395c7ac365b3d7cc680c"
176
176
  _includes/core/color-mode-init.html: "de31274204b6c5dea7e953f94e6663890a47286728484ee937b723100bf899ca"
177
177
  _includes/core/console-capture.html: "f9ca43e114faa48f6e76928b75b8baf580b6adb7efabf206a3b319938eabf019"
178
- _includes/core/favicon.html: "9ba9fc5b55f319c4af0404058eb5a3893eba52fe46cc48438037debe4baef458"
178
+ _includes/core/favicon.html: "3dd99d22b71d9619aa341c8c5ee95039b2cea88c2cc33b4e34a150df0c719914"
179
179
  _includes/core/footer-fabs.html: "4c46914fc53f3c40220501a34ffe20bb296d9f8ddeeec21e959b024f9a30e8a7"
180
- _includes/core/footer.html: "1191d080370e8c9feae3e00cc88d59eefd5c927faa053645302d44139ed1b64a"
180
+ _includes/core/footer.html: "f937cc37302e2999c0d49d0933508ac520bed721464eef04d8cb24f1ebaa5a8e"
181
181
  _includes/core/head.html: "31a470a324d17d1a91edb4d5117b33695ce5561b72dc1bd36ffc185344df18a7"
182
- _includes/core/header.html: "10e4112f6d6c6f7a6c76a35e03aed48183eebfa7dc4887c02927eb8eb487f105"
182
+ _includes/core/header.html: "63e585f42bb3fffab15c76dd44180578b9f4b0b5e3f6b13e025da4f8fecc380b"
183
183
  _includes/core/hreflang.html: "876c44ae392aace73680fb042b8cf7d2d1c2b3143dc755c4dd4c2eb5091356d1"
184
184
  _includes/core/i18n.html: "e856ab288f48a5f5f71941a8f47f7dde538deb64d513b57bdd7f4c1b1b2cd6b0"
185
185
  _includes/core/tokens-inline.html: "d5388ac882d6e39e8e415e3739c80ef84fd4e79e3b86c0da068fa992a4a08da0"
@@ -212,7 +212,7 @@ file_checksums:
212
212
  _includes/search-data.json: "1824d7a8ed778cdab23c502098cfce7dc687c18cede989294dbc989bfb15187e"
213
213
  _includes/setup/claude-session.html: "cc7459d6c3ecb846cddabf039ddf5e90afa54429a8dea7ed27f3574fe0a9c7e5"
214
214
  _includes/setup/prereq-checklist.html: "f6af6ac1d32837399cdb223593f3024db5aab13a4987e179e1e711863625d05f"
215
- _includes/setup/wizard.html: "e3c94b8bf27789cd8e9992018ec7f4caa94628189d281acd8a85d565d7a51594"
215
+ _includes/setup/wizard.html: "c9b2c78d83534adffd466a23d92ddfc9f3b086c7f33b8f06f251b0e96ee268a7"
216
216
  _includes/stats/stats-categories.html: "f9edb65068c846a973b27f2a07b582473e6ac0b0221793408fa0191082fd693d"
217
217
  _includes/stats/stats-header.html: "4f965b4a3f97d4eab8b2bb003558f7a05a99fd6a2f21e6a527e0ae30b6344ee5"
218
218
  _includes/stats/stats-metrics.html: "53066bb49d3070d842971e5ced2a394eba54f8aea80e35820ab41edfc8c979be"
@@ -220,11 +220,11 @@ file_checksums:
220
220
  _includes/stats/stats-overview.html: "6130e7beb215fac00fe0e094ec671ba1219894d32ec370aa7fdb9099168b7200"
221
221
  _includes/stats/stats-tags.html: "09d38e06b2d4cf7f0a2e29fddf0a520abcc96244691fa34cc01a55cf990d1960"
222
222
  _sass/components/_author.scss: "2b037d13e159073755cb07e9a5eda2d70dbdcf7420b2e52951d4c0538a617938"
223
- _sass/components/_back-to-top.scss: "d1b8a948cd4e2c4772b12c77e2a812d63df400f54a16301053e223410d47cc7e"
223
+ _sass/components/_back-to-top.scss: "abcb6826df9dd3fc8ddd9a56b8bbe539fdc9d5f141a49d1a1db899f4708fada4"
224
224
  _sass/components/_book.scss: "dd822c0d0cf84bb919d5b889a19cd75af4dc3603bd142e2b01c953c6b8e159f0"
225
225
  _sass/components/_callout.scss: "a17bf67c19c90ad791255c39c69c9796406c9feba40fa0ef62eeabcc1a5d8778"
226
226
  _sass/components/_content-tables.scss: "463fe822b6c885a3d4ee7ed94dca54c81001a2f346c61f1495f1334b89af12bc"
227
- _sass/components/_cookie-banner.scss: "c2e0f314e5a65b91e5aa9af778d482e6f7888c08434ca3a41c76f5877edf03f7"
227
+ _sass/components/_cookie-banner.scss: "2d1c7c5b813f8f3fa03c8a959eb8af13cbffd224f3a76b51dc8aa57bf8a2ba02"
228
228
  _sass/components/_footer.scss: "aeda30d678adf29cfb9a052fe0faba2cdaf00f289fe3017cab309b5cfb74fb99"
229
229
  _sass/components/_mermaid.scss: "02de7801b8c82b160c312ac97cf0870e36fa7899cd1d698a46b6488ef669ac23"
230
230
  _sass/components/_notes-index.scss: "7abb34307cba043e3100a0c4311b9eb279b7dfdd42ea3a44631d7b6eda47b9fe"
@@ -272,7 +272,7 @@ file_checksums:
272
272
  _sass/tokens/_shadow.scss: "c15a3610aba4c3f92154ec0fde33201ee69284557d74a74681c019453de584d9"
273
273
  _sass/tokens/_spacing.scss: "c73d9b53f9fb194670a01f9a276471994b174ef7d62df52094aafcc173f64515"
274
274
  _sass/tokens/_typography.scss: "c732da33555126f22230df5f2012d00bcfb7fe22c4a3cd9b39822495d83954e5"
275
- _sass/utilities/_focus.scss: "863979686d0ba6c42097ef468669e72d8632a3285afc1c3de16905fd5f0d8210"
275
+ _sass/utilities/_focus.scss: "b84c989d21e349137e2fafbd0a49eb4e471d021589a6077c172a798e01a24feb"
276
276
  _sass/utilities/_layout.scss: "3f12b385c2b14c603e7a4e055bee862c9635c2c16f40bca0d709851a0dc03efb"
277
277
  _sass/utilities/_motion.scss: "21441bdb990d961acbe2101ee361fc6b7338ffd815a1c0f0a84bf516d74440fe"
278
278
  assets/css/custom.css: "5b74a5e7282f09e17bb8105c144bcfd779efd29b4438f4eeb52ce7126a09d55f"
@@ -298,10 +298,10 @@ file_checksums:
298
298
  assets/js/modules/navigation/config.js: "226f341b4d0c7ef2b6a4eb98f5ab1ba9d626a9a24a9c66d889f1b3da3e0ad9f5"
299
299
  assets/js/modules/navigation/focus.js: "cd73b2bf9d6701a35f075a6304ebf92173c4b89eb021ce8df594e27e173528ca"
300
300
  assets/js/modules/navigation/gestures.js: "9fded02fe6d3ce429793e5b10e9a59317c5d9bccf81076d88718ae2eb07716ae"
301
- assets/js/modules/navigation/index.js: "a0d9f81341266f5007d2a6530233f56363f262fe9c29aad3ed6cb3b72bd0c469"
301
+ assets/js/modules/navigation/index.js: "8430ba77ca21db648ff5c9441437f2158937d562c3e811a11b12eaab7276d67b"
302
302
  assets/js/modules/navigation/keyboard.js: "25fb5659e7717c8d3425ea3c6a79fe3d6893677a78976c1fdd6c773cd3a26887"
303
303
  assets/js/modules/navigation/navbar.js: "f80320d273526a8352b963f5a6c18c3da99368aaac3cc653e59fc52db2b40bb8"
304
- assets/js/modules/navigation/scroll-spy.js: "e835a3a47b03df2593e0325f7b8c442d07980d42cd8b4a5034ec69356a6c17db"
304
+ assets/js/modules/navigation/scroll-spy.js: "9bfcad2512fbf926e329affd9d1fa8d0407d07bee1a3afb143ce7b25488fc773"
305
305
  assets/js/modules/navigation/sidebar-state.js: "d9f1a8e7bee3e3ab00e9658e2f0c9ab51f0f15ecb68129b1650120983e5c6d62"
306
306
  assets/js/modules/navigation/sidebar-visibility.js: "e7e4396181013bd2c3324e04b4eeb48f3d5ba743bb7a8e7db9505bed0003fb22"
307
307
  assets/js/modules/navigation/smooth-scroll.js: "3e1b11718ebe4dbe78386140a3afee1d66d9326b72f156472ea41daea35a349c"
@@ -1,4 +1,18 @@
1
1
  {% comment %} Feature: ZER0-038 {% endcomment %}
2
+ {%- comment -%}
3
+ Consent gate. When the site requires consent, gtag.js is not requested and
4
+ no _ga cookie is set until the visitor accepts the "analytics" category in
5
+ the cookie-consent banner (localStorage "zer0-cookie-consent"). Accepting
6
+ loads it on the spot (the banner dispatches `cookieConsentChanged`), so no
7
+ reload is needed. A site configures its consent posture once: this follows
8
+ `posthog.privacy.require_consent`, the same flag that gates PostHog and the
9
+ page-view counter. `google_analytics_require_consent: true|false` overrides
10
+ it for GA alone, for a site that runs GA without PostHog.
11
+ With neither flag set, GA loads exactly as before.
12
+ {%- endcomment -%}
13
+ {%- assign ga_require_consent = false -%}
14
+ {%- if site.posthog.privacy.require_consent -%}{%- assign ga_require_consent = true -%}{%- endif -%}
15
+ {%- if site.google_analytics_require_consent == true -%}{%- assign ga_require_consent = true -%}{%- elsif site.google_analytics_require_consent == false -%}{%- assign ga_require_consent = false -%}{%- endif -%}
2
16
  <!-- Global site tag (gtag.js) - Google Analytics -->
3
17
  <script>
4
18
  (function () {
@@ -6,13 +20,36 @@
6
20
  var h = location.hostname;
7
21
  if (h === 'localhost' || h === '127.0.0.1' || h === '0.0.0.0' || h === '[::1]' ||
8
22
  h === 'host.docker.internal' || h.endsWith('.local') || h.endsWith('.test')) return;
9
- var s = document.createElement('script');
10
- s.async = true;
11
- s.src = 'https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}';
12
- document.head.appendChild(s);
13
- window.dataLayer = window.dataLayer || [];
14
- function gtag(){dataLayer.push(arguments);}
15
- gtag('js', new Date());
16
- gtag('config', '{{ site.google_analytics }}');
23
+ var id = {{ site.google_analytics | jsonify }};
24
+ var requireConsent = {{ ga_require_consent | jsonify }};
25
+ var loaded = false;
26
+ function load() {
27
+ if (loaded) return;
28
+ loaded = true;
29
+ window['ga-disable-' + id] = false;
30
+ var s = document.createElement('script');
31
+ s.async = true;
32
+ s.src = 'https://www.googletagmanager.com/gtag/js?id=' + encodeURIComponent(id);
33
+ document.head.appendChild(s);
34
+ window.dataLayer = window.dataLayer || [];
35
+ function gtag(){dataLayer.push(arguments);}
36
+ window.gtag = window.gtag || gtag;
37
+ gtag('js', new Date());
38
+ gtag('config', id);
39
+ }
40
+ if (!requireConsent) { load(); return; }
41
+ // Same record and 365-day expiry as components/cookie-consent.html.
42
+ var granted = false;
43
+ try {
44
+ var c = JSON.parse(window.localStorage.getItem('zer0-cookie-consent') || 'null');
45
+ granted = !!(c && c.analytics === true && (Date.now() - c.timestamp) <= 365 * 864e5);
46
+ } catch (e) { /* localStorage unavailable: stay off */ }
47
+ if (granted) load();
48
+ document.addEventListener('cookieConsentChanged', function (e) {
49
+ var ok = !!(e.detail && e.detail.analytics === true);
50
+ if (ok) load();
51
+ // Withdrawn after loading: gtag's documented per-property kill switch.
52
+ else if (loaded) window['ga-disable-' + id] = true;
53
+ });
17
54
  })();
18
- </script>
55
+ </script>