jekyll-theme-zer0 1.28.0 → 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1143 -13
  3. data/_data/README.md +2 -0
  4. data/_data/ai.yml +5 -3
  5. data/_data/ai_pricing.yml +36 -0
  6. data/_data/backlog.yml +507 -2
  7. data/_data/consumers.yml +157 -9
  8. data/_data/features.yml +303 -20
  9. data/_data/feedback_types.yml +17 -12
  10. data/_data/i18n/fr.yml +12 -7
  11. data/_data/i18n/manifest.yml +39 -12
  12. data/_data/ingredient_densities.yml +122 -0
  13. data/_data/landing.yml +5 -2
  14. data/_data/navigation/main.yml +16 -0
  15. data/_data/navigation/quickstart.yml +4 -0
  16. data/_data/recipe_courses.yml +64 -0
  17. data/_data/site_builder.yml +874 -0
  18. data/_data/theme-manifest.yml +160 -124
  19. data/_data/ui-text.yml +26 -0
  20. data/_includes/README.md +26 -2
  21. data/_includes/analytics/posthog.html +2 -2
  22. data/_includes/components/admin-links.html +2 -2
  23. data/_includes/components/admin-tabs.html +2 -2
  24. data/_includes/components/ai-chat.html +14 -11
  25. data/_includes/components/analytics-dashboard.html +8 -8
  26. data/_includes/components/author-bio.html +1 -1
  27. data/_includes/components/author-card.html +10 -2
  28. data/_includes/components/author-eeat.html +4 -4
  29. data/_includes/components/background-customizer.html +10 -10
  30. data/_includes/components/background-image.html +114 -0
  31. data/_includes/components/background-settings.html +28 -15
  32. data/_includes/components/collection-manager.html +5 -5
  33. data/_includes/components/component-showcase.html +13 -13
  34. data/_includes/components/config-editor.html +12 -12
  35. data/_includes/components/config-viewer.html +8 -8
  36. data/_includes/components/cookie-consent.html +15 -15
  37. data/_includes/components/cta-button.html +7 -2
  38. data/_includes/components/dev-shortcuts.html +7 -7
  39. data/_includes/components/env-dashboard.html +8 -8
  40. data/_includes/components/env-switcher.html +9 -9
  41. data/_includes/components/feature-card.html +2 -2
  42. data/_includes/components/halfmoon.html +2 -2
  43. data/_includes/components/info-section.html +42 -37
  44. data/_includes/components/js-cdn.html +15 -15
  45. data/_includes/components/language-toggle.html +168 -21
  46. data/_includes/components/mermaid.html +72 -435
  47. data/_includes/components/nanobar.html +5 -5
  48. data/_includes/components/nav-editor.html +2 -2
  49. data/_includes/components/nav-export.html +2 -2
  50. data/_includes/components/nav-overview.html +2 -2
  51. data/_includes/components/page-feedback.html +45 -30
  52. data/_includes/components/page-views-init.html +55 -0
  53. data/_includes/components/page-views.html +33 -0
  54. data/_includes/components/post-card.html +22 -22
  55. data/_includes/components/post-type-badge.html +2 -2
  56. data/_includes/components/powered-by.html +2 -2
  57. data/_includes/components/preview-image.html +6 -0
  58. data/_includes/components/quick-index.html +2 -2
  59. data/_includes/components/recipe-card.html +67 -0
  60. data/_includes/components/recipe-duration.html +50 -0
  61. data/_includes/components/recipe-grams.html +58 -0
  62. data/_includes/components/recipe-index.html +96 -0
  63. data/_includes/components/recipe-ingredients.html +90 -0
  64. data/_includes/components/recipe-meta.html +96 -0
  65. data/_includes/components/recipe-nutrition.html +57 -0
  66. data/_includes/components/recipe-qty.html +73 -0
  67. data/_includes/components/recipe-ratio.html +151 -0
  68. data/_includes/components/recipe-scaler.html +73 -0
  69. data/_includes/components/recipe-steps.html +86 -0
  70. data/_includes/components/recipe-temp.html +45 -0
  71. data/_includes/components/search-modal.html +29 -4
  72. data/_includes/components/searchbar.html +2 -2
  73. data/_includes/components/shortcuts-modal.html +3 -0
  74. data/_includes/components/svg-background.html +2 -2
  75. data/_includes/components/theme-customizer.html +2 -2
  76. data/_includes/components/theme-info.html +14 -7
  77. data/_includes/components/theme-preview-gallery.html +22 -22
  78. data/_includes/content/giscus.html +2 -2
  79. data/_includes/content/intro.html +8 -8
  80. data/_includes/content/jsonld-faq.html +2 -2
  81. data/_includes/content/jsonld-software.html +24 -5
  82. data/_includes/content/seo.html +4 -4
  83. data/_includes/content/sitemap.html +27 -27
  84. data/_includes/content/toc.html +183 -183
  85. data/_includes/core/branding.html +6 -6
  86. data/_includes/core/console-capture.html +32 -74
  87. data/_includes/core/favicon.html +49 -7
  88. data/_includes/core/footer-fabs.html +17 -3
  89. data/_includes/core/footer.html +49 -34
  90. data/_includes/core/head.html +110 -86
  91. data/_includes/core/header.html +76 -54
  92. data/_includes/docs/bootstrap-docs.html +8 -8
  93. data/_includes/landing/landing-install-cards.html +2 -2
  94. data/_includes/landing/landing-quick-links.html +1 -1
  95. data/_includes/navigation/admin-nav.html +2 -2
  96. data/_includes/navigation/nav-tree.html +8 -8
  97. data/_includes/navigation/navbar.html +12 -12
  98. data/_includes/navigation/section-sidebar.html +109 -27
  99. data/_includes/navigation/sidebar-config.html +36 -2
  100. data/_includes/navigation/sidebar-left.html +17 -16
  101. data/_includes/navigation/sidebar-right.html +8 -7
  102. data/_includes/obsidian/full-graph.html +2 -2
  103. data/_includes/setup/claude-session.html +72 -0
  104. data/_includes/setup/prereq-checklist.html +90 -0
  105. data/_includes/setup/wizard.html +924 -222
  106. data/_includes/stats/stats-categories.html +8 -8
  107. data/_includes/stats/stats-header.html +14 -14
  108. data/_includes/stats/stats-metrics.html +14 -14
  109. data/_includes/stats/stats-no-data.html +12 -12
  110. data/_includes/stats/stats-overview.html +6 -6
  111. data/_includes/stats/stats-tags.html +8 -8
  112. data/_layouts/404.html +38 -24
  113. data/_layouts/README.md +2 -0
  114. data/_layouts/admin.html +24 -24
  115. data/_layouts/article.html +43 -33
  116. data/_layouts/author.html +20 -20
  117. data/_layouts/authors.html +2 -2
  118. data/_layouts/book-abc.html +12 -12
  119. data/_layouts/book-story.html +15 -15
  120. data/_layouts/book.html +12 -12
  121. data/_layouts/collection.html +33 -33
  122. data/_layouts/cookbook.html +88 -0
  123. data/_layouts/default.html +31 -28
  124. data/_layouts/home.html +23 -23
  125. data/_layouts/index.html +10 -10
  126. data/_layouts/landing.html +17 -17
  127. data/_layouts/news.html +44 -44
  128. data/_layouts/note.html +38 -38
  129. data/_layouts/notebook.html +34 -34
  130. data/_layouts/recipe.html +274 -0
  131. data/_layouts/root.html +92 -55
  132. data/_layouts/section.html +62 -33
  133. data/_layouts/setup.html +3 -3
  134. data/_layouts/sitemap-collection.html +49 -49
  135. data/_layouts/stats.html +40 -40
  136. data/_layouts/tag.html +12 -12
  137. data/_layouts/welcome.html +21 -21
  138. data/_sass/components/_callout.scss +1 -1
  139. data/_sass/components/_footer.scss +37 -1
  140. data/_sass/components/_mermaid.scss +375 -0
  141. data/_sass/components/_page-views.scss +36 -0
  142. data/_sass/components/_recipe.scss +506 -0
  143. data/_sass/components/_setup-wizard.scss +764 -0
  144. data/_sass/components/_ui-enhancements.scss +6 -6
  145. data/_sass/core/_navbar.scss +261 -46
  146. data/_sass/layouts/_landing.scss +2 -2
  147. data/_sass/layouts/_navbar-extras.scss +14 -4
  148. data/_sass/tokens/_color.scss +6 -0
  149. data/_sass/tokens/_index.scss +2 -0
  150. data/_sass/tokens/_radius.scss +21 -0
  151. data/_sass/tokens/_typography.scss +4 -0
  152. data/_sass/utilities/_focus.scss +14 -0
  153. data/assets/css/main.scss +4 -0
  154. data/assets/js/ai-chat.js +47 -5
  155. data/assets/js/fleet-feedback-capture.js +124 -0
  156. data/assets/js/fleet-feedback.js +853 -0
  157. data/assets/js/mermaid-diagrams.js +1267 -0
  158. data/assets/js/modules/navigation/config.js +9 -6
  159. data/assets/js/modules/navigation/navbar.js +55 -0
  160. data/assets/js/modules/navigation/scroll-spy.js +315 -80
  161. data/assets/js/modules/theme/appearance.js +8 -2
  162. data/assets/js/obsidian-wiki-links.js +8 -3
  163. data/assets/js/page-feedback.js +125 -192
  164. data/assets/js/page-views.js +372 -0
  165. data/assets/js/recipe-scaler.js +501 -0
  166. data/assets/js/search-modal.js +36 -0
  167. data/assets/js/setup-wizard.js +2279 -226
  168. data/assets/js/site-builder.js +1834 -0
  169. data/assets/js/ui-enhancements.js +11 -3
  170. data/scripts/README.md +44 -0
  171. data/scripts/ai/README.md +38 -0
  172. data/scripts/ai/api_call.rb +124 -0
  173. data/scripts/ai/usage.rb +314 -0
  174. data/scripts/ai/usage_report.rb +225 -0
  175. data/scripts/bin/audit-consumer +39 -7
  176. data/scripts/bin/giscus-discussions +213 -14
  177. data/scripts/bin/manifest +35 -12
  178. data/scripts/ci/agent_review_result.py +164 -0
  179. data/scripts/ci/test_agent_review_result.py +172 -0
  180. data/scripts/ci/test_visual_evidence_autogen.py +341 -0
  181. data/scripts/ci/visual_evidence_autogen.py +1060 -0
  182. data/scripts/content-review.rb +20 -1
  183. data/scripts/design-system-check.rb +170 -0
  184. data/scripts/lib/audit.sh +42 -2
  185. data/scripts/lint-liquid-raw.rb +137 -0
  186. data/scripts/test/integration/mermaid +22 -8
  187. data/scripts/test/lib/run_tests.sh +3 -1
  188. data/scripts/test/lib/test_agent_review_result.sh +27 -0
  189. data/scripts/test/lib/test_visual_evidence_autogen.sh +24 -0
  190. data/scripts/translate.rb +94 -16
  191. metadata +48 -2
