{"id":6382,"date":"2026-06-12T17:03:18","date_gmt":"2026-06-12T17:03:18","guid":{"rendered":"https:\/\/3solutions.pt\/?page_id=6382"},"modified":"2026-06-17T17:11:14","modified_gmt":"2026-06-17T17:11:14","slug":"jobmaps-o-mapa-do-trabalho-local","status":"publish","type":"page","link":"https:\/\/3solutions.pt\/en\/jobmaps-o-mapa-do-trabalho-local\/","title":{"rendered":"Jobmaps \u2014 O mapa do trabalho local"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"6382\" class=\"elementor elementor-6382\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5bc4c3c e-flex e-con-boxed e-con e-parent\" data-id=\"5bc4c3c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-928a794 elementor-widget elementor-widget-html\" data-id=\"928a794\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<header class=\"jm-site-header\">\r\n  <div class=\"jm-site-header-inner\">\r\n\r\n    <a href=\"\/jobmaps-o-mapa-do-trabalho-local\/\" class=\"jm-site-brand\" aria-label=\"Ir para a p\u00e1gina inicial do WIW\">\r\n      <span class=\"jm-site-logo\">\r\n        <img decoding=\"async\" src=\"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/06\/WIW.png\" alt=\"WIW - Work is Worth\">\r\n      <\/span>\r\n      <span class=\"jm-site-tagline\">O mapa de ofertas salariais na sua zona<\/span>\r\n    <\/a>\r\n\r\n    <nav class=\"jm-site-nav\" aria-label=\"Menu WIW\">\r\n      <a id=\"jm-link-contratar\" href=\"\/jobmaps-login\/\" class=\"jm-site-nav-link jm-primary-link\">Quero contratar<\/a>\r\n      <a id=\"jm-link-trabalhar\" href=\"\/jobmaps-login-candidato\/\" class=\"jm-site-nav-link\">Quero trabalhar<\/a>\r\n      <a id=\"jm-link-recrutador\" href=\"\/jobmaps-recrutador\/\" class=\"jm-site-nav-link\">Sou recrutador<\/a>\r\n\r\n      <a id=\"jm-user-pill\" href=\"\/jobmaps-o-mapa-do-trabalho-local\/\" class=\"jm-user-pill\" style=\"display:none;\">\r\n        <span class=\"jm-user-icon\">\ud83d\udc64<\/span>\r\n        <span id=\"jm-user-name\">\u00c1rea<\/span>\r\n      <\/a>\r\n\r\n      <a id=\"jm-logout-link\" href=\"#\" class=\"jm-site-nav-link jm-logout-link\" style=\"display:none;\">Sair<\/a>\r\n    <\/nav>\r\n\r\n  <\/div>\r\n<\/header>\r\n\r\n<script>\r\ndocument.addEventListener(\"DOMContentLoaded\", function () {\r\n  const contratarLink = document.getElementById(\"jm-link-contratar\");\r\n  const trabalharLink = document.getElementById(\"jm-link-trabalhar\");\r\n  const recrutadorLink = document.getElementById(\"jm-link-recrutador\");\r\n  const userPill = document.getElementById(\"jm-user-pill\");\r\n  const userName = document.getElementById(\"jm-user-name\");\r\n  const logoutLink = document.getElementById(\"jm-logout-link\");\r\n\r\n  function showLogout(data) {\r\n    if (logoutLink) {\r\n      const cleanLogoutUrl = (data.logout_url || \"#\")\r\n        .replace(\/&amp;\/g, \"&\")\r\n        .replace(\/&#038;\/g, \"&\");\r\n\r\n      logoutLink.href = cleanLogoutUrl;\r\n      logoutLink.style.display = \"inline-flex\";\r\n    }\r\n  }\r\n\r\n  function showUserPill(label, href) {\r\n    if (userPill && userName) {\r\n      userName.textContent = label || \"\u00c1rea\";\r\n      userPill.href = href || \"\/jobmaps-o-mapa-do-trabalho-local\/\";\r\n      userPill.style.display = \"inline-flex\";\r\n    }\r\n  }\r\n\r\n  function estadoNaoLogado() {\r\n    if (contratarLink) {\r\n      contratarLink.href = \"\/jobmaps-login\/\";\r\n      contratarLink.textContent = \"Quero contratar\";\r\n      contratarLink.classList.remove(\"jm-logged-link\");\r\n      contratarLink.classList.add(\"jm-primary-link\");\r\n    }\r\n\r\n    if (trabalharLink) {\r\n      trabalharLink.href = \"\/jobmaps-login-candidato\/\";\r\n      trabalharLink.textContent = \"Quero trabalhar\";\r\n      trabalharLink.classList.remove(\"jm-logged-link\");\r\n    }\r\n\r\n    if (recrutadorLink) {\r\n      recrutadorLink.href = \"\/jobmaps-recrutador\/\";\r\n      recrutadorLink.textContent = \"Sou recrutador\";\r\n      recrutadorLink.classList.remove(\"jm-logged-link\");\r\n    }\r\n\r\n    if (userPill) {\r\n      userPill.style.display = \"none\";\r\n    }\r\n\r\n    if (logoutLink) {\r\n      logoutLink.style.display = \"none\";\r\n      logoutLink.href = \"#\";\r\n    }\r\n  }\r\n\r\n  function estadoEmpresaLogada(data) {\r\n    if (contratarLink) {\r\n      contratarLink.href = \"\/jobmaps-area-empresa\/\";\r\n      contratarLink.textContent = \"\u00c1rea da empresa\";\r\n      contratarLink.classList.add(\"jm-logged-link\");\r\n      contratarLink.classList.remove(\"jm-primary-link\");\r\n    }\r\n\r\n    if (trabalharLink) {\r\n      trabalharLink.href = \"\/jobmaps-login-candidato\/\";\r\n      trabalharLink.textContent = \"Quero trabalhar\";\r\n      trabalharLink.classList.remove(\"jm-logged-link\");\r\n    }\r\n\r\n    if (recrutadorLink) {\r\n      recrutadorLink.href = \"\/jobmaps-recrutador\/\";\r\n      recrutadorLink.textContent = \"Sou recrutador\";\r\n      recrutadorLink.classList.remove(\"jm-logged-link\");\r\n    }\r\n\r\n    showUserPill(data.empresa_titulo || data.display_name || \"Empresa\", \"\/jobmaps-area-empresa\/\");\r\n    showLogout(data);\r\n  }\r\n\r\n  function estadoCandidatoLogado(data) {\r\n    if (contratarLink) {\r\n      contratarLink.href = \"\/jobmaps-login\/\";\r\n      contratarLink.textContent = \"Quero contratar\";\r\n      contratarLink.classList.remove(\"jm-logged-link\");\r\n      contratarLink.classList.add(\"jm-primary-link\");\r\n    }\r\n\r\n    if (trabalharLink) {\r\n      trabalharLink.href = \"\/jobmaps-area-candidato\/\";\r\n      trabalharLink.textContent = \"\u00c1rea do candidato\";\r\n      trabalharLink.classList.add(\"jm-logged-link\");\r\n    }\r\n\r\n    if (recrutadorLink) {\r\n      recrutadorLink.href = \"\/jobmaps-recrutador\/\";\r\n      recrutadorLink.textContent = \"Sou recrutador\";\r\n      recrutadorLink.classList.remove(\"jm-logged-link\");\r\n    }\r\n\r\n    showUserPill(data.candidato_nome || data.display_name || \"Candidato\", \"\/jobmaps-area-candidato\/\");\r\n    showLogout(data);\r\n  }\r\n\r\n  function estadoRecrutadorLogado(data) {\r\n    if (contratarLink) {\r\n      contratarLink.href = \"\/jobmaps-login\/\";\r\n      contratarLink.textContent = \"Quero contratar\";\r\n      contratarLink.classList.remove(\"jm-logged-link\");\r\n      contratarLink.classList.add(\"jm-primary-link\");\r\n    }\r\n\r\n    if (trabalharLink) {\r\n      trabalharLink.href = \"\/jobmaps-login-candidato\/\";\r\n      trabalharLink.textContent = \"Quero trabalhar\";\r\n      trabalharLink.classList.remove(\"jm-logged-link\");\r\n    }\r\n\r\n    if (recrutadorLink) {\r\n      recrutadorLink.href = \"\/jobmaps-area-recrutador\/\";\r\n      recrutadorLink.textContent = \"\u00c1rea do recrutador\";\r\n      recrutadorLink.classList.add(\"jm-logged-link\");\r\n    }\r\n\r\n    showUserPill(data.recrutador_nome || data.display_name || \"Recrutador WIW\", \"\/jobmaps-area-recrutador\/\");\r\n    showLogout(data);\r\n  }\r\n\r\n  fetch(\"\/wp-admin\/admin-ajax.php?action=jm5_header_me&t=\" + Date.now(), {\r\n    method: \"GET\",\r\n    credentials: \"same-origin\",\r\n    cache: \"no-store\"\r\n  })\r\n    .then(response => response.json())\r\n    .then(data => {\r\n      if (!data || !data.logged_in) {\r\n        estadoNaoLogado();\r\n        return;\r\n      }\r\n\r\n      if (data.user_type === \"empresa\" || data.is_empresa) {\r\n        estadoEmpresaLogada(data);\r\n        return;\r\n      }\r\n\r\n      if (data.user_type === \"candidato\" || data.is_candidato) {\r\n        estadoCandidatoLogado(data);\r\n        return;\r\n      }\r\n\r\n      if (data.user_type === \"recrutador\" || data.is_recrutador) {\r\n        estadoRecrutadorLogado(data);\r\n        return;\r\n      }\r\n\r\n      estadoNaoLogado();\r\n    })\r\n    .catch(() => {\r\n      estadoNaoLogado();\r\n    });\r\n});\r\n<\/script>\r\n\r\n<style>\r\n.jm-site-header {\r\n  width: 100%;\r\n  padding: 0;\r\n  background: #ffffff;\r\n  box-sizing: border-box;\r\n  font-family: inherit;\r\n  position: relative;\r\n  z-index: 20;\r\n  border-bottom: 1px solid #e8ebf0;\r\n}\r\n\r\n.jm-site-header-inner {\r\n  width: 100%;\r\n  margin: 0 auto;\r\n  padding: 4px 24px;\r\n  min-height: 66px;\r\n  background: #ffffff;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: space-between;\r\n  gap: 22px;\r\n  box-sizing: border-box;\r\n  overflow: visible;\r\n  position: relative;\r\n}\r\n\r\n.jm-site-brand {\r\n  display: inline-flex;\r\n  flex-direction: column;\r\n  align-items: flex-start;\r\n  justify-content: center;\r\n  text-decoration: none;\r\n  flex-shrink: 0;\r\n  min-width: 250px;\r\n  overflow: visible;\r\n}\r\n\r\n.jm-site-logo {\r\n  height: 52px;\r\n  display: inline-flex;\r\n  align-items: center;\r\n  justify-content: flex-start;\r\n  overflow: visible;\r\n}\r\n\r\n.jm-site-logo img {\r\n  height: 150px;\r\n  width: auto;\r\n  max-width: 285px;\r\n  display: block;\r\n  transform: scale(1.16);\r\n  transform-origin: left center;\r\n}\r\n\r\n.jm-site-tagline {\r\n  margin-top: -9px;\r\n  padding-left: 6px;\r\n  color: #587092;\r\n  font-size: 12px;\r\n  font-weight: 750;\r\n  line-height: 1.2;\r\n  letter-spacing: -0.1px;\r\n  white-space: nowrap;\r\n}\r\n\r\n.jm-site-nav {\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: flex-end;\r\n  gap: 22px;\r\n  flex-wrap: nowrap;\r\n}\r\n\r\n.jm-site-nav-link {\r\n  position: relative;\r\n  display: inline-flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  padding: 8px 0;\r\n  text-align: center;\r\n  text-decoration: none;\r\n  font-size: 12px;\r\n  font-weight: 650;\r\n  line-height: 1;\r\n  color: #405066;\r\n  background: transparent;\r\n  border: 0;\r\n  box-shadow: none;\r\n  transition: color 0.15s ease, opacity 0.15s ease;\r\n  box-sizing: border-box;\r\n  white-space: nowrap;\r\n  opacity: 0.86;\r\n}\r\n\r\n.jm-site-nav-link::after {\r\n  content: \"\";\r\n  position: absolute;\r\n  left: 0;\r\n  right: 0;\r\n  bottom: -5px;\r\n  height: 2px;\r\n  border-radius: 999px;\r\n  background: #1556ff;\r\n  transform: scaleX(0);\r\n  transform-origin: center;\r\n  transition: transform 0.15s ease;\r\n}\r\n\r\n.jm-site-nav-link:hover {\r\n  color: #1556ff;\r\n  opacity: 1;\r\n}\r\n\r\n.jm-site-nav-link:hover::after {\r\n  transform: scaleX(1);\r\n}\r\n\r\n.jm-primary-link {\r\n  color: #1556ff;\r\n  font-weight: 750;\r\n  opacity: 0.95;\r\n}\r\n\r\n.jm-logged-link {\r\n  color: #15396f;\r\n  font-weight: 750;\r\n  opacity: 0.95;\r\n}\r\n\r\n.jm-logout-link {\r\n  color: #a12626;\r\n  font-weight: 750;\r\n}\r\n\r\n.jm-logout-link::after {\r\n  background: #a12626;\r\n}\r\n\r\n.jm-user-pill {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  gap: 5px;\r\n  padding: 0;\r\n  border-radius: 0;\r\n  background: transparent;\r\n  color: #587092;\r\n  text-decoration: none;\r\n  font-size: 11.5px;\r\n  font-weight: 650;\r\n  border: 0;\r\n  white-space: nowrap;\r\n  max-width: 170px;\r\n  overflow: hidden;\r\n  text-overflow: ellipsis;\r\n  transition: color 0.15s ease;\r\n}\r\n\r\n.jm-user-pill:hover {\r\n  color: #1556ff;\r\n}\r\n\r\n.jm-user-icon {\r\n  font-size: 12px;\r\n  line-height: 1;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#jm-user-name {\r\n  display: inline-block;\r\n  overflow: hidden;\r\n  text-overflow: ellipsis;\r\n  white-space: nowrap;\r\n}\r\n\r\n\/* Tablet *\/\r\n@media (max-width: 900px) {\r\n  .jm-site-header-inner {\r\n    padding: 5px 16px;\r\n    min-height: 64px;\r\n    gap: 14px;\r\n  }\r\n\r\n  .jm-site-brand {\r\n    min-width: 220px;\r\n  }\r\n\r\n  .jm-site-logo {\r\n    height: 50px;\r\n  }\r\n\r\n  .jm-site-logo img {\r\n    height: 135px;\r\n    max-width: 250px;\r\n    transform: scale(1.13);\r\n    transform-origin: left center;\r\n  }\r\n\r\n  .jm-site-tagline {\r\n    margin-top: -8px;\r\n    padding-left: 4px;\r\n    font-size: 11.5px;\r\n  }\r\n\r\n  .jm-site-nav {\r\n    gap: 15px;\r\n  }\r\n\r\n  .jm-site-nav-link {\r\n    font-size: 11.5px;\r\n    padding: 7px 0;\r\n  }\r\n\r\n  .jm-user-pill {\r\n    font-size: 11px;\r\n    max-width: 135px;\r\n  }\r\n}\r\n\r\n\/* Mobile *\/\r\n@media (max-width: 680px) {\r\n  .jm-site-header-inner {\r\n    padding: 8px 12px 13px;\r\n    min-height: auto;\r\n    flex-direction: column;\r\n    align-items: flex-start;\r\n    gap: 0;\r\n  }\r\n\r\n  .jm-site-brand {\r\n    width: 100%;\r\n    min-width: 0;\r\n    align-items: flex-start;\r\n    padding-right: 92px;\r\n  }\r\n\r\n  .jm-site-logo {\r\n    height: 70px;\r\n    width: 100%;\r\n    justify-content: flex-start;\r\n  }\r\n\r\n  .jm-site-logo img {\r\n    height: 156px;\r\n    max-width: 292px;\r\n    transform: scale(1.18);\r\n    transform-origin: left center;\r\n  }\r\n\r\n  .jm-site-tagline {\r\n    margin-top: -5px;\r\n    padding-left: 3px;\r\n    margin-bottom: 13px;\r\n    font-size: 12px;\r\n    text-align: left;\r\n    white-space: normal;\r\n    max-width: 100%;\r\n    line-height: 1.25;\r\n  }\r\n\r\n  .jm-site-nav {\r\n    width: 100%;\r\n    justify-content: center;\r\n    gap: 11px 16px;\r\n    flex-wrap: wrap;\r\n    padding-top: 6px;\r\n  }\r\n\r\n  .jm-site-nav-link {\r\n    font-size: 12px;\r\n    font-weight: 650;\r\n    padding: 5px 0;\r\n  }\r\n\r\n  .jm-site-nav-link::after {\r\n    bottom: -3px;\r\n    height: 2px;\r\n  }\r\n\r\n  .jm-user-pill {\r\n    position: absolute;\r\n    top: 12px;\r\n    right: 12px;\r\n    font-size: 11px;\r\n    max-width: 92px;\r\n    justify-content: flex-end;\r\n    margin-top: 0;\r\n    color: #587092;\r\n  }\r\n\r\n  .jm-user-icon {\r\n    font-size: 12px;\r\n  }\r\n\r\n  .jm-logout-link {\r\n    color: #a12626;\r\n  }\r\n}\r\n\r\n\/* Mobile muito estreito *\/\r\n@media (max-width: 420px) {\r\n  .jm-site-header-inner {\r\n    padding: 8px 10px 12px;\r\n  }\r\n\r\n  .jm-site-brand {\r\n    padding-right: 82px;\r\n  }\r\n\r\n  .jm-site-logo {\r\n    height: 64px;\r\n  }\r\n\r\n  .jm-site-logo img {\r\n    height: 138px;\r\n    max-width: 255px;\r\n    transform: scale(1.13);\r\n    transform-origin: left center;\r\n  }\r\n\r\n  .jm-site-tagline {\r\n    margin-top: -3px;\r\n    margin-bottom: 12px;\r\n    padding-left: 2px;\r\n    font-size: 11.2px;\r\n    line-height: 1.25;\r\n    max-width: 100%;\r\n  }\r\n\r\n  .jm-site-nav {\r\n    gap: 9px 12px;\r\n    padding-top: 6px;\r\n  }\r\n\r\n  .jm-site-nav-link {\r\n    font-size: 11.5px;\r\n    padding: 4px 0;\r\n  }\r\n\r\n  .jm-user-pill {\r\n    top: 11px;\r\n    right: 10px;\r\n    font-size: 10.5px;\r\n    max-width: 78px;\r\n  }\r\n\r\n  .jm-user-icon {\r\n    font-size: 11px;\r\n  }\r\n}\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-23de181 elementor-widget elementor-widget-html\" data-id=\"23de181\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<section class=\"jm-hero\">\r\n\r\n  <div class=\"jm-bg\"><\/div>\r\n\r\n  <div class=\"jm-inner\">\r\n\r\n    <div class=\"jm-left\">\r\n\r\n      <h1>Encontre oportunidades.<br>Construa o seu futuro.<\/h1>\r\n\r\n      <p>\r\n        O JobMaps aproxima pessoas e oportunidades locais, porque o trabalho deve valer a pena.\r\n      <\/p>\r\n\r\n      <div class=\"jm-filters\">\r\n\r\n        <label>Zona<\/label>\r\n        <input list=\"jm-zonas\" id=\"jm-zone\" placeholder=\"Escreva a zona...\" autocomplete=\"off\">\r\n\r\n        <datalist id=\"jm-zonas\">\r\n          <option value=\"Aveiro\">\r\n          <option value=\"Beja\">\r\n          <option value=\"Braga\">\r\n          <option value=\"Bragan\u00e7a\">\r\n          <option value=\"Castelo Branco\">\r\n          <option value=\"Coimbra\">\r\n          <option value=\"\u00c9vora\">\r\n          <option value=\"Faro\">\r\n          <option value=\"Guarda\">\r\n          <option value=\"Leiria\">\r\n          <option value=\"Lisboa\">\r\n          <option value=\"Portalegre\">\r\n          <option value=\"Porto\">\r\n          <option value=\"Santar\u00e9m\">\r\n          <option value=\"Set\u00fabal\">\r\n          <option value=\"Viana do Castelo\">\r\n          <option value=\"Vila Real\">\r\n          <option value=\"Viseu\">\r\n          <option value=\"Cascais\">\r\n          <option value=\"Estoril\">\r\n          <option value=\"Parede\">\r\n          <option value=\"Carcavelos\">\r\n          <option value=\"Sintra\">\r\n          <option value=\"Oeiras\">\r\n          <option value=\"Almada\">\r\n          <option value=\"Vila Nova de Gaia\">\r\n          <option value=\"Oliveira do Hospital\">\r\n          <option value=\"A\u00e7ores\">\r\n          <option value=\"Madeira\">\r\n        <\/datalist>\r\n\r\n        <label>Vencimento m\u00ednimo<\/label>\r\n        <select id=\"jm-salary\"><\/select>\r\n\r\n        <label>Fun\u00e7\u00e3o<\/label>\r\n        <select id=\"jm-function\">\r\n          <option value=\"all\">Todas as fun\u00e7\u00f5es<\/option>\r\n          <option value=\"retalho\">Retalho<\/option>\r\n          <option value=\"restauracao\">Restaura\u00e7\u00e3o<\/option>\r\n          <option value=\"hotelaria\">Hotelaria<\/option>\r\n          <option value=\"armazem\">Armaz\u00e9m e log\u00edstica<\/option>\r\n          <option value=\"administrativo\">Administrativo<\/option>\r\n          <option value=\"comercial\">Comercial<\/option>\r\n          <option value=\"tecnologia\">Tecnologia<\/option>\r\n          <option value=\"saude\">Sa\u00fade e bem-estar<\/option>\r\n          <option value=\"servicos\">Servi\u00e7os gerais<\/option>\r\n        <\/select>\r\n\r\n        <button id=\"jm-search\" class=\"jm-filter-btn\">Encontrar oportunidades<\/button>\r\n\r\n        <div id=\"jm-map-status\" class=\"jm-map-status\">\r\n          A carregar oportunidades...\r\n        <\/div>\r\n\r\n      <\/div>\r\n\r\n      <div class=\"jm-stats\">\r\n        <div>\r\n          <strong id=\"jm-stat-offers\">0<\/strong>\r\n          <span>Oportunidades<\/span>\r\n        <\/div>\r\n        <div>\r\n          <strong id=\"jm-stat-companies\">0<\/strong>\r\n          <span>Entidades<\/span>\r\n        <\/div>\r\n        <div>\r\n          <strong id=\"jm-stat-cities\">0<\/strong>\r\n          <span>Zonas<\/span>\r\n        <\/div>\r\n      <\/div>\r\n\r\n    <\/div>\r\n\r\n    <div class=\"jm-right\">\r\n      <div id=\"mapa\" class=\"jm-map\"><\/div>\r\n    <\/div>\r\n\r\n  <\/div>\r\n<\/section>\r\n\r\n<link rel=\"stylesheet\" href=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.css\">\r\n<script src=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.js\"><\/script>\r\n\r\n<script>\r\nsetTimeout(function () {\r\n  if (!document.getElementById(\"mapa\") || typeof L === \"undefined\") return;\r\n\r\n  var salarySelect = document.getElementById(\"jm-salary\");\r\n  var statusBox = document.getElementById(\"jm-map-status\");\r\n\r\n  if (salarySelect && salarySelect.options.length === 0) {\r\n    var firstOption = document.createElement(\"option\");\r\n    firstOption.value = 0;\r\n    firstOption.textContent = \"Qualquer vencimento\";\r\n    salarySelect.appendChild(firstOption);\r\n\r\n    for (var i = 920; i <= 10000; i += 100) {\r\n      var option = document.createElement(\"option\");\r\n      option.value = i;\r\n      option.textContent = \"A partir de \" + i.toLocaleString(\"pt-PT\") + \"\u20ac\";\r\n      salarySelect.appendChild(option);\r\n    }\r\n  }\r\n\r\n  var map = L.map(\"mapa\", {\r\n    zoomControl: true,\r\n    scrollWheelZoom: true\r\n  }).setView([39.5, -8.0], 7);\r\n\r\n  L.tileLayer(\"https:\/\/{s}.tile.openstreetmap.org\/{z}\/{x}\/{y}.png\", {\r\n    attribution: \"\u00a9 OpenStreetMap\"\r\n  }).addTo(map);\r\n\r\n  var companies = [];\r\n  var currentCompanies = [];\r\n  var markers = [];\r\n\r\n  \/*\r\n    Coordenadas para o foco r\u00e1pido do mapa.\r\n    Quando o utilizador escreve ou escolhe uma zona, o mapa aproxima logo.\r\n  *\/\r\n  var jmZoneCoordinates = {\r\n    \"aveiro\": { lat: 40.6405, lng: -8.6538, zoom: 11 },\r\n    \"beja\": { lat: 38.0151, lng: -7.8632, zoom: 11 },\r\n    \"braga\": { lat: 41.5454, lng: -8.4265, zoom: 11 },\r\n    \"braganca\": { lat: 41.8061, lng: -6.7567, zoom: 11 },\r\n    \"bragan\u00e7a\": { lat: 41.8061, lng: -6.7567, zoom: 11 },\r\n    \"castelo branco\": { lat: 39.8230, lng: -7.4931, zoom: 11 },\r\n    \"coimbra\": { lat: 40.2033, lng: -8.4103, zoom: 11 },\r\n    \"evora\": { lat: 38.5714, lng: -7.9135, zoom: 11 },\r\n    \"\u00e9vora\": { lat: 38.5714, lng: -7.9135, zoom: 11 },\r\n    \"faro\": { lat: 37.0194, lng: -7.9304, zoom: 11 },\r\n    \"guarda\": { lat: 40.5373, lng: -7.2658, zoom: 11 },\r\n    \"leiria\": { lat: 39.7436, lng: -8.8071, zoom: 11 },\r\n    \"lisboa\": { lat: 38.7223, lng: -9.1393, zoom: 11 },\r\n    \"portalegre\": { lat: 39.2967, lng: -7.4285, zoom: 11 },\r\n    \"porto\": { lat: 41.1579, lng: -8.6291, zoom: 11 },\r\n    \"santarem\": { lat: 39.2362, lng: -8.6853, zoom: 11 },\r\n    \"santar\u00e9m\": { lat: 39.2362, lng: -8.6853, zoom: 11 },\r\n    \"setubal\": { lat: 38.5244, lng: -8.8882, zoom: 11 },\r\n    \"set\u00fabal\": { lat: 38.5244, lng: -8.8882, zoom: 11 },\r\n    \"viana do castelo\": { lat: 41.6918, lng: -8.8344, zoom: 11 },\r\n    \"vila real\": { lat: 41.3002, lng: -7.7398, zoom: 11 },\r\n    \"viseu\": { lat: 40.6566, lng: -7.9125, zoom: 11 },\r\n\r\n    \"cascais\": { lat: 38.6968, lng: -9.4215, zoom: 13 },\r\n    \"estoril\": { lat: 38.7057, lng: -9.3977, zoom: 14 },\r\n    \"parede\": { lat: 38.6928, lng: -9.3547, zoom: 14 },\r\n    \"carcavelos\": { lat: 38.6911, lng: -9.3226, zoom: 14 },\r\n    \"sintra\": { lat: 38.8029, lng: -9.3817, zoom: 12 },\r\n    \"oeiras\": { lat: 38.6979, lng: -9.3015, zoom: 13 },\r\n    \"almada\": { lat: 38.6765, lng: -9.1651, zoom: 13 },\r\n    \"vila nova de gaia\": { lat: 41.1239, lng: -8.6118, zoom: 13 },\r\n    \"oliveira do hospital\": { lat: 40.3618, lng: -7.8601, zoom: 13 },\r\n\r\n    \"acores\": { lat: 37.7412, lng: -25.6756, zoom: 8 },\r\n    \"a\u00e7ores\": { lat: 37.7412, lng: -25.6756, zoom: 8 },\r\n    \"madeira\": { lat: 32.7607, lng: -16.9595, zoom: 9 }\r\n  };\r\n\r\n  function normalizeText(value) {\r\n    return String(value || \"\")\r\n      .toLowerCase()\r\n      .normalize(\"NFD\")\r\n      .replace(\/[\\u0300-\\u036f]\/g, \"\")\r\n      .trim();\r\n  }\r\n\r\n  function focusMapOnZone(zoneValue) {\r\n    var key = normalizeText(zoneValue);\r\n\r\n    if (!key || !jmZoneCoordinates[key]) {\r\n      return false;\r\n    }\r\n\r\n    var zone = jmZoneCoordinates[key];\r\n\r\n    map.flyTo([zone.lat, zone.lng], zone.zoom, {\r\n      animate: true,\r\n      duration: 0.75\r\n    });\r\n\r\n    return true;\r\n  }\r\n\r\n  function escapeHtml(value) {\r\n    return String(value || \"\")\r\n      .replace(\/&\/g, \"&amp;\")\r\n      .replace(\/<\/g, \"&lt;\")\r\n      .replace(\/>\/g, \"&gt;\")\r\n      .replace(\/\"\/g, \"&quot;\")\r\n      .replace(\/'\/g, \"&#039;\");\r\n  }\r\n\r\n  function normalizeCompany(company) {\r\n    return {\r\n      company: company.company || \"Entidade WIW\",\r\n      companyId: company.companyId || \"\",\r\n      shortName: company.shortName || \"JM\",\r\n      type: company.type || \"\",\r\n      category: company.category || \"servicos\",\r\n      categoryName: company.categoryName || company.category || \"Servi\u00e7os gerais\",\r\n      zone: company.zone || \"Portugal\",\r\n      district: company.district || \"\",\r\n      county: company.county || \"\",\r\n      parish: company.parish || \"\",\r\n      locality: company.locality || \"\",\r\n      lat: parseFloat(company.lat) || 39.5,\r\n      lng: parseFloat(company.lng) || -8.0,\r\n      logoUrl: company.logoUrl || \"\",\r\n      featured: company.featured || false,\r\n      plan: company.plan || \"base\",\r\n      entityTotalOffers: parseInt(company.entityTotalOffers) || 0,\r\n      offers: Array.isArray(company.offers) ? company.offers.map(function(offer) {\r\n        return {\r\n          id: offer.id || \"\",\r\n          companyId: offer.companyId || company.companyId || \"\",\r\n          company: offer.company || company.company || \"Entidade WIW\",\r\n          title: offer.title || \"Oferta de trabalho\",\r\n          category: offer.category || company.category || \"servicos\",\r\n          categoryName: offer.categoryName || company.categoryName || \"Servi\u00e7os gerais\",\r\n          zone: offer.zone || company.zone || \"Portugal\",\r\n          district: offer.district || company.district || \"\",\r\n          county: offer.county || company.county || \"\",\r\n          parish: offer.parish || company.parish || \"\",\r\n          locality: offer.locality || company.locality || \"\",\r\n          salary: parseInt(offer.salary) || 920,\r\n          contractType: offer.contractType || \"\",\r\n          workMode: offer.workMode || \"\",\r\n          schedule: offer.schedule || \"\",\r\n          description: offer.description || \"\",\r\n          requirements: offer.requirements || \"\",\r\n          benefits: offer.benefits || \"\",\r\n          logoUrl: offer.logoUrl || company.logoUrl || \"\",\r\n          featured: offer.featured || false,\r\n          plan: offer.plan || \"base\"\r\n        };\r\n      }) : []\r\n    };\r\n  }\r\n\r\n  function getOfferZoneKey(offer, company) {\r\n    return normalizeText(\r\n      offer.zone ||\r\n      company.zone ||\r\n      \"Portugal\"\r\n    );\r\n  }\r\n\r\n  function mergeCompaniesByEntityAndZone(companyList) {\r\n    var grouped = {};\r\n\r\n    companyList.forEach(function(company) {\r\n      if (!company.offers || company.offers.length === 0) return;\r\n\r\n      company.offers.forEach(function(offer) {\r\n        var empresaKey = String(company.companyId || offer.companyId || company.company || \"entidade\");\r\n        var zonaKey = getOfferZoneKey(offer, company);\r\n        var key = empresaKey + \"|\" + zonaKey;\r\n\r\n        if (!grouped[key]) {\r\n          grouped[key] = {\r\n            company: company.company,\r\n            companyId: company.companyId || offer.companyId || \"\",\r\n            shortName: company.shortName,\r\n            type: company.type,\r\n            category: offer.category || company.category,\r\n            categoryName: offer.categoryName || company.categoryName,\r\n            zone: offer.zone || company.zone || \"Portugal\",\r\n            lat: company.lat,\r\n            lng: company.lng,\r\n            logoUrl: company.logoUrl || offer.logoUrl || \"\",\r\n            featured: company.featured || offer.featured || false,\r\n            plan: company.plan || offer.plan || \"base\",\r\n            offers: []\r\n          };\r\n        }\r\n\r\n        grouped[key].offers.push(offer);\r\n      });\r\n    });\r\n\r\n    return Object.keys(grouped).map(function(key) {\r\n      return grouped[key];\r\n    });\r\n  }\r\n\r\n  function getOfferWord(count) {\r\n    return count === 1 ? \"oferta\" : \"ofertas\";\r\n  }\r\n\r\n  function cloneCompanyWithOffers(company, filteredOffers) {\r\n    return {\r\n      company: company.company,\r\n      companyId: company.companyId,\r\n      shortName: company.shortName,\r\n      type: company.type,\r\n      category: filteredOffers[0] ? filteredOffers[0].category : company.category,\r\n      categoryName: filteredOffers[0] ? filteredOffers[0].categoryName : company.categoryName,\r\n      zone: filteredOffers[0] ? filteredOffers[0].zone : company.zone,\r\n      district: filteredOffers[0] ? filteredOffers[0].district : company.district,\r\n      county: filteredOffers[0] ? filteredOffers[0].county : company.county,\r\n      parish: filteredOffers[0] ? filteredOffers[0].parish : company.parish,\r\n      locality: filteredOffers[0] ? filteredOffers[0].locality : company.locality,\r\n      lat: company.lat,\r\n      lng: company.lng,\r\n      logoUrl: company.logoUrl,\r\n      featured: company.featured,\r\n      plan: company.plan,\r\n      entityTotalOffers: company.entityTotalOffers || filteredOffers.length,\r\n      offers: filteredOffers\r\n    };\r\n  }\r\n\r\n  function getHighestSalary(company) {\r\n    if (!company.offers || company.offers.length === 0) return 0;\r\n\r\n    return Math.max.apply(null, company.offers.map(function(offer) {\r\n      return parseInt(offer.salary) || 0;\r\n    }));\r\n  }\r\n\r\n  function getTotalOffers(companyList) {\r\n    return companyList.reduce(function(total, company) {\r\n      return total + company.offers.length;\r\n    }, 0);\r\n  }\r\n\r\n  function getTotalZones(companyList) {\r\n    var zones = {};\r\n\r\n    companyList.forEach(function(company) {\r\n      if (company.zone) {\r\n        zones[normalizeText(company.zone)] = true;\r\n      }\r\n    });\r\n\r\n    return Object.keys(zones).length;\r\n  }\r\n\r\n\r\n  function applyEntityTotals(companyList) {\r\n    var totals = {};\r\n\r\n    companyList.forEach(function(company) {\r\n      var key = company.companyId || normalizeText(company.company || \"\");\r\n      if (!totals[key]) totals[key] = 0;\r\n      totals[key] += company.offers ? company.offers.length : 0;\r\n    });\r\n\r\n    companyList.forEach(function(company) {\r\n      var key = company.companyId || normalizeText(company.company || \"\");\r\n      company.entityTotalOffers = totals[key] || (company.offers ? company.offers.length : 0);\r\n    });\r\n\r\n    return companyList;\r\n  }\r\n\r\n  function updateStats(companyList) {\r\n    var offersEl = document.getElementById(\"jm-stat-offers\");\r\n    var companiesEl = document.getElementById(\"jm-stat-companies\");\r\n    var citiesEl = document.getElementById(\"jm-stat-cities\");\r\n\r\n    if (offersEl) offersEl.textContent = getTotalOffers(companyList);\r\n    if (companiesEl) {\r\n      var uniqueCompanies = {};\r\n\r\n      companyList.forEach(function(company) {\r\n        uniqueCompanies[String(company.companyId || company.company)] = true;\r\n      });\r\n\r\n      companiesEl.textContent = Object.keys(uniqueCompanies).length;\r\n    }\r\n    if (citiesEl) citiesEl.textContent = getTotalZones(companyList);\r\n  }\r\n\r\n  function getPinSize() {\r\n    var zoom = map.getZoom();\r\n\r\n    \/*\r\n      Pins mais pequenos para o mapa continuar leg\u00edvel\r\n      quando existirem muitas entidades\/ofertas no mesmo ecr\u00e3.\r\n    *\/\r\n    if (zoom <= 8) {\r\n      return {\r\n        iconSize: [58, 66],\r\n        iconAnchor: [29, 64],\r\n        popupAnchor: [0, -54]\r\n      };\r\n    }\r\n\r\n    return {\r\n      iconSize: [48, 58],\r\n      iconAnchor: [24, 56],\r\n      popupAnchor: [0, -48]\r\n    };\r\n  }\r\n\r\n  function getPinHtml(company) {\r\n    var zoom = map.getZoom();\r\n    var highestSalary = getHighestSalary(company).toLocaleString(\"pt-PT\");\r\n\r\n    var logoHtml = \"\";\r\n\r\n    if (company.logoUrl) {\r\n      logoHtml =\r\n        \"<div class='jm-map-pin-logo'>\" +\r\n          \"<img src='\" + escapeHtml(company.logoUrl) + \"' alt='\" + escapeHtml(company.company) + \"'>\" +\r\n        \"<\/div>\";\r\n    }\r\n\r\n    if (zoom <= 8) {\r\n      return (\r\n        \"<div class='jm-map-pin jm-map-pin-salary'>\" +\r\n          \"<div class='jm-map-pin-shape'>\" +\r\n            logoHtml +\r\n            \"<div class='jm-map-pin-content'>\" +\r\n              \"<span class='jm-map-pin-label'>Maior<\/span>\" +\r\n              \"<span class='jm-map-pin-main'>\" + highestSalary + \"\u20ac<\/span>\" +\r\n            \"<\/div>\" +\r\n          \"<\/div>\" +\r\n          \"<div class='jm-map-pin-shadow'><\/div>\" +\r\n        \"<\/div>\"\r\n      );\r\n    }\r\n\r\n    var totalEntityOffers = company.entityTotalOffers || company.offers.length;\r\n\r\n    return (\r\n      \"<div class='jm-map-pin jm-map-pin-count'>\" +\r\n        \"<div class='jm-map-pin-shape'>\" +\r\n          logoHtml +\r\n          \"<div class='jm-map-pin-content'>\" +\r\n            \"<span class='jm-map-pin-main'>\" + totalEntityOffers + \"<\/span>\" +\r\n            \"<span class='jm-map-pin-label'>\" + getOfferWord(totalEntityOffers) + \"<\/span>\" +\r\n          \"<\/div>\" +\r\n        \"<\/div>\" +\r\n        \"<div class='jm-pin-salary-badge'>Maior \" + highestSalary + \"\u20ac<\/div>\" +\r\n        \"<div class='jm-map-pin-shadow'><\/div>\" +\r\n      \"<\/div>\"\r\n    );\r\n  }\r\n\r\n  function getEntityOffersUrl(company) {\r\n    var empresaId = company.companyId || \"\";\r\n\r\n    if (!empresaId && company.offers && company.offers.length > 0) {\r\n      empresaId = company.offers[0].companyId || \"\";\r\n    }\r\n\r\n    if (!empresaId) {\r\n      return \"\/jobmaps-o-mapa-do-trabalho-local\/\";\r\n    }\r\n\r\n    return \"\/jobmaps-ofertas-entidade\/?empresa_id=\" + encodeURIComponent(empresaId);\r\n  }\r\n\r\n  function createPopup(company) {\r\n    var highestSalary = getHighestSalary(company);\r\n\r\n    var logoHtml = company.logoUrl\r\n      ? \"<div class='jm-popup-logo'><img src='\" + escapeHtml(company.logoUrl) + \"' alt='\" + escapeHtml(company.company) + \"'><\/div>\"\r\n      : \"\";\r\n\r\n    var orderedOffers = company.offers.slice().sort(function(a, b) {\r\n      return (parseInt(b.salary) || 0) - (parseInt(a.salary) || 0);\r\n    });\r\n\r\n    var previewOffers = orderedOffers.slice(0, 3);\r\n\r\n    var offersList = previewOffers.map(function(offer) {\r\n      var details = [];\r\n\r\n      if (offer.contractType) details.push(offer.contractType);\r\n      if (offer.workMode) details.push(offer.workMode);\r\n      if (offer.schedule) details.push(offer.schedule);\r\n\r\n      return (\r\n        \"<div class='jm-popup-offer'>\" +\r\n          \"<strong>\" + escapeHtml(offer.title) + \"<\/strong><br>\" +\r\n          \"<span class='jm-popup-salary'>\" + parseInt(offer.salary).toLocaleString(\"pt-PT\") + \"\u20ac<\/span>\" +\r\n          (details.length ? \"<br><small>\" + escapeHtml(details.join(\" \u00b7 \")) + \"<\/small>\" : \"\") +\r\n        \"<\/div>\"\r\n      );\r\n    }).join(\"\");\r\n\r\n    var moreNote = \"\";\r\n\r\n    if (orderedOffers.length > 3) {\r\n      moreNote = \"<div class='jm-popup-more-note'>+ \" + (orderedOffers.length - 3) + \" \" + getOfferWord(orderedOffers.length - 3) + \" desta entidade nesta localiza\u00e7\u00e3o<\/div>\";\r\n    }\r\n\r\n    return (\r\n      logoHtml +\r\n      \"<strong>\" + escapeHtml(company.company) + \"<\/strong><br>\" +\r\n      company.offers.length + \" \" + getOfferWord(company.offers.length) + \" nesta localiza\u00e7\u00e3o<br>\" +\r\n      \"Vencimento mais alto: \" + highestSalary.toLocaleString(\"pt-PT\") + \"\u20ac<br>\" +\r\n      \"Zona: \" + escapeHtml(company.zone) + \"<br><br>\" +\r\n      offersList +\r\n      moreNote +\r\n      \"<br>\" +\r\n      \"<a class='jm-popup-btn' href='\" + escapeHtml(getEntityOffersUrl(company)) + \"'>Ver todas as ofertas desta entidade<\/a>\"\r\n    );\r\n  }\r\n\r\n  function clearMarkers() {\r\n    markers.forEach(function(item) {\r\n      map.removeLayer(item.marker);\r\n    });\r\n\r\n    markers = [];\r\n  }\r\n\r\n  function getCoordKey(company) {\r\n    var lat = parseFloat(company.lat) || 0;\r\n    var lng = parseFloat(company.lng) || 0;\r\n    return lat.toFixed(5) + \"|\" + lng.toFixed(5);\r\n  }\r\n\r\n  function buildOverlapGroups(companyList) {\r\n    var groups = {};\r\n\r\n    companyList.forEach(function(company) {\r\n      var key = getCoordKey(company);\r\n\r\n      if (!groups[key]) {\r\n        groups[key] = [];\r\n      }\r\n\r\n      groups[key].push(company);\r\n    });\r\n\r\n    return groups;\r\n  }\r\n\r\n\r\n  function getLogicalGroupKey(company) {\r\n    var companyId = company.companyId || normalizeText(company.company || \"\");\r\n    var parish = normalizeText(company.parish || \"\");\r\n    var county = normalizeText(company.county || \"\");\r\n    var zone = normalizeText(company.zone || \"\");\r\n\r\n    if (parish && county) {\r\n      return companyId + \"|parish|\" + county + \"|\" + parish;\r\n    }\r\n\r\n    if (parish) {\r\n      return companyId + \"|parish|\" + parish;\r\n    }\r\n\r\n    if (county) {\r\n      return companyId + \"|county|\" + county;\r\n    }\r\n\r\n    return companyId + \"|zone|\" + zone;\r\n  }\r\n\r\n  function mergeCompaniesByParish(companyList) {\r\n    var grouped = {};\r\n\r\n    companyList.forEach(function(company) {\r\n      var key = getLogicalGroupKey(company);\r\n\r\n      if (!grouped[key]) {\r\n        grouped[key] = {\r\n          company: company.company,\r\n          companyId: company.companyId,\r\n          shortName: company.shortName,\r\n          type: company.type,\r\n          category: company.category,\r\n          categoryName: company.categoryName,\r\n          zone: company.zone,\r\n          district: company.district,\r\n          county: company.county,\r\n          parish: company.parish,\r\n          locality: company.locality,\r\n          lat: company.lat,\r\n          lng: company.lng,\r\n          logoUrl: company.logoUrl,\r\n          featured: company.featured,\r\n          plan: company.plan,\r\n          offers: []\r\n        };\r\n      }\r\n\r\n      grouped[key].offers = grouped[key].offers.concat(company.offers || []);\r\n\r\n      if (company.featured) {\r\n        grouped[key].featured = true;\r\n        grouped[key].plan = company.plan || \"destaque\";\r\n      }\r\n    });\r\n\r\n    return Object.keys(grouped).map(function(key) {\r\n      return grouped[key];\r\n    });\r\n  }\r\n\r\n  function getOffsetLatLng(company, index, total) {\r\n    var lat = parseFloat(company.lat) || 39.5;\r\n    var lng = parseFloat(company.lng) || -8.0;\r\n\r\n    if (total <= 1) {\r\n      return L.latLng(lat, lng);\r\n    }\r\n\r\n    var zoom = map.getZoom();\r\n    var radius = 22;\r\n\r\n    if (zoom <= 8) {\r\n      radius = 16;\r\n    } else if (zoom >= 13) {\r\n      radius = 34;\r\n    }\r\n\r\n    var angle = (Math.PI * 2 * index) \/ total;\r\n    var point = map.project([lat, lng], zoom);\r\n\r\n    point.x += Math.cos(angle) * radius;\r\n    point.y += Math.sin(angle) * radius;\r\n\r\n    return map.unproject(point, zoom);\r\n  }\r\n\r\n  function drawMarkers() {\r\n    clearMarkers();\r\n\r\n    var overlapGroups = buildOverlapGroups(currentCompanies);\r\n\r\n    currentCompanies.forEach(function(company) {\r\n      var pinSize = getPinSize();\r\n      var coordKey = getCoordKey(company);\r\n      var group = overlapGroups[coordKey] || [company];\r\n      var index = group.indexOf(company);\r\n      var markerLatLng = getOffsetLatLng(company, index, group.length);\r\n\r\n      var icon = L.divIcon({\r\n        className: \"jm-pin\",\r\n        html: getPinHtml(company),\r\n        iconSize: pinSize.iconSize,\r\n        iconAnchor: pinSize.iconAnchor,\r\n        popupAnchor: pinSize.popupAnchor\r\n      });\r\n\r\n      var marker = L.marker(markerLatLng, { icon: icon, riseOnHover: true })\r\n        .addTo(map)\r\n        .bindPopup(createPopup(company));\r\n\r\n      markers.push({\r\n        marker: marker,\r\n        company: company\r\n      });\r\n    });\r\n  }\r\n\r\n  function refreshMarkerIcons() {\r\n    markers.forEach(function(item) {\r\n      var pinSize = getPinSize();\r\n\r\n      var icon = L.divIcon({\r\n        className: \"jm-pin\",\r\n        html: getPinHtml(item.company),\r\n        iconSize: pinSize.iconSize,\r\n        iconAnchor: pinSize.iconAnchor,\r\n        popupAnchor: pinSize.popupAnchor\r\n      });\r\n\r\n      item.marker.setIcon(icon);\r\n    });\r\n  }\r\n\r\n  function applyFilters() {\r\n    var zoneInput = document.getElementById(\"jm-zone\");\r\n    var salaryInput = document.getElementById(\"jm-salary\");\r\n    var functionInput = document.getElementById(\"jm-function\");\r\n\r\n    var selectedZoneRaw = zoneInput ? zoneInput.value.trim() : \"\";\r\n    var selectedZone = normalizeText(selectedZoneRaw);\r\n    var selectedSalary = salaryInput ? parseInt(salaryInput.value) || 0 : 0;\r\n    var selectedFunction = functionInput ? functionInput.value : \"all\";\r\n\r\n    currentCompanies = [];\r\n\r\n    companies.forEach(function(company) {\r\n      var filteredOffers = company.offers.filter(function(offer) {\r\n        var offerZone = normalizeText(offer.zone || company.zone || \"\");\r\n        var offerCategory = offer.category || company.category;\r\n        var offerSalary = parseInt(offer.salary) || 0;\r\n\r\n        var zoneMatch = !selectedZone || offerZone.includes(selectedZone);\r\n        var functionMatch = selectedFunction === \"all\" || offerCategory === selectedFunction;\r\n        var salaryMatch = selectedSalary === 0 || offerSalary >= selectedSalary;\r\n\r\n        return zoneMatch && functionMatch && salaryMatch;\r\n      });\r\n\r\n      if (filteredOffers.length > 0) {\r\n        currentCompanies.push(cloneCompanyWithOffers(company, filteredOffers));\r\n      }\r\n    });\r\n\r\n    applyEntityTotals(currentCompanies);\r\n    drawMarkers();\r\n    updateStats(currentCompanies);\r\n\r\n    if (statusBox) {\r\n      if (companies.length === 0) {\r\n        statusBox.textContent = \"Ainda n\u00e3o existem oportunidades publicadas.\";\r\n      } else if (currentCompanies.length === 0) {\r\n        statusBox.textContent = \"N\u00e3o encontr\u00e1mos oportunidades com esses filtros.\";\r\n      } else {\r\n        var totalFiltradas = getTotalOffers(currentCompanies);\r\n        statusBox.textContent = \"A mostrar \" + totalFiltradas + \" \" + (totalFiltradas === 1 ? \"oportunidade filtrada.\" : \"oportunidades filtradas.\");\r\n      }\r\n    }\r\n\r\n    \/*\r\n      Regra de enquadramento do mapa:\r\n      1. Se o utilizador escolheu uma zona conhecida, o mapa foca essa zona.\r\n      2. Se n\u00e3o escolheu zona, foca os pins encontrados.\r\n      3. Se n\u00e3o houver resultados, volta a Portugal.\r\n    *\/\r\n    if (selectedZoneRaw && focusMapOnZone(selectedZoneRaw)) {\r\n      \/\/ A zona escolhida manda primeiro no enquadramento do mapa.\r\n    } else if (currentCompanies.length > 0 && markers.length > 0) {\r\n      var markerList = markers.map(function(item) {\r\n        return item.marker;\r\n      });\r\n\r\n      var group = new L.featureGroup(markerList);\r\n\r\n      map.fitBounds(group.getBounds(), {\r\n        padding: [45, 45],\r\n        maxZoom: 10\r\n      });\r\n    } else {\r\n      map.setView([39.5, -8.0], 7);\r\n    }\r\n\r\n    setTimeout(function () {\r\n      refreshMarkerIcons();\r\n    }, 300);\r\n  }\r\n\r\n  async function loadCompaniesFromWordPress() {\r\n    try {\r\n      if (statusBox) {\r\n        statusBox.textContent = \"A carregar oportunidades reais...\";\r\n        statusBox.classList.remove(\"demo\");\r\n        statusBox.classList.remove(\"real\");\r\n      }\r\n\r\n      var response = await fetch(\"https:\/\/3solutions.pt\/wp-json\/jobmaps\/v1\/ofertas?nocache=\" + Date.now());\r\n\r\n      if (!response.ok) {\r\n        throw new Error(\"N\u00e3o foi poss\u00edvel carregar ofertas reais.\");\r\n      }\r\n\r\n      var data = await response.json();\r\n\r\n      if (Array.isArray(data) && data.length > 0) {\r\n        companies = data.map(normalizeCompany).filter(function(company) {\r\n          return company.offers && company.offers.length > 0;\r\n        });\r\n\r\n        applyEntityTotals(companies);\r\n\r\n        companies = mergeCompaniesByEntityAndZone(companies);\r\n\r\n        if (statusBox) {\r\n          statusBox.textContent = \"A mostrar oportunidades publicadas.\";\r\n          statusBox.classList.add(\"real\");\r\n          statusBox.classList.remove(\"demo\");\r\n        }\r\n      } else {\r\n        companies = [];\r\n\r\n        if (statusBox) {\r\n          statusBox.textContent = \"Ainda n\u00e3o existem oportunidades publicadas.\";\r\n          statusBox.classList.add(\"demo\");\r\n          statusBox.classList.remove(\"real\");\r\n        }\r\n      }\r\n\r\n    } catch (error) {\r\n      companies = [];\r\n\r\n      if (statusBox) {\r\n        statusBox.textContent = \"N\u00e3o foi poss\u00edvel carregar oportunidades publicadas.\";\r\n        statusBox.classList.add(\"demo\");\r\n        statusBox.classList.remove(\"real\");\r\n      }\r\n    }\r\n\r\n    currentCompanies = companies;\r\n    applyFilters();\r\n\r\n    setTimeout(function () {\r\n      map.invalidateSize();\r\n      refreshMarkerIcons();\r\n    }, 600);\r\n  }\r\n\r\n  map.on(\"zoomend\", function () {\r\n    if (currentCompanies && currentCompanies.length > 0) {\r\n      drawMarkers();\r\n    }\r\n  });\r\n\r\n  var searchButton = document.getElementById(\"jm-search\");\r\n  if (searchButton) {\r\n    searchButton.addEventListener(\"click\", applyFilters);\r\n  }\r\n\r\n var salaryInput = document.getElementById(\"jm-salary\");\r\nif (salaryInput) {\r\n  salaryInput.addEventListener(\"change\", function() {\r\n    \/*\r\n      N\u00e3o filtramos automaticamente para n\u00e3o fazer desaparecer pins\r\n      enquanto o utilizador ainda est\u00e1 a escolher.\r\n      O filtro final acontece no bot\u00e3o \"Encontrar oportunidades\".\r\n    *\/\r\n  });\r\n}\r\n\r\nvar functionInput = document.getElementById(\"jm-function\");\r\nif (functionInput) {\r\n  functionInput.addEventListener(\"change\", function() {\r\n    \/*\r\n      Mantemos os pins vis\u00edveis at\u00e9 o utilizador carregar no bot\u00e3o.\r\n    *\/\r\n  });\r\n}\r\n\r\nvar zoneInput = document.getElementById(\"jm-zone\");\r\nif (zoneInput) {\r\n  var zoneFocusTimer = null;\r\n\r\n  zoneInput.addEventListener(\"input\", function() {\r\n    clearTimeout(zoneFocusTimer);\r\n\r\n    zoneFocusTimer = setTimeout(function() {\r\n      focusMapOnZone(zoneInput.value);\r\n    }, 350);\r\n  });\r\n\r\n  zoneInput.addEventListener(\"change\", function() {\r\n    focusMapOnZone(zoneInput.value);\r\n  });\r\n\r\n  zoneInput.addEventListener(\"keydown\", function(event) {\r\n    if (event.key === \"Enter\") {\r\n      event.preventDefault();\r\n      applyFilters();\r\n    }\r\n  });\r\n}\r\n\r\n  loadCompaniesFromWordPress();\r\n\r\n}, 800);\r\n<\/script>\r\n\r\n<style>\r\nhtml, body {\r\n  margin: 0;\r\n  padding: 0;\r\n}\r\n\r\n.jm-hero {\r\n  min-height: calc(100vh - 120px);\r\n  padding: 24px;\r\n  padding-top: 20px;\r\n  background: #f5f9ff;\r\n  box-sizing: border-box;\r\n}\r\n\r\n.jm-inner {\r\n  position: relative;\r\n  display: grid;\r\n  grid-template-columns: 34% 66%;\r\n  min-height: calc(100vh - 48px);\r\n  max-width: 1660px;\r\n  margin: 0 auto;\r\n  border-radius: 32px;\r\n  overflow: hidden;\r\n  box-shadow: 0 30px 90px rgba(20, 80, 170, 0.16);\r\n  background: #ffffff;\r\n}\r\n\r\n.jm-bg {\r\n  position: absolute;\r\n  inset: 0;\r\n  background:\r\n    linear-gradient(90deg, rgba(255,255,255,0.98) 0%, rgba(255,255,255,0.92) 34%, rgba(255,255,255,0.55) 70%, rgba(255,255,255,0.25) 100%),\r\n    url(\"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/06\/Imagem-de-fundo.png\");\r\n  background-size: cover;\r\n  background-position: center;\r\n  z-index: 1;\r\n}\r\n\r\n.jm-left,\r\n.jm-right {\r\n  position: relative;\r\n  z-index: 2;\r\n}\r\n\r\n.jm-left {\r\n  padding: 48px 0 46px 58px;\r\n  display: flex;\r\n  flex-direction: column;\r\n  justify-content: center;\r\n}\r\n\r\n.jm-left h1 {\r\n  margin: 0 0 22px;\r\n  font-size: 42px;\r\n  line-height: 1.08;\r\n  color: #15396f;\r\n  font-weight: 900;\r\n  letter-spacing: -0.8px;\r\n}\r\n\r\n.jm-left p {\r\n  max-width: 360px;\r\n  margin: 0 0 26px;\r\n  font-size: 17px;\r\n  line-height: 1.45;\r\n  color: #284a7c;\r\n}\r\n\r\n.jm-filters {\r\n  width: 100%;\r\n  max-width: 360px;\r\n  padding: 20px;\r\n  border-radius: 24px;\r\n  background: rgba(255,255,255,0.9);\r\n  box-shadow: 0 18px 45px rgba(30, 80, 160, 0.12);\r\n  backdrop-filter: blur(12px);\r\n}\r\n\r\n.jm-filters label {\r\n  display: block;\r\n  margin: 0 0 7px;\r\n  font-size: 13px;\r\n  font-weight: 800;\r\n  color: #15396f;\r\n}\r\n\r\n.jm-filters input,\r\n.jm-filters select {\r\n  width: 100%;\r\n  margin: 0 0 14px;\r\n  padding: 13px 14px;\r\n  border-radius: 14px;\r\n  border: 1px solid #c9d9f2;\r\n  background: #ffffff;\r\n  color: #213b66;\r\n  font-size: 15px;\r\n  outline: none;\r\n  box-sizing: border-box;\r\n}\r\n\r\n.jm-filter-btn {\r\n  width: 100%;\r\n  margin-top: 4px;\r\n  padding: 15px 18px;\r\n  border: 0;\r\n  border-radius: 999px;\r\n  background: linear-gradient(135deg, #2049ff, #20a9ff);\r\n  color: #ffffff;\r\n  font-size: 16px;\r\n  font-weight: 900;\r\n  cursor: pointer;\r\n  box-shadow: 0 14px 30px rgba(24, 95, 255, 0.24);\r\n}\r\n\r\n.jm-filter-btn:hover {\r\n  transform: translateY(-1px);\r\n}\r\n\r\n.jm-map-status {\r\n  margin-top: 14px;\r\n  padding: 11px 13px;\r\n  border-radius: 14px;\r\n  background: rgba(21, 86, 255, 0.08);\r\n  color: #15396f;\r\n  font-size: 12.8px;\r\n  line-height: 1.35;\r\n  font-weight: 750;\r\n}\r\n\r\n.jm-map-status.real {\r\n  background: rgba(35, 150, 85, 0.1);\r\n  color: #167044;\r\n}\r\n\r\n.jm-map-status.demo {\r\n  background: rgba(255, 170, 0, 0.13);\r\n  color: #835700;\r\n}\r\n\r\n.jm-stats {\r\n  display: flex;\r\n  gap: 18px;\r\n  margin-top: 28px;\r\n  padding: 18px 20px;\r\n  border-radius: 22px;\r\n  background: rgba(255,255,255,0.88);\r\n  backdrop-filter: blur(12px);\r\n  box-shadow: 0 20px 50px rgba(30, 80, 160, 0.10);\r\n  width: fit-content;\r\n}\r\n\r\n.jm-stats div {\r\n  min-width: 88px;\r\n}\r\n\r\n.jm-stats strong {\r\n  display: block;\r\n  font-size: 25px;\r\n  line-height: 1;\r\n  color: #1556ff;\r\n  font-weight: 900;\r\n}\r\n\r\n.jm-stats span {\r\n  display: block;\r\n  margin-top: 7px;\r\n  font-size: 13px;\r\n  color: #506783;\r\n}\r\n\r\n.jm-right {\r\n  padding: 44px 58px 44px 32px;\r\n  display: flex;\r\n  flex-direction: column;\r\n}\r\n\r\n.jm-map {\r\n  flex: 1;\r\n  min-height: 720px;\r\n  border-radius: 28px;\r\n  overflow: hidden;\r\n  box-shadow: 0 24px 70px rgba(20, 80, 170, 0.20);\r\n  border: 1px solid rgba(255,255,255,0.75);\r\n}\r\n\r\n.jm-pin {\r\n  background: transparent !important;\r\n  border: 0 !important;\r\n}\r\n\r\n.jm-map-pin {\r\n  position: relative;\r\n  width: 100%;\r\n  height: 100%;\r\n  transform-origin: center bottom;\r\n  transition: transform 0.18s ease;\r\n  cursor: pointer;\r\n}\r\n\r\n.jm-map-pin:hover {\r\n  transform: translateY(-4px) scale(1.04);\r\n}\r\n\r\n.jm-map-pin-shape {\r\n  position: absolute;\r\n  left: 50%;\r\n  top: 0;\r\n  background:\r\n    radial-gradient(circle at 35% 28%, rgba(255,255,255,0.95) 0%, rgba(255,255,255,0.72) 18%, rgba(255,255,255,0) 34%),\r\n    linear-gradient(145deg, #ffffff 0%, #eef7ff 45%, #dcecff 100%);\r\n  border: 2px solid #155eef;\r\n  border-radius: 50% 50% 50% 0;\r\n  transform: translateX(-50%) rotate(-45deg);\r\n  box-shadow:\r\n    0 6px 12px rgba(21, 94, 239, 0.22),\r\n    0 2px 5px rgba(0, 0, 0, 0.14);\r\n  overflow: hidden;\r\n}\r\n\r\n.jm-map-pin-shape::before {\r\n  content: \"\";\r\n  position: absolute;\r\n  inset: 4px;\r\n  border-radius: 50% 50% 50% 0;\r\n  border: 1px solid rgba(21, 94, 239, 0.18);\r\n  z-index: 3;\r\n  pointer-events: none;\r\n}\r\n\r\n.jm-map-pin-shape::after {\r\n  content: \"\";\r\n  position: absolute;\r\n  inset: 7px;\r\n  border-radius: 50%;\r\n  background: rgba(255,255,255,0.72);\r\n  box-shadow: inset 0 0 0 1px rgba(21, 94, 239, 0.10);\r\n  z-index: 1;\r\n  pointer-events: none;\r\n}\r\n\r\n.jm-map-pin-count .jm-map-pin-shape {\r\n  width: 40px;\r\n  height: 40px;\r\n}\r\n\r\n.jm-map-pin-salary .jm-map-pin-shape {\r\n  width: 52px;\r\n  height: 52px;\r\n}\r\n\r\n.jm-map-pin-logo {\r\n  position: absolute;\r\n  inset: 8px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  opacity: 0.24;\r\n  z-index: 2;\r\n  transform: rotate(45deg);\r\n  pointer-events: none;\r\n}\r\n\r\n.jm-map-pin-logo img {\r\n  max-width: 100%;\r\n  max-height: 100%;\r\n  object-fit: contain;\r\n  display: block;\r\n}\r\n\r\n.jm-map-pin-content {\r\n  position: absolute;\r\n  left: 50%;\r\n  top: 50%;\r\n  z-index: 4;\r\n  transform: translate(-50%, -50%) rotate(45deg);\r\n  min-width: 26px;\r\n  padding: 2px 3px;\r\n  text-align: center;\r\n  line-height: 1;\r\n  font-family: Arial, sans-serif;\r\n}\r\n\r\n.jm-map-pin-main {\r\n  display: block;\r\n  font-size: 14px;\r\n  font-weight: 950;\r\n  letter-spacing: -0.35px;\r\n  color: #123c7c;\r\n  text-shadow: 0 1px 0 rgba(255,255,255,0.85);\r\n}\r\n\r\n.jm-map-pin-label {\r\n  display: block;\r\n  margin-top: 3px;\r\n  font-size: 5.5px;\r\n  font-weight: 950;\r\n  letter-spacing: 0.35px;\r\n  text-transform: none;\r\n  color: #123c7c;\r\n  text-shadow: 0 1px 0 rgba(255,255,255,0.85);\r\n}\r\n\r\n.jm-map-pin-salary .jm-map-pin-content {\r\n  min-width: 40px;\r\n}\r\n\r\n.jm-map-pin-salary .jm-map-pin-main {\r\n  font-size: 10.5px;\r\n  letter-spacing: -0.3px;\r\n}\r\n\r\n.jm-map-pin-salary .jm-map-pin-label {\r\n  margin-top: 0;\r\n  margin-bottom: 3px;\r\n  font-size: 5.5px;\r\n}\r\n\r\n\r\n.jm-pin-salary-badge {\r\n  position: absolute;\r\n  left: 50%;\r\n  top: 43px;\r\n  transform: translateX(-50%);\r\n  z-index: 8;\r\n  white-space: nowrap;\r\n  padding: 4px 7px;\r\n  border-radius: 999px;\r\n  background: #ffffff;\r\n  border: 1px solid rgba(21, 94, 239, 0.25);\r\n  box-shadow: 0 5px 12px rgba(20, 80, 170, 0.16);\r\n  color: #123c7c;\r\n  font-size: 9px;\r\n  line-height: 1;\r\n  font-weight: 950;\r\n  letter-spacing: -0.1px;\r\n  pointer-events: none;\r\n}\r\n\r\n.jm-map-pin-shadow {\r\n  position: absolute;\r\n  left: 50%;\r\n  bottom: 1px;\r\n  width: 18px;\r\n  height: 5px;\r\n  transform: translateX(-50%);\r\n  border-radius: 50%;\r\n  background: rgba(0, 38, 110, 0.20);\r\n  filter: blur(2px);\r\n}\r\n\r\n.jm-map-pin-salary .jm-map-pin-shadow {\r\n  width: 22px;\r\n  bottom: 1px;\r\n}\r\n\r\n.jm-popup-logo {\r\n  width: 70px;\r\n  height: 46px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  margin-bottom: 8px;\r\n  padding: 5px;\r\n  border-radius: 10px;\r\n  background: #ffffff;\r\n  border: 1px solid rgba(0,0,0,0.08);\r\n}\r\n\r\n.jm-popup-logo img {\r\n  max-width: 100%;\r\n  max-height: 100%;\r\n  object-fit: contain;\r\n  display: block;\r\n}\r\n\r\n.jm-popup-offer {\r\n  margin-bottom: 9px;\r\n  padding-bottom: 8px;\r\n  border-bottom: 1px solid rgba(0,0,0,0.08);\r\n}\r\n\r\n.jm-popup-offer small {\r\n  color: #5c6b7a;\r\n}\r\n\r\n.jm-popup-salary {\r\n  color: #1556ff;\r\n  font-weight: 900;\r\n}\r\n\r\n.jm-popup-more-note {\r\n  margin: 6px 0 2px;\r\n  color: #15396f;\r\n  font-size: 12.5px;\r\n  font-weight: 850;\r\n}\r\n\r\n.jm-popup-btn {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  padding: 10px 14px;\r\n  border: 0;\r\n  border-radius: 10px;\r\n  background: #1556ff;\r\n  color: #fff !important;\r\n  font-weight: 850;\r\n  text-decoration: none !important;\r\n  cursor: pointer;\r\n}\r\n\r\n.jm-popup-btn:hover {\r\n  background: #0d43d8;\r\n  color: #fff !important;\r\n}\r\n\r\n.leaflet-popup-content {\r\n  font-size: 14px;\r\n  line-height: 1.4;\r\n}\r\n\r\n@media (max-width: 1000px) {\r\n  .jm-hero {\r\n    padding: 12px;\r\n  }\r\n\r\n  .jm-inner {\r\n    display: flex;\r\n    flex-direction: column;\r\n    grid-template-columns: 1fr;\r\n    min-height: auto;\r\n    border-radius: 24px;\r\n  }\r\n\r\n  \/*\r\n    Em mobile, o mapa sobe para aparecer logo depois do header\/site.\r\n    A zona de texto, filtros e estat\u00edsticas fica por baixo.\r\n  *\/\r\n  .jm-right {\r\n    order: 1;\r\n    padding: 18px 18px 10px;\r\n  }\r\n\r\n  .jm-left {\r\n    order: 2;\r\n    padding: 22px 24px 28px;\r\n    align-items: center;\r\n    text-align: center;\r\n  }\r\n\r\n  .jm-left h1 {\r\n    font-size: 36px;\r\n  }\r\n\r\n  .jm-left p {\r\n    font-size: 17px;\r\n    max-width: 340px;\r\n  }\r\n\r\n  .jm-filters {\r\n    max-width: 100%;\r\n  }\r\n\r\n  .jm-stats {\r\n    width: 100%;\r\n    justify-content: space-between;\r\n    box-sizing: border-box;\r\n  }\r\n\r\n  .jm-stats div {\r\n    min-width: 0;\r\n    flex: 1;\r\n  }\r\n\r\n  .jm-map {\r\n    min-height: 500px;\r\n    border-radius: 22px;\r\n  }\r\n}\r\n\r\n@media (max-width: 520px) {\r\n\r\n  .jm-pin-salary-badge {\r\n    top: 39px;\r\n    font-size: 8px;\r\n    padding: 3px 6px;\r\n  }\r\n\r\n  .jm-hero {\r\n    padding: 8px;\r\n  }\r\n\r\n  .jm-right {\r\n    padding: 12px 12px 8px;\r\n  }\r\n\r\n  .jm-left {\r\n    padding: 20px 18px 24px;\r\n  }\r\n\r\n  .jm-left h1 {\r\n    font-size: 30px;\r\n  }\r\n\r\n  .jm-left p {\r\n    font-size: 12.5px;\r\n  }\r\n\r\n  .jm-stats {\r\n    flex-direction: column;\r\n    text-align: center;\r\n  }\r\n\r\n  .jm-map {\r\n    min-height: 430px;\r\n  }\r\n\r\n  .jm-map-pin-count .jm-map-pin-shape {\r\n    width: 36px;\r\n    height: 36px;\r\n  }\r\n\r\n  .jm-map-pin-salary .jm-map-pin-shape {\r\n    width: 46px;\r\n    height: 46px;\r\n  }\r\n\r\n  .jm-map-pin-main {\r\n    font-size: 12.5px;\r\n  }\r\n\r\n  .jm-map-pin-salary .jm-map-pin-main {\r\n    font-size: 9.5px;\r\n  }\r\n\r\n  .jm-map-pin-label {\r\n    font-size: 5px;\r\n  }\r\n}\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>O mapa de ofertas salariais na sua zona Quero contratar Quero trabalhar Sou recrutador \ud83d\udc64 \u00c1rea Sair Encontre oportunidades.Construa o seu futuro. O JobMaps aproxima pessoas e oportunidades locais, porque o trabalho deve valer a pena. Zona Vencimento m\u00ednimo Fun\u00e7\u00e3o Todas as fun\u00e7\u00f5esRetalhoRestaura\u00e7\u00e3oHotelariaArmaz\u00e9m e log\u00edsticaAdministrativoComercialTecnologiaSa\u00fade e bem-estarServi\u00e7os gerais Encontrar oportunidades A carregar oportunidades&#8230; 0 Oportunidades [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"page-builder","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-6382","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Jobmaps \u2014 O mapa do trabalho local - 3Solutions Consultoria em Marketing e Gest\u00e3o<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/3solutions.pt\/en\/jobmaps-o-mapa-do-trabalho-local\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Jobmaps \u2014 O mapa do trabalho local - 3Solutions Consultoria em Marketing e Gest\u00e3o\" \/>\n<meta property=\"og:description\" content=\"O mapa de ofertas salariais na sua zona Quero contratar Quero trabalhar Sou recrutador \ud83d\udc64 \u00c1rea Sair Encontre oportunidades.Construa o seu futuro. O JobMaps aproxima pessoas e oportunidades locais, porque o trabalho deve valer a pena. Zona Vencimento m\u00ednimo Fun\u00e7\u00e3o Todas as fun\u00e7\u00f5esRetalhoRestaura\u00e7\u00e3oHotelariaArmaz\u00e9m e log\u00edsticaAdministrativoComercialTecnologiaSa\u00fade e bem-estarServi\u00e7os gerais Encontrar oportunidades A carregar oportunidades&#8230; 0 Oportunidades [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/3solutions.pt\/en\/jobmaps-o-mapa-do-trabalho-local\/\" \/>\n<meta property=\"og:site_name\" content=\"3Solutions Consultoria em Marketing e Gest\u00e3o\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/share\/17VAXrDnwy\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-17T17:11:14+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/06\/WIW.png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/3solutions.pt\\\/jobmaps-o-mapa-do-trabalho-local\\\/\",\"url\":\"https:\\\/\\\/3solutions.pt\\\/jobmaps-o-mapa-do-trabalho-local\\\/\",\"name\":\"Jobmaps \u2014 O mapa do trabalho local - 3Solutions Consultoria em Marketing e Gest\u00e3o\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/3solutions.pt\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/3solutions.pt\\\/jobmaps-o-mapa-do-trabalho-local\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/3solutions.pt\\\/jobmaps-o-mapa-do-trabalho-local\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/3solutions.pt\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/WIW.png\",\"datePublished\":\"2026-06-12T17:03:18+00:00\",\"dateModified\":\"2026-06-17T17:11:14+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/3solutions.pt\\\/jobmaps-o-mapa-do-trabalho-local\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/3solutions.pt\\\/jobmaps-o-mapa-do-trabalho-local\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/3solutions.pt\\\/jobmaps-o-mapa-do-trabalho-local\\\/#primaryimage\",\"url\":\"https:\\\/\\\/3solutions.pt\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/WIW.png\",\"contentUrl\":\"https:\\\/\\\/3solutions.pt\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/WIW.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/3solutions.pt\\\/jobmaps-o-mapa-do-trabalho-local\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"In\u00edcio\",\"item\":\"https:\\\/\\\/3solutions.pt\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Jobmaps \u2014 O mapa do trabalho local\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/3solutions.pt\\\/#website\",\"url\":\"https:\\\/\\\/3solutions.pt\\\/\",\"name\":\"3Solutions Consultoria em Marketing e Gest\u00e3o\",\"description\":\"Consultoria e Marketing Digital\",\"publisher\":{\"@id\":\"https:\\\/\\\/3solutions.pt\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/3solutions.pt\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/3solutions.pt\\\/#organization\",\"name\":\"3Solutions Consultoria em Marketing e Gest\u00e3o\",\"url\":\"https:\\\/\\\/3solutions.pt\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/3solutions.pt\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/3solutions.pt\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/cropped-Prancheta-1-copia-scaled-1.png\",\"contentUrl\":\"https:\\\/\\\/3solutions.pt\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/cropped-Prancheta-1-copia-scaled-1.png\",\"width\":1505,\"height\":785,\"caption\":\"3Solutions Consultoria em Marketing e Gest\u00e3o\"},\"image\":{\"@id\":\"https:\\\/\\\/3solutions.pt\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/share\\\/17VAXrDnwy\\\/\",\"https:\\\/\\\/www.instagram.com\\\/wespeakretail?igsh=d2Y0a2RzY29nN2Fv\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Jobmaps \u2014 O mapa do trabalho local - 3Solutions Consultoria em Marketing e Gest\u00e3o","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:\/\/3solutions.pt\/en\/jobmaps-o-mapa-do-trabalho-local\/","og_locale":"en_GB","og_type":"article","og_title":"Jobmaps \u2014 O mapa do trabalho local - 3Solutions Consultoria em Marketing e Gest\u00e3o","og_description":"O mapa de ofertas salariais na sua zona Quero contratar Quero trabalhar Sou recrutador \ud83d\udc64 \u00c1rea Sair Encontre oportunidades.Construa o seu futuro. O JobMaps aproxima pessoas e oportunidades locais, porque o trabalho deve valer a pena. Zona Vencimento m\u00ednimo Fun\u00e7\u00e3o Todas as fun\u00e7\u00f5esRetalhoRestaura\u00e7\u00e3oHotelariaArmaz\u00e9m e log\u00edsticaAdministrativoComercialTecnologiaSa\u00fade e bem-estarServi\u00e7os gerais Encontrar oportunidades A carregar oportunidades&#8230; 0 Oportunidades [&hellip;]","og_url":"https:\/\/3solutions.pt\/en\/jobmaps-o-mapa-do-trabalho-local\/","og_site_name":"3Solutions Consultoria em Marketing e Gest\u00e3o","article_publisher":"https:\/\/www.facebook.com\/share\/17VAXrDnwy\/","article_modified_time":"2026-06-17T17:11:14+00:00","og_image":[{"url":"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/06\/WIW.png","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_misc":{"Estimated reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/3solutions.pt\/jobmaps-o-mapa-do-trabalho-local\/","url":"https:\/\/3solutions.pt\/jobmaps-o-mapa-do-trabalho-local\/","name":"Jobmaps \u2014 O mapa do trabalho local - 3Solutions Consultoria em Marketing e Gest\u00e3o","isPartOf":{"@id":"https:\/\/3solutions.pt\/#website"},"primaryImageOfPage":{"@id":"https:\/\/3solutions.pt\/jobmaps-o-mapa-do-trabalho-local\/#primaryimage"},"image":{"@id":"https:\/\/3solutions.pt\/jobmaps-o-mapa-do-trabalho-local\/#primaryimage"},"thumbnailUrl":"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/06\/WIW.png","datePublished":"2026-06-12T17:03:18+00:00","dateModified":"2026-06-17T17:11:14+00:00","breadcrumb":{"@id":"https:\/\/3solutions.pt\/jobmaps-o-mapa-do-trabalho-local\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/3solutions.pt\/jobmaps-o-mapa-do-trabalho-local\/"]}]},{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/3solutions.pt\/jobmaps-o-mapa-do-trabalho-local\/#primaryimage","url":"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/06\/WIW.png","contentUrl":"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/06\/WIW.png"},{"@type":"BreadcrumbList","@id":"https:\/\/3solutions.pt\/jobmaps-o-mapa-do-trabalho-local\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"In\u00edcio","item":"https:\/\/3solutions.pt\/"},{"@type":"ListItem","position":2,"name":"Jobmaps \u2014 O mapa do trabalho local"}]},{"@type":"WebSite","@id":"https:\/\/3solutions.pt\/#website","url":"https:\/\/3solutions.pt\/","name":"3Solutions Consultoria em Marketing e Gest\u00e3o","description":"Consultoria e Marketing Digital","publisher":{"@id":"https:\/\/3solutions.pt\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/3solutions.pt\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":"Organization","@id":"https:\/\/3solutions.pt\/#organization","name":"3Solutions Consultoria em Marketing e Gest\u00e3o","url":"https:\/\/3solutions.pt\/","logo":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/3solutions.pt\/#\/schema\/logo\/image\/","url":"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/05\/cropped-Prancheta-1-copia-scaled-1.png","contentUrl":"https:\/\/3solutions.pt\/wp-content\/uploads\/2026\/05\/cropped-Prancheta-1-copia-scaled-1.png","width":1505,"height":785,"caption":"3Solutions Consultoria em Marketing e Gest\u00e3o"},"image":{"@id":"https:\/\/3solutions.pt\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/share\/17VAXrDnwy\/","https:\/\/www.instagram.com\/wespeakretail?igsh=d2Y0a2RzY29nN2Fv"]}]}},"_links":{"self":[{"href":"https:\/\/3solutions.pt\/en\/wp-json\/wp\/v2\/pages\/6382","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/3solutions.pt\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/3solutions.pt\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/3solutions.pt\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/3solutions.pt\/en\/wp-json\/wp\/v2\/comments?post=6382"}],"version-history":[{"count":175,"href":"https:\/\/3solutions.pt\/en\/wp-json\/wp\/v2\/pages\/6382\/revisions"}],"predecessor-version":[{"id":7158,"href":"https:\/\/3solutions.pt\/en\/wp-json\/wp\/v2\/pages\/6382\/revisions\/7158"}],"wp:attachment":[{"href":"https:\/\/3solutions.pt\/en\/wp-json\/wp\/v2\/media?parent=6382"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}