diff --git a/src/bpp/newsfragments/animacja-paska-nawigacji-wyszukiwanie.feature.rst b/src/bpp/newsfragments/animacja-paska-nawigacji-wyszukiwanie.feature.rst
new file mode 100644
index 000000000..be4d9b0fa
--- /dev/null
+++ b/src/bpp/newsfragments/animacja-paska-nawigacji-wyszukiwanie.feature.rst
@@ -0,0 +1,2 @@
+Pasek nawigacji chowa się i wraca płynną animacją przy otwieraniu oraz
+zamykaniu okna wyszukiwania globalnego, zamiast znikać i pojawiać się skokowo.
diff --git a/src/bpp/static/scss/top_bar.scss b/src/bpp/static/scss/top_bar.scss
index ae179ec35..af49c231b 100644
--- a/src/bpp/static/scss/top_bar.scss
+++ b/src/bpp/static/scss/top_bar.scss
@@ -18,6 +18,49 @@ nav.sticky-header {
z-index: 2000; // Must be highest to ensure dropdown appears above all sticky elements
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
+
+ // Chowanie paska na czas otwartego okna wyszukiwania globalnego.
+ //
+ // Modal blokuje przewijanie ustawiajac na
`position: fixed`
+ // z ujemnym `top` (global_search_modal.html). To lamie `position:
+ // sticky` powyzej: przestaje byc kontenerem scrollujacym, wiec
+ // pasek wraca na swoja pozycje w dokumencie i - gdy strona byla
+ // przewinieta - znika skokowo za gorna krawedzia. Dlatego na czas
+ // trwania modala przypinamy go recznie klasa `global-search-pinned`
+ // i dopiero wtedy mozemy go plynnie wysunac klasa
+ // `global-search-hidden`. Obie klasy zdejmuje `closeGlobalSearch()`.
+ //
+ // `position: fixed` jest tu wzgledem viewportu, bo zaden przodek
+ // (, ) nie ma transform/filter/perspective/contain -
+ // samo `position: relative`/`fixed` na containing blocku dla
+ // fixed nie tworzy.
+ transition: transform 0.25s ease-out, opacity 0.25s ease-out;
+
+ // Opoznienie dotyczy stanu DOCELOWEGO przejscia, czyli powrotu paska:
+ // wjezdza chwile po starcie zwijania okna, zamiast scigac sie z nim.
+ transition-delay: 0.1s;
+
+ &.global-search-pinned {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ }
+
+ &.global-search-hidden {
+ transform: translateY(-100%);
+ opacity: 0;
+ pointer-events: none;
+
+ // Chowanie ma ruszac natychmiast, rownolegle z rozwijaniem okna.
+ transition-delay: 0s;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ nav.sticky-header {
+ transition: none;
+ }
}
.top-bar {
diff --git a/src/django_bpp/templates/global_search_modal.html b/src/django_bpp/templates/global_search_modal.html
index 45aa381f1..0b6da1f82 100644
--- a/src/django_bpp/templates/global_search_modal.html
+++ b/src/django_bpp/templates/global_search_modal.html
@@ -479,6 +479,12 @@ Jak wyszukiwać?
// Save scroll position and block background scrolling
scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
+ // Zmierz pasek nawigacji ZANIM cokolwiek ruszymy - za chwile
+ // wypadnie z flow i jego wysokosc bedzie potrzebna do
+ // kompensacji na .
+ var nav = document.querySelector('nav.sticky-header');
+ var navHeight = nav ? nav.offsetHeight : 0;
+
// Lock the body completely
document.body.style.position = 'fixed';
document.body.style.top = '-' + scrollPosition + 'px';
@@ -490,6 +496,19 @@ Jak wyszukiwać?
// Also lock html element for extra security
document.documentElement.style.overflow = 'hidden';
+ // Przypnij pasek nawigacji do viewportu i wysun go poza kadr.
+ // Blokada scrolla powyzej (body -> position: fixed) lamie jego
+ // `position: sticky`, wiec bez tego pasek znikalby skokowo;
+ // klasy sa zdejmowane w closeGlobalSearch(). Reflow miedzy
+ // klasami jest konieczny: bez niego przegladarka scala oba
+ // zapisy stylu w jeden i przejscia nie ma.
+ if (nav) {
+ nav.classList.add('global-search-pinned');
+ document.body.style.paddingTop = navHeight + 'px';
+ void nav.offsetHeight;
+ nav.classList.add('global-search-hidden');
+ }
+
// Remove previous animation classes
container.classList.remove('animating-out');
@@ -622,11 +641,19 @@ Jak wyszukiwać?
window.closeGlobalSearch = function() {
var modal = document.getElementById('globalSearchModal');
var container = document.querySelector('.global-search-container');
+ var nav = document.querySelector('nav.sticky-header');
// Add closing animation
container.classList.add('animating-out');
modal.classList.add('closing');
+ // Pasek wjezdza ROWNOLEGLE ze zwijaniem okna, nie po nim.
+ // Wlasne opoznienie 0.1s ma w CSS (top_bar.scss), zeby ruch nie
+ // startowal dokladnie w tej samej klatce co collapseToButton.
+ if (nav) {
+ nav.classList.remove('global-search-hidden');
+ }
+
// After animation completes, hide modal and restore scrolling
setTimeout(function() {
modal.classList.remove('show', 'closing');
@@ -647,6 +674,16 @@ Jak wyszukiwać?
// Restore scroll position
window.scrollTo(0, scrollPosition);
+ // Oddaj pasek z powrotem `position: sticky`. Musi to isc w
+ // tej samej klatce co przywrocenie scrolla powyzej: pasek
+ // przypiety (fixed, top 0) i sticky przy top 0 sa w tym
+ // samym miejscu, wiec przelaczenie jest niewidoczne, a
+ // kompensacja paddingu znika razem z powrotem nav do flow.
+ if (nav) {
+ nav.classList.remove('global-search-pinned');
+ document.body.style.paddingTop = '';
+ }
+
// Reset container styles for next opening
container.style.transform = '';
container.style.opacity = '';