@@ -82,7 +82,7 @@ img {
82
82
  left: 50%;
83
83
  width: 0;
84
84
  height: 0;
85
- border-radius: 50%;
85
+ border-radius: var(--zer0-radius-circle);
86
86
  background: rgba(255, 255, 255, 0.2);
87
87
  transform: translate(-50%, -50%);
88
88
  transition: width 0.6s, height 0.6s;
@@ -405,7 +405,7 @@ a:not(.btn) {
405
405
  .btn {
406
406
  .ripple {
407
407
  position: absolute;
408
- border-radius: 50%;
408
+ border-radius: var(--zer0-radius-circle);
409
409
  background: rgba(255, 255, 255, 0.6);
410
410
  transform: scale(0);
411
411
  animation: ripple-animation 0.6s ease-out;
@@ -424,7 +424,7 @@ a:not(.btn) {
424
424
  @media (max-width: 991.98px) {
425
425
  .navbar-collapse {
426
426
  background-color: var(--bs-body-bg);
427
- border-radius: 0.5rem;
427
+ border-radius: var(--zer0-radius-lg);
428
428
  margin-top: 1rem;
429
429
  padding: 1rem;
430
430
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
@@ -432,7 +432,7 @@ a:not(.btn) {
432
432
 
433
433
  .navbar-nav .nav-link {
434
434
  padding: 0.75rem 1rem;
435
- border-radius: 0.375rem;
435
+ border-radius: var(--zer0-radius);
436
436
  transition: all 0.2s ease;
437
437
 
438
438
  &:hover {
@@ -506,7 +506,7 @@ a:not(.btn) {
506
506
  *:focus-visible {
507
507
  outline: 2px solid var(--bs-primary);
508
508
  outline-offset: 2px;
509
- border-radius: 0.25rem;
509
+ border-radius: var(--zer0-radius-sm);
510
510
  }
511
511
 
512
512
  // Enhanced active link states
@@ -530,7 +530,7 @@ a:not(.btn) {
530
530
  // Better table responsiveness
531
531
  @media (max-width: 768px) {
532
532
  .table-responsive {
533
- border-radius: 0.5rem;
533
+ border-radius: var(--zer0-radius-lg);
534
534
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
535
535
  }
536
536
 
@@ -7,8 +7,9 @@
7
7
  // - Desktop >= 992px (inline nav; label density via @container bd-nav)
8
8
  // - Mobile < 992px (offcanvas)
9
9
  // Nav label tiers (center track / bd-nav container width):
10
- // - >= 38rem (~608px): full labels (with ellipsis safety when crowded)
11
- // - < 38rem: icon-only (tooltips on lg–xl viewports)
10
+ // - >= 51rem (~816px): icon + full label
11
+ // - 41-50.99rem: label only (icons dropped so the labels still fit)
12
+ // - < 41rem (~656px): icon-only (tooltips on lg–xl viewports)
12
13
  // ==============================================================================
13
14
 
14
15
  // -----------------------------------------------------------------------------
@@ -136,21 +137,16 @@
136
137
  overflow: visible;
137
138
  }
138
139
 
140
+ // No transform on :hover. A translate moves the element out from under a
141
+ // pointer parked on the edge it vacates, hover exits, the element returns —
142
+ // an infinite flicker. Nav items are thin enough for a 1px lift to do it.
139
143
  #bdNavbar .nav-link:hover {
140
144
  background-color: var(--bs-tertiary-bg);
141
- transform: translateY(-1px);
142
145
  }
143
146
 
144
147
  .nav-hover-dropdown .dropdown-toggle-split {
145
148
  padding: var(--zer0-space-1) var(--zer0-space-2);
146
149
 
147
- &::after {
148
- transition: transform 0.2s ease-in-out;
149
- }
150
-
151
- &:hover::after {
152
- transform: translateY(2px);
153
- }
154
150
  }
155
151
  }
156
152
 
@@ -180,12 +176,18 @@
180
176
  &:hover {
181
177
  color: var(--bs-primary);
182
178
  background-color: var(--bs-tertiary-bg);
183
- transform: translateY(-1px);
184
179
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
180
+ // These are `.btn`s, and _ui-enhancements.scss lifts every button by 2px
181
+ // on hover. Dropping the navbar's own translateY(-1px) is not enough —
182
+ // the inherited lift flickers the same way. `transform: none` is the
183
+ // repo's existing corrective pattern (see _post-navigation.scss).
184
+ transform: none;
185
185
  }
186
186
 
187
+ // A pressed cue is safe: :active only holds while the button is held down,
188
+ // so the pointer cannot leave and re-enter in a loop.
187
189
  &:active {
188
- transform: translateY(0);
190
+ transform: translateY(1px);
189
191
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
190
192
  }
191
193
 
@@ -196,11 +198,6 @@
196
198
 
197
199
  i {
198
200
  font-size: 1.15rem;
199
- transition: transform 0.15s ease-in-out;
200
- }
201
-
202
- &:hover i {
203
- transform: scale(1.1);
204
201
  }
205
202
  }
206
203
  }
@@ -399,16 +396,22 @@
399
396
  transform: rotate(180deg);
400
397
  }
401
398
 
402
- // Show labels whenever the center track has room (>= ~38rem / 608px).
403
- // Items keep min-width:0 + ellipsis so a crowded row degrades gracefully
404
- // before falling all the way back to the icon-only tier below.
405
- @container bd-nav (min-width: 38rem) {
399
+ // Label density degrades in three tiers, measured on the center track
400
+ // (the `bd-nav` container), so items fit instead of ellipsizing:
401
+ // >= 51rem (816px) icon + label — the roomy default
402
+ // 41-50.99rem label only — icons dropped to buy ~20px/item
403
+ // < 41rem (656px) icon only — labels no longer fit at all
404
+ // Each boundary is the MEASURED width the tier below it needs for the
405
+ // theme's seven demo items (815px with icons, 647px without), so a tier only
406
+ // engages once its own content fits. Items keep min-width:0 + ellipsis as the
407
+ // last-resort safety net for consumers with more or longer entries.
408
+ @container bd-nav (min-width: 41rem) {
406
409
  #bdNavbar .navbar-nav {
407
410
  gap: 0.125rem;
408
411
  }
409
412
 
410
413
  #bdNavbar .nav-link {
411
- padding: 0.375rem 0.5rem;
414
+ padding: 0.375rem;
412
415
  }
413
416
 
414
417
  #bdNavbar .nav-link .nav-link-text {
@@ -439,16 +442,11 @@
439
442
  #bdNavbar .nav-link i {
440
443
  margin-right: 0;
441
444
  font-size: 1rem;
442
- transition: transform 0.15s ease-in-out;
443
445
  }
444
446
 
445
447
  #bdNavbar .nav-link:hover {
446
448
  background-color: var(--bs-tertiary-bg);
447
449
  border-radius: 0.375rem;
448
-
449
- i {
450
- transform: scale(1.1);
451
- }
452
450
  }
453
451
 
454
452
  .nav-hover-dropdown > .nav-link {
@@ -462,14 +460,36 @@
462
460
  min-width: 1.25rem;
463
461
  min-height: 0;
464
462
  width: 1.25rem;
465
- padding-left: 0.125rem;
466
- padding-right: 0.125rem;
463
+ padding-left: 0;
464
+ padding-right: 0;
467
465
  margin-left: 0 !important;
468
466
  }
469
467
  }
470
468
 
471
- // Icon-only when the center track is too narrow even for ellipsized labels
472
- @container bd-nav (max-width: 37.99rem) {
469
+ // Middle tier — the labels fit but the icons no longer do. Dropping the
470
+ // decorative icon (the label is the accessible name) and tightening the
471
+ // chevron buys back roughly 20px per item, which is the difference between
472
+ // "Notebooks" and "N…" at 992-1200px viewports.
473
+ @container bd-nav (min-width: 41rem) and (max-width: 50.99rem) {
474
+ #bdNavbar .nav-link i {
475
+ display: none;
476
+ }
477
+
478
+ #bdNavbar .nav-item > .nav-link:not(.dropdown-toggle-split),
479
+ #bdNavbar .nav-hover-dropdown > .nav-link:first-child {
480
+ gap: 0;
481
+ }
482
+
483
+ // Scoped with #bdNavbar to outrank the shared base rule at the top of this
484
+ // file, which sets the chevron to 1.5rem.
485
+ #bdNavbar .nav-hover-dropdown > .dropdown-toggle-split {
486
+ min-width: 1rem;
487
+ width: 1rem;
488
+ }
489
+ }
490
+
491
+ // Icon-only when the center track is too narrow even for bare labels
492
+ @container bd-nav (max-width: 40.99rem) {
473
493
  @include navbar-nav-icon-only;
474
494
  }
475
495
  }
@@ -502,6 +522,27 @@
502
522
  z-index: 1046; // $zindex-offcanvas (1045) + 1
503
523
  }
