{"id":49533,"date":"2026-02-25T10:56:36","date_gmt":"2026-02-25T09:56:36","guid":{"rendered":"https:\/\/cmm.imgw.pl\/?page_id=49533"},"modified":"2026-06-29T14:33:46","modified_gmt":"2026-06-29T12:33:46","slug":"pomiary","status":"publish","type":"page","link":"https:\/\/cmm.imgw.pl\/?page_id=49533","title":{"rendered":"Pogoda bie\u017c\u0105ca"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"49533\" class=\"elementor elementor-49533\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-27444d1 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"27444d1\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7f7183b\" data-id=\"7f7183b\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6cb3e0f elementor-widget elementor-widget-html\" data-id=\"6cb3e0f\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<div id=\"synop-app\" class=\"forecast-app synop-current-app\">\n\t<div class=\"layout-container\">\n\t\t<div class=\"left-column\">\n\t\t\t<div class=\"section\">\n\t\t\t\t<h3>Kategoria:<\/h3>\n\t\t\t\t<div id=\"synCategoryButtons\" class=\"buttons category-buttons\"><\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"section\" id=\"synParamSection\">\n\t\t\t\t<h3 id=\"synParamTitle\">Parametr:<\/h3>\n\t\t\t\t<div id=\"synParamButtons\" class=\"buttons params-buttons\"><\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"section\" id=\"synFramesSection\" style=\"display: none;\">\n\t\t\t\t<h3 id=\"synFramesTitle\">Czas (UTC):<\/h3>\n\t\t\t\t<div id=\"synFrames\" class=\"buttons frames-buttons\"><\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"keyboard-info\">\n\t\t\t\t<strong>\ud83d\udca1 Skr\u00f3ty klawiszowe:<\/strong><br>\n\t\t\t\t1-6 | Kategoria<br>\n\t\t\t\t<span id=\"synKeyboardFramesHints\" hidden>\u2190 \u2192 | Zmiana czasu <br><\/span>\n\t\t\t\t<span id=\"synKeyboardParamHints\" hidden>\u2191 \u2193 | Zmiana parametru<br><\/span>\n\t\t\t\t<span id=\"synKeyboardTimeHints\" hidden>A | Animacja<br>\n\t\t\t\tN | Najnowsza mapa<br>\n\t\t\t\tR | Od\u015bwie\u017c<\/span>\n\t\t\t<\/div>\n\t\t<\/div>\n\n\t\t<div class=\"right-column\">\n\t\t\t<div class=\"section images\">\n\t\t\t\t<div class=\"horizontal-slider-container\" id=\"synSliderContainer\" style=\"display: none;\">\n\t\t\t\t\t<div class=\"slider-header\">\n\t\t\t\t\t\t<span class=\"slider-title\">Czas (UTC):<\/span>\n\t\t\t\t\t\t<span class=\"hour-value\" id=\"synFrameValue\">--<\/span>\n\t\t\t\t\t\t<div class=\"slider-right\">\n\t\t\t\t\t\t\t<div id=\"synRefreshInfo\" class=\"refresh-info header-refresh\">Ostatnie sprawdzenie: jeszcze nie wykonano<\/div>\n\t\t\t\t\t\t\t<div class=\"slider-controls\">\n\t\t\t\t\t\t\t\t<button id=\"synAnimateBtn\" class=\"control-btn\" title=\"Animuj\" type=\"button\">&#9654;<\/button>\n\t\t\t\t\t\t\t\t<button id=\"synLatestBtn\" class=\"control-btn\" title=\"Najnowsza mapa\" type=\"button\">N<\/button>\n\t\t\t\t\t\t\t\t<button id=\"synRefreshBtn\" class=\"control-btn\" title=\"Od\u015bwie\u017c\" type=\"button\">R<\/button>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t<input type=\"range\" id=\"synFrameSlider\" class=\"horizontal-slider\" min=\"0\" max=\"0\" step=\"1\" value=\"0\" aria-label=\"Wybierz czas\">\n\t\t\t\t\t<div class=\"hour-labels\" id=\"synFrameLabels\"><\/div>\n\t\t\t\t\t<div class=\"date-cutoffs\" id=\"synDateCutoffs\"><\/div>\n\t\t\t\t<\/div>\n\n\t\t\t\t<div id=\"synStatus\" class=\"date-warning\"><\/div>\n\t\t\t\t<div id=\"synLoader\" class=\"loader-container\" style=\"display: none;\">\n\t\t\t\t\t<div class=\"loader\"><\/div>\n\t\t\t\t\t<p>\u0141adowanie mapy...<\/p>\n\t\t\t\t<\/div>\n\t\t\t\t<div id=\"synAeroIntro\" class=\"syn-aero-text syn-aero-intro\" hidden>\n\t\t\t\t\t<p>Sonda\u017c aerologiczny, zwany r\u00f3wnie\u017c radiosonda\u017cem, to pomiary warto\u015bci wielko\u015bci fizycznych, wykonane przy pomocy radiosondy, w pionowym profilu atmosfery. Radiosonda to niewielkie urz\u0105dzenie pomiarowe unoszone przez balon meteorologiczny do g\u00f3rnych warstw troposfery. Radiosonda zawiera zestaw czujnik\u00f3w mierz\u0105cych ci\u015bnienie, temperatur\u0119, wilgotno\u015b\u0107 oraz pozycj\u0119. <a href=\"https:\/\/cmm.imgw.pl\/?page_id=38637\" target=\"_blank\" rel=\"noopener\">Czytaj dalej w #AkademiaLMM<\/a>.<\/p>\n\t\t\t\t<\/div>\n\t\t\t\t<div id=\"synImages\" class=\"images\"><\/div>\n\t\t\t\t<div id=\"synTempOdczNote\" class=\"syn-aero-text syn-temp-odcz-note\" hidden>\n\t\t\t\t\t<p>Ka\u017cdego dnia, niezale\u017cnie od miejsca pobytu, cia\u0142o cz\u0142owieka funkcjonuje w \u015brodowisku termicznym. Pomiar temperatury powietrza dostarcza nam cz\u0105stkowych informacji na temat fizycznych w\u0142a\u015bciwo\u015bci tego \u015brodowiska. Na jego podstawie mo\u017cemy jedynie po\u015brednio szacowa\u0107 jakiego rodzaju odczucia (termiczne) mog\u0105 zosta\u0107 wyzwolone w naszym ciele. Dlaczego? Czytaj dalej w <strong><a href=\"https:\/\/cmm.imgw.pl\/?page_id=32534\" target=\"_blank\" rel=\"noopener\">#AkademiaLMM\u2026<\/a><\/strong><\/p>\n\t\t\t\t<\/div>\n\t\t\t\t<div id=\"synAeroCredit\" class=\"syn-aero-text syn-aero-credit\" hidden>\n\t\t\t\t\t<p>Wizualizacje zosta\u0142y opracowane z wykorzystaniem biblioteki thundeR. Czernecki B, Taszarek M, Szuster P (2023). thunder: Computation and Visualisation of Atmospheric Convective Parameters. R package version 1.1.1. (<a href=\"https:\/\/www.rawinsonde.com\" target=\"_blank\" rel=\"noopener\">www.rawinsonde.com<\/a>)<\/p>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n<div class=\"lightbox\" id=\"synLightbox\">\n\t<span class=\"lightbox-close\" id=\"synLightboxClose\">&times;<\/span>\n\t<img id=\"synLightboxImg\" src=\"\" alt=\"Powi\u0119kszona mapa\">\n<\/div>\n\n<style>\n\t.forecast-app {\n\t\tfont-family: Arial, sans-serif;\n\t\tmax-width: 1200px;\n\t\tmargin: 0 auto;\n\t}\n\n\t.layout-container {\n\t\tdisplay: flex;\n\t\tflex-wrap: wrap;\n\t\tgap: 10px;\n\t}\n\n\t.left-column {\n\t\tflex: 1;\n\t\tmin-width: 260px;\n\t\tmax-width: 300px;\n\t}\n\n\t.right-column {\n\t\tflex: 2;\n\t\tmin-width: 400px;\n\t}\n\n\t.section {\n\t\tmargin-bottom: 12px;\n\t\tbackground: #f9f9f9;\n\t\tpadding: 10px;\n\t\tborder-radius: 8px;\n\t\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n\t}\n\n\t.section h3 {\n\t\tmargin-top: 0;\n\t\tmargin-bottom: 6px;\n\t\tborder-bottom: 1px solid #ddd;\n\t\tpadding-bottom: 5px;\n\t\tcolor: #333;\n\t}\n\n\t.buttons {\n\t\tdisplay: flex;\n\t\tflex-wrap: wrap;\n\t\tgap: 5px;\n\t\tmargin-top: 3px;\n\t}\n\n\t.buttons button {\n\t\tpadding: 6px 10px;\n\t\tmin-width: 45px;\n\t\tborder: 1px solid #666;\n\t\tborder-radius: 6px;\n\t\tbackground: #f5f5f5;\n\t\tcursor: pointer;\n\t\ttransition: all 0.2s;\n\t\tfont-size: 0.85em;\n\t\tline-height: 1.2;\n\t}\n\n\t.buttons button:hover {\n\t\tbackground: #e3f5f3;\n\t\tborder-color: rgba(86, 221, 208, 1);\n\t}\n\n\t.buttons button.active {\n\t\tbackground: rgba(86, 221, 208, 1);\n\t\tborder-color: rgba(56, 191, 178, 1);\n\t\tcolor: #fff;\n\t}\n\n\t.category-buttons {\n\t\tflex-direction: column;\n\t\talign-items: stretch;\n\t\tgap: 4px;\n\t}\n\n\t.category-buttons button {\n\t\twidth: 100%;\n\t\ttext-align: center;\n\t\tpadding: 8px 10px;\n\t}\n\n\t.params-buttons {\n\t\tflex-direction: column;\n\t\talign-items: stretch;\n\t\tgap: 4px;\n\t}\n\n\t.params-buttons button {\n\t\twidth: 100%;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 6px;\n\t\ttext-align: left;\n\t\tpadding: 5px 8px;\n\t}\n\n\t.param-btn-icon {\n\t\twidth: 18px;\n\t\theight: 18px;\n\t\tobject-fit: contain;\n\t\tflex-shrink: 0;\n\t}\n\n\t.param-btn-label {\n\t\tflex: 1;\n\t\tline-height: 1.2;\n\t\tfont-size: 0.85em;\n\t}\n\n\t.frames-buttons {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(auto-fit, minmax(68px, 1fr));\n\t\tpadding-right: 2px;\n\t}\n\n\t.frames-buttons button {\n\t\twidth: 100%;\n\t\tmin-width: 0;\n\t\ttext-align: center;\n\t\tfont-variant-numeric: tabular-nums;\n\t\tpadding: 2px 8px;\n\t\tfont-size: 0.82em;\n\t}\n\n\t.frames-buttons button.preload-pending:not(.active) {\n\t\tbackground: #ececec;\n\t\tborder-color: #b8b8b8;\n\t\tcolor: #7a7a7a;\n\t}\n\n\t.frames-buttons button.preload-loaded:not(.active) {\n\t\tbackground: linear-gradient(135deg, #d8d8d8 0%, #c9c9c9 100%);\n\t\tborder-color: #b1b1b1;\n\t\tcolor: #4f4f4f;\n\t}\n\n\t.horizontal-slider-container {\n\t\twidth: 100%;\n\t\tmargin: 0 0 16px;\n\t\tpadding: 10px 0;\n\t\tbackground-color: #f5f5f5;\n\t\tborder-radius: 5px;\n\t\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n\t}\n\n\t.slider-header {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 10px;\n\t\tflex-wrap: wrap;\n\t}\n\n\t.slider-right {\n\t\tmargin-left: auto;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 12px;\n\t}\n\n\t.slider-controls {\n\t\tdisplay: flex;\n\t\tgap: 8px;\n\t}\n\n\t.control-btn {\n\t\tbackground: rgba(86, 221, 208, 0.1);\n\t\tborder: 2px solid rgba(86, 221, 208, 1);\n\t\tcolor: rgba(56, 191, 178, 1);\n\t\tfont-size: 1em;\n\t\twidth: 40px;\n\t\theight: 40px;\n\t\tborder-radius: 8px;\n\t\tcursor: pointer;\n\t\ttransition: all 0.2s;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tpadding: 0;\n\t}\n\n\t.control-btn:hover {\n\t\tbackground: rgba(86, 221, 208, 0.2);\n\t}\n\n\t.control-btn.active {\n\t\tbackground: rgba(86, 221, 208, 1);\n\t\tcolor: #fff;\n\t}\n\n\t.slider-title {\n\t\tfont-weight: bold;\n\t\tcolor: #333;\n\t}\n\n\t.hour-value {\n\t\tfont-size: 1.15em;\n\t\tfont-weight: bold;\n\t\tcolor: rgba(86, 221, 208, 1);\n\t}\n\n\t.refresh-info {\n\t\tfont-size: 11px;\n\t\tcolor: #555;\n\t\tmax-width: 240px;\n\t\ttext-align: right;\n\t}\n\n\t.horizontal-slider {\n\t\t-webkit-appearance: none;\n\t\tappearance: none;\n\t\twidth: 100%;\n\t\theight: 10px;\n\t\tborder-radius: 5px;\n\t\tbackground: #e0e0e0;\n\t\toutline: none;\n\t\tmargin: 8px 0;\n\t}\n\n\t.horizontal-slider::-webkit-slider-thumb {\n\t\t-webkit-appearance: none;\n\t\tappearance: none;\n\t\twidth: 24px;\n\t\theight: 24px;\n\t\tborder-radius: 50%;\n\t\tbackground: rgba(86, 221, 208, 1);\n\t\tcursor: pointer;\n\t\tborder: 2px solid #fff;\n\t\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n\t}\n\n\t.horizontal-slider::-moz-range-thumb {\n\t\twidth: 24px;\n\t\theight: 24px;\n\t\tborder-radius: 50%;\n\t\tbackground: rgba(86, 221, 208, 1);\n\t\tcursor: pointer;\n\t\tborder: 2px solid #fff;\n\t}\n\n\t.hour-labels {\n\t\tposition: relative;\n\t\theight: 20px;\n\t\tfont-size: 0.82em;\n\t\tcolor: #666;\n\t}\n\n\t.hour-label-marker {\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\ttransform: translateX(-50%);\n\t\twhite-space: nowrap;\n\t}\n\n\t.hour-label-marker.first {\n\t\tleft: 0 !important;\n\t\ttransform: none;\n\t}\n\n\t.hour-label-marker.last {\n\t\ttransform: translateX(-100%);\n\t}\n\n\t.date-cutoffs {\n\t\tposition: relative;\n\t\theight: 22px;\n\t\tmargin-top: 4px;\n\t}\n\n\t.date-cutoff-marker {\n\t\tposition: absolute;\n\t\tbottom: 0;\n\t\ttransform: translateX(-50%);\n\t\tfont-size: 10px;\n\t\tcolor: #5f5f5f;\n\t\twhite-space: nowrap;\n\t}\n\n\t.date-cutoff-marker::before {\n\t\tcontent: \"\";\n\t\tposition: absolute;\n\t\tleft: 50%;\n\t\ttransform: translateX(-50%);\n\t\ttop: -11px;\n\t\theight: 8px;\n\t\tborder-left: 1px solid #909090;\n\t}\n\n\t.frame-date-divider {\n\t\tgrid-column: 1 \/ -1;\n\t\twidth: 100%;\n\t\tmargin: 4px 0 0;\n\t\tpadding-top: 4px;\n\t\tborder-top: 1px dashed #cfcfcf;\n\t\tfont-size: 11px;\n\t\tcolor: #666;\n\t\tfont-weight: 600;\n\t}\n\n\t.date-warning {\n\t\tdisplay: none;\n\t\ttext-align: center;\n\t\tpadding: 8px 15px;\n\t\tbackground: rgba(255, 152, 0, 0.1);\n\t\tborder: 1px solid rgba(255, 152, 0, 0.3);\n\t\tborder-radius: 6px;\n\t\tfont-size: 13px;\n\t\tcolor: #e65100;\n\t\tmargin: 10px 0;\n\t}\n\n\t.loader-container {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tflex-direction: column;\n\t\twidth: 100%;\n\t\theight: 280px;\n\t\tbackground-color: rgba(245, 245, 245, 0.7);\n\t\tborder-radius: 8px;\n\t}\n\n\t.loader {\n\t\tborder: 12px solid #f3f3f3;\n\t\tborder-radius: 50%;\n\t\tborder-top: 12px solid rgba(86, 221, 208, 1);\n\t\twidth: 90px;\n\t\theight: 90px;\n\t\tanimation: syn-spin 0.8s linear infinite;\n\t}\n\n\t@keyframes syn-spin {\n\t\tto { transform: rotate(360deg); }\n\t}\n\n\t.images {\n\t\tposition: relative;\n\t\twidth: 100%;\n\t\tmin-height: 480px;\n\t}\n\n\t.images img {\n\t\tmax-width: 100%;\n\t\tmargin: 5px auto;\n\t\tborder: 1px solid #ccc;\n\t\tdisplay: block;\n\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n\t\tcursor: zoom-in;\n\t}\n\n\t.syn-aero-text {\n\t\tfont-size: 0.9em;\n\t\tline-height: 1.5;\n\t\tcolor: #444;\n\t}\n\n\t.syn-aero-intro {\n\t\tmargin: 0 0 12px;\n\t\tpadding: 10px 12px;\n\t\tbackground: #f0f8ff;\n\t\tborder-left: 3px solid rgba(86, 221, 208, 1);\n\t\tborder-radius: 4px;\n\t}\n\n\t.syn-aero-intro p {\n\t\tmargin: 0;\n\t\ttext-align: justify;\n\t}\n\n\t.syn-aero-credit {\n\t\tmargin: 12px 0 0;\n\t\tpadding: 8px 10px;\n\t\tfont-size: 0.82em;\n\t\tcolor: #666;\n\t\tborder-top: 1px solid #e0e0e0;\n\t}\n\n\t.syn-temp-odcz-note {\n\t\tmargin: 12px 0 0;\n\t\tpadding: 10px 12px;\n\t\tbackground: #f0f8ff;\n\t\tborder-left: 3px solid rgba(86, 221, 208, 1);\n\t\tborder-radius: 4px;\n\t}\n\n\t.syn-temp-odcz-note p {\n\t\tmargin: 0;\n\t\ttext-align: justify;\n\t}\n\n\t.syn-temp-odcz-note a {\n\t\tcolor: rgba(56, 191, 178, 1);\n\t}\n\n\t.syn-aero-credit p {\n\t\tmargin: 0;\n\t}\n\n\t.syn-aero-text a {\n\t\tcolor: rgba(56, 191, 178, 1);\n\t}\n\n\t.keyboard-info {\n\t\tfont-size: 11px;\n\t\tcolor: #555;\n\t\tmargin-top: 16px;\n\t\tpadding: 10px;\n\t\tline-height: 1.6;\n\t\tbackground-color: #f0f8ff;\n\t\tborder-left: 3px solid rgba(86, 221, 208, 1);\n\t\tborder-radius: 4px;\n\t}\n\n\t.keyboard-info strong {\n\t\tcolor: rgba(86, 221, 208, 1);\n\t}\n\n\t.lightbox {\n\t\tdisplay: none;\n\t\tposition: fixed;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tbackground: rgba(0, 0, 0, 0.9);\n\t\tz-index: 1000;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tcursor: pointer;\n\t}\n\n\t.lightbox.active {\n\t\tdisplay: flex;\n\t}\n\n\t.lightbox img {\n\t\tmax-width: 95%;\n\t\tmax-height: 95%;\n\t\tobject-fit: contain;\n\t}\n\n\t.lightbox-close {\n\t\tposition: absolute;\n\t\ttop: 20px;\n\t\tright: 30px;\n\t\tcolor: #fff;\n\t\tfont-size: 40px;\n\t\tcursor: pointer;\n\t}\n\n\t@media (max-width: 768px) {\n\t\t.layout-container { flex-direction: column; }\n\t\t.left-column, .right-column { max-width: 100%; width: 100%; }\n\t\t.slider-header { flex-direction: column; align-items: flex-start; }\n\t\t.slider-right { margin-left: 0; width: 100%; justify-content: space-between; }\n\t\t.keyboard-info { display: none; }\n\t\t.hour-label-marker { font-size: 0.72em; }\n\t\t.date-cutoffs { display: none; }\n\t}\n<\/style>\n\n<script>\n(function() {\n\tvar BASE_PATH = (function() {\n\t\tvar path = window.location && window.location.pathname ? window.location.pathname : \"\";\n\t\tif (path.indexOf(\"\/cmm\/\") === 0 || path.indexOf(\"\/cmm\") !== -1) {\n\t\t\treturn \"\/cmm\/wp-content\/uploads\/production\";\n\t\t}\n\t\treturn \"\/wp-content\/uploads\/production\";\n\t})();\n\tvar ICONS_PATH = (function() {\n\t\tvar path = window.location && window.location.pathname ? window.location.pathname : \"\";\n\t\tif (path.indexOf(\"\/cmm\/\") === 0 || path.indexOf(\"\/cmm\") !== -1) {\n\t\t\treturn \"\/cmm\/wp-content\/uploads\/IKONY\";\n\t\t}\n\t\treturn \"\/wp-content\/uploads\/IKONY\";\n\t})();\n\tvar AUTO_REFRESH_MS = 5 * 60 * 1000;\n\n\tvar categoriesConfig = {\n\t\tSYNOP: {\n\t\t\tlabel: \"Pomiary (Stacje SYNOP)\",\n\t\t\ttype: \"static\",\n\t\t\tfolder: \"SYNOP\",\n\t\t\textension: \"png\",\n\t\t\tautoRefresh: true,\n\t\t\tparameters: [\n\t\t\t\t{ id: \"TEMPERATURA\", label: \"Temperatura powietrza\", file: \"TEMPERATURA.png\", icon: \"temp.png\" },\n\t\t\t\t{ id: \"TEMP_MAX_W_DZIEN\", label: \"Temperatura maksymalna\", file: \"TEMP_MAX_W_DZIEN.png\", icon: \"temp_max.png\" },\n\t\t\t\t{ id: \"TEMP_MIN_W_NOCY\", label: \"Temperatura minimalna\", file: \"TEMP_MIN_W_NOCY.png\", icon: \"temp_min.png\" },\n\t\t\t\t{ id: \"TEMPERATURA_SREDNIA_DOBOWA\", label: \"Temp. \u015brednia dobowa\", file: \"TEMPERATURA_SREDNIA_DOBOWA.png\", icon: \"temp_srednia_dobowa.png\" },\n\t\t\t\t{ id: \"TEMP_GRUNT_MIN_W_NOCY\", label: \"Temp. min. przy gruncie\", file: \"TEMP_GRUNT_MIN_W_NOCY.png\", icon: \"temp_min_przy_gruncie.png\" },\n\t\t\t\t{ id: \"TEMP_ODCZ\", label: \"Temperatura odczuwalna\", file: \"TEMP_ODCZ.png\", icon: \"temp_odczuwalna.png\" },\n\t\t\t\t{ id: \"CISNIENIE\", label: \"Ci\u015bnienie n.p.m.\", file: \"CISNIENIE.png\", icon: \"cisnienie.png\" },\n\t\t\t\t{ id: \"CISNIENIE_ZMIANA_DOBOWA\", label: \"Zmiana ci\u015bnienia\", file: \"CISNIENIE_ZMIANA_DOBOWA.png\", icon: \"zmiana_cisnienia.png\" },\n\t\t\t\t{ id: \"WIATR\", label: \"Pr\u0119dko\u015b\u0107 i kierunek wiatru\", file: \"WIATR.png\", icon: \"wiatr.png\" },\n\t\t\t\t{ id: \"PORYW_MAX\", label: \"Maksymalny poryw wiatru\", file: \"PORYW_MAX.png\", icon: \"porywy.png\" },\n\t\t\t\t{ id: \"WILGOTNOSC\", label: \"Wilgotno\u015b\u0107 powietrza\", file: \"WILGOTNOSC.png\", icon: \"wilgotnosc.png\" },\n\t\t\t\t{ id: \"WIDZIALNOSC\", label: \"Widzialno\u015b\u0107\", file: \"WIDZIALNOSC.png\", icon: \"widzialnosc.png\" },\n\t\t\t\t{ id: \"ZACHMURZENIE_GODZ\", label: \"Zachmurzenie [%]\", file: \"ZACHMURZENIE_GODZ.png\", icon: \"zachmurzenie.png\" },\n\t\t\t\t{ id: \"PODSTAWA_GODZ\", label: \"Wysoko\u015b\u0107 podstawy chmur\", file: \"PODSTAWA_GODZ.png\", icon: \"Wysoko\u015b\u0107 podstawy chmur.png\" },\n\t\t\t\t{ id: \"USLONECZNIENIE\", label: \"Us\u0142onecznienie\", file: \"USLONECZNIENIE.png\", icon: \"irradiancja.png\" },\n\t\t\t\t{ id: \"OPAD_SUMA_DOBOWA\", label: \"Suma opadu\", file: \"OPAD_SUMA_DOBOWA.png\", icon: \"opad_calkowity.png\" }\n\t\t\t\t\/*{ id: \"GRUBOSC_POKRYWY_SNIEZNEJ\", label: \"Grubo\u015b\u0107 pokrywy \u015bnie\u017cnej\", file: \"GRUBOSC_POKRYWY_SNIEZNEJ.png\", icon: \"grubosc_pokrywy_snieznej.png\" },\n\t\t\t\t{ id: \"POKRYWA_ZMIANA_DOBOWA\", label: \"Zmiana grubo\u015bci pokrywy \u015bnie\u017cnej\", file: \"POKRYWA_ZMIANA_DOBOWA.png\", icon: \"zmiana_grubosci_pokrywy.png\" },\n\t\t\t\t{ id: \"POKRYWA_PLUS_ZMIANA\", label: \"Grubo\u015b\u0107 pokrywy \u015bnie\u017cnej + zmiana 24h\", file: \"POKRYWA_PLUS_ZMIANA.png\", icon: \"grubosc_pokrywy_snieznej.png\" }*\/\n\t\t\t]\n\t\t},\n\t\tGIOS: {\n\t\t\tlabel: \"Zanieczyszczenia (GIO\u015a)\",\n\t\t\ttype: \"static-single\",\n\t\t\tautoRefresh: true,\n\t\t\tparameters: [\n\t\t\t\t{ id: \"GIOS\", label: \"Pomiar jako\u015bci powietrza\", file: \"GIOS_pomiar.png\", folder: \"zanieczyszczenia\/biezace\" }\n\t\t\t]\n\t\t},\n\t\tCMAX: {\n\t\t\tlabel: \"Odbicowo\u015b\u0107 radarowa (CMAX)\",\n\t\t\ttype: \"timeseries\",\n\t\t\tfolder: \"RADCMX10\",\n\t\t\textension: \"jpg\",\n\t\t\tautoRefresh: true,\n\t\t\tparameters: [\n\t\t\t\t{ id: \"CMAX_10\", label: \"CMAX (co 10 min)\", filePrefix: \"RADCOMPOSITE_RAD_CMAX_10_\", stepMinutes: 10, lookBackHours: 8, horizonHours: 0 }\n\t\t\t]\n\t\t},\n\t\tGRS: {\n\t\t\tlabel: \"Opad (RainGRS)\",\n\t\t\ttype: \"timeseries\",\n\t\t\tfolder: \"GRS\",\n\t\t\textension: \"jpg\",\n\t\t\tautoRefresh: true,\n\t\t\tparameters: [\n\t\t\t\t{ id: \"GRS_10\", label: \"Opad 10 min\", filePrefix: \"RAIN_GRS_GRS_10_\", stepMinutes: 10, lookBackHours: 8, horizonHours: 0, icon: \"opad_calkowity_10min.png\" },\n\t\t\t\t{ id: \"GRS_60\", label: \"Opad 60 min\", filePrefix: \"RAIN_GRS_GRS_60_\", stepMinutes: 60, lookBackHours: 24, horizonHours: 0, icon: \"opad_calkowity_1h.png\" },\n\t\t\t\t{ id: \"GRS_6H\", label: \"Opad 6 h\", filePrefix: \"RAIN_GRS_GRS_6H_\", stepMinutes: 360, lookBackHours: 48, horizonHours: 0, issueHoursUTC: [0, 6, 12, 18], icon: \"opad_calkowity_6h.png\" },\n\t\t\t\t{ id: \"GRS_12H\", label: \"Opad 12 h\", filePrefix: \"RAIN_GRS_GRS_12H_\", stepMinutes: 720, lookBackHours: 48, horizonHours: 0, issueHoursUTC: [6, 18], icon: \"opad_calkowity_12h.png\" },\n\t\t\t\t{ id: \"GRS_24H\", label: \"Opad 24 h\", filePrefix: \"RAIN_GRS_GRS_24H_\", stepMinutes: 1440, lookBackHours: 48, horizonHours: 0, issueHoursUTC: [6], icon: \"opad_calkowity_24h.png\" }\n\t\t\t]\n\t\t},\n\t\tLIGHTNING: {\n\t\t\tlabel: \"Wy\u0142adowania\",\n\t\t\ttype: \"timeseries\",\n\t\t\tfolder: \"LIGHTNING\",\n\t\t\textension: \"jpg\",\n\t\t\tautoRefresh: true,\n\t\t\tparameters: [\n\t\t\t\t{ id: \"L10_CG\", label: \"10 min \u2013 wy\u0142adowania doziemne (CG)\", filePrefix: \"LIGHTNING_LIGHTNING_10_cg_sum_\", stepMinutes: 10, lookBackHours: 8, horizonHours: 0, icon: \"liczba_wyladowan_CG_10.png\" },\n\t\t\t\t{ id: \"L10_ICCG\", label: \"10 min \u2013 wy\u0142adowania doziemne i wewn\u0105trzchmurowe (IC+CG)\", filePrefix: \"LIGHTNING_LIGHTNING_10_ic_cg_sum_\", stepMinutes: 10, lookBackHours: 8, horizonHours: 0, icon: \"liczba_wyladowan_CG_IC_10.png\" },\n\t\t\t\t{ id: \"L60_CG\", label: \"60 min \u2013 wy\u0142adowania doziemne (CG)\", filePrefix: \"LIGHTNING_LIGHTNING_60_cg_sum_\", stepMinutes: 60, lookBackHours: 24, horizonHours: 0, icon: \"liczba_wyladowan_CG_1.png\" },\n\t\t\t\t{ id: \"L60_ICCG\", label: \"60 min \u2013 wy\u0142adowania doziemne i wewn\u0105trzchmurowe (IC+CG)\", filePrefix: \"LIGHTNING_LIGHTNING_60_ic_cg_sum_\", stepMinutes: 60, lookBackHours: 24, horizonHours: 0, icon: \"liczba_wyladowan_CG_IC_1.png\" },\n\t\t\t\t{ id: \"L6H_CG\", label: \"6 h \u2013 wy\u0142adowania doziemne (CG)\", filePrefix: \"LIGHTNING_LIGHTNING_6H_cg_sum_\", stepMinutes: 360, lookBackHours: 48, horizonHours: 0, icon: \"liczba_wyladowan_CG_6.png\" },\n\t\t\t\t{ id: \"L6H_ICCG\", label: \"6 h \u2013 wy\u0142adowania doziemne i wewn\u0105trzchmurowe (IC+CG)\", filePrefix: \"LIGHTNING_LIGHTNING_6H_ic_cg_sum_\", stepMinutes: 360, lookBackHours: 48, horizonHours: 0, icon: \"liczba_wyladowan_CG_IC_6.png\" },\n\t\t\t\t{ id: \"L24H_CG\", label: \"24 h \u2013 wy\u0142adowania doziemne (CG)\", filePrefix: \"LIGHTNING_LIGHTNING_24H_cg_sum_\", stepMinutes: 1440, lookBackHours: 48, horizonHours: 0, issueHoursUTC: [6], icon: \"liczba_wyladowan_CG_24.png\" },\n\t\t\t\t{ id: \"L24H_ICCG\", label: \"24 h \u2013 wy\u0142adowania doziemne i wewn\u0105trzchmurowe (IC+CG)\", filePrefix: \"LIGHTNING_LIGHTNING_24H_ic_cg_sum_\", stepMinutes: 1440, lookBackHours: 48, horizonHours: 0, issueHoursUTC: [6], icon: \"liczba_wyladowan_CG_IC_24.png\" }\n\t\t\t]\n\t\t},\n\t\tAERO: {\n\t\t\tlabel: \"Sonda\u017c aerologiczny\",\n\t\t\ttype: \"static\",\n\t\t\tfolder: \"aerologia\",\n\t\t\textension: \"png\",\n\t\t\tautoRefresh: true,\n\t\t\tparameters: [\n\t\t\t\t{ id: \"Legionowo\", label: \"Legionowo\", file: \"Legionowo.png\" },\n\t\t\t\t{ id: \"Wroclaw\", label: \"Wroc\u0142aw\", file: \"Wroclaw.png\" },\n\t\t\t\t{ id: \"Leba\", label: \"\u0141eba\", file: \"Leba.png\" },\n\t\t\t\t{ id: \"Tarnow\", label: \"Tarn\u00f3w\", file: \"Tarnow.png\" }\n\t\t\t]\n\t\t}\n\t};\n\n\tvar categoryOrder = [\"SYNOP\", \"GIOS\", \"CMAX\", \"GRS\", \"LIGHTNING\", \"AERO\"];\n\n\tvar state = {\n\t\tcategory: categoryOrder[0],\n\t\tparam: categoriesConfig[categoryOrder[0]].parameters[0].id,\n\t\tframes: [],\n\t\tselectedFrameIndex: 0,\n\t\tisAnimating: false,\n\t\tanimationTimer: null,\n\t\tautoRefreshTimer: null,\n\t\tlastRefreshAt: null,\n\t\tisRefreshing: false,\n\t\tpendingRefresh: false,\n\t\trefreshToken: 0,\n\t\timageToken: 0,\n\t\tcacheVersion: 0,\n\t\timageCache: {},\n\t\timageLoadPromises: {},\n\t\tpreloadQueue: [],\n\t\tisPreloading: false,\n\t\tpreloadGeneration: 0\n\t};\n\n\tfunction getCategoryConfig(id) {\n\t\treturn categoriesConfig[id];\n\t}\n\n\tfunction getCurrentCategoryConfig() {\n\t\treturn getCategoryConfig(state.category);\n\t}\n\n\tfunction getParamConfig(catConfig, paramId) {\n\t\tvar params = catConfig.parameters;\n\t\tfor (var i = 0; i < params.length; i += 1) {\n\t\t\tif (params[i].id === paramId) {\n\t\t\t\treturn params[i];\n\t\t\t}\n\t\t}\n\t\treturn params[0] || null;\n\t}\n\n\tfunction getCurrentParamConfig() {\n\t\treturn getParamConfig(getCurrentCategoryConfig(), state.param);\n\t}\n\n\tfunction isTimeSeriesCategory(catConfig) {\n\t\treturn catConfig && catConfig.type === \"timeseries\";\n\t}\n\n\tfunction escapeRegExp(value) {\n\t\treturn value.replace(\/[.*+?^${}()|[\\]\\\\]\/g, \"\\\\$&\");\n\t}\n\n\tfunction floorToStepUTC(dateObj, stepMinutes) {\n\t\tvar rounded = new Date(dateObj.getTime());\n\t\trounded.setUTCSeconds(0, 0);\n\t\tvar minutes = rounded.getUTCMinutes();\n\t\trounded.setUTCMinutes(minutes - (minutes % stepMinutes));\n\t\tif (stepMinutes >= 60) {\n\t\t\tvar hours = rounded.getUTCHours();\n\t\t\tif (stepMinutes >= 360) {\n\t\t\t\trounded.setUTCHours(hours - (hours % (stepMinutes \/ 60)));\n\t\t\t\trounded.setUTCMinutes(0);\n\t\t\t} else if (stepMinutes === 60) {\n\t\t\t\trounded.setUTCMinutes(0);\n\t\t\t}\n\t\t}\n\t\treturn rounded;\n\t}\n\n\tfunction formatTimestampUTC(dateObj) {\n\t\tvar y = String(dateObj.getUTCFullYear());\n\t\tvar m = String(dateObj.getUTCMonth() + 1).padStart(2, \"0\");\n\t\tvar d = String(dateObj.getUTCDate()).padStart(2, \"0\");\n\t\tvar hh = String(dateObj.getUTCHours()).padStart(2, \"0\");\n\t\tvar mm = String(dateObj.getUTCMinutes()).padStart(2, \"0\");\n\t\treturn y + \"-\" + m + \"-\" + d + \"_\" + hh + \"_\" + mm + \"_00\";\n\t}\n\n\tfunction parseTimestampUTC(timestamp) {\n\t\tif (!timestamp) {\n\t\t\treturn null;\n\t\t}\n\t\tvar match = timestamp.match(\/^(\\d{4})-(\\d{2})-(\\d{2})_(\\d{2})_(\\d{2})_(\\d{2})$\/);\n\t\tif (!match) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new Date(Date.UTC(\n\t\t\tparseInt(match[1], 10),\n\t\t\tparseInt(match[2], 10) - 1,\n\t\t\tparseInt(match[3], 10),\n\t\t\tparseInt(match[4], 10),\n\t\t\tparseInt(match[5], 10),\n\t\t\tparseInt(match[6], 10)\n\t\t));\n\t}\n\n\tfunction formatFrameButtonLabel(timestamp) {\n\t\tvar dateObj = parseTimestampUTC(timestamp);\n\t\tif (!dateObj) {\n\t\t\treturn \"Najnowsza\";\n\t\t}\n\t\tvar step = (getCurrentParamConfig() || {}).stepMinutes || 10;\n\t\tif (step >= 720) {\n\t\t\treturn String(dateObj.getUTCDate()).padStart(2, \"0\") + \".\" +\n\t\t\t\tString(dateObj.getUTCMonth() + 1).padStart(2, \"0\") + \" \" +\n\t\t\t\tString(dateObj.getUTCHours()).padStart(2, \"0\") + \":00\";\n\t\t}\n\t\tif (step >= 360) {\n\t\t\treturn String(dateObj.getUTCHours()).padStart(2, \"0\") + \":00\";\n\t\t}\n\t\tif (step >= 60) {\n\t\t\treturn String(dateObj.getUTCHours()).padStart(2, \"0\") + \":\" + String(dateObj.getUTCMinutes()).padStart(2, \"0\");\n\t\t}\n\t\treturn String(dateObj.getUTCHours()).padStart(2, \"0\") + \":\" + String(dateObj.getUTCMinutes()).padStart(2, \"0\");\n\t}\n\n\tfunction formatFrameDateLabel(timestamp) {\n\t\tvar dateObj = parseTimestampUTC(timestamp);\n\t\tif (!dateObj) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn String(dateObj.getUTCDate()).padStart(2, \"0\") + \".\" +\n\t\t\tString(dateObj.getUTCMonth() + 1).padStart(2, \"0\") + \".\" +\n\t\t\tdateObj.getUTCFullYear();\n\t}\n\n\tfunction formatFrameVerboseLabel(timestamp) {\n\t\tvar dateObj = parseTimestampUTC(timestamp);\n\t\tif (!dateObj) {\n\t\t\treturn \"Najnowsza dost\u0119pna mapa\";\n\t\t}\n\t\treturn formatFrameDateLabel(timestamp) + \" \" +\n\t\t\tString(dateObj.getUTCHours()).padStart(2, \"0\") + \":\" +\n\t\t\tString(dateObj.getUTCMinutes()).padStart(2, \"0\") + \" UTC\";\n\t}\n\n\tfunction formatLocalDateTime(dateObj) {\n\t\tif (!dateObj) {\n\t\t\treturn \"jeszcze nie wykonano\";\n\t\t}\n\t\tvar dd = String(dateObj.getDate()).padStart(2, \"0\");\n\t\tvar mm = String(dateObj.getMonth() + 1).padStart(2, \"0\");\n\t\tvar yyyy = dateObj.getFullYear();\n\t\tvar hh = String(dateObj.getHours()).padStart(2, \"0\");\n\t\tvar min = String(dateObj.getMinutes()).padStart(2, \"0\");\n\t\tvar ss = String(dateObj.getSeconds()).padStart(2, \"0\");\n\t\treturn dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + min + \":\" + ss;\n\t}\n\n\tfunction buildStaticUrl(catConfig, paramConfig) {\n\t\tvar folder = paramConfig.folder || catConfig.folder;\n\t\treturn BASE_PATH + \"\/\" + folder + \"\/\" + paramConfig.file;\n\t}\n\n\tfunction buildFrameUrl(catConfig, fileName) {\n\t\treturn BASE_PATH + \"\/\" + catConfig.folder + \"\/\" + fileName;\n\t}\n\n\tfunction getTimeSeriesTiming(paramConfig) {\n\t\treturn {\n\t\t\tstepMinutes: paramConfig.stepMinutes || 10,\n\t\t\tlookBackHours: paramConfig.lookBackHours || 8,\n\t\t\thorizonHours: paramConfig.horizonHours || 0\n\t\t};\n\t}\n\n\tfunction buildTimestampCandidatesForIssueHours(paramConfig) {\n\t\tvar timing = getTimeSeriesTiming(paramConfig);\n\t\tvar issueHours = paramConfig.issueHoursUTC || [];\n\t\tvar now = new Date();\n\t\tvar start = new Date(now.getTime() - timing.lookBackHours * 3600000);\n\t\tvar end = new Date(now.getTime() + timing.horizonHours * 3600000);\n\t\tvar values = [];\n\t\tvar dayCursor = new Date(Date.UTC(\n\t\t\tstart.getUTCFullYear(),\n\t\t\tstart.getUTCMonth(),\n\t\t\tstart.getUTCDate()\n\t\t));\n\t\tvar lastDay = new Date(Date.UTC(\n\t\t\tend.getUTCFullYear(),\n\t\t\tend.getUTCMonth(),\n\t\t\tend.getUTCDate()\n\t\t));\n\n\t\twhile (dayCursor.getTime() <= lastDay.getTime()) {\n\t\t\tvar h;\n\t\t\tfor (h = 0; h < issueHours.length; h += 1) {\n\t\t\t\tvar slot = new Date(Date.UTC(\n\t\t\t\t\tdayCursor.getUTCFullYear(),\n\t\t\t\t\tdayCursor.getUTCMonth(),\n\t\t\t\t\tdayCursor.getUTCDate(),\n\t\t\t\t\tissueHours[h],\n\t\t\t\t\t0,\n\t\t\t\t\t0\n\t\t\t\t));\n\t\t\t\tif (slot.getTime() >= start.getTime() && slot.getTime() <= end.getTime()) {\n\t\t\t\t\tvalues.push(formatTimestampUTC(slot));\n\t\t\t\t}\n\t\t\t}\n\t\t\tdayCursor = new Date(dayCursor.getTime() + 86400000);\n\t\t}\n\n\t\treturn values;\n\t}\n\n\tfunction buildTimestampCandidates(paramConfig) {\n\t\tif (paramConfig.issueHoursUTC && paramConfig.issueHoursUTC.length) {\n\t\t\treturn buildTimestampCandidatesForIssueHours(paramConfig);\n\t\t}\n\n\t\tvar timing = getTimeSeriesTiming(paramConfig);\n\t\tvar step = timing.stepMinutes;\n\t\tvar nowRounded = floorToStepUTC(new Date(), step);\n\t\tvar start = new Date(nowRounded.getTime() - timing.lookBackHours * 3600000);\n\t\tvar end = new Date(nowRounded.getTime() + timing.horizonHours * 3600000);\n\t\tvar values = [];\n\t\tvar pointer = floorToStepUTC(start, step);\n\n\t\twhile (pointer.getTime() <= end.getTime()) {\n\t\t\tvalues.push(formatTimestampUTC(pointer));\n\t\t\tpointer = new Date(pointer.getTime() + step * 60000);\n\t\t}\n\n\t\treturn values;\n\t}\n\n\tfunction isTimestampInWindow(timestamp, paramConfig) {\n\t\tvar dateObj = parseTimestampUTC(timestamp);\n\t\tif (!dateObj) {\n\t\t\treturn false;\n\t\t}\n\t\tvar timing = getTimeSeriesTiming(paramConfig);\n\t\tvar diffHours = (dateObj.getTime() - Date.now()) \/ 3600000;\n\t\treturn diffHours >= (-timing.lookBackHours - 0.2) && diffHours <= (timing.horizonHours + 0.2);\n\t}\n\n\tfunction extractTimestampByPrefix(fileName, prefix, ext) {\n\t\tvar regex = new RegExp(\"^\" + escapeRegExp(prefix) + \"(\\\\d{4}-\\\\d{2}-\\\\d{2}_\\\\d{2}_\\\\d{2}_\\\\d{2})\\\\.\" + escapeRegExp(ext) + \"$\", \"i\");\n\t\tvar match = fileName.match(regex);\n\t\treturn match ? match[1] : null;\n\t}\n\n\tasync function checkUrlExists(url) {\n\t\ttry {\n\t\t\tvar headResponse = await fetch(url, { method: \"HEAD\", cache: \"no-store\" });\n\t\t\tif (headResponse.ok) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (headResponse.status !== 405 && headResponse.status !== 501) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch (e) {\n\t\t}\n\t\ttry {\n\t\t\tvar getResponse = await fetch(url, {\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tcache: \"no-store\",\n\t\t\t\theaders: { Range: \"bytes=0-0\" }\n\t\t\t});\n\t\t\treturn getResponse.ok;\n\t\t} catch (e2) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync function fetchDirectoryFiles(folder, extension) {\n\t\tvar directoryUrl = BASE_PATH + \"\/\" + folder + \"\/\";\n\t\tvar ext = (extension || \"jpg\").toLowerCase();\n\t\ttry {\n\t\t\tvar response = await fetch(directoryUrl, { method: \"GET\", cache: \"no-store\" });\n\t\t\tif (!response.ok) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tvar html = await response.text();\n\t\t\tvar files = {};\n\t\t\tvar hrefRegex = new RegExp(\"href=[\\\"']([^\\\"']+\\\\.\" + escapeRegExp(ext) + \"(?:\\\\?[^\\\"']*)?)[\\\"']\", \"gi\");\n\t\t\tvar match;\n\t\t\twhile ((match = hrefRegex.exec(html)) !== null) {\n\t\t\t\tvar raw = match[1].split(\"?\")[0];\n\t\t\t\tvar fileName = decodeURIComponent(raw.split(\"\/\").pop());\n\t\t\t\tif (fileName) {\n\t\t\t\t\tfiles[fileName] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!Object.keys(files).length) {\n\t\t\t\tvar plainRegex = new RegExp(\"([A-Za-z0-9._-]+\\\\.\" + escapeRegExp(ext) + \")\", \"gi\");\n\t\t\t\twhile ((match = plainRegex.exec(html)) !== null) {\n\t\t\t\t\tfiles[match[1]] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Object.keys(files);\n\t\t} catch (error) {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tfunction sortFramesAscending(frames) {\n\t\tframes.sort(function(a, b) {\n\t\t\tvar aDate = parseTimestampUTC(a.timestamp);\n\t\t\tvar bDate = parseTimestampUTC(b.timestamp);\n\t\t\tif (!aDate && !bDate) return 0;\n\t\t\tif (!aDate) return -1;\n\t\t\tif (!bDate) return 1;\n\t\t\treturn aDate.getTime() - bDate.getTime();\n\t\t});\n\t\treturn frames;\n\t}\n\n\tasync function loadTimeSeriesFrames(catConfig, paramConfig) {\n\t\tvar ext = catConfig.extension || \"jpg\";\n\t\tvar files = await fetchDirectoryFiles(catConfig.folder, ext);\n\t\tvar byTimestamp = {};\n\t\tvar i;\n\n\t\tfor (i = 0; i < files.length; i += 1) {\n\t\t\tvar ts = extractTimestampByPrefix(files[i], paramConfig.filePrefix, ext);\n\t\t\tif (ts && isTimestampInWindow(ts, paramConfig)) {\n\t\t\t\tbyTimestamp[ts] = {\n\t\t\t\t\ttimestamp: ts,\n\t\t\t\t\turl: buildFrameUrl(catConfig, files[i]),\n\t\t\t\t\tstatic: false\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tvar frames = Object.keys(byTimestamp).map(function(ts) {\n\t\t\treturn byTimestamp[ts];\n\t\t});\n\n\t\tif (!frames.length) {\n\t\t\tvar timestamps = buildTimestampCandidates(paramConfig);\n\t\t\tvar checks = await Promise.all(timestamps.map(async function(ts) {\n\t\t\t\tvar url = buildFrameUrl(catConfig, paramConfig.filePrefix + ts + \".\" + ext);\n\t\t\t\tif (await checkUrlExists(url)) {\n\t\t\t\t\treturn { timestamp: ts, url: url, static: false };\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}));\n\t\t\tframes = checks.filter(function(item) { return item !== null; });\n\t\t}\n\n\t\treturn sortFramesAscending(frames);\n\t}\n\n\tfunction getFrameCacheKey(frame) {\n\t\treturn frame.url + \"::\" + state.cacheVersion;\n\t}\n\n\tfunction getFrameRequestUrl(frame) {\n\t\tvar separator = frame.url.indexOf(\"?\") === -1 ? \"?\" : \"&\";\n\t\treturn frame.url + separator + \"v=\" + state.cacheVersion;\n\t}\n\n\tfunction getFrameLoadState(frame) {\n\t\tvar key = getFrameCacheKey(frame);\n\t\tif (state.imageCache[key]) return \"loaded\";\n\t\tif (state.imageLoadPromises[key]) return \"loading\";\n\t\treturn \"pending\";\n\t}\n\n\tfunction updateTimeControlsVisibility() {\n\t\tvar catConfig = getCurrentCategoryConfig();\n\t\tvar isTs = isTimeSeriesCategory(catConfig);\n\t\tdocument.getElementById(\"synFramesSection\").style.display = isTs ? \"block\" : \"none\";\n\t\tdocument.getElementById(\"synSliderContainer\").style.display = isTs && state.frames.length ? \"block\" : \"none\";\n\t\tvar paramTitle = \"Parametr:\";\n\t\tif (state.category === \"AERO\") {\n\t\t\tparamTitle = \"Stacja:\";\n\t\t} else if (catConfig.type === \"static-single\") {\n\t\t\tparamTitle = \"\u0179r\u00f3d\u0142o:\";\n\t\t}\n\t\tdocument.getElementById(\"synParamTitle\").textContent = paramTitle;\n\t\tvar framesHints = document.getElementById(\"synKeyboardFramesHints\");\n\t\tvar timeHints = document.getElementById(\"synKeyboardTimeHints\");\n\t\tif (framesHints) {\n\t\t\tframesHints.hidden = !isTs;\n\t\t}\n\t\tif (timeHints) {\n\t\t\ttimeHints.hidden = !isTs;\n\t\t}\n\t\tvar paramHints = document.getElementById(\"synKeyboardParamHints\");\n\t\tif (paramHints) {\n\t\t\tparamHints.hidden = catConfig.parameters.length <= 1;\n\t\t}\n\t}\n\n\tfunction updateRefreshInfo() {\n\t\tvar catConfig = getCurrentCategoryConfig();\n\t\tvar autoText = catConfig.autoRefresh ? \"w\u0142\u0105czone (5 min)\" : \"wy\u0142\u0105czone\";\n\t\tdocument.getElementById(\"synRefreshInfo\").textContent =\n\t\t\t\"Ostatnie sprawdzenie: \" + formatLocalDateTime(state.lastRefreshAt) + \" | Auto: \" + autoText;\n\t}\n\n\tfunction showLoader(show) {\n\t\tdocument.getElementById(\"synLoader\").style.display = show ? \"flex\" : \"none\";\n\t}\n\n\tfunction showStatus(message) {\n\t\tvar status = document.getElementById(\"synStatus\");\n\t\tif (!message) {\n\t\t\tstatus.style.display = \"none\";\n\t\t\tstatus.textContent = \"\";\n\t\t\treturn;\n\t\t}\n\t\tstatus.style.display = \"block\";\n\t\tstatus.textContent = message;\n\t}\n\n\tfunction isAeroCategory(catId) {\n\t\treturn catId === \"AERO\";\n\t}\n\n\tfunction updateAeroAnnotations(visible) {\n\t\tvar show = visible && isAeroCategory(state.category);\n\t\tvar intro = document.getElementById(\"synAeroIntro\");\n\t\tvar credit = document.getElementById(\"synAeroCredit\");\n\t\tintro.hidden = !show;\n\t\tcredit.hidden = !show;\n\t}\n\n\tfunction updateTempOdczNote(visible) {\n\t\tvar show = visible && state.category === \"SYNOP\" && state.param === \"TEMP_ODCZ\";\n\t\tdocument.getElementById(\"synTempOdczNote\").hidden = !show;\n\t}\n\n\tfunction updateImageAnnotations(visible) {\n\t\tupdateAeroAnnotations(visible);\n\t\tupdateTempOdczNote(visible);\n\t}\n\n\tfunction resetParamUi() {\n\t\tvar container = document.getElementById(\"synParamButtons\");\n\t\tcontainer.innerHTML = \"\";\n\t}\n\n\tfunction ensureParamForCategory(catConfig) {\n\t\tvar found = false;\n\t\tvar i;\n\t\tfor (i = 0; i < catConfig.parameters.length; i += 1) {\n\t\t\tif (catConfig.parameters[i].id === state.param) {\n\t\t\t\tfound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!found && catConfig.parameters.length) {\n\t\t\tstate.param = catConfig.parameters[0].id;\n\t\t}\n\t}\n\n\tfunction renderCategoryButtons() {\n\t\tvar container = document.getElementById(\"synCategoryButtons\");\n\t\tcontainer.innerHTML = \"\";\n\t\tcategoryOrder.forEach(function(catId) {\n\t\t\tvar cfg = categoriesConfig[catId];\n\t\t\tvar btn = document.createElement(\"button\");\n\t\t\tbtn.type = \"button\";\n\t\t\tbtn.textContent = cfg.label;\n\t\t\tbtn.dataset.value = catId;\n\t\t\tif (catId === state.category) {\n\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t}\n\t\t\tbtn.addEventListener(\"click\", function() {\n\t\t\t\tif (state.category === catId) return;\n\t\t\t\thandleCategoryChange(catId);\n\t\t\t});\n\t\t\tcontainer.appendChild(btn);\n\t\t});\n\t}\n\n\tfunction buildIconUrl(iconFile) {\n\t\tif (!iconFile) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn ICONS_PATH + \"\/\" + encodeURIComponent(iconFile);\n\t}\n\n\tfunction createParamButton(param) {\n\t\tvar btn = document.createElement(\"button\");\n\t\tbtn.type = \"button\";\n\t\tbtn.dataset.value = param.id;\n\t\tif (param.icon) {\n\t\t\tvar icon = document.createElement(\"img\");\n\t\t\ticon.className = \"param-btn-icon\";\n\t\t\ticon.src = buildIconUrl(param.icon);\n\t\t\ticon.alt = \"\";\n\t\t\ticon.loading = \"lazy\";\n\t\t\tbtn.appendChild(icon);\n\t\t}\n\t\tvar label = document.createElement(\"span\");\n\t\tlabel.className = \"param-btn-label\";\n\t\tlabel.textContent = param.label;\n\t\tbtn.appendChild(label);\n\t\tif (param.id === state.param) {\n\t\t\tbtn.classList.add(\"active\");\n\t\t}\n\t\tbtn.addEventListener(\"click\", function() {\n\t\t\thandleParamChange(param.id);\n\t\t});\n\t\treturn btn;\n\t}\n\n\tfunction renderParamButtons() {\n\t\tvar container = document.getElementById(\"synParamButtons\");\n\t\tcontainer.innerHTML = \"\";\n\t\tvar catConfig = getCurrentCategoryConfig();\n\t\tensureParamForCategory(catConfig);\n\t\tvar paramConfig = getCurrentParamConfig();\n\t\tif (!paramConfig && catConfig.parameters.length) {\n\t\t\tstate.param = catConfig.parameters[0].id;\n\t\t}\n\t\tdocument.getElementById(\"synParamSection\").style.display =\n\t\t\tcatConfig.parameters.length <= 1 ? \"none\" : \"block\";\n\n\t\tcatConfig.parameters.forEach(function(param) {\n\t\t\tcontainer.appendChild(createParamButton(param));\n\t\t});\n\t}\n\n\tfunction renderFrameButtons() {\n\t\tvar container = document.getElementById(\"synFrames\");\n\t\tcontainer.innerHTML = \"\";\n\t\tif (!state.frames.length) {\n\t\t\tvar noData = document.createElement(\"div\");\n\t\t\tnoData.style.fontSize = \"12px\";\n\t\t\tnoData.style.color = \"#777\";\n\t\t\tnoData.textContent = \"Brak ramek czasowych.\";\n\t\t\tcontainer.appendChild(noData);\n\t\t\treturn;\n\t\t}\n\t\tvar lastDateLabel = \"\";\n\t\tstate.frames.forEach(function(frame, index) {\n\t\t\tif (frame.timestamp) {\n\t\t\t\tvar dateLabel = formatFrameDateLabel(frame.timestamp);\n\t\t\t\tif (index === 0 || dateLabel !== lastDateLabel) {\n\t\t\t\t\tvar divider = document.createElement(\"div\");\n\t\t\t\t\tdivider.className = \"frame-date-divider\";\n\t\t\t\t\tdivider.textContent = dateLabel;\n\t\t\t\t\tcontainer.appendChild(divider);\n\t\t\t\t\tlastDateLabel = dateLabel;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar btn = document.createElement(\"button\");\n\t\t\tbtn.type = \"button\";\n\t\t\tbtn.textContent = formatFrameButtonLabel(frame.timestamp);\n\t\t\tvar loadState = getFrameLoadState(frame);\n\t\t\tif (loadState === \"pending\" || loadState === \"loading\") btn.classList.add(\"preload-pending\");\n\t\t\tif (loadState === \"loaded\") btn.classList.add(\"preload-loaded\");\n\t\t\tif (index === state.selectedFrameIndex) btn.classList.add(\"active\");\n\t\t\tbtn.addEventListener(\"click\", function() {\n\t\t\t\tstopAnimation();\n\t\t\t\tselectFrameByIndex(index, true);\n\t\t\t});\n\t\t\tcontainer.appendChild(btn);\n\t\t});\n\t}\n\n\tfunction isMobileViewport() {\n\t\treturn window.innerWidth <= 768;\n\t}\n\n\tfunction getMinLabelSpacingPx(stepMinutes) {\n\t\tif (stepMinutes <= 10) {\n\t\t\treturn isMobileViewport() ? 76 : 54;\n\t\t}\n\t\tif (stepMinutes === 60) {\n\t\t\treturn isMobileViewport() ? 64 : 48;\n\t\t}\n\t\treturn isMobileViewport() ? 52 : 40;\n\t}\n\n\tfunction getFrameLabelCandidateIndexes(frames, stepMinutes) {\n\t\tvar labelIndexes = [];\n\t\tvar isMobile = isMobileViewport();\n\t\tvar i;\n\t\tvar dateObj;\n\t\tvar minute;\n\n\t\tfor (i = 0; i < frames.length; i += 1) {\n\t\t\tif (!frames[i].timestamp) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tdateObj = parseTimestampUTC(frames[i].timestamp);\n\t\t\tif (!dateObj) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tminute = dateObj.getUTCMinutes();\n\n\t\t\tif (stepMinutes <= 10) {\n\t\t\t\tif (isMobile ? minute === 0 : (minute === 0 || minute === 30)) {\n\t\t\t\t\tlabelIndexes.push(i);\n\t\t\t\t}\n\t\t\t} else if (stepMinutes === 60) {\n\t\t\t\tif (minute === 0) {\n\t\t\t\t\tlabelIndexes.push(i);\n\t\t\t\t}\n\t\t\t} else if (stepMinutes >= 360) {\n\t\t\t\tlabelIndexes.push(i);\n\t\t\t}\n\t\t}\n\n\t\tif (!labelIndexes.length && frames.length) {\n\t\t\tlabelIndexes.push(0);\n\t\t\tif (frames.length > 1) {\n\t\t\t\tlabelIndexes.push(frames.length - 1);\n\t\t\t}\n\t\t}\n\n\t\treturn labelIndexes;\n\t}\n\n\tfunction filterIndexesByMinSpacing(labelIndexes, frameCount, sliderWidth, minSpacingPx) {\n\t\tvar filtered = [];\n\n\t\tlabelIndexes.forEach(function(idx) {\n\t\t\tif (!filtered.length) {\n\t\t\t\tfiltered.push(idx);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar prevIdx = filtered[filtered.length - 1];\n\t\t\tvar prevPx = (prevIdx \/ Math.max(1, frameCount - 1)) * sliderWidth;\n\t\t\tvar currentPx = (idx \/ Math.max(1, frameCount - 1)) * sliderWidth;\n\n\t\t\tif (currentPx - prevPx >= minSpacingPx) {\n\t\t\t\tfiltered.push(idx);\n\t\t\t}\n\t\t});\n\n\t\tif (labelIndexes.length) {\n\t\t\tvar lastCandidate = labelIndexes[labelIndexes.length - 1];\n\t\t\tvar lastFiltered = filtered[filtered.length - 1];\n\t\t\tif (lastFiltered !== lastCandidate) {\n\t\t\t\tif (filtered.length > 1) {\n\t\t\t\t\tvar beforeLast = filtered[filtered.length - 2];\n\t\t\t\t\tvar beforeLastPx = (beforeLast \/ Math.max(1, frameCount - 1)) * sliderWidth;\n\t\t\t\t\tvar lastCandidatePx = (lastCandidate \/ Math.max(1, frameCount - 1)) * sliderWidth;\n\t\t\t\t\tif (lastCandidatePx - beforeLastPx < minSpacingPx) {\n\t\t\t\t\t\tfiltered.pop();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfiltered.push(lastCandidate);\n\t\t\t}\n\t\t}\n\n\t\treturn filtered;\n\t}\n\n\tfunction appendFrameSliderLabel(labelsContainer, frames, idx) {\n\t\tvar label = document.createElement(\"div\");\n\t\tlabel.className = \"hour-label-marker\";\n\t\tlabel.textContent = formatFrameButtonLabel(frames[idx].timestamp);\n\n\t\tif (idx === 0) {\n\t\t\tlabel.classList.add(\"first\");\n\t\t} else if (idx === frames.length - 1) {\n\t\t\tlabel.classList.add(\"last\");\n\t\t\tlabel.style.left = ((idx \/ Math.max(1, frames.length - 1)) * 100) + \"%\";\n\t\t} else {\n\t\t\tlabel.style.left = ((idx \/ Math.max(1, frames.length - 1)) * 100) + \"%\";\n\t\t}\n\n\t\tlabelsContainer.appendChild(label);\n\t}\n\n\tfunction renderFrameSlider() {\n\t\tvar slider = document.getElementById(\"synFrameSlider\");\n\t\tvar valueEl = document.getElementById(\"synFrameValue\");\n\t\tvar labels = document.getElementById(\"synFrameLabels\");\n\t\tvar dateCutoffs = document.getElementById(\"synDateCutoffs\");\n\n\t\tif (!state.frames.length) {\n\t\t\tvalueEl.textContent = \"--\";\n\t\t\tlabels.innerHTML = \"\";\n\t\t\tdateCutoffs.innerHTML = \"\";\n\t\t\treturn;\n\t\t}\n\n\t\tslider.min = \"0\";\n\t\tslider.max = String(state.frames.length - 1);\n\t\tslider.value = String(state.selectedFrameIndex);\n\t\tvar activeFrame = state.frames[state.selectedFrameIndex];\n\t\tvalueEl.textContent = formatFrameButtonLabel(activeFrame.timestamp);\n\n\t\tvar step = (getCurrentParamConfig() || {}).stepMinutes || 10;\n\t\tvar candidateIndexes = getFrameLabelCandidateIndexes(state.frames, step);\n\t\tvar sliderWidth = Math.max(1, slider.clientWidth || slider.offsetWidth || 1);\n\t\tvar labelIndexes = filterIndexesByMinSpacing(\n\t\t\tcandidateIndexes,\n\t\t\tstate.frames.length,\n\t\t\tsliderWidth,\n\t\t\tgetMinLabelSpacingPx(step)\n\t\t);\n\n\t\tlabels.innerHTML = \"\";\n\t\tlabelIndexes.forEach(function(idx) {\n\t\t\tappendFrameSliderLabel(labels, state.frames, idx);\n\t\t});\n\n\t\tdateCutoffs.innerHTML = \"\";\n\t\tif (isMobileViewport()) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar lastDateLabel = \"\";\n\t\tvar i;\n\t\tfor (i = 0; i < state.frames.length; i += 1) {\n\t\t\tif (!state.frames[i].timestamp) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvar dateLabel = formatFrameDateLabel(state.frames[i].timestamp);\n\t\t\tif (i === 0 || dateLabel !== lastDateLabel) {\n\t\t\t\tvar marker = document.createElement(\"div\");\n\t\t\t\tmarker.className = \"date-cutoff-marker\" + (i === 0 ? \" first\" : \"\");\n\t\t\t\tmarker.textContent = dateLabel;\n\t\t\t\tif (state.frames.length > 1 && i > 0) {\n\t\t\t\t\tmarker.style.left = ((i \/ (state.frames.length - 1)) * 100) + \"%\";\n\t\t\t\t}\n\t\t\t\tdateCutoffs.appendChild(marker);\n\t\t\t\tlastDateLabel = dateLabel;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction renderFrameGradient() {\n\t\tvar slider = document.getElementById(\"synFrameSlider\");\n\t\tif (!state.frames.length) {\n\t\t\tslider.style.background = \"#e0e0e0\";\n\t\t\treturn;\n\t\t}\n\t\tvar loadedEnd = -1;\n\t\tfor (var j = 0; j < state.frames.length; j += 1) {\n\t\t\tif (getFrameLoadState(state.frames[j]) === \"loaded\") {\n\t\t\t\tloadedEnd = j;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tvar denominator = Math.max(1, state.frames.length - 1);\n\t\tvar loadedPercent = loadedEnd >= 0 ? (loadedEnd \/ denominator) * 100 : 0;\n\t\tslider.style.background = \"linear-gradient(to right, #c7c7c7 0%, #c7c7c7 \" + loadedPercent + \"%, #e0e0e0 \" + loadedPercent + \"%, #e0e0e0 100%)\";\n\t}\n\n\tfunction attachImage(frame) {\n\t\treturn new Promise(function(resolve, reject) {\n\t\t\tvar img = new Image();\n\t\t\tvar requestUrl = getFrameRequestUrl(frame);\n\t\t\timg.onload = function() { resolve(img); };\n\t\t\timg.onerror = function() { reject(new Error(\"load failed\")); };\n\t\t\timg.src = requestUrl;\n\t\t});\n\t}\n\n\tfunction ensureFrameImage(frame) {\n\t\tvar key = getFrameCacheKey(frame);\n\t\tif (state.imageCache[key]) {\n\t\t\treturn Promise.resolve(state.imageCache[key]);\n\t\t}\n\t\tif (state.imageLoadPromises[key]) {\n\t\t\treturn state.imageLoadPromises[key];\n\t\t}\n\t\tstate.imageLoadPromises[key] = attachImage(frame)\n\t\t\t.then(function(loaded) {\n\t\t\t\tstate.imageCache[key] = loaded;\n\t\t\t\tdelete state.imageLoadPromises[key];\n\t\t\t\trenderFrameButtons();\n\t\t\t\trenderFrameSlider();\n\t\t\t\trenderFrameGradient();\n\t\t\t\treturn loaded;\n\t\t\t})\n\t\t\t.catch(function(err) {\n\t\t\t\tdelete state.imageLoadPromises[key];\n\t\t\t\trenderFrameButtons();\n\t\t\t\trenderFrameSlider();\n\t\t\t\trenderFrameGradient();\n\t\t\t\tthrow err;\n\t\t\t});\n\t\treturn state.imageLoadPromises[key];\n\t}\n\n\tfunction buildPreloadOrder(frames, centerIndex) {\n\t\tvar order = [];\n\t\tvar added = {};\n\t\tfunction addFrame(index) {\n\t\t\tif (index < 0 || index >= frames.length || added[index]) return;\n\t\t\tadded[index] = true;\n\t\t\tvar frame = frames[index];\n\t\t\tvar key = getFrameCacheKey(frame);\n\t\t\tif (!state.imageCache[key] && !state.imageLoadPromises[key]) {\n\t\t\t\torder.push(frame);\n\t\t\t}\n\t\t}\n\t\taddFrame(centerIndex);\n\t\tfor (var offset = 1; offset < frames.length; offset += 1) {\n\t\t\taddFrame(centerIndex + offset);\n\t\t\taddFrame(centerIndex - offset);\n\t\t}\n\t\treturn order;\n\t}\n\n\tasync function processPreloadQueue(generation) {\n\t\tif (state.isPreloading) return;\n\t\tstate.isPreloading = true;\n\t\ttry {\n\t\t\twhile (generation === state.preloadGeneration && state.preloadQueue.length > 0) {\n\t\t\t\tvar batch = state.preloadQueue.splice(0, 4);\n\t\t\t\tawait Promise.all(batch.map(function(frame) {\n\t\t\t\t\treturn ensureFrameImage(frame).catch(function() { return null; });\n\t\t\t\t}));\n\t\t\t}\n\t\t} finally {\n\t\t\tstate.isPreloading = false;\n\t\t\tif (generation !== state.preloadGeneration && state.preloadQueue.length > 0) {\n\t\t\t\tprocessPreloadQueue(state.preloadGeneration);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction scheduleFramePreload() {\n\t\tif (!state.frames.length) {\n\t\t\tstate.preloadQueue = [];\n\t\t\treturn;\n\t\t}\n\t\tstate.preloadGeneration += 1;\n\t\tvar generation = state.preloadGeneration;\n\t\tstate.preloadQueue = buildPreloadOrder(state.frames, state.selectedFrameIndex);\n\t\tif (!state.isPreloading) {\n\t\t\tprocessPreloadQueue(generation);\n\t\t}\n\t}\n\n\tfunction buildStaticFramesForCategory(catConfig) {\n\t\treturn catConfig.parameters.map(function(param) {\n\t\t\treturn {\n\t\t\t\turl: buildStaticUrl(catConfig, param),\n\t\t\t\ttimestamp: null,\n\t\t\t\tstatic: true\n\t\t\t};\n\t\t});\n\t}\n\n\tfunction getStaticParamIndex(catConfig, paramId) {\n\t\tvar i;\n\t\tfor (i = 0; i < catConfig.parameters.length; i += 1) {\n\t\t\tif (catConfig.parameters[i].id === paramId) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tfunction scheduleStaticParamPreload() {\n\t\tvar catConfig = getCurrentCategoryConfig();\n\t\tif (isTimeSeriesCategory(catConfig)) {\n\t\t\treturn;\n\t\t}\n\t\tvar frames = buildStaticFramesForCategory(catConfig);\n\t\tif (frames.length < 2) {\n\t\t\treturn;\n\t\t}\n\t\tstate.preloadGeneration += 1;\n\t\tvar generation = state.preloadGeneration;\n\t\tstate.preloadQueue = buildPreloadOrder(frames, getStaticParamIndex(catConfig, state.param));\n\t\tif (!state.isPreloading) {\n\t\t\tprocessPreloadQueue(generation);\n\t\t}\n\t}\n\n\tfunction openLightbox(src) {\n\t\tdocument.getElementById(\"synLightboxImg\").src = src;\n\t\tdocument.getElementById(\"synLightbox\").classList.add(\"active\");\n\t}\n\n\tfunction closeLightbox() {\n\t\tdocument.getElementById(\"synLightbox\").classList.remove(\"active\");\n\t\tdocument.getElementById(\"synLightboxImg\").src = \"\";\n\t}\n\n\tfunction displayImageElement(imgEl) {\n\t\tvar container = document.getElementById(\"synImages\");\n\t\tcontainer.innerHTML = \"\";\n\t\timgEl.alt = isAeroCategory(state.category) ? \"Sonda\u017c aerologiczny\" : \"Mapa synoptyczna\";\n\t\timgEl.addEventListener(\"click\", function() {\n\t\t\topenLightbox(imgEl.currentSrc || imgEl.src);\n\t\t});\n\t\tcontainer.appendChild(imgEl);\n\t\tupdateImageAnnotations(true);\n\t}\n\n\tasync function showStaticImage() {\n\t\tvar catConfig = getCurrentCategoryConfig();\n\t\tvar paramConfig = getCurrentParamConfig();\n\t\tvar frame = {\n\t\t\turl: buildStaticUrl(catConfig, paramConfig),\n\t\t\ttimestamp: null,\n\t\t\tstatic: true\n\t\t};\n\t\tvar imageToken = ++state.imageToken;\n\t\tvar cacheKey = getFrameCacheKey(frame);\n\t\tvar cachedImage = state.imageCache[cacheKey];\n\n\t\tif (cachedImage) {\n\t\t\tvar cachedDisplay = new Image();\n\t\t\tcachedDisplay.src = cachedImage.src;\n\t\t\tdisplayImageElement(cachedDisplay);\n\t\t\tshowLoader(false);\n\t\t\tshowStatus(\"\");\n\t\t\tscheduleStaticParamPreload();\n\t\t\treturn;\n\t\t}\n\n\t\tshowLoader(true);\n\t\tshowStatus(\"\");\n\t\ttry {\n\t\t\tvar loaded = await ensureFrameImage(frame);\n\t\t\tif (imageToken !== state.imageToken) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar displayImg = new Image();\n\t\t\tdisplayImg.src = loaded.src;\n\t\t\tdisplayImageElement(displayImg);\n\t\t\tshowStatus(\"\");\n\t\t\tscheduleStaticParamPreload();\n\t\t} catch (e) {\n\t\t\tif (imageToken === state.imageToken) {\n\t\t\t\tdocument.getElementById(\"synImages\").innerHTML = \"\";\n\t\t\t\tupdateImageAnnotations(false);\n\t\t\t\tshowStatus(\"Nie uda\u0142o si\u0119 wczyta\u0107 mapy. Spr\u00f3buj ponownie p\u00f3\u017aniej.\");\n\t\t\t}\n\t\t} finally {\n\t\t\tif (imageToken === state.imageToken) {\n\t\t\t\tshowLoader(false);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function showSelectedFrame() {\n\t\tvar container = document.getElementById(\"synImages\");\n\t\tcontainer.innerHTML = \"\";\n\t\tupdateImageAnnotations(false);\n\t\tif (!state.frames.length) {\n\t\t\tshowStatus(\"Brak map dla wybranego zestawu.\");\n\t\t\treturn;\n\t\t}\n\t\tvar frame = state.frames[state.selectedFrameIndex];\n\t\tvar imageToken = ++state.imageToken;\n\t\tvar cacheKey = getFrameCacheKey(frame);\n\t\tvar cachedImage = state.imageCache[cacheKey];\n\t\tif (cachedImage) {\n\t\t\tvar cachedDisplay = new Image();\n\t\t\tcachedDisplay.src = cachedImage.src;\n\t\t\tdisplayImageElement(cachedDisplay);\n\t\t\tshowLoader(false);\n\t\t\tshowStatus(\"\");\n\t\t\trenderFrameGradient();\n\t\t\treturn;\n\t\t}\n\t\tshowLoader(true);\n\t\tshowStatus(\"\");\n\t\ttry {\n\t\t\tvar loaded = await ensureFrameImage(frame);\n\t\t\tif (imageToken !== state.imageToken) return;\n\t\t\tvar displayImg = new Image();\n\t\t\tdisplayImg.src = loaded.src;\n\t\t\tdisplayImageElement(displayImg);\n\t\t\tshowStatus(\"\");\n\t\t} catch (e) {\n\t\t\tif (imageToken === state.imageToken) {\n\t\t\t\tshowStatus(\"Nie uda\u0142o si\u0119 wczyta\u0107 wybranej mapy.\");\n\t\t\t}\n\t\t} finally {\n\t\t\tif (imageToken === state.imageToken) {\n\t\t\t\tshowLoader(false);\n\t\t\t\trenderFrameGradient();\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction getTimestampMs(timestamp) {\n\t\tvar dateObj = parseTimestampUTC(timestamp);\n\t\treturn dateObj ? dateObj.getTime() : null;\n\t}\n\n\tfunction findCurrentFrameIndex(frames) {\n\t\tif (!frames.length) return 0;\n\t\tvar nowMs = Date.now();\n\t\tvar bestPastIndex = -1;\n\t\tvar bestPastTs = Number.NEGATIVE_INFINITY;\n\t\tfor (var i = 0; i < frames.length; i += 1) {\n\t\t\tif (!frames[i].timestamp) continue;\n\t\t\tvar frameTs = getTimestampMs(frames[i].timestamp);\n\t\t\tif (frameTs === null) continue;\n\t\t\tif (frameTs <= nowMs && frameTs > bestPastTs) {\n\t\t\t\tbestPastTs = frameTs;\n\t\t\t\tbestPastIndex = i;\n\t\t\t}\n\t\t}\n\t\treturn bestPastIndex !== -1 ? bestPastIndex : frames.length - 1;\n\t}\n\n\tfunction selectFrameByIndex(index, shouldDisplay) {\n\t\tif (!state.frames.length) {\n\t\t\tstate.selectedFrameIndex = 0;\n\t\t\trenderFrameButtons();\n\t\t\trenderFrameSlider();\n\t\t\trenderFrameGradient();\n\t\t\treturn;\n\t\t}\n\t\tstate.selectedFrameIndex = Math.max(0, Math.min(index, state.frames.length - 1));\n\t\trenderFrameButtons();\n\t\trenderFrameSlider();\n\t\trenderFrameGradient();\n\t\tscheduleFramePreload();\n\t\tif (shouldDisplay) {\n\t\t\tshowSelectedFrame();\n\t\t}\n\t}\n\n\tfunction stopAnimation() {\n\t\tif (state.animationTimer) {\n\t\t\tclearInterval(state.animationTimer);\n\t\t\tstate.animationTimer = null;\n\t\t}\n\t\tstate.isAnimating = false;\n\t\tvar btn = document.getElementById(\"synAnimateBtn\");\n\t\tbtn.classList.remove(\"active\");\n\t\tbtn.textContent = \"\\u25B6\";\n\t}\n\n\tfunction toggleAnimation() {\n\t\tif (state.isAnimating) {\n\t\t\tstopAnimation();\n\t\t\treturn;\n\t\t}\n\t\tif (state.frames.length < 2) return;\n\t\tstate.isAnimating = true;\n\t\tvar btn = document.getElementById(\"synAnimateBtn\");\n\t\tbtn.classList.add(\"active\");\n\t\tbtn.textContent = \"\\u23F8\";\n\t\tstate.animationTimer = setInterval(function() {\n\t\t\tif (!state.frames.length) {\n\t\t\t\tstopAnimation();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar next = state.selectedFrameIndex + 1;\n\t\t\tif (next >= state.frames.length) {\n\t\t\t\tnext = 0;\n\t\t\t}\n\t\t\tselectFrameByIndex(next, true);\n\t\t}, 800);\n\t}\n\n\tfunction startAutoRefreshTimer() {\n\t\tif (state.autoRefreshTimer) {\n\t\t\tclearInterval(state.autoRefreshTimer);\n\t\t\tstate.autoRefreshTimer = null;\n\t\t}\n\t\tstate.autoRefreshTimer = setInterval(function() {\n\t\t\trefreshView(\"auto\");\n\t\t}, AUTO_REFRESH_MS);\n\t}\n\n\tasync function refreshView(reason) {\n\t\tif (state.isRefreshing) {\n\t\t\tstate.pendingRefresh = true;\n\t\t\treturn;\n\t\t}\n\t\tstate.cacheVersion += 1;\n\t\tstate.imageCache = {};\n\t\tstate.imageLoadPromises = {};\n\t\tstate.preloadQueue = [];\n\t\tstate.preloadGeneration += 1;\n\t\tstate.imageToken += 1;\n\t\tstate.isRefreshing = true;\n\n\t\tvar catConfig = getCurrentCategoryConfig();\n\t\tvar paramConfig = getCurrentParamConfig();\n\t\tvar previousTimestamp = state.frames[state.selectedFrameIndex]\n\t\t\t? state.frames[state.selectedFrameIndex].timestamp\n\t\t\t: null;\n\t\tvar refreshToken = ++state.refreshToken;\n\t\tvar forceLatest = reason === \"init\" || reason === \"category\" || reason === \"param\" || reason === \"latest\";\n\n\t\tdocument.getElementById(\"synImages\").innerHTML = \"\";\n\t\tupdateImageAnnotations(false);\n\t\tshowLoader(true);\n\t\tshowStatus(\"\");\n\t\tupdateTimeControlsVisibility();\n\n\t\ttry {\n\t\t\tif (isTimeSeriesCategory(catConfig)) {\n\t\t\t\tvar frames = await loadTimeSeriesFrames(catConfig, paramConfig);\n\t\t\t\tif (refreshToken !== state.refreshToken) return;\n\n\t\t\t\tstate.frames = frames;\n\t\t\t\tif (!frames.length) {\n\t\t\t\t\tstate.selectedFrameIndex = 0;\n\t\t\t\t\trenderFrameButtons();\n\t\t\t\t\trenderFrameSlider();\n\t\t\t\t\tupdateTimeControlsVisibility();\n\t\t\t\t\tshowStatus(\"Brak dost\u0119pnych map dla wybranego zestawu.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (previousTimestamp && !forceLatest) {\n\t\t\t\t\tvar matched = frames.findIndex(function(f) { return f.timestamp === previousTimestamp; });\n\t\t\t\t\tstate.selectedFrameIndex = matched !== -1 ? matched : findCurrentFrameIndex(frames);\n\t\t\t\t} else {\n\t\t\t\t\tstate.selectedFrameIndex = findCurrentFrameIndex(frames);\n\t\t\t\t}\n\n\t\t\t\trenderFrameButtons();\n\t\t\t\trenderFrameSlider();\n\t\t\t\trenderFrameGradient();\n\t\t\t\tupdateTimeControlsVisibility();\n\t\t\t\tscheduleFramePreload();\n\t\t\t\tawait showSelectedFrame();\n\t\t\t} else {\n\t\t\t\tstate.frames = [];\n\t\t\t\tupdateTimeControlsVisibility();\n\t\t\t\tawait showStaticImage();\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tshowStatus(\"Wyst\u0105pi\u0142 b\u0142\u0105d podczas od\u015bwie\u017cania danych.\");\n\t\t} finally {\n\t\t\tstate.lastRefreshAt = new Date();\n\t\t\tupdateRefreshInfo();\n\t\t\tshowLoader(false);\n\t\t\tstate.isRefreshing = false;\n\t\t\tif (state.pendingRefresh) {\n\t\t\t\tstate.pendingRefresh = false;\n\t\t\t\trefreshView(\"pending\");\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction handleCategoryChange(catId) {\n\t\tstopAnimation();\n\t\tstate.category = catId;\n\t\tstate.param = categoriesConfig[catId].parameters[0].id;\n\t\tstate.selectedFrameIndex = 0;\n\t\tstate.frames = [];\n\t\tstate.imageToken += 1;\n\t\tdocument.getElementById(\"synImages\").innerHTML = \"\";\n\t\tdocument.getElementById(\"synFrames\").innerHTML = \"\";\n\t\tupdateImageAnnotations(false);\n\t\tshowStatus(\"\");\n\t\tresetParamUi();\n\t\trenderCategoryButtons();\n\t\trenderParamButtons();\n\t\tupdateTimeControlsVisibility();\n\t\trefreshView(\"category\");\n\t}\n\n\tfunction updateParamButtonsActiveState() {\n\t\tvar container = document.getElementById(\"synParamButtons\");\n\t\tcontainer.querySelectorAll(\"button\").forEach(function(btn) {\n\t\t\tbtn.classList.toggle(\"active\", btn.dataset.value === state.param);\n\t\t});\n\t}\n\n\tfunction handleParamChange(paramId) {\n\t\tif (state.param === paramId) return;\n\t\tstopAnimation();\n\t\tstate.param = paramId;\n\t\tstate.selectedFrameIndex = 0;\n\t\tupdateParamButtonsActiveState();\n\t\tif (isTimeSeriesCategory(getCurrentCategoryConfig())) {\n\t\t\trefreshView(\"param\");\n\t\t\treturn;\n\t\t}\n\t\tshowStaticImage();\n\t}\n\n\tfunction setupEvents() {\n\t\tdocument.getElementById(\"synFrameSlider\").addEventListener(\"input\", function(event) {\n\t\t\tstopAnimation();\n\t\t\tselectFrameByIndex(parseInt(event.target.value, 10) || 0, true);\n\t\t});\n\t\tdocument.getElementById(\"synAnimateBtn\").addEventListener(\"click\", toggleAnimation);\n\t\tdocument.getElementById(\"synLatestBtn\").addEventListener(\"click\", function() {\n\t\t\tstopAnimation();\n\t\t\tif (!state.frames.length) return;\n\t\t\tselectFrameByIndex(findCurrentFrameIndex(state.frames), true);\n\t\t});\n\t\tdocument.getElementById(\"synRefreshBtn\").addEventListener(\"click\", function() {\n\t\t\trefreshView(\"manual\");\n\t\t});\n\t\tdocument.getElementById(\"synLightbox\").addEventListener(\"click\", function(event) {\n\t\t\tif (event.target.id === \"synLightbox\" || event.target.id === \"synLightboxClose\") {\n\t\t\t\tcloseLightbox();\n\t\t\t}\n\t\t});\n\n\t\tvar resizeTimer = null;\n\t\twindow.addEventListener(\"resize\", function() {\n\t\t\tif (!state.frames.length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclearTimeout(resizeTimer);\n\t\t\tresizeTimer = setTimeout(function() {\n\t\t\t\trenderFrameSlider();\n\t\t\t}, 150);\n\t\t});\n\n\t\tdocument.addEventListener(\"keydown\", function(event) {\n\t\t\tvar tag = event.target && event.target.tagName ? event.target.tagName.toUpperCase() : \"\";\n\t\t\tif (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") return;\n\n\t\t\tif (event.key === \"Escape\") {\n\t\t\t\tcloseLightbox();\n\t\t\t\tstopAnimation();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (event.key >= \"1\" && event.key <= \"6\") {\n\t\t\t\tvar idx = parseInt(event.key, 10) - 1;\n\t\t\t\tif (idx < categoryOrder.length && categoryOrder[idx] !== state.category) {\n\t\t\t\t\thandleCategoryChange(categoryOrder[idx]);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (event.key === \"ArrowLeft\" || event.key === \"ArrowRight\") {\n\t\t\t\tif (!isTimeSeriesCategory(getCurrentCategoryConfig())) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (!state.frames.length) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tstopAnimation();\n\t\t\t\tvar shift = event.key === \"ArrowLeft\" ? -1 : 1;\n\t\t\t\tvar next = state.selectedFrameIndex + shift;\n\t\t\t\tif (next < 0 || next >= state.frames.length) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tselectFrameByIndex(next, true);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (event.key === \"ArrowUp\" || event.key === \"ArrowDown\") {\n\t\t\t\tvar catConfig = getCurrentCategoryConfig();\n\t\t\t\tvar params = catConfig.parameters;\n\t\t\t\tif (!params.length || params.length <= 1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tvar currentIdx = 0;\n\t\t\t\tfor (var i = 0; i < params.length; i += 1) {\n\t\t\t\t\tif (params[i].id === state.param) currentIdx = i;\n\t\t\t\t}\n\t\t\t\tvar direction = event.key === \"ArrowUp\" ? -1 : 1;\n\t\t\t\tvar nextIdx = (currentIdx + direction + params.length) % params.length;\n\t\t\t\thandleParamChange(params[nextIdx].id);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (event.key === \"a\" || event.key === \"A\") {\n\t\t\t\tevent.preventDefault();\n\t\t\t\ttoggleAnimation();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.key === \"r\" || event.key === \"R\") {\n\t\t\t\tevent.preventDefault();\n\t\t\t\trefreshView(\"keyboard\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.key === \"n\" || event.key === \"N\") {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (!state.frames.length) return;\n\t\t\t\tstopAnimation();\n\t\t\t\tselectFrameByIndex(findCurrentFrameIndex(state.frames), true);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction init() {\n\t\trenderCategoryButtons();\n\t\trenderParamButtons();\n\t\tupdateTimeControlsVisibility();\n\t\tsetupEvents();\n\t\tupdateRefreshInfo();\n\t\tstartAutoRefreshTimer();\n\t\trefreshView(\"init\");\n\t}\n\n\tif (document.readyState === \"loading\") {\n\t\tdocument.addEventListener(\"DOMContentLoaded\", init);\n\t} else {\n\t\tinit();\n\t}\n})();\nconsole.log(\"Autor Bart\u0142omiej Sobczyk 2026\");\n<\/script>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Kategoria: Parametr: Czas (UTC): \ud83d\udca1 Skr\u00f3ty klawiszowe: 1-6 | Kategoria \u2190 \u2192 | Zmiana czasu \u2191 \u2193 | Zmiana parametru A | Animacja N | Najnowsza mapa R | Od\u015bwie\u017c Czas (UTC): &#8212; Ostatnie sprawdzenie: jeszcze nie wykonano &#9654; N R \u0141adowanie mapy&#8230; Sonda\u017c aerologiczny, zwany r\u00f3wnie\u017c radiosonda\u017cem, to pomiary warto\u015bci wielko\u015bci fizycznych, wykonane przy [&hellip;]<\/p>\n","protected":false},"author":11,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"ocean_post_layout":"","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"","ocean_second_sidebar":"","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"","ocean_custom_header_template":"","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"","ocean_menu_typo_font_family":"","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":""},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.5.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Pogoda bie\u017c\u0105ca - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB<\/title>\n<meta name=\"description\" content=\"Pogoda bie\u017c\u0105ca \u2013 przegl\u0105d aktualnych danych pomiarowych ze stacji synoptycznych, radar\u00f3w czy sonda\u017cy aerologicznych.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cmm.imgw.pl\/?page_id=49533\" \/>\n<meta property=\"og:locale\" content=\"pl_PL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Pogoda bie\u017c\u0105ca - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB\" \/>\n<meta property=\"og:description\" content=\"Pogoda bie\u017c\u0105ca \u2013 przegl\u0105d aktualnych danych pomiarowych ze stacji synoptycznych, radar\u00f3w czy sonda\u017cy aerologicznych.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cmm.imgw.pl\/?page_id=49533\" \/>\n<meta property=\"og:site_name\" content=\"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Meteoimgw\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-29T12:33:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cmm.imgw.pl\/wp-content\/uploads\/2025\/10\/MODELE_LOGO_UNIFIKACJA_v2.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1356\" \/>\n\t<meta property=\"og:image:height\" content=\"365\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@IMGW_CMM\" \/>\n<meta name=\"twitter:label1\" content=\"Szacowany czas czytania\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minuta\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cmm.imgw.pl\/?page_id=49533\",\"url\":\"https:\/\/cmm.imgw.pl\/?page_id=49533\",\"name\":\"Pogoda bie\u017c\u0105ca - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB\",\"isPartOf\":{\"@id\":\"https:\/\/cmm.imgw.pl\/#website\"},\"datePublished\":\"2026-02-25T09:56:36+00:00\",\"dateModified\":\"2026-06-29T12:33:46+00:00\",\"description\":\"Pogoda bie\u017c\u0105ca \u2013 przegl\u0105d aktualnych danych pomiarowych ze stacji synoptycznych, radar\u00f3w czy sonda\u017cy aerologicznych.\",\"breadcrumb\":{\"@id\":\"https:\/\/cmm.imgw.pl\/?page_id=49533#breadcrumb\"},\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cmm.imgw.pl\/?page_id=49533\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cmm.imgw.pl\/?page_id=49533#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cmm.imgw.pl\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Pogoda bie\u017c\u0105ca\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cmm.imgw.pl\/#website\",\"url\":\"https:\/\/cmm.imgw.pl\/\",\"name\":\"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB\",\"description\":\"CMOK-LMM Laboratorium pe\u0142ni pa\u0144stwow\u0105 s\u0142u\u017cb\u0119 hydrologiczno-meteorologiczn\u0105 w zakresie numerycznych prognoz pogody, kt\u00f3rego zadaniem jest konsolidacja kompetencji w obszarze modelowania zjawisk pogodowych oraz dalszego rozwoju numerycznych modeli pogody (NMP).\",\"publisher\":{\"@id\":\"https:\/\/cmm.imgw.pl\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cmm.imgw.pl\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pl-PL\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cmm.imgw.pl\/#organization\",\"name\":\"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB\",\"url\":\"https:\/\/cmm.imgw.pl\/\",\"sameAs\":[\"https:\/\/www.facebook.com\/Meteoimgw\/\",\"https:\/\/twitter.com\/IMGW_CMM\"],\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\/\/cmm.imgw.pl\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/cmm.imgw.pl\/wp-content\/uploads\/2025\/10\/MODELE_LOGO_UNIFIKACJA_v2.png\",\"contentUrl\":\"https:\/\/cmm.imgw.pl\/wp-content\/uploads\/2025\/10\/MODELE_LOGO_UNIFIKACJA_v2.png\",\"width\":1356,\"height\":365,\"caption\":\"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB\"},\"image\":{\"@id\":\"https:\/\/cmm.imgw.pl\/#\/schema\/logo\/image\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Pogoda bie\u017c\u0105ca - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","description":"Pogoda bie\u017c\u0105ca \u2013 przegl\u0105d aktualnych danych pomiarowych ze stacji synoptycznych, radar\u00f3w czy sonda\u017cy aerologicznych.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cmm.imgw.pl\/?page_id=49533","og_locale":"pl_PL","og_type":"article","og_title":"Pogoda bie\u017c\u0105ca - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","og_description":"Pogoda bie\u017c\u0105ca \u2013 przegl\u0105d aktualnych danych pomiarowych ze stacji synoptycznych, radar\u00f3w czy sonda\u017cy aerologicznych.","og_url":"https:\/\/cmm.imgw.pl\/?page_id=49533","og_site_name":"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","article_publisher":"https:\/\/www.facebook.com\/Meteoimgw\/","article_modified_time":"2026-06-29T12:33:46+00:00","og_image":[{"width":1356,"height":365,"url":"https:\/\/cmm.imgw.pl\/wp-content\/uploads\/2025\/10\/MODELE_LOGO_UNIFIKACJA_v2.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_site":"@IMGW_CMM","twitter_misc":{"Szacowany czas czytania":"1 minuta"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/cmm.imgw.pl\/?page_id=49533","url":"https:\/\/cmm.imgw.pl\/?page_id=49533","name":"Pogoda bie\u017c\u0105ca - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","isPartOf":{"@id":"https:\/\/cmm.imgw.pl\/#website"},"datePublished":"2026-02-25T09:56:36+00:00","dateModified":"2026-06-29T12:33:46+00:00","description":"Pogoda bie\u017c\u0105ca \u2013 przegl\u0105d aktualnych danych pomiarowych ze stacji synoptycznych, radar\u00f3w czy sonda\u017cy aerologicznych.","breadcrumb":{"@id":"https:\/\/cmm.imgw.pl\/?page_id=49533#breadcrumb"},"inLanguage":"pl-PL","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cmm.imgw.pl\/?page_id=49533"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/cmm.imgw.pl\/?page_id=49533#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cmm.imgw.pl\/"},{"@type":"ListItem","position":2,"name":"Pogoda bie\u017c\u0105ca"}]},{"@type":"WebSite","@id":"https:\/\/cmm.imgw.pl\/#website","url":"https:\/\/cmm.imgw.pl\/","name":"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","description":"CMOK-LMM Laboratorium pe\u0142ni pa\u0144stwow\u0105 s\u0142u\u017cb\u0119 hydrologiczno-meteorologiczn\u0105 w zakresie numerycznych prognoz pogody, kt\u00f3rego zadaniem jest konsolidacja kompetencji w obszarze modelowania zjawisk pogodowych oraz dalszego rozwoju numerycznych modeli pogody (NMP).","publisher":{"@id":"https:\/\/cmm.imgw.pl\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cmm.imgw.pl\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"pl-PL"},{"@type":"Organization","@id":"https:\/\/cmm.imgw.pl\/#organization","name":"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","url":"https:\/\/cmm.imgw.pl\/","sameAs":["https:\/\/www.facebook.com\/Meteoimgw\/","https:\/\/twitter.com\/IMGW_CMM"],"logo":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/cmm.imgw.pl\/#\/schema\/logo\/image\/","url":"https:\/\/cmm.imgw.pl\/wp-content\/uploads\/2025\/10\/MODELE_LOGO_UNIFIKACJA_v2.png","contentUrl":"https:\/\/cmm.imgw.pl\/wp-content\/uploads\/2025\/10\/MODELE_LOGO_UNIFIKACJA_v2.png","width":1356,"height":365,"caption":"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB"},"image":{"@id":"https:\/\/cmm.imgw.pl\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=\/wp\/v2\/pages\/49533"}],"collection":[{"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=49533"}],"version-history":[{"count":148,"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=\/wp\/v2\/pages\/49533\/revisions"}],"predecessor-version":[{"id":50432,"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=\/wp\/v2\/pages\/49533\/revisions\/50432"}],"wp:attachment":[{"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=49533"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}