jekyll-theme-zer0 1.19.0 → 1.20.2

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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +415 -0
  3. data/README.md +31 -23
  4. data/_data/authors.yml +154 -5
  5. data/_data/backlog.yml +5 -5
  6. data/_data/content_statistics.yml +273 -297
  7. data/_data/features.yml +4 -25
  8. data/_data/navigation/README.md +24 -0
  9. data/_data/navigation/about.yml +2 -0
  10. data/_data/navigation/main.yml +2 -7
  11. data/_data/roadmap.yml +86 -12
  12. data/_includes/components/author-avatar-url.html +28 -0
  13. data/_includes/components/author-bio.html +86 -0
  14. data/_includes/components/author-card.html +184 -121
  15. data/_includes/components/author-eeat.html +10 -4
  16. data/_includes/components/info-section.html +1 -1
  17. data/_includes/components/mermaid.html +0 -3
  18. data/_includes/components/post-card.html +19 -9
  19. data/_includes/content/giscus.html +3 -2
  20. data/_includes/core/footer-fabs.html +28 -0
  21. data/_includes/core/footer.html +7 -17
  22. data/_includes/core/head.html +2 -2
  23. data/_includes/navigation/breadcrumbs.html +20 -2
  24. data/_includes/navigation/local-graph.html +18 -2
  25. data/_includes/obsidian/full-graph.html +4 -6
  26. data/_layouts/article.html +44 -74
  27. data/_layouts/author.html +274 -0
  28. data/_layouts/authors.html +55 -0
  29. data/_layouts/news.html +3 -3
  30. data/_layouts/note.html +21 -6
  31. data/_layouts/notebook.html +21 -6
  32. data/_layouts/root.html +31 -17
  33. data/_layouts/section.html +3 -3
  34. data/_plugins/author_pages_generator.rb +121 -0
  35. data/_sass/components/_author.scss +219 -0
  36. data/_sass/components/_content-tables.scss +16 -1
  37. data/_sass/components/_notes-index.scss +102 -0
  38. data/_sass/components/_search-modal.scss +40 -0
  39. data/_sass/components/_ui-enhancements.scss +570 -0
  40. data/_sass/core/_docs-code-examples.scss +463 -0
  41. data/_sass/core/_docs-layout.scss +1 -453
  42. data/_sass/core/_navbar.scss +253 -0
  43. data/_sass/core/_sidebar-extras.scss +79 -0
  44. data/_sass/core/_toc.scss +87 -0
  45. data/_sass/core/_variables.scss +7 -142
  46. data/_sass/custom.scss +24 -1122
  47. data/_sass/layouts/_global-chrome.scss +59 -0
  48. data/assets/css/main.scss +19 -2
  49. data/assets/js/author-profile.js +190 -0
  50. data/assets/js/modules/navigation/navbar.js +104 -0
  51. data/assets/js/obsidian-graph.js +2 -2
  52. data/assets/js/obsidian-local-graph.js +11 -5
  53. data/assets/vendor/cytoscape/cytoscape.min.js +32 -0
  54. data/scripts/README.md +39 -0
  55. data/scripts/bin/validate +11 -1
  56. data/scripts/dev/css-diff.sh +49 -0
  57. data/scripts/dev/shot.js +37 -0
  58. data/scripts/features/generate-preview-images +110 -6
  59. data/scripts/features/pixelate-preview-images +126 -0
  60. data/scripts/features/pixelate_images.py +662 -0
  61. data/scripts/github-setup.sh +0 -0
  62. data/scripts/lib/preview_generator.py +47 -3
  63. data/scripts/pixelate-preview-images.sh +12 -0
  64. data/scripts/test/integration/auto-version +10 -8
  65. data/scripts/test/lib/run_tests.sh +2 -0
  66. data/scripts/test/lib/test_content_review.sh +205 -0
  67. data/scripts/test/lib/test_pixelate_images.sh +108 -0
  68. metadata +25 -20
  69. data/_data/hub.yml +0 -68
  70. data/_data/hub_index.yml +0 -203
  71. data/_data/navigation/hub.yml +0 -110
  72. data/assets/vendor/font-awesome/css/all.min.css +0 -9
  73. data/assets/vendor/font-awesome/webfonts/fa-brands-400.ttf +0 -0
  74. data/assets/vendor/font-awesome/webfonts/fa-brands-400.woff2 +0 -0
  75. data/assets/vendor/font-awesome/webfonts/fa-regular-400.ttf +0 -0
  76. data/assets/vendor/font-awesome/webfonts/fa-regular-400.woff2 +0 -0
  77. data/assets/vendor/font-awesome/webfonts/fa-solid-900.ttf +0 -0
  78. data/assets/vendor/font-awesome/webfonts/fa-solid-900.woff2 +0 -0
  79. data/assets/vendor/font-awesome/webfonts/fa-v4compatibility.ttf +0 -0
  80. data/assets/vendor/font-awesome/webfonts/fa-v4compatibility.woff2 +0 -0
  81. data/assets/vendor/jquery/jquery-3.7.1.min.js +0 -2
  82. data/scripts/lib/hub.rb +0 -208
  83. data/scripts/provision-org-sites.rb +0 -252
  84. data/scripts/provision-org-sites.sh +0 -23
  85. data/scripts/sync-hub-metadata.rb +0 -184
  86. data/scripts/sync-hub-metadata.sh +0 -22