504
524
 
525
+ // ...but that lift must never bury Settings. #info-section is a body-level
526
+ // offcanvas at the SAME edge and the same z-index (1045), so while the nav
527
+ // menu is still on screen — including the ~300ms `.hiding` tail after a tap
528
+ // on its own "Settings" item — the lifted header painted the whole Settings
529
+ // panel out of sight. Drop the header back below the offcanvas layer for as
530
+ // long as Settings is on screen; navbar.js also closes the nav menu first so
531
+ // the two panels do not overlap at all in browsers that support it.
532
+ body:has(#info-section.offcanvas.showing) header.fixed-top,
533
+ body:has(#info-section.offcanvas.show) header.fixed-top,
534
+ body:has(#info-section.offcanvas.hiding) header.fixed-top {
535
+ z-index: 1030; // $zindex-fixed — back under the offcanvas backdrop
536
+ }
537
+
538
+ // Belt and braces for browsers without :has() — Settings outranks the header
539
+ // stacking context on its own.
540
+ #info-section.offcanvas.showing,
541
+ #info-section.offcanvas.show,
542
+ #info-section.offcanvas.hiding {
543
+ z-index: 1047; // above the lifted header (1046)
544
+ }
545
+
505
546
  // Wrapper is inert on mobile so offcanvas layout matches pre-wrapper structure
506
547
  #bdNavbar .bd-navbar-nav-viewport {
507
548
  display: contents;
@@ -631,7 +672,6 @@
631
672
 
632
673
  &:hover {
633
674
  background-color: var(--bs-tertiary-bg);
634
- transform: rotate(90deg);
635
675
  }
636
676
 
637
677
  &:focus-visible {
@@ -718,20 +758,10 @@
718
758
  i {
719
759
  font-size: 1rem;
720
760
  width: 1.5rem;
721
- transition: transform 0.15s ease-in-out;
722
761
  }
723
762
 
724
763
  &:hover {
725
764
  background-color: var(--bs-tertiary-bg);
726
-
727
- // translateX widens overflow; desktop menus sit inside a clipped nav track
728
- @media (max-width: 991.98px) {
729
- transform: translateX(4px);
730
- }
731
-
732
- i {
733
- transform: scale(1.1);
734
- }
735
765
  }
736
766
 
737
767
  &:focus-visible {
@@ -831,6 +861,156 @@
831
861
  }
832
862
  }
833
863
 
864
+ // -----------------------------------------------------------------------------
865
+ // Language section inside the Settings offcanvas
866
+ // (components/language-toggle.html variant="panel")
867
+ // -----------------------------------------------------------------------------
868
+
869
+ .nav-lang-panel .nav-lang-options {
870
+ --bs-list-group-border-radius: 0.375rem;
871
+
872
+ .list-group-item {
873
+ display: flex;
874
+ align-items: center;
875
+ gap: 0.625rem;
876
+ padding: 0.5rem 0.75rem;
877
+ min-height: 44px; // WCAG touch target
878
+ font-size: 0.9375rem;
879
+ }
880
+
881
+ .nav-lang-code {
882
+ flex-shrink: 0;
883
+ min-width: 2.25rem;
884
+ padding: 0.05rem 0.35rem;
885
+ font-family: var(--zer0-font-mono);
886
+ font-size: 0.7rem;
887
+ line-height: 1.4;
888
+ text-align: center;
889
+ color: var(--zer0-color-ink-muted);
890
+ background: var(--zer0-color-bg-muted);
891
+ border-radius: var(--zer0-radius-sm);
892
+ }
893
+
894
+ .nav-lang-name {
895
+ min-width: 0;
896
+ overflow: hidden;
897
+ text-overflow: ellipsis;
898
+ white-space: nowrap;
899
+ }
900
+ }
901
+
902
+ // -----------------------------------------------------------------------------
903
+ // Language menu — shared by BOTH variants (T-038 / #406)
904
+ // -----------------------------------------------------------------------------
905
+ // The current language reads as "you are here", not as a selected nav item, so
906
+ // it gets a tint + check icon rather than Bootstrap's `.active` primary fill.
907
+ // Rows are links even when a translation does not exist yet (they fall back to
908
+ // the source page), and the reason lives in one footnote instead of on every
909
+ // row — per-row "(Not yet translated)" was what made the menu wide.
910
+
911
+ .nav-lang-item {
912
+ display: flex;
913
+ align-items: center;
914
+ gap: 0.625rem;
915
+
916
+ &.is-current {
917
+ font-weight: 600;
918
+ color: var(--zer0-color-ink, inherit);
919
+ background: var(--zer0-color-bg-muted);
920
+ }
921
+
922
+ // The marker is the footnote's anchor; the note itself carries the wording.
923
+ &.is-untranslated .nav-lang-name {
924
+ color: var(--zer0-color-ink-muted);
925
+ }
926
+ }
927
+
928
+ .nav-lang-check {
929
+ flex-shrink: 0;
930
+ margin-left: auto;
931
+ }
932
+
933
+ .nav-lang-mark {
934
+ flex-shrink: 0;
935
+ margin-left: auto;
936
+ color: var(--zer0-color-ink-muted);
937
+ }
938
+
939
+ // "auto" — this language was machine-generated (scripts/translate.rb).
940
+ .nav-lang-auto {
941
+ flex-shrink: 0;
942
+ padding: 0.05rem 0.3rem;
943
+ font-family: var(--zer0-font-mono);
944
+ font-size: 0.625rem;
945
+ line-height: 1.4;
946
+ text-transform: lowercase;
947
+ color: var(--zer0-color-ink-muted);
948
+ background: var(--zer0-color-bg-muted);
949
+ border-radius: var(--zer0-radius-sm);
950
+ }
951
+
952
+ // The one footnote that replaced the per-row notices. It is the only element
953
+ // in the menu allowed to wrap — everything else ellipsises inside the 220px.
954
+ .nav-lang-note {
955
+ margin: 0;
956
+ padding: 0.25rem 0.75rem 0.125rem;
957
+ font-size: 0.75rem;
958
+ line-height: 1.35;
959
+ color: var(--zer0-color-ink-muted);
960
+ white-space: normal;
961
+ }
962
+
963
+ .nav-lang-divider {
964
+ margin: 0.5rem 0 0.25rem;
965
+ opacity: 0.15;
966
+ }
967
+
968
+ // -----------------------------------------------------------------------------
969
+ // Navbar dropdown variant (components/language-toggle.html, default variant)
970
+ // -----------------------------------------------------------------------------
971
+
972
+ .nav-lang-toggle {
973
+ .nav-lang-button {
974
+ display: inline-flex;
975
+ align-items: center;
976
+ justify-content: center;
977
+ width: 2.375rem; // 38px square — the icon carries the whole control
978
+ height: 2.375rem;
979
+ padding: 0;
980
+ line-height: 1;
981
+
982
+ // Belt and braces: if `dropdown-toggle` is ever re-added, no caret returns.
983
+ &::after {
984
+ display: none;
985
+ }
986
+ }
987
+
988
+ .nav-lang-menu {
989
+ min-width: 0;
990
+ max-width: 220px;
991
+
992
+ .nav-lang-item {
993
+ // Bootstrap's dropdown-item is nowrap; the name ellipsises instead so a
994
+ // long native name cannot push the menu past its cap.
995
+ overflow: hidden;
996
+
997
+ &.is-current {
998
+ // Beat `.dropdown-item.active`'s specificity is unnecessary (we no
999
+ // longer emit `.active`), but a hovered current row should not flip to
1000
+ // the link-hover colour and lose the "you are here" reading.
1001
+ color: var(--zer0-color-ink, inherit);
1002
+ }
1003
+ }
1004
+
1005
+ .nav-lang-name {
1006
+ min-width: 0;
1007
+ overflow: hidden;
1008
+ text-overflow: ellipsis;
1009
+ white-space: nowrap;
1010
+ }
1011
+ }
1012
+ }
1013
+
834
1014
  // -----------------------------------------------------------------------------
835
1015
  // Navigation Tooltips
836
1016
  // Enhanced tooltips for compact desktop view
@@ -930,26 +1110,57 @@
930
1110
  gap: 0.25rem;
931
1111
  }
