{"id":49784,"date":"2026-04-07T13:22:11","date_gmt":"2026-04-07T11:22:11","guid":{"rendered":"https:\/\/cmm.imgw.pl\/?page_id=49784"},"modified":"2026-07-16T20:27:00","modified_gmt":"2026-07-16T18:27:00","slug":"prognozy-srednioterminowe","status":"publish","type":"page","link":"https:\/\/cmm.imgw.pl\/?page_id=49784","title":{"rendered":"\u015arednioterminowe"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"49784\" class=\"elementor elementor-49784\">\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=\"midterm-app\" class=\"forecast-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<div class=\"model-group-title\">Obszar<\/div>\n\t\t\t\t<div id=\"midtermRegions\" class=\"buttons\"><\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"midterm-select-grid\">\n\t\t\t\t<div class=\"section midterm-models-section\">\n\t\t\t\t\t<div id=\"midtermModels\" class=\"buttons models-buttons\"><\/div>\n\t\t\t\t<\/div>\n\n\t\t\t\t<div class=\"section midterm-params-section\">\n\t\t\t\t\t<div class=\"model-group-title\">Parametr<\/div>\n\t\t\t\t\t<div id=\"midtermParams\" class=\"buttons params-buttons\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"section\" id=\"midtermFramesSection\">\n\t\t\t\t<div class=\"model-group-title\">Termin prognozy<\/div>\n\t\t\t\t<div id=\"midtermFrames\" class=\"buttons frames-buttons\"><\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"section compare-section\" id=\"midtermCompareSection\">\n\t\t\t\t<div class=\"compare-actions-row\">\n\t\t\t\t\t<button id=\"midtermCompareBtn\" class=\"compare-action-btn\" type=\"button\">\u229e Por\u00f3wnaj modele<\/button>\n\t\t\t\t\t<button id=\"midtermCompareParamsBtn\" class=\"compare-action-btn\" type=\"button\">\u229e Por\u00f3wnaj parametry<\/button>\n\t\t\t\t\t<button id=\"midtermAnimateBtnLeft\" class=\"compare-action-btn\" type=\"button\" style=\"display: none;\">\u25b6 Animuj<\/button>\n\t\t\t\t\t<button id=\"midtermFullscreenBtn\" class=\"compare-action-btn\" type=\"button\" style=\"display: none;\">\u26f6 Pe\u0142ny ekran<\/button>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"keyboard-info\">\n\t\t\t\t<strong>\ud83d\udca1 Skroty klawiszowe:<\/strong><br>\n\t\t\t\tQ\/E | Zmiana obszaru<br>\n\t\t\t\t<span id=\"midtermModelShortcutRow\">1-8 | Zmiana modelu<br><\/span>\n\t\t\t\t<span id=\"midtermFramesShortcutRow\">\u2190 \u2192 | Zmiana terminu<br><\/span>\n\t\t\t\t\u2191 \u2193 | Zmiana parametru<br>\n\t\t\t\tC | Por\u00f3wnanie modeli<br>\n\t\t\t\tP | Por\u00f3wnanie parametr\u00f3w<br>\n\t\t\t\t<span id=\"midtermAnimShortcutRow\">A | Animacja<br><\/span>\n\t\t\t\t<span id=\"midtermFullscreenShortcutRow\" style=\"display: none;\">F | Pe\u0142ny ekran por\u00f3wnania<br><\/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=\"midtermSliderWrap\">\n\t\t\t\t\t<input type=\"range\" id=\"midtermFrameSlider\" class=\"horizontal-slider\" min=\"0\" max=\"0\" step=\"1\" value=\"0\" aria-label=\"Wybierz termin\">\n\t\t\t\t\t<div class=\"hour-labels\" id=\"midtermFrameLabels\"><\/div>\n\t\t\t\t<\/div>\n\n\t\t\t\t<div id=\"midtermStatus\" class=\"date-warning\"><\/div>\n\t\t\t\t<div id=\"midtermLoader\" 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=\"midtermImages\" class=\"images\"><\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n<div class=\"lightbox\" id=\"midtermLightbox\">\n\t<span class=\"lightbox-close\" id=\"midtermLightboxClose\">&times;<\/span>\n\t<img id=\"midtermLightboxImg\" src=\"\" alt=\"Powiekszony obraz prognozy srednioterminowej\">\n<\/div>\n\n<div id=\"midtermCompareFullscreen\" class=\"compare-fullscreen\">\n\t<div id=\"midtermCompareFullscreenGrid\" class=\"compare-fullscreen-grid\"><\/div>\n<\/div>\n\n<div id=\"midtermCompareModal\" class=\"compare-modal\" style=\"display: none;\">\n\t<div class=\"compare-modal-content\">\n\t\t<div class=\"compare-modal-header\">\n\t\t\t<div class=\"model-group-title\">Wybierz modele do por\u00f3wnania<\/div>\n\t\t\t<button id=\"midtermCompareClose\" class=\"compare-modal-close\" type=\"button\">\u2715<\/button>\n\t\t<\/div>\n\t\t<div class=\"compare-modal-body\">\n\t\t\t<div id=\"midtermCompareSelectGrid\" class=\"compare-modal-select-grid\">\n\t\t\t\t<div id=\"midtermCompareParamSection\" class=\"compare-param-section\" style=\"display: none;\">\n\t\t\t\t\t<div class=\"model-group-title\">Parametr do por\u00f3wnania<\/div>\n\t\t\t\t\t<div id=\"midtermCompareParams\" class=\"compare-params-list\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div id=\"midtermCompareModelSection\" class=\"compare-model-section\">\n\t\t\t\t\t<div class=\"model-group-title\">Modele do por\u00f3wnania<\/div>\n\t\t\t\t\t<div id=\"midtermCompareList\" class=\"compare-models-list\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t<div class=\"compare-modal-footer\">\n\t\t\t<button id=\"midtermCompareConfirm\" class=\"confirm-btn\" type=\"button\">Por\u00f3wnaj<\/button>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n<div id=\"midtermCompareParamsModal\" class=\"compare-modal\" style=\"display: none;\">\n\t<div class=\"compare-modal-content\">\n\t\t<div class=\"compare-modal-header\">\n\t\t\t<div class=\"model-group-title\">Wybierz parametry do por\u00f3wnania<\/div>\n\t\t\t<button id=\"midtermCompareParamsClose\" class=\"compare-modal-close\" type=\"button\">\u2715<\/button>\n\t\t<\/div>\n\t\t<div class=\"compare-modal-body\">\n\t\t\t<div class=\"compare-param-section\">\n\t\t\t\t<div class=\"model-group-title\">Parametry modelu <span id=\"midtermCompareParamsModelLabel\"><\/span><\/div>\n\t\t\t\t<div id=\"midtermCompareParamsMultiList\" class=\"compare-params-list\"><\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t<div class=\"compare-modal-footer\">\n\t\t\t<button id=\"midtermCompareParamsConfirm\" class=\"confirm-btn\" type=\"button\">Por\u00f3wnaj<\/button>\n\t\t<\/div>\n\t<\/div>\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: 250px;\n\t\tmax-width: 280px;\n\t}\n\n\t.midterm-select-grid {\n\t\tdisplay: contents;\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.model-group-title {\n\t\twidth: 100%;\n\t\tfont-size: 0.78em;\n\t\tfont-weight: 700;\n\t\ttext-transform: uppercase;\n\t\tletter-spacing: 0.04em;\n\t\tcolor: #5d5d5d;\n\t\tpadding: 3px 4px;\n\t\tmargin-top: 0;\n\t\tmargin-bottom: 6px;\n\t\tborder-bottom: 1px dashed #c9c9c9;\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: 5px 10px;\n\t\tmin-width: 48px;\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.9em;\n\t\tline-height: 1.2;\n\t}\n\n\t.buttons button:hover {\n\t\tbackground: #ddd;\n\t}\n\n\t.buttons button.active {\n\t\tbackground-color: rgba(86, 221, 208, 1);\n\t\tcolor: #fff;\n\t\tborder-color: #2e7d32;\n\t}\n\n\t.models-buttons button.compare-selected {\n\t\tbackground-color: rgba(86, 221, 208, 1);\n\t\tcolor: #fff;\n\t\tborder-color: #2e7d32;\n\t}\n\n\t.params-buttons button.compare-selected,\n\t.params-buttons button.compare-selected.preload-loaded,\n\t.params-buttons button.compare-selected.preload-pending,\n\t.params-buttons button.compare-selected.preload-loading {\n\t\tbackground-color: rgba(86, 221, 208, 1);\n\t\tcolor: #fff;\n\t\tborder-color: #2e7d32;\n\t}\n\n\t.models-buttons,\n\t.params-buttons {\n\t\tflex-direction: column;\n\t\talign-items: stretch;\n\t}\n\n\t#midtermRegions {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(2, minmax(0, 1fr));\n\t\twidth: 100%;\n\t}\n\n\t#midtermRegions button {\n\t\twidth: 100%;\n\t\ttext-align: center;\n\t}\n\n\t.models-buttons button,\n\t.params-buttons button {\n\t\twidth: 100%;\n\t\ttext-align: center;\n\t}\n\n\t.params-buttons button.preload-pending:not(.active):not(.compare-selected) {\n\t\tbackground: #ececec;\n\t\tborder-color: #b8b8b8;\n\t\tcolor: #7a7a7a;\n\t}\n\n\t.params-buttons button.preload-loaded:not(.active):not(.compare-selected) {\n\t\tbackground: linear-gradient(135deg, #d8d8d8 0%, #c9c9c9 100%);\n\t\tborder-color: #b1b1b1;\n\t\tcolor: #4f4f4f;\n\t}\n\n\t.params-buttons button.preload-loading:not(.active):not(.compare-selected) {\n\t\tbackground-image: repeating-linear-gradient(\n\t\t\t-45deg,\n\t\t\t#e8e8e8 0,\n\t\t\t#e8e8e8 8px,\n\t\t\t#dfdfdf 8px,\n\t\t\t#dfdfdf 16px\n\t\t);\n\t}\n\n\t.models-buttons > .model-group-title {\n\t\tmargin-top: 8px;\n\t}\n\n\t.models-buttons > .model-group-title:first-child {\n\t\tmargin-top: 0;\n\t}\n\n\t.frames-buttons {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(5, minmax(0, 1fr));\n\t\tgap: 5px;\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-size: 0.78em;\n\t\tpadding: 4px 6px;\n\t\twhite-space: nowrap;\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.frames-buttons button.preload-loading:not(.active) {\n\t\tbackground-image: repeating-linear-gradient(\n\t\t\t-45deg,\n\t\t\t#e8e8e8 0,\n\t\t\t#e8e8e8 8px,\n\t\t\t#dfdfdf 8px,\n\t\t\t#dfdfdf 16px\n\t\t);\n\t}\n\n\t.horizontal-slider-container {\n\t\twidth: 100%;\n\t\tmargin: 0 0 20px 0;\n\t\tpadding: 10px;\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\tmargin-bottom: 8px;\n\t}\n\n\t.slider-controls {\n\t\tmargin-left: auto;\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(86, 221, 208, 1);\n\t\tfont-size: 1.1em;\n\t\twidth: 40px;\n\t\theight: 40px;\n\t\tborder-radius: 8px;\n\t\tcursor: pointer;\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-size: 1.05em;\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.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: #dcdcdc;\n\t\toutline: none;\n\t}\n\n\t.horizontal-slider::-webkit-slider-thumb {\n\t\t-webkit-appearance: none;\n\t\tappearance: none;\n\t\twidth: 22px;\n\t\theight: 22px;\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.horizontal-slider::-moz-range-thumb {\n\t\twidth: 22px;\n\t\theight: 22px;\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\tmargin-top: 6px;\n\t\tcolor: #666;\n\t\tfont-size: 0.82em;\n\t\tfont-variant-numeric: tabular-nums;\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.hour-label-marker.preload-pending {\n\t\tcolor: #8f8f8f;\n\t}\n\n\t.hour-label-marker.preload-loaded {\n\t\tcolor: #7a7a7a;\n\t}\n\n\t.keyboard-info {\n\t\tfont-size: 11px;\n\t\tcolor: #555;\n\t\tmargin-top: 20px;\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\tfont-size: 12px;\n\t}\n\n\t.section.images {\n\t\tmin-height: 620px;\n\t}\n\n\t.images {\n\t\tposition: relative;\n\t\twidth: 100%;\n\t\tmin-height: 540px;\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\tposition: relative;\n\t\tbackground-color: rgba(245, 245, 245, 0.7);\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: spin 0.8s linear infinite;\n\t\tbox-shadow: 0 0 20px rgba(86, 221, 208, 0.7);\n\t}\n\n\t@keyframes spin {\n\t\t0% {\n\t\t\ttransform: rotate(0deg);\n\t\t}\n\t\t100% {\n\t\t\ttransform: rotate(360deg);\n\t\t}\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.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\tfont-weight: 500;\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\tline-height: 1;\n\t}\n\n\t.compare-modal {\n\t\tposition: fixed;\n\t\tinset: 0;\n\t\tbackground: rgba(0, 0, 0, 0.45);\n\t\tz-index: 1200;\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tpadding: 16px;\n\t}\n\n\t.compare-modal-content {\n\t\twidth: min(520px, 95vw);\n\t\tbackground: #fff;\n\t\tborder-radius: 10px;\n\t\tbox-shadow: 0 8px 28px rgba(0, 0, 0, 0.25);\n\t\toverflow: hidden;\n\t}\n\n\t.compare-modal-content.compare-modal-wide {\n\t\twidth: min(680px, 95vw);\n\t}\n\n\t.compare-modal-header {\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n\t\talign-items: center;\n\t\tpadding: 12px 14px;\n\t\tborder-bottom: 1px solid #e1e1e1;\n\t\tgap: 10px;\n\t}\n\n\t.compare-modal-close {\n\t\tborder: 1px solid #aaa;\n\t\tbackground: #fff;\n\t\tborder-radius: 6px;\n\t\twidth: 32px;\n\t\theight: 32px;\n\t\tcursor: pointer;\n\t}\n\n\t.compare-modal-body {\n\t\tpadding: 12px 14px;\n\t\tmax-height: 46vh;\n\t\toverflow: auto;\n\t}\n\n\t.compare-modal-select-grid {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n\t\tgap: 12px;\n\t\talign-items: start;\n\t}\n\n\t.compare-modal-select-grid.models-only {\n\t\tgrid-template-columns: 1fr;\n\t}\n\n\t.compare-param-section,\n\t.compare-model-section {\n\t\tmin-width: 0;\n\t\ttext-align: center;\n\t}\n\n\t.compare-param-section .model-group-title,\n\t.compare-model-section .model-group-title {\n\t\ttext-align: center;\n\t}\n\n\t.compare-models-list,\n\t.compare-params-list {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tgap: 10px;\n\t\talign-items: stretch;\n\t}\n\n\t.compare-param-section {\n\t\tmargin-bottom: 0;\n\t}\n\n\t.compare-model-item,\n\t.compare-param-item {\n\t\tpadding: 12px;\n\t\tborder: 2px solid #ddd;\n\t\tborder-radius: 8px;\n\t\tcursor: pointer;\n\t\ttransition: all 0.2s;\n\t\tbackground: #f9f9f9;\n\t\ttext-align: center;\n\t}\n\n\t.compare-model-item:hover {\n\t\tborder-color: rgba(86, 221, 208, 0.5);\n\t\tbackground: #f0f8ff;\n\t}\n\n\t.compare-param-item:hover {\n\t\tborder-color: rgba(86, 221, 208, 0.5);\n\t\tbackground: #f0f8ff;\n\t}\n\n\t.compare-model-item.selected,\n\t.compare-param-item.selected {\n\t\tborder-color: rgba(86, 221, 208, 1);\n\t\tbackground: rgba(86, 221, 208, 0.1);\n\t\tfont-weight: bold;\n\t}\n\n\t.compare-modal-footer {\n\t\tpadding: 12px 14px;\n\t\tborder-top: 1px solid #e1e1e1;\n\t\tdisplay: flex;\n\t\tjustify-content: flex-end;\n\t}\n\n\t.confirm-btn {\n\t\tborder: 1px solid #2e7d32;\n\t\tbackground: rgba(86, 221, 208, 1);\n\t\tcolor: #fff;\n\t\tborder-radius: 8px;\n\t\tpadding: 8px 14px;\n\t\tcursor: pointer;\n\t}\n\n\t.confirm-btn:disabled {\n\t\topacity: 0.5;\n\t\tcursor: not-allowed;\n\t}\n\n\t.compare-section {\n\t\ttext-align: center;\n\t}\n\n\t.compare-actions-row {\n\t\tdisplay: flex;\n\t\tgap: 6px;\n\t}\n\n\t.compare-actions-row .compare-action-btn {\n\t\tflex: 1;\n\t\tmin-width: 0;\n\t\tfont-size: 0.82em;\n\t\tpadding: 10px 6px;\n\t}\n\n\t.compare-action-btn {\n\t\tdisplay: block;\n\t\twidth: 100%;\n\t\tmargin-top: 4px;\n\t\tpadding: 10px 12px;\n\t\tborder: 2px dashed rgba(86, 221, 208, 1);\n\t\tborder-radius: 8px;\n\t\tbackground: linear-gradient(135deg, rgba(86, 221, 208, 0.12) 0%, rgba(86, 221, 208, 0.04) 100%);\n\t\tcolor: #2a6f68;\n\t\tfont-size: 0.92em;\n\t\tfont-weight: 600;\n\t\tcursor: pointer;\n\t\ttransition: all 0.2s;\n\t\tline-height: 1.3;\n\t}\n\n\t.compare-action-btn:hover:not(:disabled) {\n\t\tbackground: rgba(86, 221, 208, 0.2);\n\t\tborder-style: solid;\n\t\ttransform: translateY(-1px);\n\t}\n\n\t.compare-action-btn.active {\n\t\tbackground: rgba(86, 221, 208, 1);\n\t\tborder-style: solid;\n\t\tborder-color: #2e7d32;\n\t\tcolor: #fff;\n\t}\n\n\t.compare-action-btn:disabled {\n\t\topacity: 0.45;\n\t\tcursor: not-allowed;\n\t\tborder-style: dashed;\n\t\tbackground: #ececec;\n\t\tcolor: #888;\n\t}\n\n\t.compare-grid {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tgap: 12px;\n\t}\n\n\t.compare-grid-side {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(2, minmax(0, 1fr));\n\t\tgap: 12px;\n\t}\n\n\t.compare-card {\n\t\tbackground: #fff;\n\t\tborder: 1px solid #dcdcdc;\n\t\tborder-radius: 8px;\n\t\tpadding: 6px;\n\t}\n\n\t.compare-card-label {\n\t\ttext-align: center;\n\t\tfont-size: 0.85em;\n\t\tfont-weight: 600;\n\t\tmargin-bottom: 4px;\n\t\tcolor: #333;\n\t}\n\n\t.compare-card img {\n\t\twidth: 100%;\n\t\theight: auto;\n\t\tdisplay: block;\n\t\tborder: 1px solid #eee;\n\t}\n\n\t.compare-fullscreen .compare-card-label {\n\t\tcolor: #eee;\n\t}\n\n\t.compare-fullscreen {\n\t\tdisplay: none;\n\t\tposition: fixed;\n\t\tinset: 0;\n\t\tz-index: 1100;\n\t\tbackground: rgba(0, 0, 0, 0.94);\n\t\tpadding: 12px;\n\t\tbox-sizing: border-box;\n\t}\n\n\t.compare-fullscreen.active {\n\t\tdisplay: flex;\n\t\talign-items: stretch;\n\t\tjustify-content: center;\n\t}\n\n\t.compare-fullscreen-grid {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tmin-height: 0;\n\t\toverflow: hidden;\n\t}\n\n\t.compare-fullscreen .compare-grid-side {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tmax-height: 100%;\n\t\tgap: 10px;\n\t\tgrid-template-columns: repeat(2, minmax(0, 1fr));\n\t\tgrid-auto-rows: minmax(0, 1fr);\n\t\talign-content: stretch;\n\t\toverflow: hidden;\n\t}\n\n\t.compare-fullscreen .compare-card {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tmin-height: 0;\n\t\tmin-width: 0;\n\t\theight: 100%;\n\t\tmax-height: 100%;\n\t\toverflow: hidden;\n\t\tbackground: transparent;\n\t\tborder-color: rgba(255, 255, 255, 0.15);\n\t\tpadding: 4px;\n\t\tbox-sizing: border-box;\n\t}\n\n\t.compare-fullscreen .compare-card img {\n\t\tdisplay: block;\n\t\tmax-width: 100%;\n\t\tmax-height: 100%;\n\t\twidth: auto;\n\t\theight: auto;\n\t\tobject-fit: contain;\n\t\tborder: none;\n\t}\n\n\t.compare-modal-header .model-group-title {\n\t\tmargin-bottom: 0;\n\t\tborder-bottom: none;\n\t\tpadding-bottom: 0;\n\t\tflex: 1;\n\t\ttext-align: center;\n\t}\n\n\t@media (max-width: 768px) {\n\t\t.layout-container {\n\t\t\tflex-direction: column;\n\t\t}\n\n\t\t.left-column,\n\t\t.right-column {\n\t\t\tmax-width: 100%;\n\t\t\twidth: 100%;\n\t\t}\n\n\t\t.midterm-select-grid {\n\t\t\tdisplay: grid;\n\t\t\tgrid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n\t\t\tgap: 8px;\n\t\t\tmargin-bottom: 12px;\n\t\t}\n\n\t\t.midterm-select-grid .section {\n\t\t\tmargin-bottom: 0;\n\t\t\tmin-width: 0;\n\t\t\tpadding: 8px;\n\t\t}\n\n\t\t.midterm-models-section .model-group-title,\n\t\t.midterm-params-section .model-group-title {\n\t\t\tfont-size: 0.68em;\n\t\t\tmargin-bottom: 4px;\n\t\t}\n\n\t\t.models-buttons > .model-group-title {\n\t\t\tfont-size: 0.62em;\n\t\t\tpadding: 2px 2px;\n\t\t\tmargin-top: 6px;\n\t\t}\n\n\t\t.models-buttons button,\n\t\t.params-buttons button {\n\t\t\tfont-size: 0.72em;\n\t\t\tpadding: 4px 6px;\n\t\t\tline-height: 1.15;\n\t\t}\n\n\t\t.frames-buttons {\n\t\t\tgrid-template-columns: repeat(4, minmax(0, 1fr));\n\t\t}\n\n\t\t.compare-grid-side {\n\t\t\tgrid-template-columns: 1fr;\n\t\t}\n\n\t\t.slider-header {\n\t\t\tflex-wrap: wrap;\n\t\t}\n\n\t\t.keyboard-info {\n\t\t\tdisplay: none;\n\t\t}\n\n\t\t.compare-modal-content {\n\t\t\twidth: min(95vw, 95vw);\n\t\t}\n\n\t\t.compare-modal-body {\n\t\t\tmax-height: 62vh;\n\t\t\tpadding: 10px;\n\t\t}\n\n\t\t.compare-modal-select-grid {\n\t\t\tgap: 8px;\n\t\t}\n\n\t\t.compare-param-section .model-group-title,\n\t\t.compare-model-section .model-group-title {\n\t\t\tfont-size: 0.68em;\n\t\t\tmargin-bottom: 4px;\n\t\t}\n\n\t\t.compare-model-item,\n\t\t.compare-param-item {\n\t\t\tpadding: 8px;\n\t\t\tfont-size: 0.78em;\n\t\t\tline-height: 1.15;\n\t\t}\n\n\t\t.compare-models-list,\n\t\t.compare-params-list {\n\t\t\tgap: 6px;\n\t\t}\n\t}\n<\/style>\n\n<script>\n\t(function() {\n\t\tvar PRELOAD_CONCURRENCY = 6;\n\n\t\tvar state = {\n\t\t\tregion: \"PL\",\n\t\t\tmodel: \"IFS\",\n\t\t\tparam: \"\",\n\t\t\tframeIndex: 0,\n\t\t\tanimating: false,\n\t\t\tanimationTimer: null,\n\t\t\timageCache: {},\n\t\t\timageLoadPromises: {},\n\t\t\timageToken: 0,\n\t\t\tpreloadQueue: [],\n\t\t\tisPreloading: false,\n\t\t\tpreloadGeneration: 0,\n\t\t\tcompareMode: false,\n\t\t\tcompareKind: \"models\",\n\t\t\tcompareSelectedModels: [],\n\t\t\tcompareSelectedParams: [],\n\t\t\tcomparePreloadActive: false,\n\t\t\tcompareFullscreen: false,\n\t\t\tcompareModalParam: \"\",\n\t\t\tforecastRunVersion: \"\",\n\t\t\trequestVersion: \"\",\n\t\t\tframeResolveCache: {},\n\t\t\tframeDateLists: {},\n\t\t\tframeDateListPromises: {},\n\t\t\timageExistsCache: {}\n\t\t};\n\n\t\tvar FRAME_PRELOAD_PREFIX = \"__frame__|\";\n\n\t\tvar FORECAST_RUN_CHECK_MS = 60000;\n\n\t\tvar data = {\n\t\t\tPL: {\n\t\t\t\tlabel: \"Polska\",\n\t\t\t\tmodels: {\n\t\t\t\t\tAIFS: {\n\t\t\t\t\t\tlabel: \"AIFS (ECMWF)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t\/*{ id: \"TT_TEMP\", label: \"Temperatura\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/TT_ECMWF_TEMP.png\" },\n\t\t\t\t\t\t\t{ id: \"TT_OPAD\", label: \"Opad\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/TT_ECMWF_OPAD_2.png\" },\n\t\t\t\t\t\t\t{ id: \"TT_WIATR\", label: \"Wiatr\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/TT_ECMWF_WIATR.png\" },\n\t\t\t\t\t\t\t{ id: \"TT_WILG\", label: \"Wilgotno\u015b\u0107\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/TT_ECMWF_WILGOTNOSC.png\" },\n\t\t\t\t\t\t\t{ id: \"TT_ZACH\", label: \"Zachmurzenie\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/TT_ECMWF_ZACHMURZENIE.png\" }, *\/\n\t\t\t\t\t\t\t{ id: \"T2_MAX\", label: \"Temperatura maks. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_T2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MIN\", label: \"Temperatura min. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_T2_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_AVE\", label: \"Temperatura \u015br. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_T2_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"TSURF_MAX\", label: \"Temperatura maks. powierzchni\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_Tsurf_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"TSURF_MIN\", label: \"Temperatura min. powierzchni\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_Tsurf_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"RH2_MAX\", label: \"Wilgotno\u015b\u0107 wzgl. maks. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_rh2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"RH2_MIN\", label: \"Wilgotno\u015b\u0107 wzgl. min. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_rh2_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"PREC_ACU\", label: \"Suma opadu\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_All_PrecACU.png\" },\n\t\t\t\t\t\t\t{ id: \"PREC_TYPE\", label: \"Rodzaj opadu\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_All_PrecType.png\" },\n\t\t\t\t\t\t\t{ id: \"WSPD_MAX\", label: \"Pr\u0119dko\u015b\u0107 wiatru maks.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_Wspd_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"WSPD_AVE\", label: \"Pr\u0119dko\u015b\u0107 wiatru \u015br.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_Wspd_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"WDIR_AVE\", label: \"Kierunek wiatru \u015br.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_Wdir_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"P0_MIN\", label: \"Ci\u015bnienie min. na poziomie morza\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_P0_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"P0_AVE\", label: \"Ci\u015bnienie \u015br. na poziomie morza\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_P0_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"P0_MAX\", label: \"Ci\u015bnienie maks. na poziomie morza\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_P0_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"LCLOUD_AVE\", label: \"Zachmurzenie niskie (\u015br.)\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_Day_Lcloud_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"MCLOUD_AVE\", label: \"Zachmurzenie \u015brednie (\u015br.)\", file: \"\/wp-content\/uploads\/production\/ecmwf\/aifs_daily_maps\/ECMWF_Day_Mcloud_AVE.png\" }\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tIFS: {\n\t\t\t\t\t\tlabel: \"IFS (ECMWF)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t\/*{ id: \"TT_TEMP\", label: \"Temperatura\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/TT_ECMWF_TEMP.png\" },\n\t\t\t\t\t\t\t{ id: \"TT_OPAD\", label: \"Opad\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/TT_ECMWF_OPAD_2.png\" },\n\t\t\t\t\t\t\t{ id: \"TT_WIATR\", label: \"Wiatr\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/TT_ECMWF_WIATR.png\" },\n\t\t\t\t\t\t\t{ id: \"TT_VIS\", label: \"Widzialno\u015b\u0107\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/TT_ECMWF_VIS.png\" }, *\/\n\t\t\t\t\t\t\t{ id: \"T2_MAX\", label: \"Temperatura maks. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_T2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MIN\", label: \"Temperatura min. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_T2_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_AVE\", label: \"Temperatura \u015br. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_T2_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"TSURF_MAX\", label: \"Temperatura maks. powierzchni\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_Tsurf_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"TSURF_MIN\", label: \"Temperatura min. powierzchni\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_Tsurf_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"RH2_MAX\", label: \"Wilgotno\u015b\u0107 wzgl. maks. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_rh2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"RH2_MIN\", label: \"Wilgotno\u015b\u0107 wzgl. min. 2m\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_rh2_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"PREC_ACU\", label: \"Suma opadu\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_All_PrecACU.png\" },\n\t\t\t\t\t\t\t{ id: \"PREC_TYPE\", label: \"Rodzaj opadu\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_All_PrecType.png\" },\n\t\t\t\t\t\t\t{ id: \"WSPD_MAX\", label: \"Pr\u0119dko\u015b\u0107 wiatru maks.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_Wspd_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"WSPD_AVE\", label: \"Pr\u0119dko\u015b\u0107 wiatru \u015br.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_Wspd_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"WDIR_AVE\", label: \"Kierunek wiatru \u015br.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_Wdir_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"GUST_MAX\", label: \"Porywy wiatru\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_Gust_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"P0_MIN\", label: \"Ci\u015bnienie min. na poziomie morza\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_P0_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"P0_AVE\", label: \"Ci\u015bnienie \u015br. na poziomie morza\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_P0_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"P0_MAX\", label: \"Ci\u015bnienie maks. na poziomie morza\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_P0_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"VIS_MIN\", label: \"Widzialno\u015b\u0107 min.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_VIS_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"VIS_AVE\", label: \"Widzialno\u015b\u0107 \u015br.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_VIS_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"VIS_MAX\", label: \"Widzialno\u015b\u0107 maks.\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_VIS_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"LCLOUD_AVE\", label: \"Zachmurzenie niskie (\u015br.)\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_Day_Lcloud_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"MCLOUD_AVE\", label: \"Zachmurzenie \u015brednie (\u015br.)\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_Day_Mcloud_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"SUN\", label: \"Nas\u0142onecznienie\", file: \"\/wp-content\/uploads\/production\/ecmwf\/ECMWF_daily_maps\/ECMWF_SUN.png\" }\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tGFS: {\n\t\t\t\t\t\tlabel: \"GFS (NOAA)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t\/*{ id: \"TT_TEMP\", label: \"Temperatura\", file: \"\/wp-content\/uploads\/production\/gfs\/TT_GFS_TEMP.png\" },\n\t\t\t\t\t\t\t{ id: \"TT_OPAD\", label: \"Opad\", file: \"\/wp-content\/uploads\/production\/gfs\/TT_GFS_OPAD_2.png\" }, *\/\n\t\t\t\t\t\t\t{ id: \"T2_MAX\", label: \"Temperatura maks. 2m\", file: \"\/wp-content\/uploads\/production\/gfs\/GFS_T2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MIN\", label: \"Temperatura min. 2m\", file: \"\/wp-content\/uploads\/production\/gfs\/GFS_T2_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"PREC_ACU\", label: \"Suma opadu\", file: \"\/wp-content\/uploads\/production\/gfs\/GFS_All_PrecACU.png\" },\n\t\t\t\t\t\t\t{ id: \"PREC_TYPE\", label: \"Rodzaj opadu\", file: \"\/wp-content\/uploads\/production\/gfs\/GFS_All_PrecType.png\" }\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tAURORA: {\n\t\t\t\t\t\tlabel: \"Aurora (Microsoft)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t\/*{ id: \"TT_TEMP\", label: \"Temperatura\", file: \"\/wp-content\/uploads\/production\/modele_ai\/aurora\/aurora_TT_TEMP.png\" },*\/\n\t\t\t\t\t\t\t{ id: \"T2_AVE\", label: \"Temperatura sr. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/aurora\/aurora_T2_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MAX\", label: \"Temperatura maks. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/aurora\/aurora_T2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MIN\", label: \"Temperatura min. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/aurora\/aurora_T2_MIN.png\" }\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tFOURCASTNET: {\n\t\t\t\t\t\tlabel: \"FourCastNet (Nvidia)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t\/*{ id: \"TT_TEMP\", label: \"Temperatura\", file: \"\/wp-content\/uploads\/production\/modele_ai\/fourcastnet\/fourcastnet_TT_TEMP.png\" },*\/\n\t\t\t\t\t\t\t{ id: \"T2_AVE\", label: \"Temperatura sr. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/fourcastnet\/fourcastnet_T2_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MAX\", label: \"Temperatura maks. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/fourcastnet\/fourcastnet_T2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MIN\", label: \"Temperatura min. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/fourcastnet\/fourcastnet_T2_MIN.png\" }\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tFOURCASTNETV2: {\n\t\t\t\t\t\tlabel: \"FourCastNet v2 (Nvidia)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t\/*{ id: \"TT_TEMP\", label: \"Temperatura\", file: \"\/wp-content\/uploads\/production\/modele_ai\/fourcastnetv2\/fourcastnetv2_TT_TEMP.png\" },*\/\n\t\t\t\t\t\t\t{ id: \"T2_AVE\", label: \"Temperatura sr. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/fourcastnetv2\/fourcastnetv2_T2_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MAX\", label: \"Temperatura maks. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/fourcastnetv2\/fourcastnetv2_T2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MIN\", label: \"Temperatura min. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/fourcastnetv2\/fourcastnetv2_T2_MIN.png\" }\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tGRAPHCAST: {\n\t\t\t\t\t\tlabel: \"GraphCast (Google)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t\/*{ id: \"TT_TEMP\", label: \"Temperatura\", file: \"\/wp-content\/uploads\/production\/modele_ai\/graphcast\/graphcast_TT_TEMP.png\" },*\/\n\t\t\t\t\t\t\t{ id: \"T2_AVE\", label: \"Temperatura sr. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/graphcast\/graphcast_T2_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MAX\", label: \"Temperatura maks. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/graphcast\/graphcast_T2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MIN\", label: \"Temperatura min. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/graphcast\/graphcast_T2_MIN.png\" },\n\t\t\t\t\t\t\t{ id: \"PREC_ACU\", label: \"Suma opadu\", file: \"\/wp-content\/uploads\/production\/modele_ai\/graphcast\/graphcast_All_PrecACU.png\" }\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tPANGUWEATHER: {\n\t\t\t\t\t\tlabel: \"PanguWeather (Huawei)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t\/*{ id: \"TT_TEMP\", label: \"Temperatura\", file: \"\/wp-content\/uploads\/production\/modele_ai\/panguweather\/panguweather_TT_TEMP.png\" },*\/\n\t\t\t\t\t\t\t{ id: \"T2_AVE\", label: \"Temperatura sr. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/panguweather\/panguweather_T2_AVE.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MAX\", label: \"Temperatura maks. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/panguweather\/panguweather_T2_MAX.png\" },\n\t\t\t\t\t\t\t{ id: \"T2_MIN\", label: \"Temperatura min. 2m\", file: \"\/wp-content\/uploads\/production\/modele_ai\/panguweather\/panguweather_T2_MIN.png\" }\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tEU: {\n\t\t\t\tlabel: \"Europa\",\n\t\t\t\tmodels: {\n\t\t\t\t\tIFS: {\n\t\t\t\t\t\tlabel: \"IFS (ECMWF)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"PREC_ACU\",\n\t\t\t\t\t\t\t\tlabel: \"Suma opadu\",\n\t\t\t\t\t\t\t\tsequence: {\n\t\t\t\t\t\t\t\t\tpath: \"\/wp-content\/uploads\/production\/ecmwf\/ecmwf_ifs_eu\/\",\n\t\t\t\t\t\t\t\t\tpattern: \"ecmwf_prec_acu_EU_{n}.png\",\n\t\t\t\t\t\t\t\t\tsteps: 10\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"TMAX\",\n\t\t\t\t\t\t\t\tlabel: \"Temperatura maksymalna\",\n\t\t\t\t\t\t\t\tsequence: {\n\t\t\t\t\t\t\t\t\tpath: \"\/wp-content\/uploads\/production\/ecmwf\/ecmwf_ifs_eu\/\",\n\t\t\t\t\t\t\t\t\tpattern: \"ecmwf_tmax_EU_{n}.png\",\n\t\t\t\t\t\t\t\t\tsteps: 10\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"TMIN\",\n\t\t\t\t\t\t\t\tlabel: \"Temperatura minimalna\",\n\t\t\t\t\t\t\t\tsequence: {\n\t\t\t\t\t\t\t\t\tpath: \"\/wp-content\/uploads\/production\/ecmwf\/ecmwf_ifs_eu\/\",\n\t\t\t\t\t\t\t\t\tpattern: \"ecmwf_tmin_EU_{n}.png\",\n\t\t\t\t\t\t\t\t\tsteps: 10\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tGFS: {\n\t\t\t\t\t\tlabel: \"GFS (NOAA)\",\n\t\t\t\t\t\tparams: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"PREC_ACU\",\n\t\t\t\t\t\t\t\tlabel: \"Suma opadu\",\n\t\t\t\t\t\t\t\tsequence: {\n\t\t\t\t\t\t\t\t\tpath: \"\/wp-content\/uploads\/production\/gfs\/maps_opad24\/\",\n\t\t\t\t\t\t\t\t\tpattern: \"gfs_prec_acu_EU_{n}.png\",\n\t\t\t\t\t\t\t\t\tsteps: 10\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"TMAX\",\n\t\t\t\t\t\t\t\tlabel: \"Temperatura maksymalna\",\n\t\t\t\t\t\t\t\tsequence: {\n\t\t\t\t\t\t\t\t\tpath: \"\/wp-content\/uploads\/production\/gfs\/maps_t_max\/\",\n\t\t\t\t\t\t\t\t\tpattern: \"gfs_tmax_EU_{n}.png\",\n\t\t\t\t\t\t\t\t\tsteps: 10\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"TMIN\",\n\t\t\t\t\t\t\t\tlabel: \"Temperatura minimalna\",\n\t\t\t\t\t\t\t\tsequence: {\n\t\t\t\t\t\t\t\t\tpath: \"\/wp-content\/uploads\/production\/gfs\/maps_t_min\/\",\n\t\t\t\t\t\t\t\t\tpattern: \"gfs_tmin_EU_{n}.png\",\n\t\t\t\t\t\t\t\t\tsteps: 10\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tfunction getRegionConfig() {\n\t\t\treturn data[state.region];\n\t\t}\n\n\t\tfunction getModelConfig() {\n\t\t\treturn getRegionConfig().models[state.model];\n\t\t}\n\n\t\tfunction getModelType(modelId) {\n\t\t\tvar normalizedId = String(modelId || \"\").toUpperCase();\n\t\t\tif (normalizedId === \"IFS\" || normalizedId === \"GFS\") {\n\t\t\t\treturn \"physical\";\n\t\t\t}\n\t\t\treturn \"ai\";\n\t\t}\n\n\t\tfunction getOrderedModelIds() {\n\t\t\tvar models = getRegionConfig().models;\n\t\t\tvar modelIds = Object.keys(models);\n\t\t\tvar physicalModelIds = [];\n\t\t\tvar aiModelIds = [];\n\n\t\t\tmodelIds.forEach(function(modelId) {\n\t\t\t\tif (getModelType(modelId) === \"ai\") {\n\t\t\t\t\taiModelIds.push(modelId);\n\t\t\t\t} else {\n\t\t\t\t\tphysicalModelIds.push(modelId);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn physicalModelIds.concat(aiModelIds);\n\t\t}\n\n\t\tfunction resolveModelForRegion(preferredModelId) {\n\t\t\tvar models = getRegionConfig().models;\n\t\t\tif (preferredModelId && models[preferredModelId]) {\n\t\t\t\treturn preferredModelId;\n\t\t\t}\n\t\t\tvar ordered = getOrderedModelIds();\n\t\t\treturn ordered.length ? ordered[0] : preferredModelId;\n\t\t}\n\n\t\tfunction setRegion(regionId) {\n\t\t\tif (regionId === state.region) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstopAnimation();\n\t\t\texitCompareMode();\n\n\t\t\tvar previousModel = state.model;\n\t\t\tvar previousParam = state.param;\n\t\t\tstate.region = regionId;\n\t\t\tstate.model = resolveModelForRegion(previousModel);\n\t\t\tstate.param = resolveParamForModel(state.model, previousParam);\n\t\t\tstate.frameIndex = 0;\n\t\t\trenderAll();\n\t\t}\n\n\t\tfunction getParamConfig() {\n\t\t\tvar params = getModelConfig().params;\n\t\t\tfor (var i = 0; i < params.length; i += 1) {\n\t\t\t\tif (params[i].id === state.param) {\n\t\t\t\t\treturn params[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn params[0] || null;\n\t\t}\n\n\t\tfunction resolveParamForModel(modelId, preferredParamId) {\n\t\t\tvar model = getRegionConfig().models[modelId];\n\t\t\tif (!model || !model.params || !model.params.length) {\n\t\t\t\treturn preferredParamId || \"\";\n\t\t\t}\n\t\t\tif (preferredParamId) {\n\t\t\t\tfor (var i = 0; i < model.params.length; i += 1) {\n\t\t\t\t\tif (model.params[i].id === preferredParamId) {\n\t\t\t\t\t\treturn preferredParamId;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn model.params[0].id;\n\t\t}\n\n\t\tfunction setModel(modelId) {\n\t\t\tvar previousParam = state.param;\n\t\t\tstate.model = modelId;\n\t\t\tstate.param = resolveParamForModel(modelId, previousParam);\n\t\t\tstate.frameIndex = 0;\n\t\t\tclearModelFrameDateLists(modelId);\n\n\t\t\tif (state.compareMode && state.compareKind === \"params\") {\n\t\t\t\tsyncCompareParamsForCurrentModel();\n\t\t\t}\n\t\t}\n\n\t\tfunction prefetchEuFrameDateLists() {\n\t\t\tif (state.region !== \"EU\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tgetOrderedModelIds().forEach(function(modelId) {\n\t\t\t\tvar params = getRegionConfig().models[modelId].params || [];\n\t\t\t\tparams.forEach(function(paramCfg) {\n\t\t\t\t\tif (paramCfg.sequence) {\n\t\t\t\t\t\tensureFrameDateList(modelId, paramCfg.id).then(function() {\n\t\t\t\t\t\t\tif (modelId === state.model && paramCfg.id === state.param) {\n\t\t\t\t\t\t\t\tclampFrameIndexForCurrentFrames();\n\t\t\t\t\t\t\t\trenderFrames();\n\t\t\t\t\t\t\t\tupdateKeyboardHints();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (state.compareMode) {\n\t\t\t\t\t\t\t\tclampFrameIndexForCurrentFrames();\n\t\t\t\t\t\t\t\trenderFrames();\n\t\t\t\t\t\t\t\tupdateKeyboardHints();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tfunction isParamCompareable(paramId) {\n\t\t\tif (!paramId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn getEligibleCompareModelIds(paramId).length >= 2;\n\t\t}\n\n\t\tfunction isCompareParam() {\n\t\t\treturn isParamCompareable(state.param);\n\t\t}\n\n\t\tfunction canCompareCurrentSelection() {\n\t\t\tif (state.region === \"EU\") {\n\t\t\t\tvar param = getParamConfig();\n\t\t\t\treturn !!(param && param.sequence && param.sequence.steps > 1 && isParamCompareable(state.param));\n\t\t\t}\n\t\t\treturn isCompareParam();\n\t\t}\n\n\t\tfunction getParamConfigForModel(modelId, paramId) {\n\t\t\tvar model = getRegionConfig().models[modelId];\n\t\t\tif (!model || !model.params) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tfor (var i = 0; i < model.params.length; i += 1) {\n\t\t\t\tif (model.params[i].id === paramId) {\n\t\t\t\t\treturn model.params[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tfunction getFrameDateListKey(modelId, paramId) {\n\t\t\treturn state.region + \"|\" + modelId + \"|\" + paramId;\n\t\t}\n\n\t\tfunction getFrameDateList(modelId, paramId) {\n\t\t\treturn state.frameDateLists[getFrameDateListKey(modelId, paramId)] || [];\n\t\t}\n\n\t\tfunction intersectDateLists(lists) {\n\t\t\tvar result = [];\n\t\t\tvar first;\n\t\t\tvar i;\n\t\t\tvar j;\n\t\t\tvar date;\n\t\t\tvar inAll;\n\n\t\t\tif (!lists.length) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tfirst = lists[0];\n\t\t\tfor (i = 0; i < first.length; i += 1) {\n\t\t\t\tdate = first[i];\n\t\t\t\tinAll = true;\n\t\t\t\tfor (j = 1; j < lists.length; j += 1) {\n\t\t\t\t\tif (lists[j].indexOf(date) === -1) {\n\t\t\t\t\t\tinAll = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (inAll) {\n\t\t\t\t\tresult.push(date);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction getCommonCompareDatesForModels(modelIds, paramId) {\n\t\t\tvar lists = [];\n\t\t\tvar i;\n\t\t\tvar key;\n\n\t\t\tfor (i = 0; i < modelIds.length; i += 1) {\n\t\t\t\tkey = getFrameDateListKey(modelIds[i], paramId);\n\t\t\t\tif (!Object.prototype.hasOwnProperty.call(state.frameDateLists, key)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tlists.push(getFrameDateList(modelIds[i], paramId));\n\t\t\t}\n\n\t\t\treturn intersectDateLists(lists.filter(function(list) {\n\t\t\t\treturn list.length;\n\t\t\t}));\n\t\t}\n\n\t\tfunction getCommonCompareDatesForParams(paramIds) {\n\t\t\tvar lists = [];\n\t\t\tvar i;\n\t\t\tvar key;\n\n\t\t\tfor (i = 0; i < paramIds.length; i += 1) {\n\t\t\t\tkey = getFrameDateListKey(state.model, paramIds[i]);\n\t\t\t\tif (!Object.prototype.hasOwnProperty.call(state.frameDateLists, key)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tlists.push(getFrameDateList(state.model, paramIds[i]));\n\t\t\t}\n\n\t\t\treturn intersectDateLists(lists.filter(function(list) {\n\t\t\t\treturn list.length;\n\t\t\t}));\n\t\t}\n\n\t\tfunction getActiveCompareCommonDates() {\n\t\t\tif (!state.compareMode) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (state.compareKind === \"models\") {\n\t\t\t\treturn getCommonCompareDatesForModels(getActiveCompareModelIds(), state.param);\n\t\t\t}\n\n\t\t\tif (state.compareKind === \"params\") {\n\t\t\t\treturn getCommonCompareDatesForParams(getActiveCompareParamIds());\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tfunction getDateSuffixForFrame(modelId, paramId, frameIndex) {\n\t\t\tvar index = frameIndex !== undefined ? frameIndex : state.frameIndex;\n\t\t\tvar commonDates = getActiveCompareCommonDates();\n\t\t\tvar list;\n\n\t\t\tif (state.compareMode && commonDates === null) {\n\t\t\t\tlist = getFrameDateList(modelId, paramId);\n\t\t\t\tif (list.length && index < list.length) {\n\t\t\t\t\treturn list[index];\n\t\t\t\t}\n\t\t\t\treturn formatDateSuffixForIndex(index);\n\t\t\t}\n\n\t\t\tif (commonDates && commonDates.length && index < commonDates.length) {\n\t\t\t\treturn commonDates[index];\n\t\t\t}\n\n\t\t\tlist = getFrameDateList(modelId, paramId);\n\t\t\tif (list.length && index < list.length) {\n\t\t\t\treturn list[index];\n\t\t\t}\n\n\t\t\treturn formatDateSuffixForIndex(index);\n\t\t}\n\n\t\tfunction checkImageExists(url) {\n\t\t\tvar requestUrl = getRequestUrl(url);\n\n\t\t\tif (Object.prototype.hasOwnProperty.call(state.imageExistsCache, requestUrl)) {\n\t\t\t\treturn Promise.resolve(state.imageExistsCache[requestUrl]);\n\t\t\t}\n\n\t\t\treturn fetch(requestUrl, {\n\t\t\t\tmethod: \"HEAD\",\n\t\t\t\tcache: \"no-cache\"\n\t\t\t}).then(function(response) {\n\t\t\t\tvar exists = response.ok;\n\t\t\t\tstate.imageExistsCache[requestUrl] = exists;\n\t\t\t\treturn exists;\n\t\t\t}).catch(function() {\n\t\t\t\treturn new Promise(function(resolve) {\n\t\t\t\t\tvar img = new Image();\n\t\t\t\t\tvar timer = setTimeout(function() {\n\t\t\t\t\t\timg.onload = null;\n\t\t\t\t\t\timg.onerror = null;\n\t\t\t\t\t\tstate.imageExistsCache[requestUrl] = false;\n\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t}, 4000);\n\n\t\t\t\t\timg.onload = function() {\n\t\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\t\tstate.imageExistsCache[requestUrl] = true;\n\t\t\t\t\t\tresolve(true);\n\t\t\t\t\t};\n\t\t\t\t\timg.onerror = function() {\n\t\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\t\tstate.imageExistsCache[requestUrl] = false;\n\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t};\n\t\t\t\t\timg.src = requestUrl;\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tasync function discoverFrameDateList(modelId, paramId) {\n\t\t\tvar param = getParamConfigForModel(modelId, paramId);\n\t\t\tvar key = getFrameDateListKey(modelId, paramId);\n\t\t\tvar maxSteps;\n\t\t\tvar dates = [];\n\t\t\tvar dayOffset = 0;\n\t\t\tvar maxProbe;\n\t\t\tvar suffix;\n\t\t\tvar url;\n\t\t\tvar exists;\n\n\t\t\tif (!param || !param.sequence) {\n\t\t\t\tstate.frameDateLists[key] = [];\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tmaxSteps = param.sequence.steps;\n\t\t\tmaxProbe = maxSteps + 14;\n\n\t\t\twhile (dates.length < maxSteps && dayOffset < maxProbe) {\n\t\t\t\tsuffix = formatDateSuffixForIndex(dayOffset);\n\t\t\t\turl = buildSequenceFileUrl(param, suffix);\n\t\t\t\texists = await checkImageExists(url);\n\t\t\t\tif (exists) {\n\t\t\t\t\tdates.push(suffix);\n\t\t\t\t}\n\t\t\t\tdayOffset += 1;\n\t\t\t}\n\n\t\t\tstate.frameDateLists[key] = dates;\n\t\t\treturn dates;\n\t\t}\n\n\t\tfunction ensureFrameDateList(modelId, paramId) {\n\t\t\tvar key = getFrameDateListKey(modelId, paramId);\n\n\t\t\tif (Object.prototype.hasOwnProperty.call(state.frameDateLists, key)) {\n\t\t\t\treturn Promise.resolve(state.frameDateLists[key]);\n\t\t\t}\n\n\t\t\tif (state.frameDateListPromises[key]) {\n\t\t\t\treturn state.frameDateListPromises[key];\n\t\t\t}\n\n\t\t\tstate.frameDateListPromises[key] = discoverFrameDateList(modelId, paramId).finally(function() {\n\t\t\t\tdelete state.frameDateListPromises[key];\n\t\t\t});\n\n\t\t\treturn state.frameDateListPromises[key];\n\t\t}\n\n\t\tfunction clearFrameDateList(modelId, paramId) {\n\t\t\tvar key = getFrameDateListKey(modelId, paramId);\n\t\t\tdelete state.frameDateLists[key];\n\t\t\tdelete state.frameDateListPromises[key];\n\t\t}\n\n\t\tfunction clearModelFrameDateLists(modelId) {\n\t\t\tvar model = getRegionConfig().models[modelId];\n\t\t\tvar params;\n\t\t\tvar i;\n\n\t\t\tif (!model || !model.params) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tparams = model.params;\n\t\t\tfor (i = 0; i < params.length; i += 1) {\n\t\t\t\tclearFrameDateList(modelId, params[i].id);\n\t\t\t}\n\t\t}\n\n\t\tfunction clearAllFrameDateLists() {\n\t\t\tstate.frameDateLists = {};\n\t\t\tstate.frameDateListPromises = {};\n\t\t\tstate.imageExistsCache = {};\n\t\t}\n\n\t\tfunction clampFrameIndexForCurrentFrames() {\n\t\t\tvar count = getFrameCount();\n\t\t\tif (state.frameIndex >= count) {\n\t\t\t\tstate.frameIndex = Math.max(0, count - 1);\n\t\t\t}\n\t\t}\n\n\t\tfunction ensureCompareFrameDateLists() {\n\t\t\tvar promises = [];\n\t\t\tvar modelIds;\n\t\t\tvar paramIds;\n\t\t\tvar i;\n\n\t\t\tif (!state.compareMode) {\n\t\t\t\treturn refreshFrameDatesForSelection(state.model, state.param);\n\t\t\t}\n\n\t\t\tif (state.compareKind === \"models\") {\n\t\t\t\tmodelIds = getActiveCompareModelIds();\n\t\t\t\tfor (i = 0; i < modelIds.length; i += 1) {\n\t\t\t\t\tpromises.push(ensureFrameDateList(modelIds[i], state.param));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tparamIds = getActiveCompareParamIds();\n\t\t\t\tfor (i = 0; i < paramIds.length; i += 1) {\n\t\t\t\t\tpromises.push(ensureFrameDateList(state.model, paramIds[i]));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Promise.all(promises).then(function() {\n\t\t\t\tclampFrameIndexForCurrentFrames();\n\t\t\t\trenderFrames();\n\t\t\t\tupdateKeyboardHints();\n\t\t\t});\n\t\t}\n\n\t\tfunction refreshFrameDatesForSelection(modelId, paramId) {\n\t\t\treturn ensureFrameDateList(modelId, paramId).then(function(dates) {\n\t\t\t\tclampFrameIndexForCurrentFrames();\n\t\t\t\trenderFrames();\n\t\t\t\tupdateKeyboardHints();\n\t\t\t\treturn dates;\n\t\t\t});\n\t\t}\n\n\t\tfunction getFrameLogicalKey(modelId, paramId, frameIndex) {\n\t\t\treturn state.region + \"|\" + modelId + \"|\" + paramId + \"|\" + getDateSuffixForFrame(modelId, paramId, frameIndex);\n\t\t}\n\n\t\tfunction clearFrameResolveCache() {\n\t\t\tstate.frameResolveCache = {};\n\t\t}\n\n\t\tfunction formatDateSuffixForIndex(index) {\n\t\t\tvar baseDate = new Date();\n\t\t\tbaseDate.setHours(0, 0, 0, 0);\n\t\t\tvar targetDate = new Date(baseDate.getTime());\n\t\t\ttargetDate.setDate(baseDate.getDate() + index);\n\t\t\treturn String(targetDate.getFullYear()) +\n\t\t\t\tpad2(targetDate.getMonth() + 1) +\n\t\t\t\tpad2(targetDate.getDate());\n\t\t}\n\n\t\tfunction buildSequenceFileUrl(param, suffixToken) {\n\t\t\treturn param.sequence.path + param.sequence.pattern.replace(\"{n}\", suffixToken);\n\t\t}\n\n\t\tfunction buildSequenceFrameUrl(modelId, paramId, frameIndex) {\n\t\t\tvar param = getParamConfigForModel(modelId, paramId);\n\t\t\tvar index;\n\n\t\t\tif (!param || !param.sequence) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\n\t\t\tindex = frameIndex !== undefined ? frameIndex : state.frameIndex;\n\t\t\treturn buildSequenceFileUrl(param, getDateSuffixForFrame(modelId, paramId, index));\n\t\t}\n\n\t\tfunction parseDateSuffixFromFileName(fileName) {\n\t\t\tvar match = String(fileName || \"\").match(\/_(\\d{8})\\.png$\/i);\n\t\t\treturn match ? match[1] : null;\n\t\t}\n\n\t\tfunction parseYmdDateSuffix(suffix) {\n\t\t\tvar year;\n\t\t\tvar month;\n\t\t\tvar day;\n\t\t\tvar date;\n\n\t\t\tif (!suffix || suffix.length !== 8) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tyear = parseInt(suffix.slice(0, 4), 10);\n\t\t\tmonth = parseInt(suffix.slice(4, 6), 10) - 1;\n\t\t\tday = parseInt(suffix.slice(6, 8), 10);\n\t\t\tdate = new Date(year, month, day);\n\n\t\t\tif (isNaN(date.getTime())) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn date;\n\t\t}\n\n\t\tfunction rememberFrameResolve(cacheKey, url) {\n\t\t\tvar fileName = url.split(\"\/\").pop();\n\t\t\tstate.frameResolveCache[cacheKey] = {\n\t\t\t\turl: url,\n\t\t\t\tdateSuffix: parseDateSuffixFromFileName(fileName)\n\t\t\t};\n\t\t\trefreshPreloadUi();\n\t\t}\n\n\t\tfunction getResolvedFrameUrl(modelId, paramId, frameIndex) {\n\t\t\treturn buildSequenceFrameUrl(modelId, paramId, frameIndex);\n\t\t}\n\n\t\tfunction getFrameImageLoadState(modelId, paramId, frameIndex) {\n\t\t\treturn getImageLoadState(getResolvedFrameUrl(modelId, paramId, frameIndex));\n\t\t}\n\n\t\tfunction ensureFrameImage(modelId, paramId, frameIndex) {\n\t\t\treturn ensureFrameDateList(modelId, paramId).then(function() {\n\t\t\t\tvar url = buildSequenceFrameUrl(modelId, paramId, frameIndex);\n\t\t\t\tvar cacheKey = getFrameLogicalKey(modelId, paramId, frameIndex);\n\t\t\t\tvar cached = state.frameResolveCache[cacheKey];\n\n\t\t\t\tif (!url) {\n\t\t\t\t\treturn Promise.reject(new Error(\"Brak URL klatki\"));\n\t\t\t\t}\n\n\t\t\t\tif (cached && cached.url === url) {\n\t\t\t\t\treturn ensureImage(url);\n\t\t\t\t}\n\n\t\t\t\treturn ensureImage(url).then(function(img) {\n\t\t\t\t\trememberFrameResolve(cacheKey, url);\n\t\t\t\t\treturn img;\n\t\t\t\t}).catch(function(err) {\n\t\t\t\t\tclearFrameDateList(modelId, paramId);\n\t\t\t\t\treturn discoverFrameDateList(modelId, paramId).then(function() {\n\t\t\t\t\t\tclampFrameIndexForCurrentFrames();\n\t\t\t\t\t\turl = buildSequenceFrameUrl(modelId, paramId, frameIndex);\n\t\t\t\t\t\tcacheKey = getFrameLogicalKey(modelId, paramId, frameIndex);\n\t\t\t\t\t\tif (!url) {\n\t\t\t\t\t\t\treturn Promise.reject(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn ensureImage(url).then(function(img) {\n\t\t\t\t\t\t\trememberFrameResolve(cacheKey, url);\n\t\t\t\t\t\t\treturn img;\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tfunction makePreloadItem(modelId, paramId, frameIndex) {\n\t\t\tvar param = getParamConfigForModel(modelId, paramId);\n\t\t\tif (param && param.sequence) {\n\t\t\t\treturn FRAME_PRELOAD_PREFIX + modelId + \"|\" + paramId + \"|\" + frameIndex;\n\t\t\t}\n\t\t\treturn getParamUrlForModel(modelId, paramId, frameIndex);\n\t\t}\n\n\t\tfunction preloadItem(item) {\n\t\t\tif (!item) {\n\t\t\t\treturn Promise.resolve(null);\n\t\t\t}\n\t\t\tif (item.indexOf(FRAME_PRELOAD_PREFIX) === 0) {\n\t\t\t\tvar parts = item.slice(FRAME_PRELOAD_PREFIX.length).split(\"|\");\n\t\t\t\treturn ensureFrameImage(parts[0], parts[1], parseInt(parts[2], 10)).catch(function() {\n\t\t\t\t\treturn null;\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn ensureImage(item).catch(function() {\n\t\t\t\treturn null;\n\t\t\t});\n\t\t}\n\n\t\tfunction getParamUrlForModel(modelId, paramId, frameIndex) {\n\t\t\tvar param = getParamConfigForModel(modelId, paramId);\n\t\t\tif (!param) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tif (param.sequence) {\n\t\t\t\treturn getResolvedFrameUrl(modelId, paramId, frameIndex);\n\t\t\t}\n\t\t\tif (param.file) {\n\t\t\t\treturn param.file;\n\t\t\t}\n\t\t\treturn \"\";\n\t\t}\n\n\t\tfunction getParamFileForModel(modelId, paramId) {\n\t\t\treturn getParamUrlForModel(modelId, paramId, state.frameIndex);\n\t\t}\n\n\t\tfunction getCompareParamOptions() {\n\t\t\tvar options = [];\n\t\t\tvar seen = {};\n\t\t\tvar modelIds = getOrderedModelIds();\n\t\t\tvar i;\n\t\t\tvar j;\n\n\t\t\tfor (i = 0; i < modelIds.length; i += 1) {\n\t\t\t\tvar params = getRegionConfig().models[modelIds[i]].params;\n\t\t\t\tfor (j = 0; j < params.length; j += 1) {\n\t\t\t\t\tvar paramCfg = params[j];\n\t\t\t\t\tif (seen[paramCfg.id]) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (!isParamCompareable(paramCfg.id)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tseen[paramCfg.id] = true;\n\t\t\t\t\toptions.push({ id: paramCfg.id, label: paramCfg.label });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn options;\n\t\t}\n\n\t\tfunction getCompareModalParamId() {\n\t\t\treturn state.compareModalParam || state.param;\n\t\t}\n\n\t\tfunction getEligibleCompareModelIds(paramId) {\n\t\t\tvar ordered = getOrderedModelIds();\n\t\t\tvar targetParam = paramId || state.param;\n\t\t\treturn ordered.filter(function(modelId) {\n\t\t\t\tvar param = getParamConfigForModel(modelId, targetParam);\n\t\t\t\treturn !!(param && (param.sequence || param.file));\n\t\t\t});\n\t\t}\n\n\t\tfunction getActiveCompareModelIds() {\n\t\t\tvar compareCandidates = getEligibleCompareModelIds();\n\t\t\tvar selected = state.compareSelectedModels.filter(function(modelId) {\n\t\t\t\treturn compareCandidates.indexOf(modelId) !== -1;\n\t\t\t});\n\t\t\treturn selected.length ? selected : compareCandidates.slice();\n\t\t}\n\n\t\tfunction getModelParamIds(modelId) {\n\t\t\tvar model = getRegionConfig().models[modelId || state.model];\n\t\t\tif (!model || !model.params) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn model.params.map(function(paramCfg) {\n\t\t\t\treturn paramCfg.id;\n\t\t\t});\n\t\t}\n\n\t\tfunction canCompareParamsForModel(modelId) {\n\t\t\treturn getModelParamIds(modelId).length >= 2;\n\t\t}\n\n\t\tfunction getActiveCompareParamIds() {\n\t\t\tvar available = getModelParamIds(state.model);\n\t\t\treturn state.compareSelectedParams.filter(function(paramId) {\n\t\t\t\treturn available.indexOf(paramId) !== -1;\n\t\t\t});\n\t\t}\n\n\t\tfunction syncCompareParamsForCurrentModel() {\n\t\t\tif (!state.compareMode || state.compareKind !== \"params\") {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tvar available = getModelParamIds(state.model);\n\t\t\tvar beforeCount = state.compareSelectedParams.length;\n\n\t\t\tstate.compareSelectedParams = state.compareSelectedParams.filter(function(paramId) {\n\t\t\t\treturn available.indexOf(paramId) !== -1;\n\t\t\t});\n\n\t\t\tif (available.indexOf(state.param) === -1) {\n\t\t\t\tstate.param = state.compareSelectedParams.length\n\t\t\t\t\t? state.compareSelectedParams[0]\n\t\t\t\t\t: resolveParamForModel(state.model, state.param);\n\t\t\t}\n\n\t\t\tif (state.compareSelectedParams.length < 2) {\n\t\t\t\tif (beforeCount > state.compareSelectedParams.length) {\n\t\t\t\t\tshowStatus(\"Nowy model nie ma wystarczaj\u0105cej liczby wcze\u015bniej wybranych parametr\u00f3w.\");\n\t\t\t\t}\n\t\t\t\texitCompareMode();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tfunction getEffectiveFrameCount() {\n\t\t\treturn getFrameCount();\n\t\t}\n\n\t\tfunction exitCompareMode() {\n\t\t\tstate.compareMode = false;\n\t\t\tstate.compareKind = \"models\";\n\t\t\tstate.compareSelectedParams = [];\n\t\t\tcloseCompareFullscreen();\n\t\t\tresetComparePreload();\n\t\t\tclearFrameResolveCache();\n\t\t}\n\n\t\tfunction getFrameUrlsForIndex(index) {\n\t\t\tif (state.compareMode && state.compareKind === \"params\") {\n\t\t\t\treturn getActiveCompareParamIds().map(function(paramId) {\n\t\t\t\t\treturn getParamUrlForModel(state.model, paramId, index);\n\t\t\t\t}).filter(function(url) {\n\t\t\t\t\treturn !!url;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (state.compareMode) {\n\t\t\t\treturn getActiveCompareModelIds().map(function(modelId) {\n\t\t\t\t\treturn getParamUrlForModel(modelId, state.param, index);\n\t\t\t\t}).filter(function(url) {\n\t\t\t\t\treturn !!url;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvar url = getFrameUrlByIndex(index);\n\t\t\treturn url ? [url] : [];\n\t\t}\n\n\t\tfunction getFrameLoadState(index) {\n\t\t\tvar i;\n\t\t\tvar loadState;\n\t\t\tvar hasLoading = false;\n\t\t\tvar hasLoaded = false;\n\t\t\tvar allLoaded = true;\n\t\t\tvar paramIds;\n\t\t\tvar modelIds;\n\n\t\t\tif (state.compareMode && state.compareKind === \"params\") {\n\t\t\t\tparamIds = getActiveCompareParamIds();\n\t\t\t\tif (!paramIds.length) {\n\t\t\t\t\treturn \"pending\";\n\t\t\t\t}\n\t\t\t\tfor (i = 0; i < paramIds.length; i += 1) {\n\t\t\t\t\tloadState = getFrameImageLoadState(state.model, paramIds[i], index);\n\t\t\t\t\tif (loadState === \"loading\") {\n\t\t\t\t\t\thasLoading = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState === \"loaded\") {\n\t\t\t\t\t\thasLoaded = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState !== \"loaded\") {\n\t\t\t\t\t\tallLoaded = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (state.compareMode) {\n\t\t\t\tmodelIds = getActiveCompareModelIds();\n\t\t\t\tif (!modelIds.length) {\n\t\t\t\t\treturn \"pending\";\n\t\t\t\t}\n\t\t\t\tfor (i = 0; i < modelIds.length; i += 1) {\n\t\t\t\t\tloadState = getFrameImageLoadState(modelIds[i], state.param, index);\n\t\t\t\t\tif (loadState === \"loading\") {\n\t\t\t\t\t\thasLoading = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState === \"loaded\") {\n\t\t\t\t\t\thasLoaded = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState !== \"loaded\") {\n\t\t\t\t\t\tallLoaded = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar param = getParamConfig();\n\t\t\t\tif (param && param.sequence) {\n\t\t\t\t\treturn getFrameImageLoadState(state.model, state.param, index);\n\t\t\t\t}\n\n\t\t\t\tvar urls = getFrameUrlsForIndex(index);\n\t\t\t\tif (!urls.length) {\n\t\t\t\t\treturn \"pending\";\n\t\t\t\t}\n\n\t\t\t\tfor (i = 0; i < urls.length; i += 1) {\n\t\t\t\t\tloadState = getImageLoadState(urls[i]);\n\t\t\t\t\tif (loadState === \"loading\") {\n\t\t\t\t\t\thasLoading = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState === \"loaded\") {\n\t\t\t\t\t\thasLoaded = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState !== \"loaded\") {\n\t\t\t\t\t\tallLoaded = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (allLoaded) {\n\t\t\t\treturn \"loaded\";\n\t\t\t}\n\t\t\tif (hasLoading || hasLoaded) {\n\t\t\t\treturn \"loading\";\n\t\t\t}\n\t\t\treturn \"pending\";\n\t\t}\n\n\t\tfunction resetComparePreload() {\n\t\t\tstate.comparePreloadActive = false;\n\t\t}\n\n\t\tfunction startComparePreloadIfNeeded() {\n\t\t\tif (!state.compareMode || state.comparePreloadActive) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.comparePreloadActive = true;\n\n\t\t\tvar urls = buildComparePreloadUrls();\n\t\t\tvar needsLoad = false;\n\t\t\tvar i;\n\n\t\t\tfor (i = 0; i < urls.length; i += 1) {\n\t\t\t\tif (!isImageLoaded(urls[i])) {\n\t\t\t\t\tneedsLoad = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!needsLoad) {\n\t\t\t\trefreshPreloadUi();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tenqueuePreloadUrls(urls);\n\t\t}\n\n\t\tfunction getFrameCount() {\n\t\t\tvar param = getParamConfig();\n\t\t\tvar list;\n\t\t\tvar key;\n\t\t\tvar commonDates;\n\n\t\t\tif (!param || !param.sequence) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif (state.compareMode) {\n\t\t\t\tcommonDates = getActiveCompareCommonDates();\n\t\t\t\tif (commonDates && commonDates.length) {\n\t\t\t\t\treturn commonDates.length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tkey = getFrameDateListKey(state.model, state.param);\n\t\t\tlist = getFrameDateList(state.model, state.param);\n\t\t\tif (Object.prototype.hasOwnProperty.call(state.frameDateLists, key) && list.length) {\n\t\t\t\treturn list.length;\n\t\t\t}\n\n\t\t\treturn param.sequence.steps;\n\t\t}\n\n\t\tfunction pad2(value) {\n\t\t\treturn String(value).padStart(2, \"0\");\n\t\t}\n\n\t\tfunction getFrameDateByIndex(index) {\n\t\t\tvar suffix = getDateSuffixForFrame(state.model, state.param, index);\n\t\t\treturn suffix ? parseYmdDateSuffix(suffix) : null;\n\t\t}\n\n\t\tfunction formatFrameDateLabel(index) {\n\t\t\tvar dateObj = getFrameDateByIndex(index);\n\t\t\tif (!dateObj) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\treturn pad2(dateObj.getDate()) + \".\" + pad2(dateObj.getMonth() + 1);\n\t\t}\n\n\t\tfunction formatFrameDateVerbose(index) {\n\t\t\tvar dateObj = getFrameDateByIndex(index);\n\t\t\tif (!dateObj) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\treturn pad2(dateObj.getDate()) + \".\" + pad2(dateObj.getMonth() + 1) + \".\" + dateObj.getFullYear();\n\t\t}\n\n\t\tfunction getFrameDisplayLabel(index) {\n\t\t\tvar dateShort = formatFrameDateLabel(index);\n\t\t\tif (!dateShort) {\n\t\t\t\treturn String(index + 1);\n\t\t\t}\n\t\t\treturn dateShort;\n\t\t}\n\n\t\tfunction getCurrentImageUrl() {\n\t\t\tvar param = getParamConfig();\n\t\t\tif (!param) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\n\t\t\tif (param.sequence) {\n\t\t\t\treturn getParamUrlForModel(state.model, state.param, state.frameIndex);\n\t\t\t}\n\n\t\t\treturn param.file;\n\t\t}\n\n\t\tfunction getFrameUrlByIndex(index) {\n\t\t\treturn getParamUrlForModel(state.model, state.param, index);\n\t\t}\n\n\t\tfunction ensureModelParamFrameImage(modelId, paramId, frameIndex) {\n\t\t\tvar param = getParamConfigForModel(modelId, paramId);\n\t\t\tif (param && param.sequence) {\n\t\t\t\treturn ensureFrameImage(modelId, paramId, frameIndex);\n\t\t\t}\n\t\t\treturn ensureImage(getParamUrlForModel(modelId, paramId, frameIndex));\n\t\t}\n\n\t\tfunction isFrameImageLoaded(modelId, paramId, frameIndex) {\n\t\t\tvar param = getParamConfigForModel(modelId, paramId);\n\t\t\tif (param && param.sequence) {\n\t\t\t\treturn getFrameImageLoadState(modelId, paramId, frameIndex) === \"loaded\";\n\t\t\t}\n\t\t\treturn isImageLoaded(getParamUrlForModel(modelId, paramId, frameIndex));\n\t\t}\n\n\t\tfunction getForecastRunVersion() {\n\t\t\tvar now = new Date();\n\t\t\tvar y = now.getUTCFullYear();\n\t\t\tvar m = pad2(now.getUTCMonth() + 1);\n\t\t\tvar d = pad2(now.getUTCDate());\n\t\t\tvar h = now.getUTCHours();\n\t\t\tvar runHour = 0;\n\n\t\t\tif (h >= 18) {\n\t\t\t\trunHour = 18;\n\t\t\t} else if (h >= 12) {\n\t\t\t\trunHour = 12;\n\t\t\t} else if (h >= 6) {\n\t\t\t\trunHour = 6;\n\t\t\t}\n\n\t\t\treturn String(y) + m + d + \"T\" + pad2(runHour);\n\t\t}\n\n\t\tfunction cancelPreloadWork() {\n\t\t\tstate.preloadGeneration += 1;\n\t\t\tstate.preloadQueue = [];\n\t\t}\n\n\t\tfunction invalidateImageCacheForNewRun() {\n\t\t\tstate.imageCache = {};\n\t\t\tstate.imageLoadPromises = {};\n\t\t\tstate.frameResolveCache = {};\n\t\t\tclearAllFrameDateLists();\n\t\t\tstate.imageToken += 1;\n\t\t\tcancelPreloadWork();\n\t\t}\n\n\t\tfunction syncForecastCacheVersion() {\n\t\t\tvar runVersion = getForecastRunVersion();\n\t\t\tif (state.forecastRunVersion === runVersion) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tstate.forecastRunVersion = runVersion;\n\t\t\tstate.requestVersion = runVersion;\n\t\t\tinvalidateImageCacheForNewRun();\n\t\t\treturn true;\n\t\t}\n\n\t\tfunction getRequestUrl(url) {\n\t\t\tvar separator = url.indexOf(\"?\") === -1 ? \"?\" : \"&\";\n\t\t\treturn url + separator + \"v=\" + state.requestVersion;\n\t\t}\n\n\t\tfunction refreshPreloadUi() {\n\t\t\trenderParams();\n\t\t\trenderFrames();\n\t\t}\n\n\t\tfunction getParamSequenceLoadState(modelId, paramId) {\n\t\t\tvar param = getParamConfigForModel(modelId, paramId);\n\t\t\tvar i;\n\t\t\tvar loadState;\n\t\t\tvar hasLoading = false;\n\t\t\tvar hasLoaded = false;\n\t\t\tvar allLoaded = true;\n\n\t\t\tif (!param) {\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\n\t\t\tif (param.file) {\n\t\t\t\treturn getImageLoadState(param.file);\n\t\t\t}\n\n\t\t\tif (param.sequence) {\n\t\t\t\tfor (i = 0; i < param.sequence.steps; i += 1) {\n\t\t\t\t\tloadState = getFrameImageLoadState(modelId, paramId, i);\n\t\t\t\t\tif (loadState === \"loading\") {\n\t\t\t\t\t\thasLoading = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState === \"loaded\") {\n\t\t\t\t\t\thasLoaded = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState !== \"loaded\") {\n\t\t\t\t\t\tallLoaded = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (allLoaded) {\n\t\t\t\t\treturn \"loaded\";\n\t\t\t\t}\n\t\t\t\tif (hasLoading) {\n\t\t\t\t\treturn \"loading\";\n\t\t\t\t}\n\t\t\t\tif (hasLoaded) {\n\t\t\t\t\treturn \"loading\";\n\t\t\t\t}\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\n\t\t\treturn \"pending\";\n\t\t}\n\n\t\tfunction getParamLoadState(paramId) {\n\t\t\treturn getParamSequenceLoadState(state.model, paramId);\n\t\t}\n\n\t\tfunction isImageLoaded(url) {\n\t\t\tvar cached = state.imageCache[url];\n\t\t\treturn !!(cached && cached.complete && cached.naturalWidth > 0);\n\t\t}\n\n\t\tfunction getImageLoadState(url) {\n\t\t\tif (isImageLoaded(url)) {\n\t\t\t\treturn \"loaded\";\n\t\t\t}\n\t\t\tif (state.imageLoadPromises[url]) {\n\t\t\t\treturn \"loading\";\n\t\t\t}\n\t\t\treturn \"pending\";\n\t\t}\n\n\t\tfunction ensureImage(url) {\n\t\t\tif (!url) {\n\t\t\t\treturn Promise.reject(new Error(\"Brak URL obrazu\"));\n\t\t\t}\n\t\t\tsyncForecastCacheVersion();\n\t\t\tif (isImageLoaded(url)) {\n\t\t\t\treturn Promise.resolve(state.imageCache[url]);\n\t\t\t}\n\t\t\tif (state.imageLoadPromises[url]) {\n\t\t\t\treturn state.imageLoadPromises[url];\n\t\t\t}\n\n\t\t\tstate.imageLoadPromises[url] = new Promise(function(resolve, reject) {\n\t\t\t\tvar loadVersion = state.requestVersion;\n\t\t\t\tvar img = new Image();\n\t\t\t\timg.onload = function() {\n\t\t\t\t\tif (loadVersion !== state.requestVersion) {\n\t\t\t\t\t\tdelete state.imageLoadPromises[url];\n\t\t\t\t\t\treject(new Error(\"Nieaktualny przebieg prognozy\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tstate.imageCache[url] = img;\n\t\t\t\t\tdelete state.imageLoadPromises[url];\n\t\t\t\t\tresolve(img);\n\t\t\t\t};\n\t\t\t\timg.onerror = function() {\n\t\t\t\t\tdelete state.imageLoadPromises[url];\n\t\t\t\t\tdelete state.imageCache[url];\n\t\t\t\t\treject(new Error(\"Nie uda\u0142o si\u0119 za\u0142adowa\u0107 obrazu\"));\n\t\t\t\t};\n\t\t\t\timg.src = getRequestUrl(url);\n\t\t\t});\n\n\t\t\treturn state.imageLoadPromises[url];\n\t\t}\n\n\t\tfunction showStatus(msg) {\n\t\t\tvar el = document.getElementById(\"midtermStatus\");\n\t\t\tif (!msg) {\n\t\t\t\tel.style.display = \"none\";\n\t\t\t\tel.textContent = \"\";\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tel.style.display = \"block\";\n\t\t\tel.textContent = msg;\n\t\t}\n\n\t\tfunction showLoader(show) {\n\t\t\tvar loader = document.getElementById(\"midtermLoader\");\n\t\t\tif (!loader) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tloader.style.display = show ? \"flex\" : \"none\";\n\t\t}\n\n\t\tfunction closeCompareModal() {\n\t\t\tvar modal = document.getElementById(\"midtermCompareModal\");\n\t\t\tmodal.style.display = \"none\";\n\t\t\tstate.compareModalParam = \"\";\n\t\t}\n\n\t\tfunction isCompareModalOpen() {\n\t\t\tvar modal = document.getElementById(\"midtermCompareModal\");\n\t\t\treturn !!(modal && modal.style.display === \"flex\");\n\t\t}\n\n\t\tfunction closeCompareParamsModal() {\n\t\t\tvar modal = document.getElementById(\"midtermCompareParamsModal\");\n\t\t\tif (modal) {\n\t\t\t\tmodal.style.display = \"none\";\n\t\t\t}\n\t\t}\n\n\t\tfunction isCompareParamsModalOpen() {\n\t\t\tvar modal = document.getElementById(\"midtermCompareParamsModal\");\n\t\t\treturn !!(modal && modal.style.display === \"flex\");\n\t\t}\n\n\t\tfunction renderCompareParamsMultiPicker() {\n\t\t\tvar wrap = document.getElementById(\"midtermCompareParamsMultiList\");\n\t\t\tvar modelLabel = document.getElementById(\"midtermCompareParamsModelLabel\");\n\t\t\tvar params = getModelConfig().params;\n\t\t\tvar i;\n\n\t\t\tif (!wrap) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (modelLabel) {\n\t\t\t\tmodelLabel.textContent = getModelConfig().label;\n\t\t\t}\n\n\t\t\twrap.innerHTML = \"\";\n\n\t\t\tif (params.length < 2) {\n\t\t\t\tvar noParamsMsg = document.createElement(\"div\");\n\t\t\t\tnoParamsMsg.style.padding = \"20px\";\n\t\t\t\tnoParamsMsg.style.textAlign = \"center\";\n\t\t\t\tnoParamsMsg.style.color = \"#666\";\n\t\t\t\tnoParamsMsg.textContent = \"Ten model ma mniej ni\u017c dwa parametry do por\u00f3wnania.\";\n\t\t\t\twrap.appendChild(noParamsMsg);\n\t\t\t\tupdateCompareParamsConfirmButton();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstate.compareSelectedParams = state.compareSelectedParams.filter(function(paramId) {\n\t\t\t\treturn !!getParamConfigForModel(state.model, paramId);\n\t\t\t});\n\t\t\tif (!state.compareSelectedParams.length) {\n\t\t\t\tstate.compareSelectedParams = [state.param];\n\t\t\t}\n\t\t\tif (state.compareSelectedParams.length < 2) {\n\t\t\t\tfor (i = 0; i < params.length; i += 1) {\n\t\t\t\t\tif (state.compareSelectedParams.indexOf(params[i].id) === -1) {\n\t\t\t\t\t\tstate.compareSelectedParams.push(params[i].id);\n\t\t\t\t\t\tif (state.compareSelectedParams.length >= 2) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (i = 0; i < params.length; i += 1) {\n\t\t\t\t(function(paramCfg) {\n\t\t\t\t\tvar item = document.createElement(\"div\");\n\t\t\t\t\titem.className = \"compare-param-item\";\n\t\t\t\t\titem.textContent = paramCfg.label;\n\t\t\t\t\titem.dataset.param = paramCfg.id;\n\t\t\t\t\tif (state.compareSelectedParams.indexOf(paramCfg.id) !== -1) {\n\t\t\t\t\t\titem.classList.add(\"selected\");\n\t\t\t\t\t}\n\t\t\t\t\titem.addEventListener(\"click\", function() {\n\t\t\t\t\t\tvar paramId = this.dataset.param;\n\t\t\t\t\t\tvar index = state.compareSelectedParams.indexOf(paramId);\n\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\tif (state.compareSelectedParams.length <= 1) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstate.compareSelectedParams.splice(index, 1);\n\t\t\t\t\t\t\tthis.classList.remove(\"selected\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstate.compareSelectedParams.push(paramId);\n\t\t\t\t\t\t\tthis.classList.add(\"selected\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tupdateCompareParamsConfirmButton();\n\t\t\t\t\t});\n\t\t\t\t\twrap.appendChild(item);\n\t\t\t\t}(params[i]));\n\t\t\t}\n\n\t\t\tupdateCompareParamsConfirmButton();\n\t\t}\n\n\t\tfunction openCompareParamsModal() {\n\t\t\tvar modal = document.getElementById(\"midtermCompareParamsModal\");\n\n\t\t\tif (!canCompareParamsForModel()) {\n\t\t\t\tshowStatus(\"Por\u00f3wnanie parametr\u00f3w wymaga co najmniej dw\u00f3ch map w modelu.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\trenderCompareParamsMultiPicker();\n\t\t\tmodal.style.display = \"flex\";\n\t\t}\n\n\t\tfunction updateCompareParamsConfirmButton() {\n\t\t\tvar confirmBtn = document.getElementById(\"midtermCompareParamsConfirm\");\n\t\t\tvar count = state.compareSelectedParams.length;\n\t\t\tif (!confirmBtn) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (count >= 2) {\n\t\t\t\tconfirmBtn.disabled = false;\n\t\t\t\tconfirmBtn.textContent = count === 2\n\t\t\t\t\t? \"Por\u00f3wnaj 2 parametry\"\n\t\t\t\t\t: \"Por\u00f3wnaj \" + count + \" parametry\";\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconfirmBtn.disabled = true;\n\t\t\tconfirmBtn.textContent = \"Wybierz co najmniej 2 parametry\";\n\t\t}\n\n\t\tfunction renderCompareParamPicker() {\n\t\t\tvar section = document.getElementById(\"midtermCompareParamSection\");\n\t\t\tvar wrap = document.getElementById(\"midtermCompareParams\");\n\t\t\tvar options = getCompareParamOptions();\n\t\t\tvar i;\n\n\t\t\tif (!section || !wrap) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsection.style.display = \"block\";\n\t\t\twrap.innerHTML = \"\";\n\n\t\t\tif (!options.length) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!state.compareModalParam || !isParamCompareable(state.compareModalParam)) {\n\t\t\t\tstate.compareModalParam = isCompareParam() ? state.param : options[0].id;\n\t\t\t}\n\n\t\t\tfor (i = 0; i < options.length; i += 1) {\n\t\t\t\t(function(option) {\n\t\t\t\t\tvar item = document.createElement(\"div\");\n\t\t\t\t\titem.className = \"compare-param-item\";\n\t\t\t\t\titem.textContent = option.label;\n\t\t\t\t\titem.dataset.param = option.id;\n\t\t\t\t\tif (option.id === state.compareModalParam) {\n\t\t\t\t\t\titem.classList.add(\"selected\");\n\t\t\t\t\t}\n\t\t\t\t\titem.addEventListener(\"click\", function() {\n\t\t\t\t\t\tif (state.compareModalParam === option.id) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstate.compareModalParam = option.id;\n\t\t\t\t\t\tstate.compareSelectedModels = [];\n\t\t\t\t\t\trenderCompareParamPicker();\n\t\t\t\t\t\trenderCompareModelPicker(state.compareModalParam);\n\t\t\t\t\t});\n\t\t\t\t\twrap.appendChild(item);\n\t\t\t\t}(options[i]));\n\t\t\t}\n\t\t}\n\n\t\tfunction renderCompareModelPicker(paramId) {\n\t\t\tvar eligible = getEligibleCompareModelIds(paramId);\n\t\t\tvar list = document.getElementById(\"midtermCompareList\");\n\t\t\tvar i;\n\n\t\t\tif (!list) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlist.innerHTML = \"\";\n\n\t\t\tif (eligible.length < 2) {\n\t\t\t\tvar noModelsMsg = document.createElement(\"div\");\n\t\t\t\tnoModelsMsg.style.padding = \"20px\";\n\t\t\t\tnoModelsMsg.style.textAlign = \"center\";\n\t\t\t\tnoModelsMsg.style.color = \"#666\";\n\t\t\t\tnoModelsMsg.textContent = \"Por\u00f3wnanie modeli nie jest mo\u017cliwe dla tego parametru \u2014 tylko jeden model ma ten parametr.\";\n\t\t\t\tlist.appendChild(noModelsMsg);\n\t\t\t\tupdateCompareConfirmButton();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstate.compareSelectedModels = state.compareSelectedModels.filter(function(modelId) {\n\t\t\t\treturn eligible.indexOf(modelId) !== -1;\n\t\t\t});\n\t\t\tif (!state.compareSelectedModels.length && eligible.indexOf(state.model) !== -1) {\n\t\t\t\tstate.compareSelectedModels = [state.model];\n\t\t\t}\n\t\t\tif (state.region === \"EU\" && state.compareSelectedModels.length < 2 && eligible.length >= 2) {\n\t\t\t\tstate.compareSelectedModels = eligible.slice(0, 2);\n\t\t\t}\n\n\t\t\tfor (i = 0; i < eligible.length; i += 1) {\n\t\t\t\t(function(modelId) {\n\t\t\t\t\tvar item = document.createElement(\"div\");\n\t\t\t\t\titem.className = \"compare-model-item\";\n\t\t\t\t\titem.textContent = getRegionConfig().models[modelId].label;\n\t\t\t\t\titem.dataset.model = modelId;\n\t\t\t\t\tif (state.compareSelectedModels.indexOf(modelId) !== -1) {\n\t\t\t\t\t\titem.classList.add(\"selected\");\n\t\t\t\t\t}\n\t\t\t\t\titem.addEventListener(\"click\", function() {\n\t\t\t\t\t\tvar model = this.dataset.model;\n\t\t\t\t\t\tvar index = state.compareSelectedModels.indexOf(model);\n\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\tstate.compareSelectedModels.splice(index, 1);\n\t\t\t\t\t\t\tthis.classList.remove(\"selected\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstate.compareSelectedModels.push(model);\n\t\t\t\t\t\t\tthis.classList.add(\"selected\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tupdateCompareConfirmButton();\n\t\t\t\t\t});\n\t\t\t\t\tlist.appendChild(item);\n\t\t\t\t}(eligible[i]));\n\t\t\t}\n\n\t\t\tupdateCompareConfirmButton();\n\t\t}\n\n\t\tfunction openCompareModal() {\n\t\t\tvar modal = document.getElementById(\"midtermCompareModal\");\n\t\t\tvar modalContent = modal ? modal.querySelector(\".compare-modal-content\") : null;\n\t\t\tvar selectGrid = document.getElementById(\"midtermCompareSelectGrid\");\n\t\t\tvar modalTitle = document.querySelector(\"#midtermCompareModal .compare-modal-header .model-group-title\");\n\n\t\t\tif (state.region === \"EU\" && !canCompareCurrentSelection()) {\n\t\t\t\tshowStatus(\"Por\u00f3wnanie niedost\u0119pne dla wybranego ustawienia.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (modalTitle) {\n\t\t\t\tmodalTitle.textContent = \"Wybierz parametr i modele do por\u00f3wnania\";\n\t\t\t}\n\n\t\t\trenderCompareParamPicker();\n\t\t\tif (selectGrid) {\n\t\t\t\tselectGrid.classList.remove(\"models-only\");\n\t\t\t}\n\t\t\tif (modalContent) {\n\t\t\t\tmodalContent.classList.add(\"compare-modal-wide\");\n\t\t\t}\n\n\t\t\trenderCompareModelPicker(getCompareModalParamId());\n\t\t\tmodal.style.display = \"flex\";\n\t\t}\n\n\t\tfunction updateCompareConfirmButton() {\n\t\t\tvar confirmBtn = document.getElementById(\"midtermCompareConfirm\");\n\t\t\tvar count = state.compareSelectedModels.length;\n\t\t\tif (count >= 1) {\n\t\t\t\tconfirmBtn.disabled = false;\n\t\t\t\tconfirmBtn.textContent = count === 1 ? \"Por\u00f3wnaj 1 model\" : \"Por\u00f3wnaj \" + count + \" modele\";\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconfirmBtn.disabled = true;\n\t\t\tconfirmBtn.textContent = \"Wybierz modele do por\u00f3wnania\";\n\t\t}\n\n\t\tfunction toggleCompareMode() {\n\t\t\tif (isCompareModalOpen()) {\n\t\t\t\tcloseCompareModal();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (isCompareParamsModalOpen()) {\n\t\t\t\tcloseCompareParamsModal();\n\t\t\t}\n\t\t\tif (state.compareMode) {\n\t\t\t\texitCompareMode();\n\t\t\t\trenderAll();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.compareKind = \"models\";\n\t\t\topenCompareModal();\n\t\t}\n\n\t\tfunction toggleCompareParamsMode() {\n\t\t\tif (isCompareParamsModalOpen()) {\n\t\t\t\tcloseCompareParamsModal();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (isCompareModalOpen()) {\n\t\t\t\tcloseCompareModal();\n\t\t\t}\n\t\t\tif (state.compareMode && state.compareKind === \"params\") {\n\t\t\t\texitCompareMode();\n\t\t\t\trenderAll();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (state.compareMode) {\n\t\t\t\texitCompareMode();\n\t\t\t}\n\t\t\topenCompareParamsModal();\n\t\t}\n\n\t\tfunction isMobileViewport() {\n\t\t\treturn window.innerWidth <= 768;\n\t\t}\n\n\t\tfunction getCompareItemCount() {\n\t\t\tif (!state.compareMode) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (state.compareKind === \"params\") {\n\t\t\t\treturn getActiveCompareParamIds().length;\n\t\t\t}\n\t\t\treturn getActiveCompareModelIds().length;\n\t\t}\n\n\t\tfunction getAverageImageAspectRatio(results) {\n\t\t\tvar sum = 0;\n\t\t\tvar count = 0;\n\t\t\tvar i;\n\t\t\tvar img;\n\n\t\t\tfor (i = 0; i < results.length; i += 1) {\n\t\t\t\timg = results[i].img;\n\t\t\t\tif (img && img.naturalWidth > 0 && img.naturalHeight > 0) {\n\t\t\t\t\tsum += img.naturalWidth \/ img.naturalHeight;\n\t\t\t\t\tcount += 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn count ? sum \/ count : 0;\n\t\t}\n\n\t\tfunction computeCompareFullscreenColumns(itemCount, results) {\n\t\t\tvar padding = 24;\n\t\t\tvar gap = 10;\n\t\t\tvar minCellWidth = 220;\n\t\t\tvar minCellHeight = 140;\n\t\t\tvar vw = Math.max(320, window.innerWidth - padding);\n\t\t\tvar vh = Math.max(240, window.innerHeight - padding);\n\t\t\tvar aspectRatio = getAverageImageAspectRatio(results) || 1.35;\n\t\t\tvar maxColsByWidth = Math.floor((vw + gap) \/ (minCellWidth + gap));\n\t\t\tvar maxCols = Math.max(1, Math.min(itemCount, maxColsByWidth, 4));\n\t\t\tvar bestCols = Math.min(2, itemCount);\n\t\t\tvar bestScore = -1;\n\t\t\tvar cols;\n\t\t\tvar rows;\n\t\t\tvar cellW;\n\t\t\tvar cellH;\n\t\t\tvar fitW;\n\t\t\tvar fitH;\n\t\t\tvar area;\n\t\t\tvar wastePenalty;\n\t\t\tvar score;\n\n\t\t\tif (itemCount <= 1) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tfor (cols = 1; cols <= maxCols; cols += 1) {\n\t\t\t\trows = Math.ceil(itemCount \/ cols);\n\t\t\t\tcellW = (vw - gap * (cols - 1)) \/ cols;\n\t\t\t\tcellH = (vh - gap * (rows - 1)) \/ rows;\n\n\t\t\t\tif (cellW < minCellWidth * 0.8 || cellH < minCellHeight * 0.8) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfitW = Math.min(cellW, cellH * aspectRatio);\n\t\t\t\tfitH = fitW \/ aspectRatio;\n\t\t\t\tif (fitH > cellH) {\n\t\t\t\t\tfitH = cellH;\n\t\t\t\t\tfitW = fitH * aspectRatio;\n\t\t\t\t}\n\n\t\t\t\tarea = fitW * fitH;\n\t\t\t\twastePenalty = itemCount \/ (cols * rows);\n\t\t\t\tscore = area * wastePenalty;\n\n\t\t\t\tif (score > bestScore) {\n\t\t\t\t\tbestScore = score;\n\t\t\t\t\tbestCols = cols;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn bestCols;\n\t\t}\n\n\t\tfunction canUseCompareFullscreen() {\n\t\t\tif (!state.compareMode || isMobileViewport() || getCompareItemCount() < 2) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (state.region === \"EU\") {\n\t\t\t\treturn getEffectiveFrameCount() > 1;\n\t\t\t}\n\t\t\treturn state.region === \"PL\";\n\t\t}\n\n\t\tfunction closeCompareFullscreen() {\n\t\t\tif (!state.compareFullscreen) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.compareFullscreen = false;\n\t\t\tvar overlay = document.getElementById(\"midtermCompareFullscreen\");\n\t\t\tvar grid = document.getElementById(\"midtermCompareFullscreenGrid\");\n\t\t\tif (overlay) {\n\t\t\t\toverlay.classList.remove(\"active\");\n\t\t\t}\n\t\t\tif (grid) {\n\t\t\t\tgrid.innerHTML = \"\";\n\t\t\t}\n\t\t\tupdateFullscreenButtonState();\n\t\t\tupdateKeyboardHints();\n\t\t}\n\n\t\tfunction openCompareFullscreen() {\n\t\t\tif (!canUseCompareFullscreen()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.compareFullscreen = true;\n\t\t\tvar overlay = document.getElementById(\"midtermCompareFullscreen\");\n\t\t\tif (overlay) {\n\t\t\t\toverlay.classList.add(\"active\");\n\t\t\t}\n\t\t\tupdateFullscreenButtonState();\n\t\t\tupdateKeyboardHints();\n\t\t\trenderCompareFullscreen();\n\t\t}\n\n\t\tfunction toggleCompareFullscreen() {\n\t\t\tif (state.compareFullscreen) {\n\t\t\t\tcloseCompareFullscreen();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\topenCompareFullscreen();\n\t\t}\n\n\t\tfunction getCompareResultsFromCache(selectedForCompare) {\n\t\t\tvar models = getRegionConfig().models;\n\t\t\treturn selectedForCompare.map(function(modelId) {\n\t\t\t\tvar file = getParamUrlForModel(modelId, state.param, state.frameIndex);\n\t\t\t\treturn {\n\t\t\t\t\tmodelId: modelId,\n\t\t\t\t\tlabel: models[modelId].label,\n\t\t\t\t\timg: state.imageCache[file] || null\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\n\t\tfunction loadCompareResults(selectedForCompare) {\n\t\t\tvar models = getRegionConfig().models;\n\t\t\treturn ensureCompareFrameDateLists().then(function() {\n\t\t\t\treturn Promise.all(selectedForCompare.map(function(modelId) {\n\t\t\t\t\treturn ensureModelParamFrameImage(modelId, state.param, state.frameIndex).then(function(img) {\n\t\t\t\t\t\treturn { modelId: modelId, label: models[modelId].label, img: img };\n\t\t\t\t\t}).catch(function() {\n\t\t\t\t\t\treturn { modelId: modelId, label: models[modelId].label, img: null };\n\t\t\t\t\t});\n\t\t\t\t}));\n\t\t\t});\n\t\t}\n\n\t\tfunction getCompareParamResultsFromCache(selectedParams) {\n\t\t\treturn selectedParams.map(function(paramId) {\n\t\t\t\tvar paramCfg = getParamConfigForModel(state.model, paramId);\n\t\t\t\tvar file = getParamUrlForModel(state.model, paramId, state.frameIndex);\n\t\t\t\treturn {\n\t\t\t\t\tparamId: paramId,\n\t\t\t\t\tlabel: paramCfg ? paramCfg.label : paramId,\n\t\t\t\t\timg: state.imageCache[file] || null\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\n\t\tfunction loadCompareParamResults(selectedParams) {\n\t\t\treturn ensureCompareFrameDateLists().then(function() {\n\t\t\t\treturn Promise.all(selectedParams.map(function(paramId) {\n\t\t\t\t\tvar paramCfg = getParamConfigForModel(state.model, paramId);\n\t\t\t\t\treturn ensureModelParamFrameImage(state.model, paramId, state.frameIndex).then(function(img) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tparamId: paramId,\n\t\t\t\t\t\t\tlabel: paramCfg ? paramCfg.label : paramId,\n\t\t\t\t\t\t\timg: img\n\t\t\t\t\t\t};\n\t\t\t\t\t}).catch(function() {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tparamId: paramId,\n\t\t\t\t\t\t\tlabel: paramCfg ? paramCfg.label : paramId,\n\t\t\t\t\t\t\timg: null\n\t\t\t\t\t\t};\n\t\t\t\t\t});\n\t\t\t\t}));\n\t\t\t});\n\t\t}\n\n\t\tfunction renderCompareFullscreen() {\n\t\t\tif (!state.compareFullscreen || !canUseCompareFullscreen()) {\n\t\t\t\tcloseCompareFullscreen();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar grid = document.getElementById(\"midtermCompareFullscreenGrid\");\n\t\t\tvar selectedForCompare;\n\t\t\tvar allCached;\n\t\t\tvar loadPromise;\n\n\t\t\tif (!grid) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfunction paint(results) {\n\t\t\t\tif (!state.compareFullscreen) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tappendCompareGrid(grid, results, {\n\t\t\t\t\tenableLightbox: false,\n\t\t\t\t\tuseSideGrid: getCompareItemCount() > 1,\n\t\t\t\t\tshowLabels: false,\n\t\t\t\t\tfullscreen: true\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (state.compareKind === \"params\") {\n\t\t\t\tselectedForCompare = getActiveCompareParamIds();\n\t\t\t\tif (!selectedForCompare.length) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tallCached = selectedForCompare.every(function(paramId) {\n\t\t\t\t\treturn isFrameImageLoaded(state.model, paramId, state.frameIndex);\n\t\t\t\t});\n\t\t\t\tloadPromise = allCached\n\t\t\t\t\t? Promise.resolve(getCompareParamResultsFromCache(selectedForCompare))\n\t\t\t\t\t: loadCompareParamResults(selectedForCompare);\n\t\t\t} else {\n\t\t\t\tselectedForCompare = getActiveCompareModelIds();\n\t\t\t\tif (!selectedForCompare.length) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tallCached = selectedForCompare.every(function(modelId) {\n\t\t\t\t\treturn isFrameImageLoaded(modelId, state.param, state.frameIndex);\n\t\t\t\t});\n\t\t\t\tloadPromise = allCached\n\t\t\t\t\t? Promise.resolve(getCompareResultsFromCache(selectedForCompare))\n\t\t\t\t\t: loadCompareResults(selectedForCompare);\n\t\t\t}\n\n\t\t\tloadPromise.then(paint);\n\t\t}\n\n\t\tfunction updateCompareButtonState() {\n\t\t\tvar btn = document.getElementById(\"midtermCompareBtn\");\n\t\t\tif (!btn) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar compactLabels = state.region === \"EU\" && getEffectiveFrameCount() > 1;\n\t\t\tbtn.classList.remove(\"active\");\n\t\t\tif (state.compareMode && state.compareKind === \"models\") {\n\t\t\t\tbtn.textContent = compactLabels ? \"\u2715 Modele\" : \"\u2715 Wy\u0142\u0105cz por\u00f3wnanie modeli\";\n\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t\tbtn.disabled = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbtn.textContent = compactLabels ? \"\u229e Modele\" : \"\u229e Por\u00f3wnaj modele\";\n\t\t\tbtn.disabled = !canCompareCurrentSelection();\n\t\t}\n\n\t\tfunction updateCompareParamsButtonState() {\n\t\t\tvar btn = document.getElementById(\"midtermCompareParamsBtn\");\n\t\t\tif (!btn) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar compactLabels = state.region === \"EU\" && getEffectiveFrameCount() > 1;\n\t\t\tbtn.classList.remove(\"active\");\n\t\t\tif (state.compareMode && state.compareKind === \"params\") {\n\t\t\t\tbtn.textContent = compactLabels ? \"\u2715 Parametry\" : \"\u2715 Wy\u0142\u0105cz por\u00f3wnanie parametr\u00f3w\";\n\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t\tbtn.disabled = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbtn.textContent = compactLabels ? \"\u229e Parametry\" : \"\u229e Por\u00f3wnaj parametry\";\n\t\t\tbtn.disabled = canCompareParamsForModel() ? false : true;\n\t\t}\n\n\t\tfunction updateAnimateButtonState() {\n\t\t\tvar btn = document.getElementById(\"midtermAnimateBtnLeft\");\n\t\t\tif (!btn) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbtn.classList.remove(\"active\");\n\t\t\tbtn.textContent = \"\u25b6 Animuj\";\n\t\t\tif (state.animating) {\n\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t\tbtn.textContent = \"\u23f8 Stop\";\n\t\t\t}\n\t\t}\n\n\t\tfunction updateFullscreenButtonState() {\n\t\t\tvar btn = document.getElementById(\"midtermFullscreenBtn\");\n\t\t\tif (!btn) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbtn.classList.remove(\"active\");\n\t\t\tbtn.textContent = \"\u26f6 Pe\u0142ny ekran\";\n\t\t\tif (state.compareFullscreen) {\n\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t\tbtn.textContent = \"\u2715 Pe\u0142ny ekran\";\n\t\t\t}\n\t\t}\n\n\t\tfunction updateLeftActionButtons() {\n\t\t\tvar animateBtn = document.getElementById(\"midtermAnimateBtnLeft\");\n\t\t\tvar fullscreenBtn = document.getElementById(\"midtermFullscreenBtn\");\n\t\t\tvar section = document.getElementById(\"midtermCompareSection\");\n\t\t\tvar showEuFrameActions = state.region === \"EU\" && getFrameCount() > 1;\n\t\t\tvar showCompareFullscreen = canUseCompareFullscreen();\n\n\t\t\tif (animateBtn) {\n\t\t\t\tanimateBtn.style.display = showEuFrameActions ? \"block\" : \"none\";\n\t\t\t}\n\t\t\tif (fullscreenBtn) {\n\t\t\t\tfullscreenBtn.style.display = showCompareFullscreen ? \"block\" : \"none\";\n\t\t\t}\n\t\t\tif (section) {\n\t\t\t\tsection.style.display = state.region === \"PL\" || showEuFrameActions ? \"block\" : \"none\";\n\t\t\t}\n\t\t\tif (!showEuFrameActions && state.animating) {\n\t\t\t\tstopAnimation();\n\t\t\t}\n\t\t\tif (!showCompareFullscreen && state.compareFullscreen) {\n\t\t\t\tcloseCompareFullscreen();\n\t\t\t}\n\t\t\tupdateCompareButtonState();\n\t\t\tupdateCompareParamsButtonState();\n\t\t\tupdateAnimateButtonState();\n\t\t\tupdateFullscreenButtonState();\n\t\t}\n\n\t\tfunction updateKeyboardHints() {\n\t\t\tvar modelShortcut = document.getElementById(\"midtermModelShortcutRow\");\n\t\t\tvar framesShortcut = document.getElementById(\"midtermFramesShortcutRow\");\n\t\t\tvar animShortcut = document.getElementById(\"midtermAnimShortcutRow\");\n\t\t\tvar fullscreenShortcut = document.getElementById(\"midtermFullscreenShortcutRow\");\n\t\t\tvar showForecastShortcuts = state.region === \"EU\" && getFrameCount() > 1;\n\t\t\tvar modelCount = getOrderedModelIds().length;\n\t\t\tvar modelRange = modelCount > 1 ? \"1-\" + modelCount : \"1\";\n\n\t\t\tif (modelShortcut) {\n\t\t\t\tmodelShortcut.innerHTML = modelRange + \" | Zmiana modelu<br>\";\n\t\t\t}\n\t\t\tif (framesShortcut) {\n\t\t\t\tframesShortcut.style.display = showForecastShortcuts ? \"inline\" : \"none\";\n\t\t\t}\n\t\t\tif (animShortcut) {\n\t\t\t\tanimShortcut.style.display = showForecastShortcuts ? \"inline\" : \"none\";\n\t\t\t}\n\t\t\tif (fullscreenShortcut) {\n\t\t\t\tfullscreenShortcut.style.display = canUseCompareFullscreen() ? \"inline\" : \"none\";\n\t\t\t}\n\t\t}\n\n\t\tfunction renderFrameSliderLabels() {\n\t\t\tvar labels = document.getElementById(\"midtermFrameLabels\");\n\t\t\tvar frameCount = getFrameCount();\n\n\t\t\tif (!labels) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlabels.innerHTML = \"\";\n\n\t\t\tif (frameCount <= 1) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar denominator = Math.max(1, frameCount - 1);\n\t\t\tvar i;\n\n\t\t\tfor (i = 0; i < frameCount; i += 1) {\n\t\t\t\tvar loadState = getFrameLoadState(i);\n\t\t\t\tvar label = document.createElement(\"div\");\n\t\t\t\tlabel.className = \"hour-label-marker\";\n\t\t\t\tlabel.textContent = getFrameDisplayLabel(i);\n\t\t\t\tif (loadState === \"pending\" || loadState === \"loading\") {\n\t\t\t\t\tlabel.classList.add(\"preload-pending\");\n\t\t\t\t}\n\t\t\t\tif (loadState === \"loaded\") {\n\t\t\t\t\tlabel.classList.add(\"preload-loaded\");\n\t\t\t\t}\n\t\t\t\tif (i === 0) {\n\t\t\t\t\tlabel.classList.add(\"first\");\n\t\t\t\t} else if (i === frameCount - 1) {\n\t\t\t\t\tlabel.classList.add(\"last\");\n\t\t\t\t\tlabel.style.left = ((i \/ denominator) * 100) + \"%\";\n\t\t\t\t} else {\n\t\t\t\t\tlabel.style.left = ((i \/ denominator) * 100) + \"%\";\n\t\t\t\t}\n\t\t\t\tlabels.appendChild(label);\n\t\t\t}\n\t\t}\n\n\t\tfunction renderRegions() {\n\t\t\tvar wrap = document.getElementById(\"midtermRegions\");\n\t\t\twrap.innerHTML = \"\";\n\n\t\t\tObject.keys(data).forEach(function(regionId) {\n\t\t\t\tvar btn = document.createElement(\"button\");\n\t\t\t\tbtn.type = \"button\";\n\t\t\t\tbtn.textContent = data[regionId].label;\n\t\t\t\tif (regionId === state.region) {\n\t\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t\t}\n\t\t\t\tbtn.addEventListener(\"click\", function() {\n\t\t\t\t\tsetRegion(regionId);\n\t\t\t\t});\n\t\t\t\twrap.appendChild(btn);\n\t\t\t});\n\t\t}\n\n\t\tfunction toggleParamInComparison(paramId) {\n\t\t\tvar index = state.compareSelectedParams.indexOf(paramId);\n\n\t\t\tif (index !== -1) {\n\t\t\t\tif (state.compareSelectedParams.length <= 2) {\n\t\t\t\t\tshowStatus(\"W por\u00f3wnaniu musz\u0105 pozosta\u0107 co najmniej dwa parametry.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tstate.compareSelectedParams.splice(index, 1);\n\t\t\t\tif (state.param === paramId) {\n\t\t\t\t\tstate.param = state.compareSelectedParams[0];\n\t\t\t\t\tstate.frameIndex = 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstate.compareSelectedParams.push(paramId);\n\t\t\t\tstate.param = paramId;\n\t\t\t\tstate.frameIndex = 0;\n\t\t\t}\n\n\t\t\tstopAnimation();\n\t\t\tresetComparePreload();\n\t\t\tclearFrameResolveCache();\n\t\t\tshowStatus(\"\");\n\t\t\trenderParams();\n\t\t\trenderFrames();\n\t\t\tupdateLeftActionButtons();\n\t\t\tensureCompareFrameDateLists().then(function() {\n\t\t\t\trenderImage();\n\t\t\t});\n\t\t}\n\n\t\tfunction toggleModelInComparison(modelId) {\n\t\t\tvar eligible = getEligibleCompareModelIds();\n\n\t\t\tif (eligible.indexOf(modelId) === -1) {\n\t\t\t\tshowStatus(\"Ten model nie udost\u0119pnia wybranego parametru.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar index = state.compareSelectedModels.indexOf(modelId);\n\t\t\tvar minModels = eligible.length >= 2 ? 2 : 1;\n\n\t\t\tif (index !== -1) {\n\t\t\t\tif (state.compareSelectedModels.length <= minModels) {\n\t\t\t\t\tshowStatus(minModels === 2\n\t\t\t\t\t\t? \"W por\u00f3wnaniu musz\u0105 pozosta\u0107 co najmniej dwa modele.\"\n\t\t\t\t\t\t: \"W por\u00f3wnaniu musi pozosta\u0107 co najmniej jeden model.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tstate.compareSelectedModels.splice(index, 1);\n\t\t\t} else {\n\t\t\t\tstate.compareSelectedModels.push(modelId);\n\t\t\t}\n\n\t\t\tif (state.compareSelectedModels.indexOf(state.model) === -1) {\n\t\t\t\tstate.model = state.compareSelectedModels[0];\n\t\t\t}\n\n\t\t\tstopAnimation();\n\t\t\tresetComparePreload();\n\t\t\tclearFrameResolveCache();\n\t\t\tshowStatus(\"\");\n\t\t\trenderModels();\n\t\t\trenderFrames();\n\t\t\tupdateLeftActionButtons();\n\t\t\tensureCompareFrameDateLists().then(function() {\n\t\t\t\trenderImage();\n\t\t\t});\n\t\t}\n\n\t\tfunction renderModels() {\n\t\t\tvar wrap = document.getElementById(\"midtermModels\");\n\t\t\twrap.innerHTML = \"\";\n\t\t\tvar models = getRegionConfig().models;\n\t\t\tvar orderedModelIds = getOrderedModelIds();\n\t\t\tvar physicalModelIds = [];\n\t\t\tvar aiModelIds = [];\n\n\t\t\tfunction appendGroupTitle(text) {\n\t\t\t\tvar title = document.createElement(\"div\");\n\t\t\t\ttitle.className = \"model-group-title\";\n\t\t\t\ttitle.textContent = text;\n\t\t\t\twrap.appendChild(title);\n\t\t\t}\n\n\t\t\tfunction appendModelButton(modelId) {\n\t\t\t\tvar btn = document.createElement(\"button\");\n\t\t\t\tbtn.type = \"button\";\n\t\t\t\tbtn.textContent = models[modelId].label;\n\t\t\t\tif (state.compareMode && state.compareKind === \"models\") {\n\t\t\t\t\tif (state.compareSelectedModels.indexOf(modelId) !== -1) {\n\t\t\t\t\t\tbtn.classList.add(\"compare-selected\");\n\t\t\t\t\t}\n\t\t\t\t} else if (modelId === state.model) {\n\t\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t\t}\n\t\t\t\tbtn.addEventListener(\"click\", function() {\n\t\t\t\t\tif (state.compareMode && state.compareKind === \"models\") {\n\t\t\t\t\t\ttoggleModelInComparison(modelId);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.model === modelId) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tstopAnimation();\n\t\t\t\t\tresetComparePreload();\n\t\t\t\t\tsetModel(modelId);\n\t\t\t\t\trenderAll();\n\t\t\t\t});\n\t\t\t\twrap.appendChild(btn);\n\t\t\t}\n\n\t\t\torderedModelIds.forEach(function(modelId) {\n\t\t\t\tif (getModelType(modelId) === \"ai\") {\n\t\t\t\t\taiModelIds.push(modelId);\n\t\t\t\t} else {\n\t\t\t\t\tphysicalModelIds.push(modelId);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (physicalModelIds.length) {\n\t\t\t\tappendGroupTitle(\"Modele fizyczne\");\n\t\t\t\tphysicalModelIds.forEach(appendModelButton);\n\t\t\t}\n\n\t\t\tif (aiModelIds.length) {\n\t\t\t\tappendGroupTitle(\"Modele AI\");\n\t\t\t\taiModelIds.forEach(appendModelButton);\n\t\t\t}\n\t\t}\n\n\t\tfunction renderParams() {\n\t\t\tvar wrap = document.getElementById(\"midtermParams\");\n\t\t\tvar modelCfg = getModelConfig();\n\t\t\tvar params = modelCfg && modelCfg.params ? modelCfg.params : [];\n\t\t\twrap.innerHTML = \"\";\n\n\t\t\tparams.forEach(function(paramCfg) {\n\t\t\t\tvar btn = document.createElement(\"button\");\n\t\t\t\tbtn.type = \"button\";\n\t\t\t\tbtn.textContent = paramCfg.label;\n\t\t\t\tif (state.compareMode && state.compareKind === \"params\") {\n\t\t\t\t\tif (state.compareSelectedParams.indexOf(paramCfg.id) !== -1) {\n\t\t\t\t\t\tbtn.classList.add(\"compare-selected\");\n\t\t\t\t\t}\n\t\t\t\t} else if (paramCfg.id === state.param) {\n\t\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t\t}\n\t\t\t\tvar loadState = getParamLoadState(paramCfg.id);\n\t\t\t\tif (loadState === \"pending\") {\n\t\t\t\t\tbtn.classList.add(\"preload-pending\");\n\t\t\t\t}\n\t\t\t\tif (loadState === \"loading\") {\n\t\t\t\t\tbtn.classList.add(\"preload-pending\");\n\t\t\t\t\tbtn.classList.add(\"preload-loading\");\n\t\t\t\t}\n\t\t\t\tif (loadState === \"loaded\") {\n\t\t\t\t\tbtn.classList.add(\"preload-loaded\");\n\t\t\t\t}\n\t\t\t\tbtn.addEventListener(\"click\", function() {\n\t\t\t\t\tif (state.compareMode && state.compareKind === \"params\") {\n\t\t\t\t\t\ttoggleParamInComparison(paramCfg.id);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.param === paramCfg.id) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tstopAnimation();\n\t\t\t\t\tresetComparePreload();\n\t\t\t\t\tstate.param = paramCfg.id;\n\t\t\t\t\tstate.frameIndex = 0;\n\t\t\t\t\trenderAll();\n\t\t\t\t});\n\t\t\t\twrap.appendChild(btn);\n\t\t\t});\n\t\t}\n\n\t\tfunction renderFrames() {\n\t\t\tvar section = document.getElementById(\"midtermFramesSection\");\n\t\t\tvar wrap = document.getElementById(\"midtermFrames\");\n\t\t\tvar sliderWrap = document.getElementById(\"midtermSliderWrap\");\n\t\t\tvar slider = document.getElementById(\"midtermFrameSlider\");\n\t\t\tvar frameCount = getFrameCount();\n\n\t\t\twrap.innerHTML = \"\";\n\t\t\tif (frameCount <= 1) {\n\t\t\t\tsection.style.display = \"none\";\n\t\t\t\tsliderWrap.style.display = \"none\";\n\t\t\t\trenderFrameSliderLabels();\n\t\t\t\trenderFrameGradient();\n\t\t\t\tupdateKeyboardHints();\n\t\t\t\tupdateLeftActionButtons();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsection.style.display = \"block\";\n\t\t\tsliderWrap.style.display = \"block\";\n\t\t\tslider.min = \"0\";\n\t\t\tslider.max = String(frameCount - 1);\n\t\t\tslider.value = String(state.frameIndex);\n\n\t\t\tfor (var i = 0; i < frameCount; i += 1) {\n\t\t\t\t(function(index) {\n\t\t\t\t\tvar btn = document.createElement(\"button\");\n\t\t\t\t\tbtn.type = \"button\";\n\t\t\t\t\tbtn.textContent = getFrameDisplayLabel(index);\n\t\t\t\t\tbtn.title = \"Termin: \" + formatFrameDateVerbose(index);\n\t\t\t\t\tvar loadState = getFrameLoadState(index);\n\t\t\t\t\tif (loadState === \"pending\") {\n\t\t\t\t\t\tbtn.classList.add(\"preload-pending\");\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState === \"loading\") {\n\t\t\t\t\t\tbtn.classList.add(\"preload-pending\");\n\t\t\t\t\t\tbtn.classList.add(\"preload-loading\");\n\t\t\t\t\t}\n\t\t\t\t\tif (loadState === \"loaded\") {\n\t\t\t\t\t\tbtn.classList.add(\"preload-loaded\");\n\t\t\t\t\t}\n\t\t\t\t\tif (index === state.frameIndex) {\n\t\t\t\t\t\tbtn.classList.add(\"active\");\n\t\t\t\t\t}\n\t\t\t\t\tbtn.addEventListener(\"click\", function() {\n\t\t\t\t\t\tstopAnimation();\n\t\t\t\t\t\tstate.frameIndex = index;\n\t\t\t\t\t\tonFrameIndexChange();\n\t\t\t\t\t});\n\t\t\t\t\twrap.appendChild(btn);\n\t\t\t\t}(i));\n\t\t\t}\n\t\t\trenderFrameSliderLabels();\n\t\t\trenderFrameGradient();\n\t\t\tupdateKeyboardHints();\n\t\t\tupdateLeftActionButtons();\n\t\t}\n\n\t\tfunction preloadImage(url) {\n\t\t\tif (!url) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tensureImage(url).catch(function() {\n\t\t\t\treturn null;\n\t\t\t});\n\t\t}\n\n\t\tfunction buildFramePreloadUrls() {\n\t\t\tvar param = getParamConfig();\n\t\t\tif (!param || !param.sequence) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tvar frameCount = getFrameCount();\n\t\t\tvar order = [];\n\t\t\tvar i;\n\n\t\t\tfor (i = state.frameIndex; i < frameCount; i += 1) {\n\t\t\t\torder.push(i);\n\t\t\t}\n\t\t\tfor (i = 0; i < state.frameIndex; i += 1) {\n\t\t\t\torder.push(i);\n\t\t\t}\n\n\t\t\treturn order.map(function(index) {\n\t\t\t\treturn makePreloadItem(state.model, state.param, index);\n\t\t\t});\n\t\t}\n\n\t\tfunction buildPolandParamsPreloadUrls() {\n\t\t\tif (state.region !== \"PL\") {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tvar params = getModelConfig().params;\n\t\t\tif (!params || !params.length) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tvar currentIndex = 0;\n\t\t\tvar i;\n\t\t\tfor (i = 0; i < params.length; i += 1) {\n\t\t\t\tif (params[i].id === state.param) {\n\t\t\t\t\tcurrentIndex = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar urls = [];\n\t\t\tvar url;\n\t\t\tfor (i = currentIndex; i < params.length; i += 1) {\n\t\t\t\turl = getParamUrlForModel(state.model, params[i].id);\n\t\t\t\tif (url) {\n\t\t\t\t\turls.push(url);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (i = 0; i < currentIndex; i += 1) {\n\t\t\t\turl = getParamUrlForModel(state.model, params[i].id);\n\t\t\t\tif (url) {\n\t\t\t\t\turls.push(url);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn urls;\n\t\t}\n\n\t\tfunction buildPlAllModelsPreloadUrls() {\n\t\t\tif (state.region !== \"PL\") {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tvar urls = [];\n\t\t\tvar modelIds = getOrderedModelIds();\n\t\t\tvar i;\n\t\t\tvar j;\n\t\t\tvar model;\n\t\t\tvar param;\n\t\t\tvar url;\n\n\t\t\tfor (i = 0; i < modelIds.length; i += 1) {\n\t\t\t\tmodel = getRegionConfig().models[modelIds[i]];\n\t\t\t\tif (!model || !model.params) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tfor (j = 0; j < model.params.length; j += 1) {\n\t\t\t\t\tparam = model.params[j];\n\t\t\t\t\turl = getParamUrlForModel(modelIds[i], param.id);\n\t\t\t\t\tif (url) {\n\t\t\t\t\t\turls.push(url);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn urls;\n\t\t}\n\n\t\tfunction buildEuAllSequencesPreloadUrls() {\n\t\t\tif (state.region !== \"EU\") {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tvar urls = [];\n\t\t\tvar modelIds = getOrderedModelIds();\n\t\t\tvar i;\n\t\t\tvar j;\n\t\t\tvar k;\n\t\t\tvar model;\n\t\t\tvar param;\n\n\t\t\tfor (i = 0; i < modelIds.length; i += 1) {\n\t\t\t\tmodel = getRegionConfig().models[modelIds[i]];\n\t\t\t\tif (!model || !model.params) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tfor (j = 0; j < model.params.length; j += 1) {\n\t\t\t\t\tparam = model.params[j];\n\t\t\t\t\tif (!param.sequence) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tfor (k = 0; k < param.sequence.steps; k += 1) {\n\t\t\t\t\t\turls.push(makePreloadItem(modelIds[i], param.id, k));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn urls;\n\t\t}\n\n\t\tfunction buildComparePreloadUrls() {\n\t\t\tif (!state.compareMode) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (state.compareKind === \"params\") {\n\t\t\t\treturn buildParamsComparePreloadUrls();\n\t\t\t}\n\n\t\t\treturn buildModelsComparePreloadUrls();\n\t\t}\n\n\t\tfunction buildModelsComparePreloadUrls() {\n\t\t\tvar urls = [];\n\t\t\tvar models = getActiveCompareModelIds();\n\t\t\tvar frameCount = getEffectiveFrameCount();\n\t\t\tvar frameOrder = [];\n\t\t\tvar i;\n\t\t\tvar j;\n\n\t\t\tif (!models.length) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tfor (i = state.frameIndex; i < frameCount; i += 1) {\n\t\t\t\tframeOrder.push(i);\n\t\t\t}\n\t\t\tfor (i = 0; i < state.frameIndex; i += 1) {\n\t\t\t\tframeOrder.push(i);\n\t\t\t}\n\n\t\t\tfor (i = 0; i < frameOrder.length; i += 1) {\n\t\t\t\tvar frameIdx = frameOrder[i];\n\t\t\t\tfor (j = 0; j < models.length; j += 1) {\n\t\t\t\t\tvar modelId = models[j];\n\t\t\t\t\tvar param = getParamConfigForModel(modelId, state.param);\n\t\t\t\t\tif (!param) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (param.sequence) {\n\t\t\t\t\t\turls.push(makePreloadItem(modelId, state.param, frameIdx));\n\t\t\t\t\t} else if (param.file) {\n\t\t\t\t\t\turls.push(param.file);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn urls;\n\t\t}\n\n\t\tfunction buildParamsComparePreloadUrls() {\n\t\t\tvar urls = [];\n\t\t\tvar params = getActiveCompareParamIds();\n\t\t\tvar frameCount = getEffectiveFrameCount();\n\t\t\tvar frameOrder = [];\n\t\t\tvar i;\n\t\t\tvar j;\n\n\t\t\tif (!params.length) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tfor (i = state.frameIndex; i < frameCount; i += 1) {\n\t\t\t\tframeOrder.push(i);\n\t\t\t}\n\t\t\tfor (i = 0; i < state.frameIndex; i += 1) {\n\t\t\t\tframeOrder.push(i);\n\t\t\t}\n\n\t\t\tfor (i = 0; i < frameOrder.length; i += 1) {\n\t\t\t\tvar frameIdx = frameOrder[i];\n\t\t\t\tfor (j = 0; j < params.length; j += 1) {\n\t\t\t\t\turls.push(makePreloadItem(state.model, params[j], frameIdx));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn urls;\n\t\t}\n\n\t\tfunction enqueuePreloadUrls(urls) {\n\t\t\tvar unique = {};\n\t\t\tvar filtered = [];\n\t\t\tvar merged = [];\n\t\t\tvar existing = {};\n\t\t\tvar i;\n\n\t\t\tfor (i = 0; i < urls.length; i += 1) {\n\t\t\t\tvar url = urls[i];\n\t\t\t\tif (!url || unique[url]) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tunique[url] = true;\n\t\t\t\tif (!isImageLoaded(url)) {\n\t\t\t\t\tfiltered.push(url);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!filtered.length) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (i = 0; i < filtered.length; i += 1) {\n\t\t\t\tmerged.push(filtered[i]);\n\t\t\t\texisting[filtered[i]] = true;\n\t\t\t}\n\t\t\tfor (i = 0; i < state.preloadQueue.length; i += 1) {\n\t\t\t\tvar queuedUrl = state.preloadQueue[i];\n\t\t\t\tif (!existing[queuedUrl]) {\n\t\t\t\t\tmerged.push(queuedUrl);\n\t\t\t\t\texisting[queuedUrl] = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.preloadQueue = merged;\n\t\t\tif (!state.isPreloading) {\n\t\t\t\tprocessPreloadQueue(state.preloadGeneration);\n\t\t\t}\n\t\t}\n\n\t\tasync function processPreloadQueue(generation) {\n\t\t\tif (state.isPreloading) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstate.isPreloading = true;\n\t\t\ttry {\n\t\t\t\twhile (generation === state.preloadGeneration && state.preloadQueue.length > 0) {\n\t\t\t\t\tvar batch = state.preloadQueue.splice(0, PRELOAD_CONCURRENCY);\n\t\t\t\t\tawait Promise.all(batch.map(function(item) {\n\t\t\t\t\t\treturn preloadItem(item);\n\t\t\t\t\t}));\n\t\t\t\t\tif (generation === state.preloadGeneration) {\n\t\t\t\t\t\trefreshPreloadUi();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tstate.isPreloading = false;\n\t\t\t\tif (state.preloadQueue.length > 0) {\n\t\t\t\t\tprocessPreloadQueue(state.preloadGeneration);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction renderFrameGradient() {\n\t\t\tvar slider = document.getElementById(\"midtermFrameSlider\");\n\t\t\tvar frameCount = getFrameCount();\n\t\t\tif (!slider || frameCount <= 1) {\n\t\t\t\tif (slider) {\n\t\t\t\t\tslider.style.background = \"#dcdcdc\";\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar loadedEnd = -1;\n\t\t\tfor (var i = 0; i < frameCount; i += 1) {\n\t\t\t\tif (getFrameLoadState(i) === \"loaded\") {\n\t\t\t\t\tloadedEnd = i;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar denominator = Math.max(1, frameCount - 1);\n\t\t\tvar loadedPercent = loadedEnd >= 0 ? (loadedEnd \/ denominator) * 100 : 0;\n\t\t\tslider.style.background =\n\t\t\t\t\"linear-gradient(to right, #c7c7c7 0%, #c7c7c7 \" + loadedPercent + \"%, #e0e0e0 \" + loadedPercent + \"%, #e0e0e0 100%)\";\n\t\t}\n\n\t\tfunction openLightbox(src) {\n\t\t\tvar box = document.getElementById(\"midtermLightbox\");\n\t\t\tvar img = document.getElementById(\"midtermLightboxImg\");\n\t\t\timg.src = src;\n\t\t\tbox.classList.add(\"active\");\n\t\t}\n\n\t\tfunction closeLightbox() {\n\t\t\tvar box = document.getElementById(\"midtermLightbox\");\n\t\t\tvar img = document.getElementById(\"midtermLightboxImg\");\n\t\t\tbox.classList.remove(\"active\");\n\t\t\timg.src = \"\";\n\t\t}\n\n\t\tfunction appendCompareGrid(container, results, options) {\n\t\t\toptions = options || {};\n\t\t\tvar enableLightbox = options.enableLightbox !== false;\n\t\t\tvar showLabels = options.showLabels === true;\n\t\t\tvar useSideGrid = options.useSideGrid !== undefined\n\t\t\t\t? options.useSideGrid\n\t\t\t\t: (state.region === \"EU\" && results.length > 1);\n\t\t\tvar visibleResults = results.filter(function(result) {\n\t\t\t\treturn !!result.img;\n\t\t\t});\n\t\t\tcontainer.innerHTML = \"\";\n\t\t\tvar grid = document.createElement(\"div\");\n\t\t\tgrid.className = useSideGrid ? \"compare-grid-side\" : \"compare-grid\";\n\n\t\t\tif (options.fullscreen && useSideGrid && visibleResults.length) {\n\t\t\t\tvar columnCount = computeCompareFullscreenColumns(visibleResults.length, visibleResults);\n\t\t\t\tvar rowCount = Math.ceil(visibleResults.length \/ columnCount);\n\t\t\t\tgrid.style.gridTemplateColumns = \"repeat(\" + columnCount + \", minmax(0, 1fr))\";\n\t\t\t\tgrid.style.gridTemplateRows = \"repeat(\" + rowCount + \", minmax(0, 1fr))\";\n\t\t\t}\n\n\t\t\tvisibleResults.forEach(function(result) {\n\t\t\t\tvar card = document.createElement(\"div\");\n\t\t\t\tcard.className = \"compare-card\";\n\n\t\t\t\tif (result.label && showLabels) {\n\t\t\t\t\tvar caption = document.createElement(\"div\");\n\t\t\t\t\tcaption.className = \"compare-card-label\";\n\t\t\t\t\tcaption.textContent = result.label;\n\t\t\t\t\tcard.appendChild(caption);\n\t\t\t\t}\n\n\t\t\t\tvar img = new Image();\n\t\t\t\timg.src = result.img.currentSrc || result.img.src;\n\t\t\t\timg.alt = showLabels && result.label ? result.label : \"Por\u00f3wnanie prognozy\";\n\t\t\t\tif (enableLightbox) {\n\t\t\t\t\timg.addEventListener(\"click\", function() {\n\t\t\t\t\t\topenLightbox(img.currentSrc || img.src);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tcard.appendChild(img);\n\t\t\t\tgrid.appendChild(card);\n\t\t\t});\n\n\t\t\tcontainer.appendChild(grid);\n\t\t}\n\n\t\tfunction appendSingleImage(container, loaded, modelCfg, paramCfg) {\n\t\t\tvar display = new Image();\n\t\t\tdisplay.alt = modelCfg.label + \" - \" + paramCfg.label;\n\t\t\tdisplay.src = loaded.currentSrc || loaded.src;\n\t\t\tdisplay.addEventListener(\"click\", function() {\n\t\t\t\topenLightbox(display.currentSrc || display.src);\n\t\t\t});\n\t\t\tcontainer.innerHTML = \"\";\n\t\t\tcontainer.appendChild(display);\n\t\t\tshowLoader(false);\n\t\t\tshowStatus(\"\");\n\t\t\trefreshPreloadUi();\n\t\t}\n\n\t\tfunction enqueueNormalPreload() {\n\t\t\tvar priority = buildFramePreloadUrls().concat(buildPolandParamsPreloadUrls());\n\t\t\tvar background = state.region === \"PL\"\n\t\t\t\t? buildPlAllModelsPreloadUrls()\n\t\t\t\t: buildEuAllSequencesPreloadUrls();\n\t\t\tenqueuePreloadUrls(priority.concat(background));\n\t\t}\n\n\t\tfunction onFrameIndexChange() {\n\t\t\trenderFrames();\n\t\t\tif (state.compareMode) {\n\t\t\t\tensureCompareFrameDateLists().then(renderImage);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\trenderImage();\n\t\t}\n\n\t\tfunction renderImage() {\n\t\t\tvar container = document.getElementById(\"midtermImages\");\n\t\t\tvar url = getCurrentImageUrl();\n\t\t\tvar modelCfg = getModelConfig();\n\t\t\tvar paramCfg = getParamConfig();\n\t\t\tvar token = ++state.imageToken;\n\n\t\t\tcontainer.innerHTML = \"\";\n\t\t\tupdateLeftActionButtons();\n\t\t\tif (!url || !paramCfg) {\n\t\t\t\tshowLoader(false);\n\t\t\t\tshowStatus(\"Brak konfiguracji map dla wybranego ustawienia.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (state.compareMode) {\n\t\t\t\tif (state.compareKind === \"params\") {\n\t\t\t\t\tif (!canCompareParamsForModel() || getActiveCompareParamIds().length < 2) {\n\t\t\t\t\t\texitCompareMode();\n\t\t\t\t\t\tupdateLeftActionButtons();\n\t\t\t\t\t\trenderParams();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar selectedParams = getActiveCompareParamIds();\n\n\t\t\t\t\t\tstartComparePreloadIfNeeded();\n\n\t\t\t\t\t\tvar allParamsCached = selectedParams.every(function(paramId) {\n\t\t\t\t\t\t\treturn isFrameImageLoaded(state.model, paramId, state.frameIndex);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tfunction finishParamsCompareRender(results) {\n\t\t\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tappendCompareGrid(container, results);\n\t\t\t\t\t\t\tshowLoader(false);\n\t\t\t\t\t\t\tshowStatus(\"\");\n\t\t\t\t\t\t\trefreshPreloadUi();\n\t\t\t\t\t\t\trenderCompareFullscreen();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (allParamsCached) {\n\t\t\t\t\t\t\tfinishParamsCompareRender(getCompareParamResultsFromCache(selectedParams));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tshowLoader(true);\n\t\t\t\t\t\tloadCompareParamResults(selectedParams).then(finishParamsCompareRender).catch(function() {\n\t\t\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tshowLoader(false);\n\t\t\t\t\t\t\tshowStatus(\"Nie uda\u0142o si\u0119 przygotowa\u0107 por\u00f3wnania parametr\u00f3w.\");\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} else if (!canCompareCurrentSelection()) {\n\t\t\t\t\texitCompareMode();\n\t\t\t\t\tupdateLeftActionButtons();\n\t\t\t\t\trenderModels();\n\t\t\t\t} else {\n\t\t\t\t\tvar selectedForCompare = getActiveCompareModelIds();\n\n\t\t\t\t\tif (!selectedForCompare.length) {\n\t\t\t\t\t\tshowLoader(false);\n\t\t\t\t\t\tshowStatus(\"Brak modeli do por\u00f3wnania dla wybranego parametru.\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tstartComparePreloadIfNeeded();\n\n\t\t\t\t\tvar allCached = selectedForCompare.every(function(modelId) {\n\t\t\t\t\t\treturn isFrameImageLoaded(modelId, state.param, state.frameIndex);\n\t\t\t\t\t});\n\n\t\t\t\t\tfunction finishCompareRender(results) {\n\t\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tappendCompareGrid(container, results);\n\t\t\t\t\t\tshowLoader(false);\n\t\t\t\t\t\tshowStatus(\"\");\n\t\t\t\t\t\trefreshPreloadUi();\n\t\t\t\t\t\trenderCompareFullscreen();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (allCached) {\n\t\t\t\t\t\tfinishCompareRender(getCompareResultsFromCache(selectedForCompare));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tshowLoader(true);\n\t\t\t\t\tloadCompareResults(selectedForCompare).then(finishCompareRender).catch(function() {\n\t\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tshowLoader(false);\n\t\t\t\t\t\tshowStatus(\"Nie uda\u0142o si\u0119 przygotowa\u0107 por\u00f3wnania modeli.\");\n\t\t\t\t\t});\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (paramCfg.sequence) {\n\t\t\t\tif (isFrameImageLoaded(state.model, state.param, state.frameIndex)) {\n\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tappendSingleImage(container, state.imageCache[getParamUrlForModel(state.model, state.param, state.frameIndex)], modelCfg, paramCfg);\n\t\t\t\t\tenqueueNormalPreload();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tshowLoader(true);\n\t\t\t\tensureFrameImage(state.model, state.param, state.frameIndex)\n\t\t\t\t\t.then(function(loaded) {\n\t\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tappendSingleImage(container, loaded, modelCfg, paramCfg);\n\t\t\t\t\t})\n\t\t\t\t\t.catch(function() {\n\t\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontainer.innerHTML = \"\";\n\t\t\t\t\t\tshowLoader(false);\n\t\t\t\t\t\tshowStatus(\"Nie uda\u0142o si\u0119 wczyta\u0107 mapy dla wybranego terminu.\");\n\t\t\t\t\t\trenderFrames();\n\t\t\t\t\t});\n\n\t\t\t\tenqueueNormalPreload();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (isImageLoaded(url)) {\n\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tappendSingleImage(container, state.imageCache[url], modelCfg, paramCfg);\n\t\t\t\tenqueueNormalPreload();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tshowLoader(true);\n\t\t\tensureImage(url)\n\t\t\t\t.then(function(loaded) {\n\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tappendSingleImage(container, loaded, modelCfg, paramCfg);\n\t\t\t\t})\n\t\t\t\t.catch(function() {\n\t\t\t\t\tif (token !== state.imageToken) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcontainer.innerHTML = \"\";\n\t\t\t\t\tshowLoader(false);\n\t\t\t\t\tshowStatus(\"Nie uda\u0142o si\u0119 wczyta\u0107 mapy: \" + url);\n\t\t\t\t\trenderFrames();\n\t\t\t\t});\n\n\t\t\tenqueueNormalPreload();\n\t\t}\n\n\t\tfunction stopAnimation() {\n\t\t\tif (state.animationTimer) {\n\t\t\t\tclearInterval(state.animationTimer);\n\t\t\t\tstate.animationTimer = null;\n\t\t\t}\n\t\t\tstate.animating = false;\n\t\t\tupdateAnimateButtonState();\n\t\t}\n\n\t\tfunction toggleAnimation() {\n\t\t\tvar frameCount = getFrameCount();\n\t\t\tif (frameCount <= 1) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (state.animating) {\n\t\t\t\tstopAnimation();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstate.animating = true;\n\t\t\tupdateAnimateButtonState();\n\n\t\t\tstate.animationTimer = setInterval(function() {\n\t\t\t\tstate.frameIndex += 1;\n\t\t\t\tif (state.frameIndex >= frameCount) {\n\t\t\t\t\tstate.frameIndex = 0;\n\t\t\t\t}\n\t\t\t\trenderFrames();\n\t\t\t\trenderImage();\n\t\t\t}, 1000);\n\t\t}\n\n\t\tfunction changeParam(direction) {\n\t\t\tvar params = getModelConfig().params;\n\t\t\tif (!params.length) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar idx = 0;\n\t\t\tfor (var i = 0; i < params.length; i += 1) {\n\t\t\t\tif (params[i].id === state.param) {\n\t\t\t\t\tidx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar next = idx + direction;\n\t\t\tif (next < 0) {\n\t\t\t\tnext = params.length - 1;\n\t\t\t}\n\t\t\tif (next >= params.length) {\n\t\t\t\tnext = 0;\n\t\t\t}\n\n\t\t\tstopAnimation();\n\t\t\tstate.param = params[next].id;\n\t\t\tstate.frameIndex = 0;\n\t\t\trenderAll();\n\t\t}\n\n\t\tfunction setRegionByIndex(index) {\n\t\t\tvar regions = Object.keys(data);\n\t\t\tif (index < 0 || index >= regions.length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetRegion(regions[index]);\n\t\t}\n\n\t\tfunction setModelByIndex(index) {\n\t\t\tvar models = getOrderedModelIds();\n\t\t\tif (index < 0 || index >= models.length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (models[index] === state.model) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstopAnimation();\n\t\t\tresetComparePreload();\n\t\t\tsetModel(models[index]);\n\t\t\trenderAll();\n\t\t}\n\n\t\tfunction setupEvents() {\n\t\t\tvar slider = document.getElementById(\"midtermFrameSlider\");\n\t\t\tvar compareBtn = document.getElementById(\"midtermCompareBtn\");\n\t\t\tslider.addEventListener(\"input\", function(e) {\n\t\t\t\tstopAnimation();\n\t\t\t\tstate.frameIndex = parseInt(e.target.value, 10) || 0;\n\t\t\t\tonFrameIndexChange();\n\t\t\t});\n\n\t\t\tdocument.getElementById(\"midtermAnimateBtnLeft\").addEventListener(\"click\", toggleAnimation);\n\t\t\tcompareBtn.addEventListener(\"click\", toggleCompareMode);\n\t\t\tdocument.getElementById(\"midtermCompareParamsBtn\").addEventListener(\"click\", toggleCompareParamsMode);\n\t\t\tdocument.getElementById(\"midtermFullscreenBtn\").addEventListener(\"click\", toggleCompareFullscreen);\n\n\t\t\tdocument.getElementById(\"midtermCompareClose\").addEventListener(\"click\", closeCompareModal);\n\t\t\tdocument.getElementById(\"midtermCompareConfirm\").addEventListener(\"click\", function() {\n\t\t\t\tif (!state.compareSelectedModels.length) {\n\t\t\t\t\tshowStatus(\"Wybierz co najmniej jeden model do por\u00f3wnania.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (state.compareModalParam) {\n\t\t\t\t\tstate.param = state.compareModalParam;\n\t\t\t\t\tstate.frameIndex = 0;\n\t\t\t\t}\n\t\t\t\tstate.compareKind = \"models\";\n\t\t\t\tstate.compareMode = true;\n\t\t\t\tclearFrameResolveCache();\n\t\t\t\tcloseCompareModal();\n\t\t\t\trenderAll();\n\t\t\t});\n\t\t\tdocument.getElementById(\"midtermCompareModal\").addEventListener(\"click\", function(e) {\n\t\t\t\tif (e.target.id === \"midtermCompareModal\") {\n\t\t\t\t\tcloseCompareModal();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tdocument.getElementById(\"midtermCompareParamsClose\").addEventListener(\"click\", closeCompareParamsModal);\n\t\t\tdocument.getElementById(\"midtermCompareParamsConfirm\").addEventListener(\"click\", function() {\n\t\t\t\tif (state.compareSelectedParams.length < 2) {\n\t\t\t\t\tshowStatus(\"Wybierz co najmniej dwa parametry do por\u00f3wnania.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tstate.compareKind = \"params\";\n\t\t\t\tstate.compareMode = true;\n\t\t\t\tclearFrameResolveCache();\n\t\t\t\tif (state.compareSelectedParams.indexOf(state.param) === -1) {\n\t\t\t\t\tstate.param = state.compareSelectedParams[0];\n\t\t\t\t}\n\t\t\t\tstate.frameIndex = 0;\n\t\t\t\tcloseCompareParamsModal();\n\t\t\t\trenderAll();\n\t\t\t});\n\t\t\tdocument.getElementById(\"midtermCompareParamsModal\").addEventListener(\"click\", function(e) {\n\t\t\t\tif (e.target.id === \"midtermCompareParamsModal\") {\n\t\t\t\t\tcloseCompareParamsModal();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tdocument.getElementById(\"midtermLightbox\").addEventListener(\"click\", function(e) {\n\t\t\t\tif (e.target.id === \"midtermLightbox\" || e.target.id === \"midtermLightboxClose\") {\n\t\t\t\t\tcloseLightbox();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tdocument.addEventListener(\"keydown\", function(event) {\n\t\t\t\tvar tag = event.target && event.target.tagName ? event.target.tagName.toUpperCase() : \"\";\n\t\t\t\tif (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (event.key === \"Escape\") {\n\t\t\t\t\tif (state.compareFullscreen) {\n\t\t\t\t\t\tcloseCompareFullscreen();\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcloseCompareModal();\n\t\t\t\t\tcloseCompareParamsModal();\n\t\t\t\t\tcloseLightbox();\n\t\t\t\t\tstopAnimation();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (event.key === \"f\" || event.key === \"F\") {\n\t\t\t\t\tif (!canUseCompareFullscreen()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\ttoggleCompareFullscreen();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (\/^[1-8]$\/.test(event.key)) {\n\t\t\t\t\tsetModelByIndex(parseInt(event.key, 10) - 1);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (event.key === \"q\" || event.key === \"Q\") {\n\t\t\t\t\tsetRegionByIndex(0);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (event.key === \"e\" || event.key === \"E\") {\n\t\t\t\t\tsetRegionByIndex(1);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (event.key === \"ArrowLeft\" || event.key === \"ArrowRight\") {\n\t\t\t\t\tvar frameCount = getFrameCount();\n\t\t\t\t\tif (frameCount <= 1) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tstopAnimation();\n\t\t\t\t\tvar delta = event.key === \"ArrowLeft\" ? -1 : 1;\n\t\t\t\t\tvar next = state.frameIndex + delta;\n\t\t\t\t\tif (next < 0 || next >= frameCount) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tstate.frameIndex = next;\n\t\t\t\t\tonFrameIndexChange();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (event.key === \"ArrowUp\") {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tchangeParam(-1);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (event.key === \"ArrowDown\") {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tchangeParam(1);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (event.key === \"a\" || event.key === \"A\") {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\ttoggleAnimation();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (event.key === \"c\" || event.key === \"C\") {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\ttoggleCompareMode();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (event.key === \"p\" || event.key === \"P\") {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\ttoggleCompareParamsMode();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar compareResizeTimer = null;\n\t\t\twindow.addEventListener(\"resize\", function() {\n\t\t\t\tupdateLeftActionButtons();\n\t\t\t\tupdateKeyboardHints();\n\t\t\t\tif (!state.compareFullscreen) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tclearTimeout(compareResizeTimer);\n\t\t\t\tcompareResizeTimer = setTimeout(function() {\n\t\t\t\t\tif (state.compareFullscreen) {\n\t\t\t\t\t\trenderCompareFullscreen();\n\t\t\t\t\t}\n\t\t\t\t}, 120);\n\t\t\t});\n\t\t}\n\n\t\tfunction renderAll() {\n\t\t\trenderRegions();\n\t\t\trenderModels();\n\t\t\trenderParams();\n\t\t\trenderFrames();\n\t\t\tupdateLeftActionButtons();\n\t\t\tupdateKeyboardHints();\n\n\t\t\tvar param = getParamConfig();\n\t\t\tif (param && param.sequence) {\n\t\t\t\tshowLoader(true);\n\t\t\t\tensureCompareFrameDateLists().finally(function() {\n\t\t\t\t\tprefetchEuFrameDateLists();\n\t\t\t\t\trenderImage();\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\trenderImage();\n\t\t}\n\n\t\tfunction onForecastRunCheck() {\n\t\t\tif (syncForecastCacheVersion()) {\n\t\t\t\trenderAll();\n\t\t\t}\n\t\t}\n\n\t\tfunction init() {\n\t\t\tsyncForecastCacheVersion();\n\t\t\tvar orderedModels = getOrderedModelIds();\n\t\t\tif (orderedModels.length) {\n\t\t\t\tstate.model = orderedModels[0];\n\t\t\t}\n\t\t\tstate.param = getModelConfig().params[0].id;\n\t\t\tsetupEvents();\n\t\t\trenderAll();\n\t\t\tsetInterval(onForecastRunCheck, FORECAST_RUN_CHECK_MS);\n\t\t}\n\n\t\tif (document.readyState === \"loading\") {\n\t\t\tdocument.addEventListener(\"DOMContentLoaded\", init);\n\t\t} else {\n\t\t\tinit();\n\t\t}\n\t}());\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>Obszar Parametr Termin prognozy \u229e Por\u00f3wnaj modele \u229e Por\u00f3wnaj parametry \u25b6 Animuj \u26f6 Pe\u0142ny ekran \ud83d\udca1 Skroty klawiszowe: Q\/E | Zmiana obszaru 1-8 | Zmiana modelu \u2190 \u2192 | Zmiana terminu \u2191 \u2193 | Zmiana parametru C | Por\u00f3wnanie modeli P | Por\u00f3wnanie parametr\u00f3w A | Animacja F | Pe\u0142ny ekran por\u00f3wnania \u0141adowanie mapy&#8230; &times; [&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>\u015arednioterminowe - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB<\/title>\n<meta name=\"description\" content=\"Aplikacja przegl\u0105dania prognoz \u015brednioterminowych IMGW-PIB\" \/>\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=49784\" \/>\n<meta property=\"og:locale\" content=\"pl_PL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Prognozy \u015brednioterminowe\" \/>\n<meta property=\"og:description\" content=\"Prognozy \u015brednioterminowe IMGW-PIB\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cmm.imgw.pl\/?page_id=49784\" \/>\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-07-16T18:27:00+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:title\" content=\"Prognozy \u015brednioterminowe\" \/>\n<meta name=\"twitter:description\" content=\"Prognozy \u015brednioterminowe IMGW-PIB\" \/>\n<meta name=\"twitter:site\" content=\"@IMGW_CMM\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cmm.imgw.pl\/?page_id=49784\",\"url\":\"https:\/\/cmm.imgw.pl\/?page_id=49784\",\"name\":\"\u015arednioterminowe - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB\",\"isPartOf\":{\"@id\":\"https:\/\/cmm.imgw.pl\/#website\"},\"datePublished\":\"2026-04-07T11:22:11+00:00\",\"dateModified\":\"2026-07-16T18:27:00+00:00\",\"description\":\"Aplikacja przegl\u0105dania prognoz \u015brednioterminowych IMGW-PIB\",\"breadcrumb\":{\"@id\":\"https:\/\/cmm.imgw.pl\/?page_id=49784#breadcrumb\"},\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cmm.imgw.pl\/?page_id=49784\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cmm.imgw.pl\/?page_id=49784#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cmm.imgw.pl\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\u015arednioterminowe\"}]},{\"@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":"\u015arednioterminowe - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","description":"Aplikacja przegl\u0105dania prognoz \u015brednioterminowych IMGW-PIB","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=49784","og_locale":"pl_PL","og_type":"article","og_title":"Prognozy \u015brednioterminowe","og_description":"Prognozy \u015brednioterminowe IMGW-PIB","og_url":"https:\/\/cmm.imgw.pl\/?page_id=49784","og_site_name":"Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","article_publisher":"https:\/\/www.facebook.com\/Meteoimgw\/","article_modified_time":"2026-07-16T18:27:00+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_title":"Prognozy \u015brednioterminowe","twitter_description":"Prognozy \u015brednioterminowe IMGW-PIB","twitter_site":"@IMGW_CMM","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/cmm.imgw.pl\/?page_id=49784","url":"https:\/\/cmm.imgw.pl\/?page_id=49784","name":"\u015arednioterminowe - Laboratorium Modelowania Meteorologicznego CMOK IMGW-PIB","isPartOf":{"@id":"https:\/\/cmm.imgw.pl\/#website"},"datePublished":"2026-04-07T11:22:11+00:00","dateModified":"2026-07-16T18:27:00+00:00","description":"Aplikacja przegl\u0105dania prognoz \u015brednioterminowych IMGW-PIB","breadcrumb":{"@id":"https:\/\/cmm.imgw.pl\/?page_id=49784#breadcrumb"},"inLanguage":"pl-PL","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cmm.imgw.pl\/?page_id=49784"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/cmm.imgw.pl\/?page_id=49784#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cmm.imgw.pl\/"},{"@type":"ListItem","position":2,"name":"\u015arednioterminowe"}]},{"@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\/49784"}],"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=49784"}],"version-history":[{"count":235,"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=\/wp\/v2\/pages\/49784\/revisions"}],"predecessor-version":[{"id":50934,"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=\/wp\/v2\/pages\/49784\/revisions\/50934"}],"wp:attachment":[{"href":"https:\/\/cmm.imgw.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=49784"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}