@@ -648,6 +648,7 @@ a.bd-intro-badge--tag:focus {
648
648
  .bd-content :is(p, li, blockquote, td, dd) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not([class*="text-decoration"]),
649
649
  .post-content :is(p, li, blockquote, td, dd) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not([class*="text-decoration"]),
650
650
  .landing-content-body :is(p, li, blockquote, td, dd) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not([class*="text-decoration"]),
651
+ .home :is(p, li, blockquote, td, dd) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not([class*="text-decoration"]),
651
652
  #admin-content :is(p, li, blockquote, td, dd, .alert) a:not(.btn):not(.badge):not(.nav-link):not(.dropdown-item):not(.page-link):not(.card-link):not(.alert-link):not([class*="text-decoration"]) {
652
653
  text-decoration: underline;
653
654
  }
@@ -758,456 +759,3 @@ a.bd-intro-badge--tag:focus {
758
759
  text-decoration: underline
759
760
  }
760
761
 
761
- .bd-code-snippet {
762
- margin: 0 -1.5rem 1rem;
763
- border: solid var(--bs-border-color);
764
- border-width: 1px 0
765
- }
766
-
767
- @media (min-width: 768px) {
768
- .bd-code-snippet {
769
- margin-right:0;
770
- margin-left: 0;
771
- border-width: 1px;
772
- border-radius: var(--bs-border-radius)
773
- }
774
- }
775
-
776
- .bd-example {
777
- --bd-example-padding: 1rem;
778
- position: relative;
779
- padding: var(--bd-example-padding);
780
- margin: 0 -1.5rem 1rem;
781
- border: solid var(--bs-border-color);
782
- border-width: 1px 0
783
- }
784
-
785
- .bd-example::after {
786
- display: block;
787
- clear: both;
788
- content: null
789
- }
790
-
791
- @media (min-width: 768px) {
792
- .bd-example {
793
- --bd-example-padding: 1.5rem;
794
- margin-right: 0;
795
- margin-left: 0;
796
- border-width: 1px;
797
- border-radius: var(--bs-border-radius)
798
- }
799
- }
800
-
801
- .bd-example+p {
802
- margin-top: 2rem
803
- }
804
-
805
- .bd-example>.form-control+.form-control {
806
- margin-top: .5rem
807
- }
808
-
809
- .bd-example>.nav+.nav,.bd-example>.alert+.alert,.bd-example>.navbar+.navbar,.bd-example>.progress+.progress {
810
- margin-top: 1rem
811
- }
812
-
813
- .bd-example>.dropdown-menu {
814
- position: static;
815
- display: block
816
- }
817
-
818
- .bd-example>:last-child,.bd-example>nav:last-child .breadcrumb {
819
- margin-bottom: 0
820
- }
821
-
822
- .bd-example>hr:last-child {
823
- margin-bottom: 1rem
824
- }
825
-
826
- .bd-example>svg+svg,.bd-example>img+img {
827
- margin-left: .5rem
828
- }
829
-
830
- .bd-example>.btn,.bd-example>.btn-group {
831
- margin: .25rem .125rem
832
- }
833
-
834
- .bd-example>.btn-toolbar+.btn-toolbar {
835
- margin-top: .5rem
836
- }
837
-
838
- .bd-example>.list-group {
839
- max-width: 400px
840
- }
841
-
842
- .bd-example>[class*="list-group-horizontal"] {
843
- max-width: 100%
844
- }
845
-
846
- .bd-example .fixed-top,.bd-example .sticky-top {
847
- position: static;
848
- margin: calc(var(--bd-example-padding) * -1) calc(var(--bd-example-padding) * -1) var(--bd-example-padding)
849
- }
850
-
851
- .bd-example .fixed-bottom,.bd-example .sticky-bottom {
852
- position: static;
853
- margin: var(--bd-example-padding) calc(var(--bd-example-padding) * -1) calc(var(--bd-example-padding) * -1)
854
- }
855
-
856
- .bd-example .pagination {
857
- margin-bottom: 0
858
- }
859
-
860
- .bd-example-row [class^="col"],.bd-example-cols [class^="col"]>*,.bd-example-cssgrid [class*="grid"]>* {
861
- padding-top: .75rem;
862
- padding-bottom: .75rem;
863
- background-color: rgba(var(--bd-violet-rgb), 0.15);
864
- border: 1px solid rgba(var(--bd-violet-rgb), 0.3)
865
- }
866
-
867
- .bd-example-row .row+.row,.bd-example-cssgrid .grid+.grid {
868
- margin-top: 1rem
869
- }
870
-
871
- .bd-example-row-flex-cols .row {
872
- min-height: 10rem;
873
- background-color: rgba(var(--bd-violet-rgb), 0.15)
874
- }
875
-
876
- .bd-example-flex div:not(.vr) {
877
- background-color: rgba(var(--bd-violet-rgb), 0.15);
878
- border: 1px solid rgba(var(--bd-violet-rgb), 0.3)
879
- }
880
-
881
- .example-container {
882
- width: 800px;
883
- --bs-gutter-x: 1.5rem;
884
- --bs-gutter-y: 0;
885
- width: 100%;
886
- padding-right: calc(var(--bs-gutter-x) * .5);
887
- padding-left: calc(var(--bs-gutter-x) * .5);
888
- margin-right: auto;
889
- margin-left: auto
890
- }
891
-
892
- .example-row {
893
- --bs-gutter-x: 1.5rem;
894
- --bs-gutter-y: 0;
895
- display: flex;
896
- flex-wrap: wrap;
897
- margin-top: calc(-1 * var(--bs-gutter-y));
898
- margin-right: calc(-.5 * var(--bs-gutter-x));
899
- margin-left: calc(-.5 * var(--bs-gutter-x))
900
- }
901
-
902
- .example-content-main {
903
- flex-shrink: 0;
904
- width: 100%;
905
- max-width: 100%;
906
- padding-right: calc(var(--bs-gutter-x) * .5);
907
- padding-left: calc(var(--bs-gutter-x) * .5);
908
- margin-top: var(--bs-gutter-y)
909
- }
910
-
911
- @media (min-width: 576px) {
912
- .example-content-main {
913
- flex:0 0 auto;
914
- width: 50%
915
- }
916
- }
917
-
918
- @media (min-width: 992px) {
919
- .example-content-main {
920
- flex:0 0 auto;
921
- width: 66.666667%
922
- }
923
- }
924
-
925
- .example-content-secondary {
926
- flex-shrink: 0;
927
- width: 100%;
928
- max-width: 100%;
929
- padding-right: calc(var(--bs-gutter-x) * .5);
930
- padding-left: calc(var(--bs-gutter-x) * .5);
931
- margin-top: var(--bs-gutter-y)
932
- }
933
-
934
- @media (min-width: 576px) {
935
- .example-content-secondary {
936
- flex:0 0 auto;
937
- width: 50%
938
- }
939
- }
940
-
941
- @media (min-width: 992px) {
942
- .example-content-secondary {
943
- flex:0 0 auto;
944
- width: 33.333333%
945
- }
946
- }
947
-
948
- .bd-example-ratios .ratio {
949
- display: inline-block;
950
- width: 10rem;
951
- color: var(--bs-secondary-color);
952
- background-color: var(--bs-tertiary-bg);
953
- border: var(--bs-border-width) solid var(--bs-border-color)
954
- }
955
-
956
- .bd-example-ratios .ratio>div {
957
- display: flex;
958
- align-items: center;
959
- justify-content: center
960
- }
961
-
962
- .bd-example-ratios-breakpoint .ratio-4x3 {
963
- width: 16rem
964
- }
965
-
966
- @media (min-width: 768px) {
967
- .bd-example-ratios-breakpoint .ratio-4x3 {
968
- --bs-aspect-ratio: 50%
969
- }
970
- }
971
-
972
- .bd-example-offcanvas .offcanvas {
973
- position: static;
974
- display: block;
975
- height: 200px;
976
- visibility: visible;
977
- transform: translate(0)
978
- }
979
-
980
- .tooltip-demo a {
981
- white-space: nowrap
982
- }
983
-
984
- .tooltip-demo .btn {
985
- margin: .25rem .125rem
986
- }
987
-
988
- .custom-tooltip {
989
- --bs-tooltip-bg: var(--bd-violet-bg);
990
- --bs-tooltip-color: var(--bs-white)
991
- }
992
-
993
- .custom-popover {
994
- --bs-popover-max-width: 200px;
995
- --bs-popover-border-color: var(--bd-violet-bg);
996
- --bs-popover-header-bg: var(--bd-violet-bg);
997
- --bs-popover-header-color: var(--bs-white);
998
- --bs-popover-body-padding-x: 1rem;
999
- --bs-popover-body-padding-y: .5rem
1000
- }
1001
-
1002
- .scrollspy-example {
1003
- height: 200px;
1004
- margin-top: .5rem;
1005
- overflow: auto
1006
- }
1007
-
1008
- .scrollspy-example-2 {
1009
- height: 350px;
1010
- overflow: auto
1011
- }
1012
-
1013
- .simple-list-example-scrollspy .active {
1014
- background-color: rgba(var(--bd-violet-rgb), 0.15)
1015
- }
1016
-
1017
- .bd-example-border-utils [class^="border"] {
1018
- display: inline-block;
1019
- width: 5rem;
1020
- height: 5rem;
1021
- margin: .25rem;
1022
- background-color: var(--bs-tertiary-bg)
1023
- }
1024
-
1025
- .bd-example-rounded-utils [class*="rounded"] {
1026
- margin: .25rem
1027
- }
1028
-
1029
- .bd-example-position-utils {
1030
- position: relative;
1031
- padding: 2rem
1032
- }
1033
-
1034
- .bd-example-position-utils .position-relative {
1035
- height: 200px;
1036
- background-color: var(--bs-tertiary-bg)
1037
- }
1038
-
1039
- .bd-example-position-utils .position-absolute {
1040
- width: 2rem;
1041
- height: 2rem;
1042
- background-color: var(--bs-body-color);
1043
- border-radius: .375rem
1044
- }
1045
-
1046
- .bd-example-position-examples::after {
1047
- content: none
1048
- }
1049
-
1050
- .bd-example-placeholder-cards::after {
1051
- display: none
1052
- }
1053
-
1054
- .bd-example-placeholder-cards .card {
1055
- width: 18rem
1056
- }
1057
-
1058
- .bd-example-toasts {
1059
- min-height: 240px
1060
- }
1061
-
1062
- .bd-example-zindex-levels {
1063
- min-height: 15rem
1064
- }
1065
-
1066
- .bd-example-zindex-levels>div {
1067
- color: var(--bs-body-bg);
1068
- background-color: var(--bd-violet);
1069
- border: 1px solid var(--bd-purple)
1070
- }
1071
-
1072
- .bd-example-zindex-levels>div>span {
1073
- position: absolute;
1074
- right: 5px;
1075
- bottom: 0
1076
- }
1077
-
1078
- .bd-example-zindex-levels>:nth-child(2) {
1079
- top: 3rem;
1080
- left: 3rem
1081
- }
1082
-
1083
- .bd-example-zindex-levels>:nth-child(3) {
1084
- top: 4.5rem;
1085
- left: 4.5rem
1086
- }
1087
-
1088
- .bd-example-zindex-levels>:nth-child(4) {
1089
- top: 6rem;
1090
- left: 6rem
1091
- }
1092
-
1093
- .bd-example-zindex-levels>:nth-child(5) {
1094
- top: 7.5rem;
1095
- left: 7.5rem
1096
- }
1097
-
1098
- // Wrapper only — pre.highlight carries its own padding when no wrapper exists.
1099
- // Rouge blocks (.highlighter-rouge) are styled in core/code-copy.scss.
1100
- .highlight:not(pre):not(.highlighter-rouge > .highlight) {
1101
- position: relative;
1102
- padding: var(--zer0-space-2) var(--zer0-space-3);
1103
- background-color: var(--bd-pre-bg)
1104
- }
1105
-
1106
- @media (min-width: 768px) {
1107
- .highlight:not(pre):not(.highlighter-rouge > .highlight) {
1108
- border-radius: calc(var(--bs-border-radius) - 1px)
1109
- }
1110
- }
1111
-
1112
- .highlight pre {
1113
- padding: 0;
1114
- margin: 0;
1115
- overflow-x: auto;
1116
- white-space: pre;
1117
- background-color: transparent;
1118
- border: 0
1119
- }
1120
-
1121
- .highlight pre code {
1122
- font-size: inherit;
1123
- // color: var(--bs-body-color);
1124
- word-wrap: normal
1125
- }
1126
-
1127
- .bd-example-snippet .highlight pre {
1128
- margin-right: 0
1129
- }
1130
-
1131
- .highlight-toolbar {
1132
- background-color: var(--bd-pre-bg)
1133
- }
1134
-
1135
- .highlight-toolbar+.highlight {
1136
- border-top-left-radius: 0;
1137
- border-top-right-radius: 0
1138
- }
1139
-
1140
- @media (min-width: 768px) {
1141
- .bd-file-ref .highlight-toolbar {
1142
- border-top-left-radius:calc(var(--bs-border-radius) - 1px);
1143
- border-top-right-radius: calc(var(--bs-border-radius) - 1px)
1144
- }
1145
- }
1146
-
1147
- .bd-content .bd-code-snippet {
1148
- margin-bottom: 1rem
1149
- }
1150
-
1151
- .bd-clipboard,.bd-edit {
1152
- position: relative;
1153
- display: none;
1154
- float: right
1155
- }
1156
-
1157
- .bd-clipboard+.highlight,.bd-edit+.highlight {
1158
- margin-top: 0
1159
- }
1160
-
1161
- @media (min-width: 768px) {
1162
- .bd-clipboard,.bd-edit {
1163
- display:block
1164
- }
1165
- }
1166
-
1167
- .btn-clipboard,.btn-edit {
1168
- display: block;
1169
- padding: .5em;
1170
- line-height: 1;
1171
- color: var(--bs-body-color);
1172
- background-color: var(--bd-pre-bg);
1173
- border: 0;
1174
- border-radius: .25rem
1175
- }
1176
-
1177
- .btn-clipboard:hover,.btn-edit:hover {
1178
- color: var(--bs-link-hover-color)
1179
- }
1180
-
1181
- .btn-clipboard:focus,.btn-edit:focus {
1182
- z-index: 3
1183
- }
1184
-
1185
- .btn-clipboard {
1186
- position: relative;
1187
- z-index: 2;
1188
- margin-top: 1.25rem;
1189
- margin-right: .75rem
1190
- }
1191
-
1192
- .bd-placeholder-img {
1193
- font-size: 1.125rem;
1194
- -webkit-user-select: none;
1195
- -moz-user-select: none;
1196
- user-select: none;
1197
- text-anchor: middle
1198
- }
1199
-
1200
- .bd-placeholder-img-lg {
1201
- font-size: calc(1.475rem + 2.7vw)
1202
- }
1203
-
1204
- @media (min-width: 1200px) {
1205
- .bd-placeholder-img-lg {
1206
- font-size:3.5rem
1207
- }
1208
- }
1209
-
1210
- main a,main button,main input,main select,main textarea,main h2,main h3,main h4,main [tabindex="0"] {
1211
- scroll-margin-top: 80px;
1212
- scroll-margin-bottom: 100px
1213
- }
@@ -480,6 +480,15 @@
480
480
  // -----------------------------------------------------------------------------