932
1112
 
1113
+ // Shortcut affordance chip on the search button — the design-system navbar
1114
+ // pattern (ui_kits/website/Navbar.jsx). Overrides Bootstrap's inverted <kbd>
1115
+ // so the chip reads as a quiet hint, not a highlighted key.
1116
+ #navbar .nav-search-kbd {
1117
+ align-items: center;
1118
+ margin-left: 0.1rem;
1119
+ padding: 0.05rem 0.35rem;
1120
+ font-family: var(--zer0-font-mono);
1121
+ font-size: 0.7rem;
1122
+ line-height: 1.4;
1123
+ color: var(--zer0-color-ink-muted);
1124
+ background: var(--zer0-color-bg-muted);
1125
+ border-radius: var(--zer0-radius-sm);
1126
+ }
1127
+
1128
+ // The bar spans the full viewport (header markup uses .container-fluid) with a
1129
+ // fluid gutter instead of a centred .container-xl track, so the menubar gets the
1130
+ // whole screen width. Consumers that want the old capped bar set
1131
+ // --zer0-navbar-max-width (e.g. 1320px) in their own stylesheet.
1132
+ #navbar .navbar-main {
1133
+ max-width: var(--zer0-navbar-max-width, 100%);
1134
+ margin-inline: auto;
1135
+ padding-inline: clamp(0.75rem, 1.5vw, 1.5rem);
1136
+ }
1137
+
933
1138
  // Desktop (lg+): 3-column grid — [brand/title | main nav | utilities] so nav cannot paint over Search/Settings
