{"id":1597,"date":"2024-11-04T02:50:56","date_gmt":"2024-11-04T02:50:56","guid":{"rendered":"https:\/\/paragliding-in-madeira.com\/weather\/?page_id=1597"},"modified":"2026-04-30T02:49:39","modified_gmt":"2026-04-30T01:49:39","slug":"forecast","status":"publish","type":"page","link":"https:\/\/paragliding-in-madeira.com\/weather\/forecast\/","title":{"rendered":"Forecast"},"content":{"rendered":"\n<div class=\"wp-block-buttons alignfull is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-a89b3969 wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\">Home<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\/weather-info\/\">Real-time<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\/sun-and-moon\/\">Sun &amp; sea<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\/airport-live\/\">Airport<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\/pressure-chart\/\">Pressure<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/www.windy.com\/sounding\/32.792\/-16.804?gfs,clouds,32.422,-16.804,10,i:pressure\" target=\"_blank\" rel=\"noreferrer noopener\">Sounding<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\/weather-stations\/\">Weather Station<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\/webcams\/\">Webcam<\/a><\/div>\n<\/div>\n\n\n\n<p class=\"has-text-align-center\"><a href=\"#meteogram\">Meteogram<\/a><\/p>\n\n\n\n<div style=\"height:28px\" aria-hidden=\"true\" id=\"forecast\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-text-align-center\">Below you can find different models showing the weather forecast for Madeira Island for the next few days<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<div style=\"height:18px\" aria-hidden=\"true\" id=\"forecast\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div style=\"text-align:center; transform: translateX(-10px);\">\n<sup><small><i>Windguru forecast wind in km\/h at sea level:<\/i><\/small><\/sup><\/div>\n\n\n\n<style>\n  \/* Gentle pulse animation *\/\n  @keyframes gentlePulse {\n    0%   { transform: scale(1); opacity: 0.5; }\n    44%  { transform: scale(1.05); opacity: 1; }\n    100% { transform: scale(1); opacity: 0.5; }\n  }\n\n  \/* Apply pulse to the emoji only *\/\n  #windguru1-loading .pulse {\n    display: inline-block;\n    animation: gentlePulse 2.8s ease-in-out infinite;\n  }\n\n#windguru1-container {\n  position: relative; \n  min-height: 200px;\n  \/* Add this line: *\/\n  touch-action: pan-x pan-y; \n  overflow-x: auto;\n  -webkit-overflow-scrolling: touch;\n}\n\n<\/style>\n<div style=\"height: 233px; margin-top:-1px; text-align:center; transform: translateX(-15px);\">\n  <div id=\"windguru1-container\" style=\"position:relative; height: 100%;\">\n\n    <div id=\"windguru1-loading\" style=\"\n  position: absolute; top: 0; left: 0; \n  width: 100%; height: 100%; z-index: 10;\n  display: flex; flex-direction: column; justify-content: center;\n  text-align:center; color:gray; opacity:1;\n  background-color: #EBEBEF;\n\">\n  <span class=\"pulse\">&#128168; Reading the wind&#8230;<br>(Porto Santo) <\/span>\n<\/div>\n\n    <div id=\"windguru1-error\" style=\"\n      position: absolute; top: 0; left: 0; \n      width: 100%; height: 100%; z-index: 10;\n      display: none; flex-direction: column; justify-content: center;\n      text-align:center; color:black;\n      background-color: #EBEBEF; \/* Added background to cover content below *\/\n    \">\n      Didn&#8217;t load Windguru\n      <button onclick=\"reloadWindguru1()\">Try Again<\/button>\n    <\/div>\n\n    <div id=\"windguru1-widget\" style=\"opacity: 0; transition: opacity 0.6s ease;\"><\/div>\n  <\/div>\n\n  <script>\n    \/* -------------------------------------------------------------\n      Configuration\n    ------------------------------------------------------------- *\/\n    const W1_TIMEOUT = 7000;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Max wait time per attempt\n    const W1_MAX_ATTEMPTS = 3;\u00a0\u00a0\u00a0\u00a0 \/\/ Retry limit\n    const W1_MIN_LOAD_TIME = 500;\u00a0 \/\/ Minimum loader visible time\n    const W1_SMOOTH_DELAY = 400;\u00a0\u00a0 \/\/ Prevent fast-load flashing\n\n\n    \/* -------------------------------------------------------------\n      Smooth fade-out for loader, and fade-in for widget\n    ------------------------------------------------------------- *\/\n    function fadeOutAndSwap(loadingEl, widgetEl) {\n      \/\/ 1. Fade out the loader\n      loadingEl.style.transition = \"opacity 0.6s ease\";\n      loadingEl.style.opacity = \"0\";\n\n      \/\/ 2. Fade in the widget\n      widgetEl.style.opacity = \"1\";\n\n      \/\/ 3. Hide loader after transition\n      setTimeout(() => { loadingEl.style.display = \"none\"; }, 600);\n    }\n\n\n    \/* -------------------------------------------------------------\n      Detect iframe \u2192 wait for iframe load \u2192 then smoothing delay\n    ------------------------------------------------------------- *\/\n    function observeWindguruIframeFullyLoaded(widgetEl, onReady) {\n      const observer = new MutationObserver(() => {\n        const iframe = widgetEl.querySelector(\"iframe\");\n        if (!iframe) return;\n\n        observer.disconnect();\n\n        \/\/ Wait for Windguru iframe internal load\n        iframe.addEventListener(\"load\", () => {\n          \/\/ Extra smoothing to prevent loader flashing\n          setTimeout(onReady, W1_SMOOTH_DELAY);\n        });\n      });\n\n      observer.observe(widgetEl, { childList: true });\n    }\n\n\n    \/* -------------------------------------------------------------\n      Main loader\n    ------------------------------------------------------------- *\/\n    function loadWindguru1(attempt = 1) {\n      const widgetEl = document.getElementById(\"windguru1-widget\");\n      const loadingEl = document.getElementById(\"windguru1-loading\");\n      const errorEl = document.getElementById(\"windguru1-error\");\n\n      \/\/ Reset UI\n      widgetEl.innerHTML = \"\";\n      widgetEl.style.opacity = \"0\"; \/\/ Ensure widget starts hidden\n      loadingEl.style.display = \"flex\"; \/\/ Use flex display to center content\n      loadingEl.style.opacity = \"1\";\n      errorEl.style.display = \"none\";\n\n      let loadComplete = false;\n      const startTime = Date.now();\n\n      \/\/ Watch for iframe \u2192 wait for iframe load \u2192 smoothing delay \u2192 then loader fade-out\n      observeWindguruIframeFullyLoaded(widgetEl, () => {\n        if (loadComplete) return;\n        loadComplete = true;\n\n        const remaining = Math.max(0, W1_MIN_LOAD_TIME - (Date.now() - startTime));\n\n        setTimeout(() => fadeOutAndSwap(loadingEl, widgetEl), remaining);\n\n        console.log(`Windguru 1 fully loaded (iframe onload + smoothing) on attempt ${attempt}`);\n      });\n\n      \/\/ Inject WG script\n      setTimeout(() => {\n        const script = document.createElement(\"script\");\n        script.id = \"wg_fwdg_237_100_\" + Date.now();\n\n        const args = [\n          \"s=237\", \"m=100\", \"uid=\" + script.id, \"wj=kmh\", \"tj=c\", \"waj=m\", \"tij=cm\",\n          \"odh=8\", \"doh=22\", \"fhours=111\", \"hrsm=2\", \"vt=forecasts\", \"lng=en\",\n          \"idbs=1\", \"p=WINDSPD,GUST,SMER,CDC,APCP1s\"\n        ];\n\n        script.src = \"https:\/\/www.windguru.cz\/js\/widget.php?\" + args.join(\"&\");\n\n        script.onload = () => {\n          console.log(\"Windguru script loaded \u2014 waiting for iframe\u2026\");\n        };\n\n        widgetEl.appendChild(script);\n\n        \/\/ Fail-safe timeout\n        setTimeout(() => {\n          if (!loadComplete) {\n            console.warn(`Windguru 1 timed out on attempt ${attempt}`);\n\n            if (attempt < W1_MAX_ATTEMPTS) {\n              loadWindguru1(attempt + 1);\n            } else {\n              loadingEl.style.display = \"none\";\n              errorEl.style.display = \"flex\"; \/\/ Use flex display for error\n            }\n          }\n        }, W1_TIMEOUT);\n\n      }, 50);\n    }\n\n\n    \/* -------------------------------------------------------------\n      User click reload\n    ------------------------------------------------------------- *\/\n    function reloadWindguru1() {\n      loadWindguru1(1);\n    }\n\n    \/\/ Auto-load\n    document.addEventListener(\"DOMContentLoaded\", () => loadWindguru1(1));\n  <\/script>\n<\/div>\n\n\n\n<style>\n  \/* Gentle pulse animation *\/\n  @keyframes gentlePulse {\n    0%   { transform: scale(1); opacity: 0.5; }\n    44%  { transform: scale(1.05); opacity: 1; }\n    100% { transform: scale(1); opacity: 0.5; }\n  }\n\n  \/* Apply pulse to the emoji only *\/\n  #windguru2-loading .pulse {\n    display: inline-block;\n    animation: gentlePulse 2.8s ease-in-out infinite;\n  }\n\n#windguru2-container {\n  position: relative; \n  margin-top:-25px;\n  min-height: 200px;\n  \/* Add this line: *\/\n  touch-action: pan-x pan-y; \n  overflow-x: auto;\n  -webkit-overflow-scrolling: touch;\n}\n\n<\/style>\n<div style=\"text-align:center; transform: translateX(-15px);\">\n  <div id=\"windguru2-container\" style=\"position:relative; min-height: 200px;\">\n\n    <div id=\"windguru2-loading\" style=\"\n      position: absolute; top: 0; left: 0; \n      width: 100%; height: 100%; z-index: 10;\n      display: flex; flex-direction: column; justify-content: center;\n      text-align:center; color:gray; opacity:1;\n      background-color: #EBEBEF;\n    \">\n     \t<span class=\"pulse\">&#128168; Reading the wind&#8230;<br>(Madeira) <\/span>\n<\/div>\n\n    <div id=\"windguru2-error\" style=\"\n      position: absolute; top: 0; left: 0; \n      width: 100%; height: 100%; z-index: 10;\n      display: none; flex-direction: column; justify-content: center;\n      text-align:center; color:black;\n      background-color: #EBEBEF;\n    \">\n      Didn&#8217;t load Windguru\n      <button onclick=\"reloadWindguru2()\">Try Again<\/button>\n    <\/div>\n\n    <div id=\"windguru2-widget\" style=\"opacity: 0; transition: opacity 0.6s ease;\"><\/div>\n  <\/div>\n\n  <script>\n    \/* -------------------------------------------------------------\n      Configuration\n    ------------------------------------------------------------- *\/\n    const W2_TIMEOUT = 7000;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Max wait time per attempt\n    const W2_MAX_ATTEMPTS = 3;\u00a0\u00a0\u00a0\u00a0 \/\/ Retry limit\n    const W2_MIN_LOAD_TIME = 500;\u00a0 \/\/ Minimum loader visible time (reduced for snappier feel)\n    const W2_SMOOTH_DELAY = 400;\u00a0\u00a0 \/\/ Prevent fast-load flashing\n\n\n    \/* -------------------------------------------------------------\n      Smooth fade-out for loader, and fade-in for widget\n    ------------------------------------------------------------- *\/\n    function fadeOutAndSwap(loadingEl, widgetEl) {\n      \/\/ 1. Fade out the loader\n      loadingEl.style.transition = \"opacity 0.6s ease\";\n      loadingEl.style.opacity = \"0\";\n\n      \/\/ 2. Fade in the widget\n      widgetEl.style.opacity = \"1\";\n\n      \/\/ 3. Hide loader after transition\n      setTimeout(() => { loadingEl.style.display = \"none\"; }, 600);\n    }\n\n\n    \/* -------------------------------------------------------------\n      Detect iframe \u2192 wait for iframe load \u2192 then smoothing delay\n    ------------------------------------------------------------- *\/\n    function observeWindguruIframeFullyLoaded(widgetEl, onReady) {\n      const observer = new MutationObserver(() => {\n        const iframe = widgetEl.querySelector(\"iframe\");\n        if (!iframe) return;\n\n        observer.disconnect();\n\n        \/\/ Wait for Windguru iframe internal load\n        iframe.addEventListener(\"load\", () => {\n          \/\/ Extra smoothing to prevent loader flashing\n          setTimeout(onReady, W2_SMOOTH_DELAY);\n        });\n      });\n\n      observer.observe(widgetEl, { childList: true });\n    }\n\n\n    \/* -------------------------------------------------------------\n      Main loader\n    ------------------------------------------------------------- *\/\n    function loadWindguru2(attempt = 1) {\n      const widgetEl = document.getElementById(\"windguru2-widget\");\n      const loadingEl = document.getElementById(\"windguru2-loading\");\n      const errorEl = document.getElementById(\"windguru2-error\");\n\n      \/\/ Reset UI\n      widgetEl.innerHTML = \"\";\n      widgetEl.style.opacity = \"0\"; \/\/ Ensure widget starts hidden\n      loadingEl.style.display = \"flex\"; \/\/ Use flex display to center content\n      loadingEl.style.opacity = \"1\";\n      errorEl.style.display = \"none\";\n\n      let loadComplete = false;\n      const startTime = Date.now();\n\n      \/\/ Watch for iframe \u2192 wait for iframe load \u2192 smoothing delay \u2192 then loader fade-out\n      observeWindguruIframeFullyLoaded(widgetEl, () => {\n        if (loadComplete) return;\n        loadComplete = true;\n\n        const remaining = Math.max(0, W2_MIN_LOAD_TIME - (Date.now() - startTime));\n\n        setTimeout(() => fadeOutAndSwap(loadingEl, widgetEl), remaining);\n\n        console.log(`Windguru 2 fully loaded (iframe onload + smoothing) on attempt ${attempt}`);\n      });\n\n      \/\/ Inject WG script\n      setTimeout(() => {\n        const script = document.createElement(\"script\");\n        script.id = \"wg_fwdg_54_100_\" + Date.now(); \/\/ Site ID 54 for Madeira\n\n        const args = [\n          \"s=54\", \"m=100\", \"uid=\" + script.id, \"wj=kmh\", \"tj=c\", \"waj=m\", \"tij=cm\",\n          \"odh=8\", \"doh=22\", \"fhours=111\", \"hrsm=2\", \"vt=forecasts\", \"lng=en\",\n          \"idbs=1\", \"p=WINDSPD,GUST,SMER,CDC,APCP1s\"\n        ];\n\n        script.src = \"https:\/\/www.windguru.cz\/js\/widget.php?\" + args.join(\"&\");\n\n        script.onload = () => {\n          console.log(\"Windguru 2 script loaded \u2014 waiting for iframe\u2026\");\n        };\n\n        widgetEl.appendChild(script);\n\n        \/\/ Fail-safe timeout\n        setTimeout(() => {\n          if (!loadComplete) {\n            console.warn(`Windguru 2 timed out on attempt ${attempt}`);\n\n            if (attempt < W2_MAX_ATTEMPTS) {\n              loadWindguru2(attempt + 1);\n            } else {\n              loadingEl.style.display = \"none\";\n              errorEl.style.display = \"flex\"; \/\/ Use flex display for error\n            }\n          }\n        }, W2_TIMEOUT);\n\n      }, 50);\n    }\n\n\n    \/* -------------------------------------------------------------\n      User click reload\n    ------------------------------------------------------------- *\/\n    function reloadWindguru2() {\n      loadWindguru2(1);\n    }\n\n    \/\/ Auto-load\n    document.addEventListener(\"DOMContentLoaded\", () => loadWindguru2(1));\n  <\/script>\n<\/div>\n\n\n\n<div style=\"height:13px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<!-- ventusky in tests below \n<div style=\"text-align:center; margin-top:-2px;\">\n  <div style=\"\n  display:block;\n  position:relative;\n  max-width:100vw;\n  margin:auto;\n  padding:0;\n  border:0;\n  transform: translateX(-20px);\n\">\n    <div style=\"position:relative;width:100%;height:0;padding-bottom:100%;\">\n\n      <div id=\"ventusky-loading\" style=\"text-align:center;padding:10px;color:gray;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:10;width:100%;\">\n        Loading Ventusky map...\n      <\/div>\n\n      <div id=\"ventusky-error\" style=\"display:none;text-align:center;color:blue;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:10;width:100%;\">\n        Map didn't load.\n        <button onclick=\"reloadVentusky()\" style=\"margin-left:6px;padding:4px 12px;cursor:pointer;\">\n          Reload\n        <\/button>\n      <\/div>\n\n      <iframe id=\"ventusky-iframe\"\n        src=\"\"\n        style=\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;opacity:0;transition:opacity 0.8s ease;\"\n        loading=\"lazy\">\n      <\/iframe>\n\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n  const ventuskyIframe = document.getElementById(\"ventusky-iframe\");\n  const ventuskyLoading = document.getElementById(\"ventusky-loading\");\n  const ventuskyError = document.getElementById(\"ventusky-error\");\n  const ventuskyBaseUrl = \"https:\/\/embed.ventusky.com\/?p=32.81;-17.00;8&l=gust\";\n\n  const loadTimeout = 7000; \/\/ Time before a load attempt is considered a failure\n  const minLoadTime = 1500; \/\/ Minimum time to show the spinner (to prevent flicker)\n  const maxAttempts = 3;    \/\/ Maximum load attempts\n\n  \/**\n   * Loads the Ventusky iframe with retry logic and controlled loading state.\n   * @param {number} [attempt=1] - The current load attempt number.\n   *\/\n  function reloadVentusky(attempt = 1) {\n    \/\/ 1. Setup\/Reset State\n    ventuskyError.style.display = \"none\";\n    ventuskyLoading.style.display = \"block\"; \/\/ Show loading spinner\n    ventuskyIframe.style.opacity = '0';      \/\/ Hide iframe\n    ventuskyIframe.src = '';                 \/\/ Clear src\n    \/\/ Disable the reload button during the process (optional: you'd need to add an ID to the button for this)\n    \/\/ For simplicity, we skip disabling the button unless absolutely necessary.\n\n    let loadComplete = false;\n    const startTime = Date.now();\n\n    \/\/ 2. Define Successful Load Handler (runs on iframe.onload)\n    ventuskyIframe.onload = () => {\n      if (loadComplete) return; \/\/ Prevent double-firing\n      loadComplete = true;\n\n      \/\/ Calculate time remaining for minimum display\n      const elapsed = Date.now() - startTime;\n      const delay = Math.max(0, minLoadTime - elapsed);\n\n      \/\/ Ensure minimum display time\n      setTimeout(() => {\n        ventuskyLoading.style.display = \"none\"; \/\/ Hide loading spinner\n\n        \/\/ Trigger fade-in\n        ventuskyIframe.style.opacity = '1';\n        \/\/ Re-enable button here if it was disabled\n        console.log('Ventusky iframe loaded successfully.');\n      }, delay);\n    };\n\n    \/\/ 3. Set iframe source after a small delay to ensure onload is set\n    setTimeout(() => {\n      \/\/ Add cache-busting timestamp\n      const newSrc = `${ventuskyBaseUrl}&t=${Date.now()}`;\n      ventuskyIframe.src = newSrc;\n\n      \/\/ 4. Set Failure\/Retry Timeout\n      setTimeout(() => {\n        if (!loadComplete && attempt < maxAttempts) {\n          console.warn(`Ventusky failed to load. Retrying attempt ${attempt + 1}...`);\n          reloadVentusky(attempt + 1); \/\/ Retry\n        } else if (!loadComplete) {\n          console.error('Ventusky failed after max attempts.');\n          ventuskyLoading.style.display = \"none\";\n          ventuskyError.style.display = \"block\"; \/\/ Show error\/reload button\n          \/\/ Re-enable button here if it was disabled\n        }\n      }, loadTimeout);\n    }, 50); \/\/ Small delay before setting src\n  }\n\n  \/\/ Auto-load on first visit\n  window.addEventListener('load', () => reloadVentusky());\n<\/script>\n-->\n\n\n\n<div style=\"text-align:center; margin-top:-2px;\">\n  <div style=\"\n  display:block;\n  position:relative;\n  max-width:100vw;\n  margin:auto;\n  padding:0;\n  border:0;\n  transform: translateX(-20px);\n\">\n    <div style=\"position:relative;width:100%;height:0;padding-bottom:550px;\">\n<!-- Padding bottom is the iframe height -->\n\n      <div id=\"ventusky-loading\" style=\"text-align:center;padding:10px;color:gray;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:10;width:100%;\">\n        Loading Ventusky map&#8230;\n      <\/div>\n\n      <div id=\"ventusky-error\" style=\"display:none;text-align:center;color:blue;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:10;width:100%;\">\n        Map didn&#8217;t load.\n        <button onclick=\"reloadVentusky()\" style=\"margin-left:6px;padding:4px 12px;cursor:pointer;\">\n          Reload\n        <\/button>\n      <\/div>\n\n      <iframe id=\"ventusky-iframe\"\n        src=\"\"\n        style=\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;opacity:0;transition:opacity 0.8s ease;\"\n        loading=\"lazy\">\n      <\/iframe>\n\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n  const ventuskyIframe = document.getElementById(\"ventusky-iframe\");\n  const ventuskyLoading = document.getElementById(\"ventusky-loading\");\n  const ventuskyError = document.getElementById(\"ventusky-error\");\n  const ventuskyBaseUrl = \"https:\/\/www.ventusky.com\/wind-gusts-map\/1-hour#p=32.69;-17.00;8\";\n\n  const loadTimeout = 7000; \/\/ Time before a load attempt is considered a failure\n  const minLoadTime = 1500; \/\/ Minimum time to show the spinner (to prevent flicker)\n  const maxAttempts = 3;    \/\/ Maximum load attempts\n\n  \/**\n   * Loads the Ventusky iframe with retry logic and controlled loading state.\n   * @param {number} [attempt=1] - The current load attempt number.\n   *\/\n  function reloadVentusky(attempt = 1) {\n    \/\/ 1. Setup\/Reset State\n    ventuskyError.style.display = \"none\";\n    ventuskyLoading.style.display = \"block\"; \/\/ Show loading spinner\n    ventuskyIframe.style.opacity = '0';      \/\/ Hide iframe\n    ventuskyIframe.src = '';                 \/\/ Clear src\n    \/\/ Disable the reload button during the process (optional: you'd need to add an ID to the button for this)\n    \/\/ For simplicity, we skip disabling the button unless absolutely necessary.\n\n    let loadComplete = false;\n    const startTime = Date.now();\n\n    \/\/ 2. Define Successful Load Handler (runs on iframe.onload)\n    ventuskyIframe.onload = () => {\n      if (loadComplete) return; \/\/ Prevent double-firing\n      loadComplete = true;\n\n      \/\/ Calculate time remaining for minimum display\n      const elapsed = Date.now() - startTime;\n      const delay = Math.max(0, minLoadTime - elapsed);\n\n      \/\/ Ensure minimum display time\n      setTimeout(() => {\n        ventuskyLoading.style.display = \"none\"; \/\/ Hide loading spinner\n\n        \/\/ Trigger fade-in\n        ventuskyIframe.style.opacity = '1';\n        \/\/ Re-enable button here if it was disabled\n        console.log('Ventusky iframe loaded successfully.');\n      }, delay);\n    };\n\n    \/\/ 3. Set iframe source after a small delay to ensure onload is set\n    setTimeout(() => {\n      \/\/ Add cache-busting timestamp\n      const newSrc = `${ventuskyBaseUrl}&t=${Date.now()}`;\n      ventuskyIframe.src = newSrc;\n\n      \/\/ 4. Set Failure\/Retry Timeout\n      setTimeout(() => {\n        if (!loadComplete && attempt < maxAttempts) {\n          console.warn(`Ventusky failed to load. Retrying attempt ${attempt + 1}...`);\n          reloadVentusky(attempt + 1); \/\/ Retry\n        } else if (!loadComplete) {\n          console.error('Ventusky failed after max attempts.');\n          ventuskyLoading.style.display = \"none\";\n          ventuskyError.style.display = \"block\"; \/\/ Show error\/reload button\n          \/\/ Re-enable button here if it was disabled\n        }\n      }, loadTimeout);\n    }, 50); \/\/ Small delay before setting src\n  }\n\n  \/\/ Auto-load on first visit\n  window.addEventListener('load', () => reloadVentusky());\n<\/script>\n\n\n\n<div style=\"text-align:center; margin-top:-1px;\">\n  <div style=\"display:inline-block; position:relative; left:-20px; width:100%;\">\n    <iframe\n      style=\"width:100%; height:720px; border:0;\"\n      src=\"https:\/\/www.meteoblue.com\/pt\/tempo\/mapas\/widget\/santa-maria-maior_portugal_2263496?windAnimation=1&#038;gust=0&#038;satellite=0&#038;cloudsAndPrecipitation=0&#038;temperature=0&#038;sunshine=0&#038;extremeForecastIndex=0&#038;geoloc=fixed&#038;tempunit=C&#038;windunit=km%252Fh&#038;lengthunit=metric&#038;zoom=8&#038;autowidth=auto\"\n      frameborder=\"0\"\n      scrolling=\"no\"\n      allowtransparency=\"true\"\n      sandbox=\"allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox\">\n    <\/iframe>\n  <\/div>\n<\/div>\n\n\n\n<div style=\"text-align:center; margin-top:-20px;\">\n  <div style=\"display:inline-block; position:relative; left:-20px; width:100%;\">\n    <iframe loading=\"lazy\"\n      width=\"100%\"\n      height=\"333\"\n      src=\"https:\/\/embed.windy.com\/embed.html?type=map&#038;location=coordinates&#038;metricRain=mm&#038;metricTemp=\u00b0C&#038;metricWind=km\/h&#038;zoom=9&#038;overlay=wind&#038;product=ecmwf&#038;level=surface&#038;lat=32.73&#038;lon=-17.01&#038;message=true\"\n      frameborder=\"0\">\n    <\/iframe>\n  <\/div>\n<\/div>\n\n\n\n<div style=\"text-align:center; margin-top:-10px; transform: translateX(-20px);\">\n<sup><small><i><a href=\"https:\/\/www.ventusky.com\/?p=32.70;-17.03;8&#038;l=gust\" target=\"_blank\" rel=\"noopener\">Ventusky<\/a><\/i><\/small><\/sup>\n<sup><small><i> | <\/i><\/small><\/sup>\n<!-- Do Not Remove This Link -->\n<sup><small><i><a href=\"https:\/\/www.meteoblue.com\/pt\/tempo\/mapas\/santa-maria-maior_portugal_2263496?utm_source=map_widget&#038;utm_medium=linkus&#038;utm_content=map&#038;utm_campaign=Weather%2BWidget\" target=\"_blank\" rel=\"noopener\">Meteoblue<\/a><\/i><\/small><\/sup>\n<sup><small><i> | <\/i><\/small><\/sup>\n<sup><small><i><a href=\"https:\/\/www.windy.com\/?32.662,-17.001,9,i:pressure\" target=\"_blank\" rel=\"noopener\">Windy<\/a><\/i><\/small><\/sup><\/div>\n\n\n\n<details class=\"wp-block-details is-layout-flow wp-block-details-is-layout-flow\"><summary>Video info<\/summary>\n<p class=\"has-text-align-center\"><sub><sup>Windy &#8211; How to read sea level &amp; mountain wind<\/sup><\/sub><\/p>\n\n\n\n<div class=\"epyt-video-wrapper\"><div  style=\"display: block; margin: 0px auto;\"  id=\"_ytid_36652\"  width=\"480\" height=\"270\"  data-origwidth=\"480\" data-origheight=\"270\"  data-relstop=\"1\" data-facadesrc=\"https:\/\/www.youtube.com\/embed\/0aq26uKD_R8?enablejsapi=1&cc_load_policy=1&autoplay=0&cc_lang_pref=en&iv_load_policy=3&loop=0&rel=0&fs=1&playsinline=0&autohide=2&hl=en_US&theme=dark&color=red&controls=1&\" class=\"__youtube_prefs__ epyt-facade no-lazyload\" data-vol=\"0\"  data-epautoplay=\"1\" ><img decoding=\"async\" data-spai-excluded=\"true\" class=\"epyt-facade-poster skip-lazy\" loading=\"lazy\"  alt=\"YouTube player\"  src=\"https:\/\/i.ytimg.com\/vi\/0aq26uKD_R8\/hqdefault.jpg\"  \/><button class=\"epyt-facade-play\" aria-label=\"Play\"><svg data-no-lazy=\"1\" height=\"100%\" version=\"1.1\" viewBox=\"0 0 68 48\" width=\"100%\"><path class=\"ytp-large-play-button-bg\" d=\"M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z\" fill=\"#f00\"><\/path><path d=\"M 45,24 27,14 27,34\" fill=\"#fff\"><\/path><\/svg><\/button><\/div><\/div>\n\n\n\n<p class=\"has-text-align-center\"><sub><sup>The Island influence on wind readings (sound on)<\/sup><\/sub><\/p>\n\n\n\n<div class=\"epyt-video-wrapper\"><div  style=\"display: block; margin: 0px auto;\"  id=\"_ytid_16609\"  width=\"480\" height=\"270\"  data-origwidth=\"480\" data-origheight=\"270\"  data-relstop=\"1\" data-facadesrc=\"https:\/\/www.youtube.com\/embed\/TK09BZ1Vp-k?enablejsapi=1&cc_load_policy=1&autoplay=0&cc_lang_pref=en&iv_load_policy=3&loop=0&rel=0&fs=1&playsinline=0&autohide=2&hl=en_US&theme=dark&color=red&controls=1&\" class=\"__youtube_prefs__ epyt-facade no-lazyload\" data-vol=\"0\"  data-epautoplay=\"1\" ><img decoding=\"async\" data-spai-excluded=\"true\" class=\"epyt-facade-poster skip-lazy\" loading=\"lazy\"  alt=\"YouTube player\"  src=\"https:\/\/i.ytimg.com\/vi\/TK09BZ1Vp-k\/hqdefault.jpg\"  \/><button class=\"epyt-facade-play\" aria-label=\"Play\"><svg data-no-lazy=\"1\" height=\"100%\" version=\"1.1\" viewBox=\"0 0 68 48\" width=\"100%\"><path class=\"ytp-large-play-button-bg\" d=\"M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z\" fill=\"#f00\"><\/path><path d=\"M 45,24 27,14 27,34\" fill=\"#fff\"><\/path><\/svg><\/button><\/div><\/div>\n<\/details>\n\n\n\n<div style=\"height:13px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-text-align-center\" id=\"meteogram\"><strong>Meteogram<\/strong><br><em>graphical weather forecast&nbsp;<\/em><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"258\" src=\"https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2024\/11\/Weather-icons-1024x258.png\" alt=\"\" class=\"wp-image-1573\" srcset=\"https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2024\/11\/Weather-icons-1024x258.png 1024w, https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2024\/11\/Weather-icons-300x75.png 300w, https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2024\/11\/Weather-icons-768x193.png 768w, https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2024\/11\/Weather-icons.png 1117w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<div style=\"display:block; overflow: hidden; width:333px; height:170px; touch-action: pan-x pan-y; \n    -webkit-overflow-scrolling: touch;\">\n<iframe loading=\"lazy\" style=\"margin-top:-57px;margin-left:-43px\" height=\"222px\" width=\"400px\" scrolling=\"yes\" border=\"0\" src=\"https:\/\/www.wetterzentrale.de\/maps\/GFSOP12_33.0000_-17.0000_210.png\"><\/iframe><\/div>\n\n\n\n<!-- meteoblue api limit resets 29\/04\/2027 -->\n<!-- cached image version below\n\n<div style=\"text-align:center; margin-top:-1px;\">\n<div class=\"bloo-content meteogram\" style=\"height: 0; overflow:hidden; padding-bottom: 80%\">\n<div class=\"loading\" style=\"display: none;\"><\/div>\n<img decoding=\"async\" src=\"https:\/\/my.meteoblue.com\/images\/meteogram?temperature_units=C&windspeed_units=kmh&precipitation_units=mm&darkmode=false&iso2=pt&lat=32.6657&lon=-16.9255&asl=280&tz=Atlantic%2FMadeira&dpi=72&apikey=YuX9eGKs7SW2BQhI&lang=en&location_name=Funchal\" class=\"image-lazyload loaded\" data-name=\"5-days meteogram\" alt=\"meteoblue\" width=\"100%\">\n<\/div>\n<\/div>\n-->\n\n\n\n<!-- meteoblue api limit resets 29\/04\/2027 -->\n\n<div style=\"text-align:center; margin-top:-1px;\">\n    <div class=\"bloo-content meteogram\" style=\"height: 0; overflow:hidden; padding-bottom: 80%\">\n<div class=\"loading\" style=\"display: none;\"><\/div>\n<img decoding=\"async\" src=\"\/weather\/meteogram-cache.php\" \n class=\"image-lazyload loaded\" \n data-name=\"5-days meteogram\" \n  alt=\"Meteoblue Funchal 280m\" \n      width=\"100%\">\n    <\/div>\n<\/div>\n\n\n\n<div style=\"text-align:center; margin-top:-1px;\">\n<sup><small><i><a href=\"https:\/\/www.wetterzentrale.de\/en\/show_diagrams.php?geoid=102843&#038;model=gfs&#038;var=210&#038;run=12&#038;lid=OP&#038;bw=1\" target=\"_blank\" rel=\"noopener\">Wetterzentrale<\/a><\/i><\/small><\/sup>\n<sup><small><i> \/ <\/i><\/small><\/sup>\n<sup><small><i><a href=\"https:\/\/www.meteoblue.com\/en\/weather\/forecast\/meteogramweb\/funchal_portugal_2267827\" target=\"_blank\" rel=\"noopener\">Meteoblue Funchal 280m<\/a><\/i><\/small><\/sup>\n<sup><small><i> \/ <\/i><\/small><\/sup>\n<sup><small><i><a href=\"https:\/\/www.meteoblue.com\/en\/weather\/forecast\/meteogramweb\/pico-do-arieiro_portugal_2271550\" target=\"_blank\" rel=\"noopener\">Arieiro<\/a><\/i><\/small><\/sup>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Meteogram Below you can find different models showing the weather forecast for Madeira Island for the next few days Windguru forecast wind in km\/h at sea level: &#128168; Reading the wind&#8230;(Porto Santo) Didn&#8217;t load Windguru Try Again &#128168; Reading the wind&#8230;(Madeira) Didn&#8217;t load Windguru Try Again Loading Ventusky map&#8230; Map didn&#8217;t load. Reload Ventusky | [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1591,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"slim_seo":{"title":"Weather Forecast for Madeira island","description":"Forecast tools to check the evolution ot the weather for the next few days. Madeira Island weather simplified"},"footnotes":""},"class_list":["post-1597","page","type-page","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/pages\/1597","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/comments?post=1597"}],"version-history":[{"count":129,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/pages\/1597\/revisions"}],"predecessor-version":[{"id":10773,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/pages\/1597\/revisions\/10773"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/media\/1591"}],"wp:attachment":[{"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/media?parent=1597"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}