jekyll-theme-zer0 1.19.1 → 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 +395 -0
  3. data/README.md +27 -19
  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 +0 -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
@@ -759,456 +759,3 @@ a.bd-intro-badge--tag:focus {
759
759
  text-decoration: underline
760
760
  }
761
761
 
762
- .bd-code-snippet {
763
- margin: 0 -1.5rem 1rem;
764
- border: solid var(--bs-border-color);
765
- border-width: 1px 0
766
- }
767
-
768
- @media (min-width: 768px) {
769
- .bd-code-snippet {
770
- margin-right:0;
771
- margin-left: 0;
772
- border-width: 1px;
773
- border-radius: var(--bs-border-radius)
774
- }
775
- }
776
-
777
- .bd-example {
778
- --bd-example-padding: 1rem;
779
- position: relative;
780
- padding: var(--bd-example-padding);
781
- margin: 0 -1.5rem 1rem;
782
- border: solid var(--bs-border-color);
783
- border-width: 1px 0
784
- }
785
-
786
- .bd-example::after {
787
- display: block;
788
- clear: both;
789
- content: null
790
- }
791
-
792
- @media (min-width: 768px) {
793
- .bd-example {
794
- --bd-example-padding: 1.5rem;
795
- margin-right: 0;
796
- margin-left: 0;
797
- border-width: 1px;
798
- border-radius: var(--bs-border-radius)
799
- }
800
- }
801
-
802
- .bd-example+p {
803
- margin-top: 2rem
804
- }
805
-
806
- .bd-example>.form-control+.form-control {
807
- margin-top: .5rem
808
- }
809
-
810
- .bd-example>.nav+.nav,.bd-example>.alert+.alert,.bd-example>.navbar+.navbar,.bd-example>.progress+.progress {
811
- margin-top: 1rem
812
- }
813
-
814
- .bd-example>.dropdown-menu {
815
- position: static;
816
- display: block
817
- }
818
-
819
- .bd-example>:last-child,.bd-example>nav:last-child .breadcrumb {
820
- margin-bottom: 0
821
- }
822
-
823
- .bd-example>hr:last-child {
824
- margin-bottom: 1rem
825
- }
826
-
827
- .bd-example>svg+svg,.bd-example>img+img {
828
- margin-left: .5rem
829
- }
830
-
831
- .bd-example>.btn,.bd-example>.btn-group {
832
- margin: .25rem .125rem
833
- }
834
-
835
- .bd-example>.btn-toolbar+.btn-toolbar {
836
- margin-top: .5rem
837
- }
838
-
839
- .bd-example>.list-group {
840
- max-width: 400px
841
- }
842
-
843
- .bd-example>[class*="list-group-horizontal"] {
844
- max-width: 100%
845
- }
846
-
847
- .bd-example .fixed-top,.bd-example .sticky-top {
848
- position: static;
849
- margin: calc(var(--bd-example-padding) * -1) calc(var(--bd-example-padding) * -1) var(--bd-example-padding)
850
- }
851
-
852
- .bd-example .fixed-bottom,.bd-example .sticky-bottom {
853
- position: static;
854
- margin: var(--bd-example-padding) calc(var(--bd-example-padding) * -1) calc(var(--bd-example-padding) * -1)
855
- }
856
-
857
- .bd-example .pagination {
858
- margin-bottom: 0
859
- }
860
-
861
- .bd-example-row [class^="col"],.bd-example-cols [class^="col"]>*,.bd-example-cssgrid [class*="grid"]>* {
862
- padding-top: .75rem;
863
- padding-bottom: .75rem;
864
- background-color: rgba(var(--bd-violet-rgb), 0.15);
865
- border: 1px solid rgba(var(--bd-violet-rgb), 0.3)
866
- }
867
-
868
- .bd-example-row .row+.row,.bd-example-cssgrid .grid+.grid {
869
- margin-top: 1rem
870
- }
871
-
872
- .bd-example-row-flex-cols .row {
873
- min-height: 10rem;
874
- background-color: rgba(var(--bd-violet-rgb), 0.15)
875
- }
876
-
877
- .bd-example-flex div:not(.vr) {
878
- background-color: rgba(var(--bd-violet-rgb), 0.15);
879
- border: 1px solid rgba(var(--bd-violet-rgb), 0.3)
880
- }
881
-
882
- .example-container {
883
- width: 800px;
884
- --bs-gutter-x: 1.5rem;
885
- --bs-gutter-y: 0;
886
- width: 100%;
887
- padding-right: calc(var(--bs-gutter-x) * .5);
888
- padding-left: calc(var(--bs-gutter-x) * .5);
889
- margin-right: auto;
890
- margin-left: auto
891
- }
892
-
893
- .example-row {
894
- --bs-gutter-x: 1.5rem;
895
- --bs-gutter-y: 0;
896
- display: flex;
897
- flex-wrap: wrap;
898
- margin-top: calc(-1 * var(--bs-gutter-y));
899
- margin-right: calc(-.5 * var(--bs-gutter-x));
900
- margin-left: calc(-.5 * var(--bs-gutter-x))
901
- }
902
-
903
- .example-content-main {
904
- flex-shrink: 0;
905
- width: 100%;
906
- max-width: 100%;
907
- padding-right: calc(var(--bs-gutter-x) * .5);
908
- padding-left: calc(var(--bs-gutter-x) * .5);
909
- margin-top: var(--bs-gutter-y)
910
- }
911
-
912
- @media (min-width: 576px) {
913
- .example-content-main {
914
- flex:0 0 auto;
915
- width: 50%
916
- }
917
- }
918
-
919
- @media (min-width: 992px) {
920
- .example-content-main {
921
- flex:0 0 auto;
922
- width: 66.666667%
923
- }
924
- }
925
-
926
- .example-content-secondary {
927
- flex-shrink: 0;
928
- width: 100%;
929
- max-width: 100%;
930
- padding-right: calc(var(--bs-gutter-x) * .5);
931
- padding-left: calc(var(--bs-gutter-x) * .5);
932
- margin-top: var(--bs-gutter-y)
933
- }
934
-
935
- @media (min-width: 576px) {
936
- .example-content-secondary {
937
- flex:0 0 auto;
938
- width: 50%
939
- }
940
- }
941
-
942
- @media (min-width: 992px) {
943
- .example-content-secondary {
944
- flex:0 0 auto;
945
- width: 33.333333%
946
- }
947
- }
948
-
949
- .bd-example-ratios .ratio {
950
- display: inline-block;
951
- width: 10rem;
952
- color: var(--bs-secondary-color);
953
- background-color: var(--bs-tertiary-bg);
954
- border: var(--bs-border-width) solid var(--bs-border-color)
955
- }
956
-
957
- .bd-example-ratios .ratio>div {
958
- display: flex;
959
- align-items: center;
960
- justify-content: center
961
- }
962
-
963
- .bd-example-ratios-breakpoint .ratio-4x3 {
964
- width: 16rem
965
- }
966
-
967
- @media (min-width: 768px) {
968
- .bd-example-ratios-breakpoint .ratio-4x3 {
969
- --bs-aspect-ratio: 50%
970
- }
971
- }
972
-
973
- .bd-example-offcanvas .offcanvas {
974
- position: static;
975
- display: block;
976
- height: 200px;
977
- visibility: visible;
978
- transform: translate(0)
979
- }
980
-
981
- .tooltip-demo a {
982
- white-space: nowrap
983
- }
984
-
985
- .tooltip-demo .btn {
986
- margin: .25rem .125rem
987
- }
988
-
989
- .custom-tooltip {
990
- --bs-tooltip-bg: var(--bd-violet-bg);
991
- --bs-tooltip-color: var(--bs-white)
992
- }
993
-
994
- .custom-popover {
995
- --bs-popover-max-width: 200px;
996
- --bs-popover-border-color: var(--bd-violet-bg);
997
- --bs-popover-header-bg: var(--bd-violet-bg);
998
- --bs-popover-header-color: var(--bs-white);
999
- --bs-popover-body-padding-x: 1rem;
1000
- --bs-popover-body-padding-y: .5rem
1001
- }
1002
-
1003
- .scrollspy-example {
1004
- height: 200px;
1005
- margin-top: .5rem;
1006
- overflow: auto
1007
- }
1008
-
1009
- .scrollspy-example-2 {
1010
- height: 350px;
1011
- overflow: auto
1012
- }
1013
-
1014
- .simple-list-example-scrollspy .active {
1015
- background-color: rgba(var(--bd-violet-rgb), 0.15)
1016
- }
1017
-
1018
- .bd-example-border-utils [class^="border"] {
1019
- display: inline-block;
1020
- width: 5rem;
1021
- height: 5rem;
1022
- margin: .25rem;
1023
- background-color: var(--bs-tertiary-bg)
1024
- }
1025
-
1026
- .bd-example-rounded-utils [class*="rounded"] {
1027
- margin: .25rem
1028
- }
1029
-
1030
- .bd-example-position-utils {
1031
- position: relative;
1032
- padding: 2rem
1033
- }
1034
-
1035
- .bd-example-position-utils .position-relative {
1036
- height: 200px;
1037
- background-color: var(--bs-tertiary-bg)
1038
- }
1039
-
1040
- .bd-example-position-utils .position-absolute {
1041
- width: 2rem;
1042
- height: 2rem;
1043
- background-color: var(--bs-body-color);
1044
- border-radius: .375rem
1045
- }
1046
-
1047
- .bd-example-position-examples::after {
1048
- content: none
1049
- }
1050
-
1051
- .bd-example-placeholder-cards::after {
1052
- display: none
1053
- }
1054
-
1055
- .bd-example-placeholder-cards .card {
1056
- width: 18rem
1057
- }
1058
-
1059
- .bd-example-toasts {
1060
- min-height: 240px
1061
- }
1062
-
1063
- .bd-example-zindex-levels {
1064
- min-height: 15rem
1065
- }
1066
-
1067
- .bd-example-zindex-levels>div {
1068
- color: var(--bs-body-bg);
1069
- background-color: var(--bd-violet);
1070
- border: 1px solid var(--bd-purple)
1071
- }
1072
-
1073
- .bd-example-zindex-levels>div>span {
1074
- position: absolute;
1075
- right: 5px;
1076
- bottom: 0
1077
- }
1078
-
1079
- .bd-example-zindex-levels>:nth-child(2) {
1080
- top: 3rem;
1081
- left: 3rem
1082
- }
1083
-
1084
- .bd-example-zindex-levels>:nth-child(3) {
1085
- top: 4.5rem;
1086
- left: 4.5rem
1087
- }
1088
-
1089
- .bd-example-zindex-levels>:nth-child(4) {
1090
- top: 6rem;
1091
- left: 6rem
1092
- }
1093
-
1094
- .bd-example-zindex-levels>:nth-child(5) {
1095
- top: 7.5rem;
1096
- left: 7.5rem
1097
- }
1098
-
1099
- // Wrapper only — pre.highlight carries its own padding when no wrapper exists.
1100
- // Rouge blocks (.highlighter-rouge) are styled in core/code-copy.scss.
1101
- .highlight:not(pre):not(.highlighter-rouge > .highlight) {
1102
- position: relative;
1103
- padding: var(--zer0-space-2) var(--zer0-space-3);
1104
- background-color: var(--bd-pre-bg)
1105
- }
1106
-
1107
- @media (min-width: 768px) {
1108
- .highlight:not(pre):not(.highlighter-rouge > .highlight) {
1109
- border-radius: calc(var(--bs-border-radius) - 1px)
1110
- }
1111
- }
1112
-
1113
- .highlight pre {
1114
- padding: 0;
1115
- margin: 0;
1116
- overflow-x: auto;
1117
- white-space: pre;
1118
- background-color: transparent;
1119
- border: 0
1120
- }
1121
-
1122
- .highlight pre code {
1123
- font-size: inherit;
1124
- // color: var(--bs-body-color);
1125
- word-wrap: normal
1126
- }
1127
-
1128
- .bd-example-snippet .highlight pre {
1129
- margin-right: 0
1130
- }
1131
-
1132
- .highlight-toolbar {
1133
- background-color: var(--bd-pre-bg)
1134
- }
1135
-
1136
- .highlight-toolbar+.highlight {
1137
- border-top-left-radius: 0;
1138
- border-top-right-radius: 0
1139
- }
1140
-
1141
- @media (min-width: 768px) {
1142
- .bd-file-ref .highlight-toolbar {
1143
- border-top-left-radius:calc(var(--bs-border-radius) - 1px);
1144
- border-top-right-radius: calc(var(--bs-border-radius) - 1px)
1145
- }
1146
- }
1147
-
1148
- .bd-content .bd-code-snippet {
1149
- margin-bottom: 1rem
1150
- }
1151
-
1152
- .bd-clipboard,.bd-edit {
1153
- position: relative;
1154
- display: none;
1155
- float: right
1156
- }
1157
-
1158
- .bd-clipboard+.highlight,.bd-edit+.highlight {
1159
- margin-top: 0
1160
- }
1161
-
1162
- @media (min-width: 768px) {
1163
- .bd-clipboard,.bd-edit {
1164
- display:block
1165
- }
1166
- }
1167
-
1168
- .btn-clipboard,.btn-edit {
1169
- display: block;
1170
- padding: .5em;
1171
- line-height: 1;
1172
- color: var(--bs-body-color);
1173
- background-color: var(--bd-pre-bg);
1174
- border: 0;
1175
- border-radius: .25rem
1176
- }
1177
-
1178
- .btn-clipboard:hover,.btn-edit:hover {
1179
- color: var(--bs-link-hover-color)
1180
- }
1181
-
1182
- .btn-clipboard:focus,.btn-edit:focus {
1183
- z-index: 3
1184
- }
1185
-
1186
- .btn-clipboard {
1187
- position: relative;
1188
- z-index: 2;
1189
- margin-top: 1.25rem;
1190
- margin-right: .75rem
1191
- }
1192
-
1193
- .bd-placeholder-img {
1194
- font-size: 1.125rem;
1195
- -webkit-user-select: none;
1196
- -moz-user-select: none;
1197
- user-select: none;
1198
- text-anchor: middle
1199
- }
1200
-
1201
- .bd-placeholder-img-lg {
1202
- font-size: calc(1.475rem + 2.7vw)
1203
- }
1204
-
1205
- @media (min-width: 1200px) {
1206
- .bd-placeholder-img-lg {
1207
- font-size:3.5rem
1208
- }
1209
- }
1210
-
1211
- main a,main button,main input,main select,main textarea,main h2,main h3,main h4,main [tabindex="0"] {
1212
- scroll-margin-top: 80px;
1213
- scroll-margin-bottom: 100px
1214
- }
@@ -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
+ }