934
1139
  @media (min-width: 992px) {
935
1140
  #navbar .navbar-main {
936
1141
  display: grid !important;
937
1142
  grid-template-columns: minmax(0, auto) minmax(0, 1fr) auto;
938
1143
  align-items: center;
939
- column-gap: 0.5rem;
1144
+ column-gap: 0.75rem;
940
1145
  row-gap: 0.25rem;
941
1146
  flex-wrap: unset !important;
942
1147
  container-type: inline-size;
943
1148
  container-name: navbar-main;
944
1149
  }
945
1150
 
1151
+ // The brand cluster is sized by its content (grid track 1 is `auto`), so an
1152
+ // unbounded title would starve the menubar of the width its labels need.
1153
+ // Cap it at a share of the BAR — `cqi` resolves against .navbar-main (the
1154
+ // named container), where a plain percentage would resolve against the
1155
+ // content-sized track and collapse the title to nothing. The title already
1156
+ // ellipsizes past the cap.
946
1157
  #navbar .navbar-main-start {
947
1158
  grid-column: 1;
948
1159
  display: flex;
949
1160
  align-items: center;
950
1161
  gap: 0.375rem;
951
1162
  min-width: 0;
952
- max-width: none;
1163
+ max-width: 30cqi;
953
1164
  flex-shrink: 1;