481
481
 
482
482
  @media (max-width: 991.98px) {
483
+ // Cap the slide-in panels so they never exceed a narrow phone viewport.
484
+ // Bootstrap's default --bs-offcanvas-width is a fixed 400px — wider than a
485
+ // 360–390px device — which pushes part of the panel (and its close button)
486
+ // off-screen. Clamp to a comfortable width that always fits.
487
+ #bdNavbar.offcanvas-lg,
488
+ #info-section.offcanvas {
489
+ --bs-offcanvas-width: min(21rem, 86vw);
490
+ }
491
+
483
492
  // Wrapper is inert on mobile so offcanvas layout matches pre-wrapper structure
484
493
  #bdNavbar .bd-navbar-nav-viewport {
485
494
  display: contents;
@@ -861,3 +870,247 @@
861
870
  display: none !important;
862
871
  }
863
872
  }
873
+
874
+ // ============================================================================
875
+
876
+ // Navbar fixed/auto-hide layout — relocated from custom.scss (Phase 4)
877
+
878
+ // ----------------------------------------------------------------------------
879
+
880
+ // Logo sizing + the #navbar 3-column desktop grid, brand-degradation container
881
+
882
+ // queries, hidden/auto-hide state, and the <992px mobile layout. Appended after
883
+
884
+ // the existing navbar body so the navbar-internal cascade order is unchanged.
885
+
886
+ // ============================================================================
887
+ // Navbar logo: global img { max-width: 100% } shrinks it inside tight flex/grid cells on small viewports
888
+ // (Use a.navbar-brand only — div.navbar-brand.site-title should still shrink/truncate.)
889
+ #navbar a.navbar-brand {
890
+ flex-shrink: 0;
891
+ }
892
+ #navbar .navbar-brand img {
893
+ width: 30px;
894
+ height: 30px;
895
+ min-width: 30px;
896
+ min-height: 30px;
897
+ max-width: none;
898
+ object-fit: contain;
899
+ flex-shrink: 0;
900
+ }
901
+
902
+ // ============================================
903
+ // NAVBAR - Fixed positioning with auto-hide
904
+ // ============================================
905
+ // Uses Bootstrap's fixed-top class for positioning (z-index: 1030)
906
+ // JavaScript adds/removes .navbar-hidden class on scroll
907
+
908
+ #navbar {
909
+ // Transition for smooth hide/show animation
910
+ transition: transform 0.3s ease-in-out !important;
911
+
912
+ // Ensure navbar background is opaque
913
+ background-color: var(--bs-body-bg);
914
+ }
915
+
916
+ // Keep the outer Bootstrap navbar shell on one row (nanobar + nav); avoids rare wrap on wide pages
917
+ #navbar > .navbar.navbar-expand-lg {
918
+ flex-wrap: nowrap !important;
919
+ align-items: center;
920
+ }
921
+
922
+ #navbar .navbar-main {
923
+ align-items: center;
924
+ }
925
+
926
+ #navbar .site-title-text,
927
+ #navbar .site-subtitle-text {
928
+ display: inline-block;
929
+ }
930
+
931
+ #navbar .nav-search-button {
932
+ display: inline-flex;
933
+ align-items: center;
934
+ gap: 0.25rem;
935
+ }
936
+
937
+ // Desktop (lg+): 3-column grid — [brand/title | main nav | utilities] so nav cannot paint over Search/Settings
938
+ @media (min-width: 992px) {
939
+ #navbar .navbar-main {
940
+ display: grid !important;
941
+ grid-template-columns: minmax(0, auto) minmax(0, 1fr) auto;
942
+ align-items: center;
943
+ column-gap: 0.5rem;
944
+ row-gap: 0.25rem;
945
+ flex-wrap: unset !important;
946
+ container-type: inline-size;
947
+ container-name: navbar-main;
948
+ }
949
+
950
+ #navbar .navbar-main-start {
951
+ grid-column: 1;
952
+ display: flex;
953
+ align-items: center;
954
+ gap: 0.375rem;
955
+ min-width: 0;
956
+ max-width: none;
957
+ flex-shrink: 1;
958
+ }
959
+
960
+ #navbar #bdNavbar {
961
+ grid-column: 2;
962
+ width: 100%;
963
+ max-width: 100%;
964
+ min-width: 0;
965
+ justify-self: stretch;
966
+ }
967
+
968
+ #navbar .navbar-utility-controls {
969
+ grid-column: 3;
970
+ justify-self: end;
971
+ flex-shrink: 0;
972
+ min-width: 0;
973
+ max-width: max-content;
974
+ display: inline-flex;
975
+ flex-wrap: nowrap;
976
+ align-items: center;
977
+ gap: 0.25rem;
978
+ padding-left: 0.25rem;
979
+ }
980
+
981
+ #navbar .navbar-utility-controls .nav-search-button,
982
+ #navbar .navbar-utility-controls .nav-settings-button {
983
+ flex: 0 1 auto;
984
+ min-width: 0;
985
+ padding-left: 0.5rem;
986
+ padding-right: 0.5rem;
987
+ }
988
+
989
+ // Brand cluster: logo stays fixed; title flexes and ellipsizes only when crowded
990
+ #navbar .navbar-brand-group {
991
+ display: inline-flex;
992
+ align-items: center;
993
+ flex-shrink: 0;
994
+ flex-wrap: nowrap;
995
+ gap: 0.375rem;
996
+ min-width: 0;
997
+ }
998
+
999
+ #navbar .navbar-home-links {
1000
+ flex-shrink: 0;
1001
+ display: none;
1002
+ }
1003
+
1004
+ #navbar .site-title,
1005
+ #navbar .site-subtitle {
1006
+ flex-shrink: 1;
1007
+ min-width: 0;
1008
+ }
1009
+
1010
+ #navbar .site-title {
1011
+ flex: 1 1 auto;
1012
+ overflow: hidden;
1013
+ }
1014
+
1015
+ #navbar .site-title .site-title-text {
1016
+ overflow: hidden;
1017
+ text-overflow: ellipsis;
1018
+ white-space: nowrap;
1019
+ vertical-align: bottom;
1020
+ max-width: none;
1021
+ }
1022
+
1023
+ #navbar .site-subtitle .site-subtitle-text {
1024
+ overflow: hidden;
1025
+ text-overflow: ellipsis;
1026
+ white-space: nowrap;
1027
+ display: inline-block;
1028
+ vertical-align: bottom;
1029
+ max-width: none;
1030
+ }
1031
+
1032
+ // Progressive brand degradation (container width, not viewport)
1033
+ @container navbar-main (min-width: 80rem) {
1034
+ #navbar .navbar-home-links {
1035
+ display: inline-flex !important;
1036
+ }
1037
+ }
1038
+
1039
+ @container navbar-main (max-width: 68rem) {
1040
+ #navbar .site-subtitle {
1041
+ display: none !important;
1042
+ }
1043
+ }
1044
+
1045
+ @container navbar-main (max-width: 50rem) {
1046
+ #navbar .site-title .site-title-text {
1047
+ max-width: 100%;
1048
+ }
1049
+ }
1050
+ }
1051
+
1052
+ // Hidden state - slides up out of view
1053
+ // Using higher specificity to override Bootstrap's fixed-top
1054
+ #navbar.navbar-hidden {
1055
+ transform: translateY(-100%) !important;
1056
+ }
1057
+
1058
+ // Respect user's motion preferences
1059
+ @media (prefers-reduced-motion: reduce) {
1060
+ #navbar {
1061
+ transition: none !important;
1062
+ }
1063
+ }
1064
+
1065
+ @media (max-width: 991.98px) {
1066
+ #navbar .navbar-main {
1067
+ display: flex;
1068
+ align-items: center;
1069
+ justify-content: space-between;
1070
+ gap: 0.5rem;
1071
+ padding-left: 0.5rem;
1072
+ padding-right: 0.5rem;
1073
+ }
1074
+
1075
+ #navbar .navbar-main-start {
1076
+ flex: 1 1 auto;
1077
+ min-width: 0;
1078
+ }
1079
+
1080
+ #navbar .navbar-brand-group {
1081
+ flex: 0 1 auto;
1082
+ min-width: 0;
1083
+ }
1084
+
1085
+ #navbar .site-title {
1086
+ flex: 1 1 auto;
1087
+ min-width: 0;
1088
+ }
1089
+
1090
+ #navbar .site-title .nav-link {
1091
+ padding: 0;
1092
+ min-height: 2.5rem;
1093
+ align-items: center;
1094
+ }
1095
+
1096
+ // Title fills the gap between logo and utility controls; ellipsis when crowded
1097
+ #navbar .site-title-text {
1098
+ max-width: 100%;
1099
+ white-space: nowrap;
1100
+ overflow: hidden;
1101
+ text-overflow: ellipsis;
1102
+ vertical-align: middle;
1103
+ }
1104
+
1105
+ #navbar .navbar-toggler {
1106
+ width: 2.5rem;
1107
+ height: 2.5rem;
1108
+ }
1109
+
1110
+ #navbar .nav-search-button {
1111
+ width: 2.5rem;
1112
+ height: 2.5rem;
1113
+ padding: 0;
1114
+ justify-content: center;
1115
+ }
1116
+ }