954
1165
  }
955
1166
 
@@ -1025,8 +1236,12 @@
1025
1236
  max-width: none;
1026
1237
  }
1027
1238
 
1028
- // Progressive brand degradation (container width, not viewport)
1029
- @container navbar-main (min-width: 80rem) {
1239
+ // Progressive brand degradation (container width, not viewport).
1240
+ // The home-link icons add ~108px to the brand cluster, so they only appear
1241
+ // once the bar is wide enough to carry them AND the full menubar
1242
+ // (815px of items + 328px brand + 146px utilities + gaps ≈ 82rem); 86rem
1243
+ // leaves headroom for a longer site title.
1244
+ @container navbar-main (min-width: 86rem) {
1030
1245
  #navbar .navbar-home-links {
1031
1246
  display: inline-flex !important;
1032
1247
  }
@@ -44,7 +44,7 @@
44
44
  .landing-feature-card {
45
45
  height: 100%;
46
46
  border: 1px solid var(--zer0-color-border);
47
- border-radius: 0.75rem;
47
+ border-radius: var(--zer0-radius-xl);
48
48
  background: var(--zer0-color-bg);
49
49
  transition:
50
50
  transform var(--zer0-motion-duration-base) var(--zer0-motion-ease-standard),
@@ -61,7 +61,7 @@
61
61
  display: inline-flex;
62
62
  align-items: center;
63
63
  justify-content: center;
64
- border-radius: 50%;
64
+ border-radius: var(--zer0-radius-circle);
65
65
  background-color: rgba(var(--zer0-color-primary-rgb), 0.12);
66
66
  color: var(--zer0-color-primary);
67
67
  margin-bottom: var(--zer0-space-3);
@@ -53,13 +53,18 @@
53
53
  display: block;
54
54
  }
55
55
 
56
+ // No transform on :hover — a lift moves the FAB out from under a pointer
57
+ // parked on its bottom edge, hover exits, it drops back: infinite flicker.
58
+ // These are `.btn`s, so the 2px lift _ui-enhancements.scss puts on every
59
+ // button has to be cancelled explicitly, not merely not-added here.
56
60
  &:hover,
57
61
  &:focus-visible {
58
- transform: translateY(-1px);
62
+ transform: none;
59
63
  }
60
64
 
65
+ // :active is safe, because the button is held down for its whole duration.
61
66
  &:active {
62
- transform: translateY(0);
67
+ transform: translateY(1px);
63
68
  }
64
69
  }
65
70
  }
@@ -112,13 +117,18 @@
112
117
  display: block;
113
118
  }
114
119
 
120
+ // No transform on :hover — a lift moves the FAB out from under a pointer
121
+ // parked on its bottom edge, hover exits, it drops back: infinite flicker.
122
+ // These are `.btn`s, so the 2px lift _ui-enhancements.scss puts on every
123
+ // button has to be cancelled explicitly, not merely not-added here.
115
124
  &:hover,
116
125
  &:focus-visible {
117
- transform: translateY(-1px);
126
+ transform: none;
118
127
  }
119
128
 
129
+ // :active is safe, because the button is held down for its whole duration.
120
130
  &:active {
121
- transform: translateY(0);
131
+ transform: translateY(1px);
122
132
  }
123
133
  }
124
134
  }
@@ -36,6 +36,12 @@
36
36
  --zer0-color-border: var(--bs-border-color, #dee2e6);
37
37
  --zer0-color-border-translucent: color-mix(in srgb, var(--zer0-color-border) 42%, transparent);
38
38
 
39
+ // Logo palette (documented in _includes/core/branding.html) --------------
40
+ --zer0-logo-red: #a11111;
41
+ --zer0-logo-yellow: #ffe900;
42
+ --zer0-logo-teal: #376986;
43
+ --zer0-logo-blue: #007bff;
44
+
39
45
  // Code & callouts (legacy --bd-* aliases) --------------------------------
40
46
  --zer0-color-code-bg: var(--bd-pre-bg, var(--bs-tertiary-bg));
41
47
  --zer0-color-code-ink: var(--bd-callout-code-color, #ab296a);
@@ -1,3 +1,4 @@
1
+ // Feature: ZER0-081
1
2
  // ============================================================================
2
3
  // Tokens barrel — single import surface for the design-token layer
3
4
  // ----------------------------------------------------------------------------
@@ -9,6 +10,7 @@
9
10
 
10
11
  @import "tokens/color";
11
12
  @import "tokens/spacing";
13
+ @import "tokens/radius";
12
14
  @import "tokens/typography";
13
15
  @import "tokens/shadow";
14
16
  @import "tokens/motion";
@@ -0,0 +1,21 @@
1
+ // Feature: ZER0-081
2
+ // ============================================================================
3
+ // Radius tokens — semantic --zer0-radius-* custom properties
4
+ // ----------------------------------------------------------------------------
5
+ // Corner radii for every rounded surface, mirroring Bootstrap's
6
+ // --bs-border-radius family so the theme and vanilla Bootstrap components
7
+ // round identically. `xl` is the softer landing-feature-card radius; `pill`
8
+ // and `circle` cover badges, chips, avatars, and FABs.
9
+ //
10
+ // Mirrored to the Claude Design project as tokens/radius.css — keep both in
11
+ // lockstep (scripts/design-system-check.rb enforces parity).
12
+ // ============================================================================
13
+
14
+ :root {
15
+ --zer0-radius-sm: 0.25rem;
16
+ --zer0-radius: 0.375rem;
17
+ --zer0-radius-lg: 0.5rem;
18
+ --zer0-radius-xl: 0.75rem; // landing feature cards
19
+ --zer0-radius-pill: 50rem;
20
+ --zer0-radius-circle: 50%;
21
+ }
@@ -28,6 +28,10 @@
28
28
  --zer0-text-h5: 1.125rem;
29
29
  --zer0-text-h6: 1rem;
30
30
 
31
+ // Display sizes (Bootstrap .display-* — hero titles) ---------------------
32
+ --zer0-text-display-4: clamp(2.5rem, 6vw, 3.5rem);
33
+ --zer0-text-display-5: clamp(2rem, 5vw, 3rem);
34
+
31
35
  // Line heights -----------------------------------------------------------
32
36
  --zer0-leading-tight: 1.2;
33
37
  --zer0-leading-normal: 1.55;
@@ -19,6 +19,20 @@ summary:focus-visible {
19
19
  border-radius: 0.125rem;
20
20
  }
21
21
 
22
+ // Skip-link target — <main id="main-content" tabindex="-1"> in _layouts/root.html.
23
+ // The -1 lets the skip link move real keyboard focus into the content (see the
24
+ // comment there), but it also makes the container paintable by the UA's default
25
+ // focus outline. Suppress it on the container ONLY: this rule cannot match a
26
+ // descendant, so links, buttons and headings inside the content keep their rings
27
+ // — including the :focus-visible ring defined at the top of this file.
28
+ //
29
+ // Safe here specifically because the element is tabindex="-1": it is never
30
+ // reachable by Tab, so no keyboard user can land on it and be left without an
31
+ // indicator. Do not generalise this selector to focusable elements.
32
+ #main-content:focus {
33
+ outline: none;
34
+ }
35
+
22
36
  // Skip-to-content link — visually hidden until focused
23
37
  .zer0-skip-link {
24
38
  position: absolute;
data/assets/css/main.scss CHANGED
@@ -40,7 +40,11 @@
40
40
  @import "components/content-tables";
41
41
  @import "components/search-modal";
42
42
  @import "components/page-feedback";
43
+ @import "components/page-views";
43
44
  @import "components/book";
45
+ @import "components/recipe";
46
+ @import "components/setup-wizard";
47
+ @import "components/mermaid";
44
48
 
45
49
  // 6. Layout partials
46
50
  @import "layouts/landing";