{"id":651,"date":"2023-05-11T11:56:09","date_gmt":"2023-05-11T11:56:09","guid":{"rendered":"https:\/\/puttgardenrodby.nl\/?page_id=651"},"modified":"2026-06-24T12:46:01","modified_gmt":"2026-06-24T12:46:01","slug":"tidtabell","status":"publish","type":"page","link":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/","title":{"rendered":"Tidtabell"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"651\" class=\"elementor elementor-651\" data-elementor-post-type=\"page\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-348d881 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"348d881\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-2e117c7\" data-id=\"2e117c7\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-18585c6 elementor-widget elementor-widget-heading\" data-id=\"18585c6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\">Puttgarden R\u00f8dby tidtabell<\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bf504aa elementor-widget elementor-widget-text-editor\" data-id=\"bf504aa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>H\u00e4r hittar du tidtabell och avg\u00e5ngar f\u00f6r f\u00e4rjan Puttgarden\u2013R\u00f8dby och R\u00f8dby\u2013Puttgarden. V\u00e4lj datum och klicka p\u00e5 Visa avg\u00e5ngar f\u00f6r att se f\u00e4rjetiderna f\u00f6r vald dag.<\/p>\n\n<div class=\"route-facts\">\n  <div><span>Rutt<\/span> Puttgarden \u21c4 R\u00f8dby<\/div>\n  <div><span>Operat\u00f6r<\/span> Scandlines<\/div>\n  <div><span>\u00d6verfart<\/span> cirka 45 minuter<\/div>\n  <div><span>Avg\u00e5ngar<\/span> ungef\u00e4r var 30:e minut<\/div>\n<\/div>\n\n<h2>F\u00e4rjetidtabell Puttgarden R\u00f8dby<\/h2>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-65286c5 elementor-widget elementor-widget-shortcode\" data-id=\"65286c5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><div class=\"tp-wrap tp-theme-extended_cards tp-day-setup-classic\" data-config=\"{&quot;rest&quot;:&quot;https:\\\/\\\/puttgardenrodby.com\\\/se\\\/wp-json\\\/timetables-pro\\\/v1\\\/timetables&quot;,&quot;routes&quot;:[209],&quot;days&quot;:1,&quot;autoload&quot;:true,&quot;theme&quot;:&quot;extended_cards&quot;,&quot;daySetup&quot;:&quot;classic&quot;,&quot;limit10&quot;:false,&quot;routeLabels&quot;:{&quot;209&quot;:&quot;Puttgarden-Rodby&quot;},&quot;opFilter&quot;:[&quot;32&quot;],&quot;labels&quot;:{&quot;ui_date&quot;:&quot;Datum&quot;,&quot;ui_days&quot;:&quot;Dagar&quot;,&quot;ui_button&quot;:&quot;Visa avg\\u00e5ngar&quot;,&quot;status_idle&quot;:&quot;V\\u00e4lj ett datum och klicka p\\u00e5 Visa avg\\u00e5ngar&quot;,&quot;status_loading&quot;:&quot;Laddar...&quot;,&quot;status_empty&quot;:&quot;Inga avg\\u00e5ngar hittades&quot;,&quot;status_found&quot;:&quot;%d avg\\u00e5ngar hittades&quot;,&quot;th_date&quot;:&quot;Datum&quot;,&quot;th_dep&quot;:&quot;Avg\\u00e5ng&quot;,&quot;th_arr&quot;:&quot;Ankomst&quot;,&quot;th_dur&quot;:&quot;Restid&quot;,&quot;th_ship&quot;:&quot;Fartyg&quot;,&quot;th_op&quot;:&quot;Operat\\u00f6r&quot;,&quot;th_route&quot;:&quot;Rutt&quot;,&quot;wd_sun&quot;:&quot;S\\u00d6N&quot;,&quot;wd_mon&quot;:&quot;M\\u00c5N&quot;,&quot;wd_tue&quot;:&quot;TIS&quot;,&quot;wd_wed&quot;:&quot;ONS&quot;,&quot;wd_thu&quot;:&quot;TOR&quot;,&quot;wd_fri&quot;:&quot;FRE&quot;,&quot;wd_sat&quot;:&quot;L\\u00d6R&quot;,&quot;summary_footer_one&quot;:&quot;\\u00bb Se alla %s avg\\u00e5ngar i v\\u00e5r tidtabell&quot;,&quot;summary_footer_two&quot;:&quot;\\u00bb Se fler avg\\u00e5ngar f\\u00f6r %1$s och %2$s i v\\u00e5r tidtabell&quot;,&quot;summary_footer_generic&quot;:&quot;Se v\\u00e5r tidtabell f\\u00f6r fler avg\\u00e5ngar&quot;,&quot;summary_header&quot;:&quot;De tv\\u00e5 n\\u00e4sta avg\\u00e5ngarna:&quot;,&quot;summary_no_upcoming&quot;:&quot;Inga kommande avg\\u00e5ngar hittades&quot;,&quot;more_link&quot;:&quot;Fler avg\\u00e5ngar&quot;,&quot;more_departures_button&quot;:&quot;Visa fler avg\\u00e5ngar&quot;,&quot;day_nav_previous&quot;:&quot;Visa f\\u00f6reg\\u00e5ende dag&quot;,&quot;day_nav_next&quot;:&quot;Visa n\\u00e4sta dag&quot;,&quot;day_nav_today&quot;:&quot;Visa idag&quot;,&quot;day_nav_tomorrow&quot;:&quot;Visa imorgon&quot;,&quot;local_time_pair&quot;:&quot;Lokal tid avg\\u00e5ngshamn: %1$s \\\/ Lokal tid ankomsthamn: %2$s&quot;,&quot;local_time_combined&quot;:&quot;Lokal tid avg\\u00e5ngs- och ankomsthamn: %s&quot;,&quot;tag_often_booked&quot;:&quot;\\u2b50 Ofta bokad&quot;,&quot;tag_leaving_soon&quot;:&quot;\\ud83d\\udd34 Avg\\u00e5r snart&quot;,&quot;tag_currently_sailing&quot;:&quot;\\ud83d\\udfe2 P\\u00e5 v\\u00e4g nu&quot;,&quot;tag_arrived&quot;:&quot;\\u26ab Anl\\u00e4nt&quot;,&quot;tag_overnight&quot;:&quot;\\u00d6vernattning&quot;},&quot;showLogo&quot;:true,&quot;activityBoosters&quot;:true,&quot;title&quot;:&quot;&quot;,&quot;shipMap&quot;:[],&quot;shipLinks&quot;:[],&quot;showShip&quot;:false,&quot;departurePort&quot;:&quot;Puttgarden&quot;,&quot;arrivalPort&quot;:&quot;Rodby&quot;,&quot;departureTimezone&quot;:&quot;Europe\\\/Berlin&quot;,&quot;arrivalTimezone&quot;:&quot;Europe\\\/Copenhagen&quot;}\">\n  <div class=\"tp-controls\" role=\"group\" aria-label=\"Timetable controls\">\n    <div>\n      <label for=\"tp-date-ops\">Datum<\/label><br>\n      <input id=\"tp-date-ops\" class=\"tp-date\" type=\"date\" aria-label=\"Datum\">\n    <\/div>\n    <div class=\"tp-day-field\">\n      <label for=\"tp-range-ops\">Dagar<\/label><br>\n      <select id=\"tp-range-ops\" class=\"tp-range\" aria-label=\"Dagar\">\n        <option value=\"1\">1<\/option><option value=\"3\">3<\/option><option value=\"7\">7<\/option><option value=\"14\">14<\/option>\n      <\/select>\n    <\/div>\n    <div><button id=\"tp-load-ops\" class=\"tp-btn\">Visa avg\u00e5ngar<\/button><\/div>\n  <\/div>\n\n  <div class=\"tp-local-nav-row\">\n    <div class=\"tp-local-times\" id=\"tp-local-times-ops\" aria-live=\"polite\"><\/div>\n    <div class=\"tp-day-nav-host\"><\/div>\n  <\/div>\n\n  \n  <div id=\"tp-status-ops\" class=\"tp-muted\" aria-live=\"polite\">V\u00e4lj ett datum och klicka p\u00e5 Visa avg\u00e5ngar<\/div>\n\n  <div id=\"tp-ops-results\"><\/div>\n\n  <div class=\"tp-loader\" aria-hidden=\"true\">\n    <div class=\"tp-loader-card\">\n      <div class=\"tp-spinner\" aria-hidden=\"true\"><\/div>\n      <div class=\"tp-loader-text\">Laddar...<\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  const wrap   = document.currentScript.previousElementSibling;\n  const cfg    = JSON.parse(wrap.getAttribute('data-config')||'{}');\n  const L      = cfg.labels||{};\n  const dateEl = wrap.querySelector('#tp-date-ops');\n  const daysEl = wrap.querySelector('#tp-range-ops');\n  const btn    = wrap.querySelector('#tp-load-ops');\n  const status = wrap.querySelector('#tp-status-ops');\n  const out    = wrap.querySelector('#tp-ops-results');\n  const loader = wrap.querySelector('.tp-loader');\n  const navHost = wrap.querySelector('.tp-day-nav-host');\n  const localTimesEl = wrap.querySelector('#tp-local-times-ops');\n\n  const showShip = (cfg.showShip !== false && cfg.showShip !== 0 && cfg.showShip !== '0');\n  const activityBoosters = !!cfg.activityBoosters;\n  const daySetup = (cfg.daySetup === 'modern') ? 'modern' : 'classic';\n  const limit10 = !!cfg.limit10;\n  let featuredKey = '';\n  let soonKey = '';\n  let revealAll = false;\n\n  if (daySetup === 'modern') {\n    const dayField = wrap.querySelector('.tp-day-field');\n    if (dayField) dayField.style.display = 'none';\n  }\n\n  dateEl.valueAsDate = new Date();\n  dateEl.min = new Date().toISOString().split('T')[0];\n  Array.from(daysEl.options).forEach(o=>{ if(parseInt(o.value,10)===parseInt(cfg.days||7,10)) o.selected=true; });\n\n  function pad(n){ return String(n).padStart(2,'0'); }\n  function iso(d){ return d.getFullYear()+'-'+pad(d.getMonth()+1)+'-'+pad(d.getDate()); }\n  function toLocal(s){ return new Date(s); }\n  function hhmm(d){ return d.toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}); }\n  function dShort(d){ return d.toLocaleDateString([], {day:'numeric', month:'short'}); }\n  function dur(m){ const h=Math.floor(m\/60), r=m%60; return r? (h+'h '+r+'m') : (h+'h'); }\n\n  const WD = [\n    L.wd_sun || 'SUN',\n    L.wd_mon || 'MON',\n    L.wd_tue || 'TUE',\n    L.wd_wed || 'WED',\n    L.wd_thu || 'THU',\n    L.wd_fri || 'FRI',\n    L.wd_sat || 'SAT'\n  ];\n\n  function setLoader(v){ loader.classList.toggle('show', !!v); loader.setAttribute('aria-hidden', v?'false':'true'); }\n\n  function formatZoneTime(tz){\n    if (!tz) return '--:--';\n    try {\n      return new Intl.DateTimeFormat([], {hour:'2-digit', minute:'2-digit', hour12:false, timeZone: tz}).format(new Date());\n    } catch (e) {\n      return '--:--';\n    }\n  }\n\n  function renderLocalTimes(){\n    if (!localTimesEl) return;\n    if (!cfg.departureTimezone || !cfg.arrivalTimezone) {\n      localTimesEl.textContent = '';\n      return;\n    }\n    const depTime = formatZoneTime(cfg.departureTimezone);\n    const arrTime = formatZoneTime(cfg.arrivalTimezone);\n    const pairTpl = L.local_time_pair || 'Departure Port Local Time: %1$s \/ Arrival Port Local Time: %2$s';\n    const combinedTpl = L.local_time_combined || 'Departure & Arrival Port Local Time: %s';\n    if (depTime === arrTime) {\n      localTimesEl.textContent = combinedTpl.replace('%s', depTime);\n      return;\n    }\n    localTimesEl.textContent = pairTpl.replace('%1$s', depTime).replace('%2$s', arrTime);\n  }\n\n  function setStatusInline(html){\n    let box = wrap.querySelector('.tp-controls-status');\n    if (!box) {\n      box = document.createElement('div');\n      box.className = 'tp-controls-status';\n      wrap.querySelector('.tp-controls').appendChild(box);\n    }\n    box.innerHTML = html || '';\n  }\n\n  function clearStatusInline(){\n    const box = wrap.querySelector('.tp-controls-status');\n    if (box) box.innerHTML = '';\n  }\n\n  function navHtml(){\n    if (daySetup !== 'modern') return '';\n    const base = new Date(dateEl.value || new Date());\n    const today = new Date();\n    const tomorrow = new Date(today);\n    tomorrow.setDate(today.getDate() + 1);\n    const isToday = base.toDateString() === today.toDateString();\nlet prevLabel = L.day_nav_previous || 'Show previous day';\nlet nextLabel = L.day_nav_next || 'Show next day';\nif (isToday) nextLabel = L.day_nav_tomorrow || 'Show tomorrow';\nif (base.toDateString() === tomorrow.toDateString()) prevLabel = L.day_nav_today || 'Show today';\n    return '<div class=\"tp-day-nav\">'\n      + (isToday ? '' : '<a href=\"#\" data-shift=\"-1\">'+prevLabel+'<\/a>')\n      + '<a href=\"#\" data-shift=\"1\">'+nextLabel+'<\/a>'\n      + '<\/div>';\n  }\n\n  function shiftDate(delta){\n    const base = new Date(dateEl.value || new Date());\n    base.setDate(base.getDate() + delta);\n    dateEl.value = iso(base);\n    load();\n  }\n\n  function moreButtonHtml(hiddenCount){\n    if (!limit10 || revealAll || hiddenCount <= 0) return '';\n    return '<div style=\"margin-top:12px;text-align:center\">'\n      + '<button type=\"button\" class=\"tp-btn tp-more-btn\">'+(L.more_departures_button || 'Show more departures')+' ('+hiddenCount+')<\/button>'\n      + '<\/div>';\n  }\n\n  function opCell(r){\n    const name = r.opName || ('Operator '+(r.opId||''));\n    const logo = (cfg.showLogo && r.opLogo) ? '<img decoding=\"async\" src=\"'+r.opLogo+'\" alt=\"'+name+'\"> ' : '';\n    const label = logo + '<span>'+name+'<\/span>';\n    return r.opLink ? '<a class=\"tp-op\" href=\"'+r.opLink+'\" target=\"_blank\" rel=\"nofollow noopener\">'+label+'<\/a>' : '<span class=\"tp-op\">'+label+'<\/span>';\n  }\n\n  function shipInfo(original){\n    const key = (original||'').toLowerCase().trim();\n    const label = (cfg.shipMap && cfg.shipMap[key]) || original || '';\n    const href  = (cfg.shipLinks && cfg.shipLinks[key]) || '';\n    return {label, href};\n  }\n\n  function shipBadge(original){\n    const s = shipInfo(original);\n    const badge = '<span class=\"tp-badge\">'+(s.label||'')+'<\/span>';\n    return s.href ? ('<a href=\"'+s.href+'\" target=\"_blank\" rel=\"nofollow noopener\">'+badge+'<\/a>') : badge;\n  }\n\n  function rowKey(r){\n    return [String(r.routeId||''), String(r.opId||''), String(+r.dep||0), String(+r.arr||0)].join('|');\n  }\n\n  function pickFeaturedKey(rows, avoidKey){\n    if (!activityBoosters || !rows.length) return '';\n    const routesSum = Array.isArray(cfg.routes) ? cfg.routes.reduce((acc, n)=>acc + (parseInt(n,10)||0), 0) : 0;\n    const dateSeed = parseInt(String(dateEl.value || '').replace(\/-\/g,''), 10) || 0;\n\n    let pool = rows;\n    if (avoidKey) {\n      const soonIdx = rows.findIndex(r => rowKey(r) === avoidKey);\n      if (soonIdx >= 0) {\n        const later = rows.slice(soonIdx + 1).filter(r => rowKey(r) !== avoidKey);\n        pool = later.length ? later : rows.filter(r => rowKey(r) !== avoidKey);\n      } else {\n        pool = rows.filter(r => rowKey(r) !== avoidKey);\n      }\n    }\n\n    if (!pool.length) return '';\n    const idx = Math.abs((routesSum + dateSeed + rows.length) % pool.length);\n    return rowKey(pool[idx]);\n  }\n\n  function pickSoonKey(rows){\n    if (!activityBoosters || !rows.length) return '';\n    const now = Date.now();\n    const todayStr = new Date(now).toDateString();\n    const firstUpcoming = rows.find(r => (r.dep instanceof Date) && r.dep.getTime() > now && r.dep.toDateString() === todayStr);\n    return firstUpcoming ? rowKey(firstUpcoming) : '';\n  }\n\n  function boostersFor(r){\n    if (!activityBoosters) return [];\n    const now = Date.now();\n    const depMs = (r.dep instanceof Date) ? r.dep.getTime() : 0;\n    const arrMs = (r.arr instanceof Date) ? r.arr.getTime() : 0;\n    const depIsToday = (r.dep instanceof Date) && (new Date(now).toDateString() === r.dep.toDateString());\n\n    if (depMs > 0 && arrMs > 0 && depMs <= now && arrMs > now) {\n      return [{cls:'tp-booster-sailing', text:(L.tag_currently_sailing || '\ud83d\udfe2 Currently sailing')}];\n    }\n    if (depIsToday && arrMs > 0 && arrMs <= now) {\n      return [{cls:'tp-booster-arrived', text:(L.tag_arrived || '\u26ab Arrived')}];\n    }\n    if (rowKey(r) === soonKey) return [{cls:'tp-booster-soon', text:(L.tag_leaving_soon || '\ud83d\udd34 Leaving soon')}];\n    if (r.dep && r.arr && r.dep.toDateString() !== r.arr.toDateString()) return [{cls:'tp-booster-overnight', text:(L.tag_overnight || 'Overnight')}];\n\n    return [];\n  }\n\n  function boostersHtml(r, floating){\n    const tags = boostersFor(r);\n    if (!tags.length) return '';\n    const cls = floating ? 'tp-boosters tp-boosters-float' : 'tp-boosters';\n    return '<div class=\"'+cls+'\">' + tags.map(t => '<span class=\"tp-booster '+t.cls+'\">'+boosterLabelHtml(t.text)+'<\/span>').join('') + '<\/div>';\n  }\n\n  function boosterLabelHtml(text){\n    return String(text || '').replace(\/^(\ud83d\udd34|\ud83d\udfe2|\u26ab|\u2b50)\\s*\/, '<span class=\"tp-booster-emoji\">$1<\/span>');\n  }\n\n  function routeTicketHtml(label){\n    const raw = String(label || '').trim();\n    if (!raw) return '';\n    if (cfg.theme !== 'small_cards') return escAttr(raw);\n    const parts = raw.split(\/\\s*[\\-\u2013]\\s*\/, 2);\n    if (parts.length < 2) return escAttr(raw);\n    return escAttr(parts[0]) + '<br>' + escAttr(parts[1]);\n  }\n\n  function escAttr(v){\n    return String(v||'').replace(\/[&<>\"']\/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[m]));\n  }\n\n  function bindRowLinks(){\n    if (cfg.theme !== 'max_clickouts') return;\n    out.querySelectorAll('tr.tp-row-link').forEach((row)=>{\n      row.setAttribute('role','link');\n      row.setAttribute('tabindex','0');\n      row.addEventListener('click', (e)=>{\n        if (e.target && e.target.closest('a')) return;\n        const href = row.getAttribute('data-row-link');\n        if (!href) return;\n        window.open(href, '_blank', 'noopener,noreferrer');\n      });\n      row.addEventListener('keydown', (e)=>{\n        if (e.key !== 'Enter' && e.key !== ' ') return;\n        e.preventDefault();\n        row.click();\n      });\n    });\n  }\n\n  function routeLabel(rid){\n    return (cfg.routeLabels && (cfg.routeLabels[String(rid)] || cfg.routeLabels[rid])) || String(rid);\n  }\n\n  function renderTable(rows){\n    const th = {date:L.th_date,dep:L.th_dep,arr:L.th_arr,dur:L.th_dur,ship:L.th_ship,route:L.th_route,op:L.th_op};\n\n    const headCells = [\n      '<th>'+th.date+'<\/th>',\n      '<th>'+th.dep+'<\/th>',\n      '<th>'+th.arr+'<\/th>',\n      '<th>'+th.dur+'<\/th>'\n    ];\n    if (showShip) {\n      headCells.push('<th>'+th.ship+'<\/th>');\n    }\n    headCells.push('<th>'+th.route+'<\/th>');\n    headCells.push('<th>'+th.op+'<\/th>');\n\n    let html = '<table class=\"tp-table\"><thead><tr>'+headCells.join('')+'<\/tr><\/thead><tbody>';\n    rows.forEach(r=>{\n      const dow = WD[r.dep.getDay()] || '';\n      const clickable = (cfg.theme === 'max_clickouts' && r.opLink);\n      const rowAttr = clickable ? (' class=\"tp-row-link\" data-row-link=\"'+escAttr(r.opLink)+'\"') : '';\n      const dateBoosters = (cfg.theme === 'max_clickouts') ? '' : boostersHtml(r, false);\n      const routeBoosters = (cfg.theme === 'max_clickouts') ? boostersHtml(r, false) : '';\n      const cells = [\n        '<td>'+dShort(r.dep)+' <span class=\"tp-day\">'+dow+'<\/span>'+dateBoosters+'<\/td>',\n        '<td>'+hhmm(r.dep)+'<\/td>',\n        '<td>'+hhmm(r.arr)+'<\/td>',\n        '<td>'+dur(r.min)+'<\/td>'\n      ];\n      if (showShip) {\n        cells.push('<td>'+shipBadge(r.ship)+'<\/td>');\n      }\n      cells.push('<td>'+routeBoosters+'<div>'+routeLabel(r.routeId)+'<\/div><\/td>');\n      cells.push('<td>'+opCell(r)+'<\/td>');\n      html += '<tr'+rowAttr+'>'+cells.join('')+'<\/tr>';\n    });\n    html += '<\/tbody><\/table>';\n    return html;\n  }\n\n  function renderCards(rows){\n    if (cfg.theme === 'extended_cards') {\n      return renderExtendedCards(rows);\n    }\n\n    let html = '<div class=\"tp-cardlist\">';\n    rows.forEach(r=>{\n      const dow   = WD[r.dep.getDay()] || '';\n      const times = hhmm(r.dep) + ' <span class=\"tp-arrow\">\u2192<\/span> ' + hhmm(r.arr);\n      html += '<div class=\"tp-card\">'+boostersHtml(r, true)+\n        \/\/ Row 1: Date + weekday + times\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\"><span class=\"tp-sub\">'+dShort(r.dep)+'<\/span><span class=\"tp-day\">'+dow+'<\/span><\/div>'+\n          '<div class=\"rhs\"><span class=\"tp-time\">'+times+'<\/span><\/div>'+\n        '<\/div>';\n\n      if (showShip) {\n        html +=\n        \/\/ Row 2: Ship\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\">'+shipBadge(r.ship)+'<\/div>'+\n          '<div class=\"rhs\"><\/div>'+\n        '<\/div>';\n      }\n\n      html +=\n        \/\/ Row 3: Operator + route label\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\">'+opCell(r)+'<\/div>'+\n          '<div class=\"rhs\"><span class=\"tp-route-ticket\">'+routeTicketHtml(routeLabel(r.routeId))+'<\/span><\/div>'+\n        '<\/div>'+\n      '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  function renderExtendedCards(rows){\n    const ctaText = L.more_link || 'More sailings';\n    let html = '<div class=\"tp-cardlist\">';\n    rows.forEach(r=>{\n      const dow = WD[r.dep.getDay()] || '';\n      const link = r.opLink ? ('<a class=\"tp-ext-cta\" href=\"'+r.opLink+'\" target=\"_blank\" rel=\"nofollow noopener\">'+ctaText+' <span class=\"tp-ext-cta-arrow\">\u00bb<\/span><\/a>') : '<span class=\"tp-ext-cta\">'+ctaText+' <span class=\"tp-ext-cta-arrow\">\u00bb<\/span><\/span>';\n      html += '<div class=\"tp-ext-card\">'\n        + boostersHtml(r, true)\n        + '<div class=\"tp-ext-left\">'\n        +   '<div>'+opCell(r)+'<\/div>'\n        +   (showShip ? ('<div>'+shipBadge(r.ship)+'<\/div>') : '')\n        + '<\/div>'\n        + '<div class=\"tp-ext-mid\">'\n        +   '<div class=\"tp-ext-top\"><span class=\"tp-sub\">'+dShort(r.dep)+' <span class=\"tp-day\">'+dow+'<\/span><\/span><span class=\"tp-ext-dur\">'+dur(r.min)+'<\/span><\/div>'\n        +   '<div class=\"tp-ext-times\"><span class=\"tp-ext-time\">'+hhmm(r.dep)+'<\/span><span class=\"tp-ext-line\"><\/span><span class=\"tp-ext-dur\">'+dur(r.min)+'<\/span><span class=\"tp-ext-line\"><\/span><span class=\"tp-ext-time\">'+hhmm(r.arr)+'<\/span><\/div>'\n        +   '<div class=\"tp-ext-route\">'+routeLabel(r.routeId)+'<\/div>'\n        + '<\/div>'\n        + '<div class=\"tp-ext-right\">'+link+'<\/div>'\n        + '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  \/\/ Safe fetch helper\n  async function fetchOne(routeId, from, to){\n    try{\n      const url = new URL(cfg.rest);\n      url.searchParams.set('route', String(routeId));\n      url.searchParams.set('from', from);\n      url.searchParams.set('to', to);\n      const res = await fetch(url.toString(), {credentials:'same-origin'});\n      if(!res.ok) return { rid: routeId, error: 'HTTP '+res.status };\n      const json = await res.json();\n      const list = (json && json.data && Array.isArray(json.data.rows)) ? json.data.rows : [];\n      return { rid: routeId, rows: list };\n    }catch(e){\n      return { rid: routeId, error: String(e && e.message ? e.message : e) };\n    }\n  }\n\n  async function load(){\n    btn.disabled = true; setLoader(true); status.textContent = L.status_loading;\n\n    const start = new Date(dateEl.value || new Date());\n    const days  = (daySetup === 'modern') ? 1 : Math.max(1, parseInt(daysEl.value,10)||1);\n    const end   = new Date(start); end.setDate(start.getDate()+days-1);\n    const fromIso = iso(start), toIso = iso(end);\n\n    try{\n      const results  = await Promise.all((cfg.routes||[]).map(rid=>fetchOne(rid, fromIso, toIso)));\n      const oks  = results.filter(r => !r.error);\n      const errs = results.filter(r =>  r.error);\n\n      const all = [];\n      oks.forEach(({rid, rows})=>{\n        rows.forEach(t=>{\n          all.push({\n            routeId: rid,\n            opId: t.operatorId || null,\n            opName: t.operatorName || '',\n            opLogo: t.operatorLogo || '',\n            opLink: t.operatorLink || '',\n            dep: toLocal(t.departureTime),\n            arr: toLocal(t.arrivalTime),\n            min: t.durationInMinutes || 0,\n            ship: t.shipName || ''\n          });\n        });\n      });\n\n      let rows = all;\n      if (Array.isArray(cfg.opFilter) && cfg.opFilter.length>0) {\n        rows = all.filter(r => r.opId && cfg.opFilter.includes(String(r.opId)));\n      }\n\n      rows.sort((a,b)=> a.dep - b.dep);\n\n      const todayStr = new Date().toDateString();\n      const nowMs = Date.now();\n      const arrivedToday = rows\n        .filter(r => (r.dep instanceof Date) && (r.arr instanceof Date) && r.dep.toDateString() === todayStr && r.arr.getTime() <= nowMs)\n        .sort((a,b) => b.arr - a.arr);\n      if (arrivedToday.length > 2) {\n        const keep = new Set(arrivedToday.slice(0,2).map(rowKey));\n        rows = rows.filter(r => {\n          const isArrivedToday = (r.dep instanceof Date) && (r.arr instanceof Date) && r.dep.toDateString() === todayStr && r.arr.getTime() <= nowMs;\n          return !isArrivedToday || keep.has(rowKey(r));\n        });\n      }\n\n      const total = rows.length;\n      if (total===0){\n        status.textContent = L.status_empty + (errs.length ? ' (some routes returned no data or errors)' : '');\n        clearStatusInline();\n        out.innerHTML='';\n        setLoader(false); btn.disabled=false; return;\n      }\n\n      const visibleRows = (limit10 && !revealAll && rows.length > 10) ? rows.slice(0,10) : rows;\n      const hiddenCount = rows.length - visibleRows.length;\n      soonKey = pickSoonKey(visibleRows);\n      featuredKey = pickFeaturedKey(visibleRows, soonKey);\n\n      status.textContent = errs.length ? ('Skipped '+errs.length+' route'+(errs.length>1?'s':'')) : '';\n      setStatusInline(\n  (L.status_found || '%d sailings found').replace('%d', '<strong>'+total+'<\/strong>')\n);\n      out.innerHTML = renderTable(visibleRows) + renderCards(visibleRows) + moreButtonHtml(hiddenCount);\n      bindRowLinks();\n      if (navHost) navHost.innerHTML = navHtml();\n\n    } catch(e){\n      status.textContent = 'Failed to load data';\n      out.innerHTML = '<pre>'+String(e.message||e)+'<\/pre>';\n    } finally {\n      setLoader(false);\n      btn.disabled = false;\n    }\n  }\n\n  wrap.addEventListener('click', function(e){\n    const nav = e.target.closest('.tp-day-nav a[data-shift]');\n    if (nav) {\n      e.preventDefault();\n      shiftDate(parseInt(nav.getAttribute('data-shift'),10) || 0);\n      return;\n    }\n    const more = e.target.closest('.tp-more-btn');\n    if (more) {\n      e.preventDefault();\n      revealAll = true;\n      load();\n    }\n  });\n\n  btn.addEventListener('click', load);\n  if (navHost) navHost.innerHTML = navHtml();\n  renderLocalTimes();\n  setInterval(renderLocalTimes, 30000);\n  if (cfg.autoload) load();\n})();\n<\/script>\n<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-972eafd elementor-widget elementor-widget-text-editor\" data-id=\"972eafd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>F\u00e4rjetidtabell R\u00f8dby Puttgarden<\/h2>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c556108 elementor-widget elementor-widget-shortcode\" data-id=\"c556108\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><div class=\"tp-wrap tp-theme-extended_cards tp-day-setup-classic\" data-config=\"{&quot;rest&quot;:&quot;https:\\\/\\\/puttgardenrodby.com\\\/se\\\/wp-json\\\/timetables-pro\\\/v1\\\/timetables&quot;,&quot;routes&quot;:[210],&quot;days&quot;:1,&quot;autoload&quot;:true,&quot;theme&quot;:&quot;extended_cards&quot;,&quot;daySetup&quot;:&quot;classic&quot;,&quot;limit10&quot;:false,&quot;routeLabels&quot;:{&quot;210&quot;:&quot;Rodby-Puttgarden&quot;},&quot;opFilter&quot;:[&quot;32&quot;],&quot;labels&quot;:{&quot;ui_date&quot;:&quot;Datum&quot;,&quot;ui_days&quot;:&quot;Dagar&quot;,&quot;ui_button&quot;:&quot;Visa avg\\u00e5ngar&quot;,&quot;status_idle&quot;:&quot;V\\u00e4lj ett datum och klicka p\\u00e5 Visa avg\\u00e5ngar&quot;,&quot;status_loading&quot;:&quot;Laddar...&quot;,&quot;status_empty&quot;:&quot;Inga avg\\u00e5ngar hittades&quot;,&quot;status_found&quot;:&quot;%d avg\\u00e5ngar hittades&quot;,&quot;th_date&quot;:&quot;Datum&quot;,&quot;th_dep&quot;:&quot;Avg\\u00e5ng&quot;,&quot;th_arr&quot;:&quot;Ankomst&quot;,&quot;th_dur&quot;:&quot;Restid&quot;,&quot;th_ship&quot;:&quot;Fartyg&quot;,&quot;th_op&quot;:&quot;Operat\\u00f6r&quot;,&quot;th_route&quot;:&quot;Rutt&quot;,&quot;wd_sun&quot;:&quot;S\\u00d6N&quot;,&quot;wd_mon&quot;:&quot;M\\u00c5N&quot;,&quot;wd_tue&quot;:&quot;TIS&quot;,&quot;wd_wed&quot;:&quot;ONS&quot;,&quot;wd_thu&quot;:&quot;TOR&quot;,&quot;wd_fri&quot;:&quot;FRE&quot;,&quot;wd_sat&quot;:&quot;L\\u00d6R&quot;,&quot;summary_footer_one&quot;:&quot;\\u00bb Se alla %s avg\\u00e5ngar i v\\u00e5r tidtabell&quot;,&quot;summary_footer_two&quot;:&quot;\\u00bb Se fler avg\\u00e5ngar f\\u00f6r %1$s och %2$s i v\\u00e5r tidtabell&quot;,&quot;summary_footer_generic&quot;:&quot;Se v\\u00e5r tidtabell f\\u00f6r fler avg\\u00e5ngar&quot;,&quot;summary_header&quot;:&quot;De tv\\u00e5 n\\u00e4sta avg\\u00e5ngarna:&quot;,&quot;summary_no_upcoming&quot;:&quot;Inga kommande avg\\u00e5ngar hittades&quot;,&quot;more_link&quot;:&quot;Fler avg\\u00e5ngar&quot;,&quot;more_departures_button&quot;:&quot;Visa fler avg\\u00e5ngar&quot;,&quot;day_nav_previous&quot;:&quot;Visa f\\u00f6reg\\u00e5ende dag&quot;,&quot;day_nav_next&quot;:&quot;Visa n\\u00e4sta dag&quot;,&quot;day_nav_today&quot;:&quot;Visa idag&quot;,&quot;day_nav_tomorrow&quot;:&quot;Visa imorgon&quot;,&quot;local_time_pair&quot;:&quot;Lokal tid avg\\u00e5ngshamn: %1$s \\\/ Lokal tid ankomsthamn: %2$s&quot;,&quot;local_time_combined&quot;:&quot;Lokal tid avg\\u00e5ngs- och ankomsthamn: %s&quot;,&quot;tag_often_booked&quot;:&quot;\\u2b50 Ofta bokad&quot;,&quot;tag_leaving_soon&quot;:&quot;\\ud83d\\udd34 Avg\\u00e5r snart&quot;,&quot;tag_currently_sailing&quot;:&quot;\\ud83d\\udfe2 P\\u00e5 v\\u00e4g nu&quot;,&quot;tag_arrived&quot;:&quot;\\u26ab Anl\\u00e4nt&quot;,&quot;tag_overnight&quot;:&quot;\\u00d6vernattning&quot;},&quot;showLogo&quot;:true,&quot;activityBoosters&quot;:true,&quot;title&quot;:&quot;&quot;,&quot;shipMap&quot;:[],&quot;shipLinks&quot;:[],&quot;showShip&quot;:false,&quot;departurePort&quot;:&quot;Rodby&quot;,&quot;arrivalPort&quot;:&quot;Puttgarden&quot;,&quot;departureTimezone&quot;:&quot;Europe\\\/Copenhagen&quot;,&quot;arrivalTimezone&quot;:&quot;Europe\\\/Berlin&quot;}\">\n  <div class=\"tp-controls\" role=\"group\" aria-label=\"Timetable controls\">\n    <div>\n      <label for=\"tp-date-ops\">Datum<\/label><br>\n      <input id=\"tp-date-ops\" class=\"tp-date\" type=\"date\" aria-label=\"Datum\">\n    <\/div>\n    <div class=\"tp-day-field\">\n      <label for=\"tp-range-ops\">Dagar<\/label><br>\n      <select id=\"tp-range-ops\" class=\"tp-range\" aria-label=\"Dagar\">\n        <option value=\"1\">1<\/option><option value=\"3\">3<\/option><option value=\"7\">7<\/option><option value=\"14\">14<\/option>\n      <\/select>\n    <\/div>\n    <div><button id=\"tp-load-ops\" class=\"tp-btn\">Visa avg\u00e5ngar<\/button><\/div>\n  <\/div>\n\n  <div class=\"tp-local-nav-row\">\n    <div class=\"tp-local-times\" id=\"tp-local-times-ops\" aria-live=\"polite\"><\/div>\n    <div class=\"tp-day-nav-host\"><\/div>\n  <\/div>\n\n  \n  <div id=\"tp-status-ops\" class=\"tp-muted\" aria-live=\"polite\">V\u00e4lj ett datum och klicka p\u00e5 Visa avg\u00e5ngar<\/div>\n\n  <div id=\"tp-ops-results\"><\/div>\n\n  <div class=\"tp-loader\" aria-hidden=\"true\">\n    <div class=\"tp-loader-card\">\n      <div class=\"tp-spinner\" aria-hidden=\"true\"><\/div>\n      <div class=\"tp-loader-text\">Laddar...<\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n  const wrap   = document.currentScript.previousElementSibling;\n  const cfg    = JSON.parse(wrap.getAttribute('data-config')||'{}');\n  const L      = cfg.labels||{};\n  const dateEl = wrap.querySelector('#tp-date-ops');\n  const daysEl = wrap.querySelector('#tp-range-ops');\n  const btn    = wrap.querySelector('#tp-load-ops');\n  const status = wrap.querySelector('#tp-status-ops');\n  const out    = wrap.querySelector('#tp-ops-results');\n  const loader = wrap.querySelector('.tp-loader');\n  const navHost = wrap.querySelector('.tp-day-nav-host');\n  const localTimesEl = wrap.querySelector('#tp-local-times-ops');\n\n  const showShip = (cfg.showShip !== false && cfg.showShip !== 0 && cfg.showShip !== '0');\n  const activityBoosters = !!cfg.activityBoosters;\n  const daySetup = (cfg.daySetup === 'modern') ? 'modern' : 'classic';\n  const limit10 = !!cfg.limit10;\n  let featuredKey = '';\n  let soonKey = '';\n  let revealAll = false;\n\n  if (daySetup === 'modern') {\n    const dayField = wrap.querySelector('.tp-day-field');\n    if (dayField) dayField.style.display = 'none';\n  }\n\n  dateEl.valueAsDate = new Date();\n  dateEl.min = new Date().toISOString().split('T')[0];\n  Array.from(daysEl.options).forEach(o=>{ if(parseInt(o.value,10)===parseInt(cfg.days||7,10)) o.selected=true; });\n\n  function pad(n){ return String(n).padStart(2,'0'); }\n  function iso(d){ return d.getFullYear()+'-'+pad(d.getMonth()+1)+'-'+pad(d.getDate()); }\n  function toLocal(s){ return new Date(s); }\n  function hhmm(d){ return d.toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}); }\n  function dShort(d){ return d.toLocaleDateString([], {day:'numeric', month:'short'}); }\n  function dur(m){ const h=Math.floor(m\/60), r=m%60; return r? (h+'h '+r+'m') : (h+'h'); }\n\n  const WD = [\n    L.wd_sun || 'SUN',\n    L.wd_mon || 'MON',\n    L.wd_tue || 'TUE',\n    L.wd_wed || 'WED',\n    L.wd_thu || 'THU',\n    L.wd_fri || 'FRI',\n    L.wd_sat || 'SAT'\n  ];\n\n  function setLoader(v){ loader.classList.toggle('show', !!v); loader.setAttribute('aria-hidden', v?'false':'true'); }\n\n  function formatZoneTime(tz){\n    if (!tz) return '--:--';\n    try {\n      return new Intl.DateTimeFormat([], {hour:'2-digit', minute:'2-digit', hour12:false, timeZone: tz}).format(new Date());\n    } catch (e) {\n      return '--:--';\n    }\n  }\n\n  function renderLocalTimes(){\n    if (!localTimesEl) return;\n    if (!cfg.departureTimezone || !cfg.arrivalTimezone) {\n      localTimesEl.textContent = '';\n      return;\n    }\n    const depTime = formatZoneTime(cfg.departureTimezone);\n    const arrTime = formatZoneTime(cfg.arrivalTimezone);\n    const pairTpl = L.local_time_pair || 'Departure Port Local Time: %1$s \/ Arrival Port Local Time: %2$s';\n    const combinedTpl = L.local_time_combined || 'Departure & Arrival Port Local Time: %s';\n    if (depTime === arrTime) {\n      localTimesEl.textContent = combinedTpl.replace('%s', depTime);\n      return;\n    }\n    localTimesEl.textContent = pairTpl.replace('%1$s', depTime).replace('%2$s', arrTime);\n  }\n\n  function setStatusInline(html){\n    let box = wrap.querySelector('.tp-controls-status');\n    if (!box) {\n      box = document.createElement('div');\n      box.className = 'tp-controls-status';\n      wrap.querySelector('.tp-controls').appendChild(box);\n    }\n    box.innerHTML = html || '';\n  }\n\n  function clearStatusInline(){\n    const box = wrap.querySelector('.tp-controls-status');\n    if (box) box.innerHTML = '';\n  }\n\n  function navHtml(){\n    if (daySetup !== 'modern') return '';\n    const base = new Date(dateEl.value || new Date());\n    const today = new Date();\n    const tomorrow = new Date(today);\n    tomorrow.setDate(today.getDate() + 1);\n    const isToday = base.toDateString() === today.toDateString();\nlet prevLabel = L.day_nav_previous || 'Show previous day';\nlet nextLabel = L.day_nav_next || 'Show next day';\nif (isToday) nextLabel = L.day_nav_tomorrow || 'Show tomorrow';\nif (base.toDateString() === tomorrow.toDateString()) prevLabel = L.day_nav_today || 'Show today';\n    return '<div class=\"tp-day-nav\">'\n      + (isToday ? '' : '<a href=\"#\" data-shift=\"-1\">'+prevLabel+'<\/a>')\n      + '<a href=\"#\" data-shift=\"1\">'+nextLabel+'<\/a>'\n      + '<\/div>';\n  }\n\n  function shiftDate(delta){\n    const base = new Date(dateEl.value || new Date());\n    base.setDate(base.getDate() + delta);\n    dateEl.value = iso(base);\n    load();\n  }\n\n  function moreButtonHtml(hiddenCount){\n    if (!limit10 || revealAll || hiddenCount <= 0) return '';\n    return '<div style=\"margin-top:12px;text-align:center\">'\n      + '<button type=\"button\" class=\"tp-btn tp-more-btn\">'+(L.more_departures_button || 'Show more departures')+' ('+hiddenCount+')<\/button>'\n      + '<\/div>';\n  }\n\n  function opCell(r){\n    const name = r.opName || ('Operator '+(r.opId||''));\n    const logo = (cfg.showLogo && r.opLogo) ? '<img decoding=\"async\" src=\"'+r.opLogo+'\" alt=\"'+name+'\"> ' : '';\n    const label = logo + '<span>'+name+'<\/span>';\n    return r.opLink ? '<a class=\"tp-op\" href=\"'+r.opLink+'\" target=\"_blank\" rel=\"nofollow noopener\">'+label+'<\/a>' : '<span class=\"tp-op\">'+label+'<\/span>';\n  }\n\n  function shipInfo(original){\n    const key = (original||'').toLowerCase().trim();\n    const label = (cfg.shipMap && cfg.shipMap[key]) || original || '';\n    const href  = (cfg.shipLinks && cfg.shipLinks[key]) || '';\n    return {label, href};\n  }\n\n  function shipBadge(original){\n    const s = shipInfo(original);\n    const badge = '<span class=\"tp-badge\">'+(s.label||'')+'<\/span>';\n    return s.href ? ('<a href=\"'+s.href+'\" target=\"_blank\" rel=\"nofollow noopener\">'+badge+'<\/a>') : badge;\n  }\n\n  function rowKey(r){\n    return [String(r.routeId||''), String(r.opId||''), String(+r.dep||0), String(+r.arr||0)].join('|');\n  }\n\n  function pickFeaturedKey(rows, avoidKey){\n    if (!activityBoosters || !rows.length) return '';\n    const routesSum = Array.isArray(cfg.routes) ? cfg.routes.reduce((acc, n)=>acc + (parseInt(n,10)||0), 0) : 0;\n    const dateSeed = parseInt(String(dateEl.value || '').replace(\/-\/g,''), 10) || 0;\n\n    let pool = rows;\n    if (avoidKey) {\n      const soonIdx = rows.findIndex(r => rowKey(r) === avoidKey);\n      if (soonIdx >= 0) {\n        const later = rows.slice(soonIdx + 1).filter(r => rowKey(r) !== avoidKey);\n        pool = later.length ? later : rows.filter(r => rowKey(r) !== avoidKey);\n      } else {\n        pool = rows.filter(r => rowKey(r) !== avoidKey);\n      }\n    }\n\n    if (!pool.length) return '';\n    const idx = Math.abs((routesSum + dateSeed + rows.length) % pool.length);\n    return rowKey(pool[idx]);\n  }\n\n  function pickSoonKey(rows){\n    if (!activityBoosters || !rows.length) return '';\n    const now = Date.now();\n    const todayStr = new Date(now).toDateString();\n    const firstUpcoming = rows.find(r => (r.dep instanceof Date) && r.dep.getTime() > now && r.dep.toDateString() === todayStr);\n    return firstUpcoming ? rowKey(firstUpcoming) : '';\n  }\n\n  function boostersFor(r){\n    if (!activityBoosters) return [];\n    const now = Date.now();\n    const depMs = (r.dep instanceof Date) ? r.dep.getTime() : 0;\n    const arrMs = (r.arr instanceof Date) ? r.arr.getTime() : 0;\n    const depIsToday = (r.dep instanceof Date) && (new Date(now).toDateString() === r.dep.toDateString());\n\n    if (depMs > 0 && arrMs > 0 && depMs <= now && arrMs > now) {\n      return [{cls:'tp-booster-sailing', text:(L.tag_currently_sailing || '\ud83d\udfe2 Currently sailing')}];\n    }\n    if (depIsToday && arrMs > 0 && arrMs <= now) {\n      return [{cls:'tp-booster-arrived', text:(L.tag_arrived || '\u26ab Arrived')}];\n    }\n    if (rowKey(r) === soonKey) return [{cls:'tp-booster-soon', text:(L.tag_leaving_soon || '\ud83d\udd34 Leaving soon')}];\n    if (r.dep && r.arr && r.dep.toDateString() !== r.arr.toDateString()) return [{cls:'tp-booster-overnight', text:(L.tag_overnight || 'Overnight')}];\n\n    return [];\n  }\n\n  function boostersHtml(r, floating){\n    const tags = boostersFor(r);\n    if (!tags.length) return '';\n    const cls = floating ? 'tp-boosters tp-boosters-float' : 'tp-boosters';\n    return '<div class=\"'+cls+'\">' + tags.map(t => '<span class=\"tp-booster '+t.cls+'\">'+boosterLabelHtml(t.text)+'<\/span>').join('') + '<\/div>';\n  }\n\n  function boosterLabelHtml(text){\n    return String(text || '').replace(\/^(\ud83d\udd34|\ud83d\udfe2|\u26ab|\u2b50)\\s*\/, '<span class=\"tp-booster-emoji\">$1<\/span>');\n  }\n\n  function routeTicketHtml(label){\n    const raw = String(label || '').trim();\n    if (!raw) return '';\n    if (cfg.theme !== 'small_cards') return escAttr(raw);\n    const parts = raw.split(\/\\s*[\\-\u2013]\\s*\/, 2);\n    if (parts.length < 2) return escAttr(raw);\n    return escAttr(parts[0]) + '<br>' + escAttr(parts[1]);\n  }\n\n  function escAttr(v){\n    return String(v||'').replace(\/[&<>\"']\/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[m]));\n  }\n\n  function bindRowLinks(){\n    if (cfg.theme !== 'max_clickouts') return;\n    out.querySelectorAll('tr.tp-row-link').forEach((row)=>{\n      row.setAttribute('role','link');\n      row.setAttribute('tabindex','0');\n      row.addEventListener('click', (e)=>{\n        if (e.target && e.target.closest('a')) return;\n        const href = row.getAttribute('data-row-link');\n        if (!href) return;\n        window.open(href, '_blank', 'noopener,noreferrer');\n      });\n      row.addEventListener('keydown', (e)=>{\n        if (e.key !== 'Enter' && e.key !== ' ') return;\n        e.preventDefault();\n        row.click();\n      });\n    });\n  }\n\n  function routeLabel(rid){\n    return (cfg.routeLabels && (cfg.routeLabels[String(rid)] || cfg.routeLabels[rid])) || String(rid);\n  }\n\n  function renderTable(rows){\n    const th = {date:L.th_date,dep:L.th_dep,arr:L.th_arr,dur:L.th_dur,ship:L.th_ship,route:L.th_route,op:L.th_op};\n\n    const headCells = [\n      '<th>'+th.date+'<\/th>',\n      '<th>'+th.dep+'<\/th>',\n      '<th>'+th.arr+'<\/th>',\n      '<th>'+th.dur+'<\/th>'\n    ];\n    if (showShip) {\n      headCells.push('<th>'+th.ship+'<\/th>');\n    }\n    headCells.push('<th>'+th.route+'<\/th>');\n    headCells.push('<th>'+th.op+'<\/th>');\n\n    let html = '<table class=\"tp-table\"><thead><tr>'+headCells.join('')+'<\/tr><\/thead><tbody>';\n    rows.forEach(r=>{\n      const dow = WD[r.dep.getDay()] || '';\n      const clickable = (cfg.theme === 'max_clickouts' && r.opLink);\n      const rowAttr = clickable ? (' class=\"tp-row-link\" data-row-link=\"'+escAttr(r.opLink)+'\"') : '';\n      const dateBoosters = (cfg.theme === 'max_clickouts') ? '' : boostersHtml(r, false);\n      const routeBoosters = (cfg.theme === 'max_clickouts') ? boostersHtml(r, false) : '';\n      const cells = [\n        '<td>'+dShort(r.dep)+' <span class=\"tp-day\">'+dow+'<\/span>'+dateBoosters+'<\/td>',\n        '<td>'+hhmm(r.dep)+'<\/td>',\n        '<td>'+hhmm(r.arr)+'<\/td>',\n        '<td>'+dur(r.min)+'<\/td>'\n      ];\n      if (showShip) {\n        cells.push('<td>'+shipBadge(r.ship)+'<\/td>');\n      }\n      cells.push('<td>'+routeBoosters+'<div>'+routeLabel(r.routeId)+'<\/div><\/td>');\n      cells.push('<td>'+opCell(r)+'<\/td>');\n      html += '<tr'+rowAttr+'>'+cells.join('')+'<\/tr>';\n    });\n    html += '<\/tbody><\/table>';\n    return html;\n  }\n\n  function renderCards(rows){\n    if (cfg.theme === 'extended_cards') {\n      return renderExtendedCards(rows);\n    }\n\n    let html = '<div class=\"tp-cardlist\">';\n    rows.forEach(r=>{\n      const dow   = WD[r.dep.getDay()] || '';\n      const times = hhmm(r.dep) + ' <span class=\"tp-arrow\">\u2192<\/span> ' + hhmm(r.arr);\n      html += '<div class=\"tp-card\">'+boostersHtml(r, true)+\n        \/\/ Row 1: Date + weekday + times\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\"><span class=\"tp-sub\">'+dShort(r.dep)+'<\/span><span class=\"tp-day\">'+dow+'<\/span><\/div>'+\n          '<div class=\"rhs\"><span class=\"tp-time\">'+times+'<\/span><\/div>'+\n        '<\/div>';\n\n      if (showShip) {\n        html +=\n        \/\/ Row 2: Ship\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\">'+shipBadge(r.ship)+'<\/div>'+\n          '<div class=\"rhs\"><\/div>'+\n        '<\/div>';\n      }\n\n      html +=\n        \/\/ Row 3: Operator + route label\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\">'+opCell(r)+'<\/div>'+\n          '<div class=\"rhs\"><span class=\"tp-route-ticket\">'+routeTicketHtml(routeLabel(r.routeId))+'<\/span><\/div>'+\n        '<\/div>'+\n      '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  function renderExtendedCards(rows){\n    const ctaText = L.more_link || 'More sailings';\n    let html = '<div class=\"tp-cardlist\">';\n    rows.forEach(r=>{\n      const dow = WD[r.dep.getDay()] || '';\n      const link = r.opLink ? ('<a class=\"tp-ext-cta\" href=\"'+r.opLink+'\" target=\"_blank\" rel=\"nofollow noopener\">'+ctaText+' <span class=\"tp-ext-cta-arrow\">\u00bb<\/span><\/a>') : '<span class=\"tp-ext-cta\">'+ctaText+' <span class=\"tp-ext-cta-arrow\">\u00bb<\/span><\/span>';\n      html += '<div class=\"tp-ext-card\">'\n        + boostersHtml(r, true)\n        + '<div class=\"tp-ext-left\">'\n        +   '<div>'+opCell(r)+'<\/div>'\n        +   (showShip ? ('<div>'+shipBadge(r.ship)+'<\/div>') : '')\n        + '<\/div>'\n        + '<div class=\"tp-ext-mid\">'\n        +   '<div class=\"tp-ext-top\"><span class=\"tp-sub\">'+dShort(r.dep)+' <span class=\"tp-day\">'+dow+'<\/span><\/span><span class=\"tp-ext-dur\">'+dur(r.min)+'<\/span><\/div>'\n        +   '<div class=\"tp-ext-times\"><span class=\"tp-ext-time\">'+hhmm(r.dep)+'<\/span><span class=\"tp-ext-line\"><\/span><span class=\"tp-ext-dur\">'+dur(r.min)+'<\/span><span class=\"tp-ext-line\"><\/span><span class=\"tp-ext-time\">'+hhmm(r.arr)+'<\/span><\/div>'\n        +   '<div class=\"tp-ext-route\">'+routeLabel(r.routeId)+'<\/div>'\n        + '<\/div>'\n        + '<div class=\"tp-ext-right\">'+link+'<\/div>'\n        + '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  \/\/ Safe fetch helper\n  async function fetchOne(routeId, from, to){\n    try{\n      const url = new URL(cfg.rest);\n      url.searchParams.set('route', String(routeId));\n      url.searchParams.set('from', from);\n      url.searchParams.set('to', to);\n      const res = await fetch(url.toString(), {credentials:'same-origin'});\n      if(!res.ok) return { rid: routeId, error: 'HTTP '+res.status };\n      const json = await res.json();\n      const list = (json && json.data && Array.isArray(json.data.rows)) ? json.data.rows : [];\n      return { rid: routeId, rows: list };\n    }catch(e){\n      return { rid: routeId, error: String(e && e.message ? e.message : e) };\n    }\n  }\n\n  async function load(){\n    btn.disabled = true; setLoader(true); status.textContent = L.status_loading;\n\n    const start = new Date(dateEl.value || new Date());\n    const days  = (daySetup === 'modern') ? 1 : Math.max(1, parseInt(daysEl.value,10)||1);\n    const end   = new Date(start); end.setDate(start.getDate()+days-1);\n    const fromIso = iso(start), toIso = iso(end);\n\n    try{\n      const results  = await Promise.all((cfg.routes||[]).map(rid=>fetchOne(rid, fromIso, toIso)));\n      const oks  = results.filter(r => !r.error);\n      const errs = results.filter(r =>  r.error);\n\n      const all = [];\n      oks.forEach(({rid, rows})=>{\n        rows.forEach(t=>{\n          all.push({\n            routeId: rid,\n            opId: t.operatorId || null,\n            opName: t.operatorName || '',\n            opLogo: t.operatorLogo || '',\n            opLink: t.operatorLink || '',\n            dep: toLocal(t.departureTime),\n            arr: toLocal(t.arrivalTime),\n            min: t.durationInMinutes || 0,\n            ship: t.shipName || ''\n          });\n        });\n      });\n\n      let rows = all;\n      if (Array.isArray(cfg.opFilter) && cfg.opFilter.length>0) {\n        rows = all.filter(r => r.opId && cfg.opFilter.includes(String(r.opId)));\n      }\n\n      rows.sort((a,b)=> a.dep - b.dep);\n\n      const todayStr = new Date().toDateString();\n      const nowMs = Date.now();\n      const arrivedToday = rows\n        .filter(r => (r.dep instanceof Date) && (r.arr instanceof Date) && r.dep.toDateString() === todayStr && r.arr.getTime() <= nowMs)\n        .sort((a,b) => b.arr - a.arr);\n      if (arrivedToday.length > 2) {\n        const keep = new Set(arrivedToday.slice(0,2).map(rowKey));\n        rows = rows.filter(r => {\n          const isArrivedToday = (r.dep instanceof Date) && (r.arr instanceof Date) && r.dep.toDateString() === todayStr && r.arr.getTime() <= nowMs;\n          return !isArrivedToday || keep.has(rowKey(r));\n        });\n      }\n\n      const total = rows.length;\n      if (total===0){\n        status.textContent = L.status_empty + (errs.length ? ' (some routes returned no data or errors)' : '');\n        clearStatusInline();\n        out.innerHTML='';\n        setLoader(false); btn.disabled=false; return;\n      }\n\n      const visibleRows = (limit10 && !revealAll && rows.length > 10) ? rows.slice(0,10) : rows;\n      const hiddenCount = rows.length - visibleRows.length;\n      soonKey = pickSoonKey(visibleRows);\n      featuredKey = pickFeaturedKey(visibleRows, soonKey);\n\n      status.textContent = errs.length ? ('Skipped '+errs.length+' route'+(errs.length>1?'s':'')) : '';\n      setStatusInline(\n  (L.status_found || '%d sailings found').replace('%d', '<strong>'+total+'<\/strong>')\n);\n      out.innerHTML = renderTable(visibleRows) + renderCards(visibleRows) + moreButtonHtml(hiddenCount);\n      bindRowLinks();\n      if (navHost) navHost.innerHTML = navHtml();\n\n    } catch(e){\n      status.textContent = 'Failed to load data';\n      out.innerHTML = '<pre>'+String(e.message||e)+'<\/pre>';\n    } finally {\n      setLoader(false);\n      btn.disabled = false;\n    }\n  }\n\n  wrap.addEventListener('click', function(e){\n    const nav = e.target.closest('.tp-day-nav a[data-shift]');\n    if (nav) {\n      e.preventDefault();\n      shiftDate(parseInt(nav.getAttribute('data-shift'),10) || 0);\n      return;\n    }\n    const more = e.target.closest('.tp-more-btn');\n    if (more) {\n      e.preventDefault();\n      revealAll = true;\n      load();\n    }\n  });\n\n  btn.addEventListener('click', load);\n  if (navHost) navHost.innerHTML = navHtml();\n  renderLocalTimes();\n  setInterval(renderLocalTimes, 30000);\n  if (cfg.autoload) load();\n})();\n<\/script>\n<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ca4e0d8 elementor-widget elementor-widget-text-editor\" data-id=\"ca4e0d8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Innan du v\u00e4ljer avg\u00e5ng<\/h2>\n<div class=\"after-timetable-facts\">\n<div><strong>\u00d6verfartstid<\/strong>\nF\u00e4rjan mellan Puttgarden och R\u00f8dby tar cirka 45 minuter.<\/div>\n<div><strong>Check-in<\/strong>\nVar i hamnen minst 15 minuter f\u00f6re avg\u00e5ng.<\/div>\n<div><strong>Avg\u00e5ngar<\/strong>\nRutten trafikeras dygnet runt, ofta med avg\u00e5ngar var 30:e minut.<\/div>\n<\/div>\n<h2>F\u00e4rjebiljetter Puttgarden R\u00f8dby<\/h2>\nN\u00e4r du har valt en avg\u00e5ng kan du boka biljetten via Scandlines. Priset beror p\u00e5 fordon, biljettvariant, resedag och vald avg\u00e5ng.\n\n<a class=\"scandlines-booking-button\" href=\"https:\/\/puttgardenrodby.com\/se\/go\/pages-side\" target=\"_blank\" rel=\"noopener\">\n<span class=\"scandlines-button-logo\">\n<img decoding=\"async\" src=\"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2026\/06\/scandlines-logo-e1781018744673.jpg\" alt=\"Scandlines\" \/>\n<\/span>\n<span class=\"scandlines-button-text\">\n<strong>Boka f\u00e4rjan hos Scandlines<\/strong>\n<small>Puttgarden \u21c4 R\u00f8dby<\/small>\n<\/span>\n<span class=\"scandlines-button-arrow\">\u2b9e<\/span>\n<\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-9a29147\" data-id=\"9a29147\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-de19ae8 elementor-widget elementor-widget-text-editor\" data-id=\"de19ae8\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;sticky&quot;:&quot;top&quot;,&quot;sticky_parent&quot;:&quot;yes&quot;,&quot;sticky_offset&quot;:100,&quot;sticky_effects_offset&quot;:60,&quot;sticky_on&quot;:[&quot;desktop&quot;,&quot;tablet&quot;,&quot;mobile&quot;],&quot;sticky_anchor_link_offset&quot;:0}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<aside class=\"timetable-sidebar\">\n  <div class=\"sidebar-card sidebar-card-image\">\n    <img loading=\"lazy\" loading=\"lazy\" decoding=\"async\" class=\"sidebar-image alignnone size-full wp-image-132\" src=\"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2022\/04\/Puttgarden.png\" alt=\"Puttgarden f\u00e4rjehamn\" width=\"400\" height=\"300\" srcset=\"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2022\/04\/Puttgarden.png 400w, https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2022\/04\/Puttgarden-300x225.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/>\n  <\/div>\n\n  <div class=\"sidebar-card\">\n    <h3>Snabbfakta<\/h3>\n    <ul>\n      <li><strong>Rutt:<\/strong> Puttgarden \u21c4 R\u00f8dby<\/li>\n      <li><strong>Operat\u00f6r:<\/strong> Scandlines<\/li>\n      <li><strong>\u00d6verfart:<\/strong> cirka 45 minuter<\/li>\n      <li><strong>Check-in:<\/strong> minst 15 minuter f\u00f6re avg\u00e5ng<\/li>\n    <\/ul>\n  <\/div>\n\n  <div class=\"sidebar-card\">\n    <h3>Popul\u00e4rt<\/h3>\n    <ul>\n      <li><a href=\"\/se\/priser\/\">F\u00e4rjpriser &amp; biljetter<\/a><\/li>\n      <li><a href=\"\/se\/vader\/\">V\u00e4der vid f\u00e4rjan<\/a><\/li>\n      <li><a href=\"\/se\/webcams\/\">Webcams Puttgarden R\u00f8dby<\/a><\/li>\n      <li><a href=\"\/se\/puttgarden\/\">Puttgarden hamn<\/a><\/li>\n      <li><a href=\"\/se\/rodby\/\">R\u00f8dby hamn<\/a><\/li>\n    <\/ul>\n  <\/div>\n\n  <div class=\"sidebar-card sidebar-cta\">\n    <h3>Boka f\u00e4rjan<\/h3>\n    <p>J\u00e4mf\u00f6r tider och v\u00e4lj din avg\u00e5ng hos Scandlines.<\/p>\n    <a href=\"https:\/\/puttgardenrodby.com\/se\/go\/pages-side\" target=\"_blank\" rel=\"noopener\">S\u00e4tt ihop din \u00f6verfart \u2b9e<\/a>\n  <\/div>\n<\/aside>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Puttgarden R\u00f8dby tidtabell H\u00e4r hittar du tidtabell och avg\u00e5ngar f\u00f6r f\u00e4rjan Puttgarden\u2013R\u00f8dby och R\u00f8dby\u2013Puttgarden. V\u00e4lj datum och klicka p\u00e5 Visa avg\u00e5ngar f\u00f6r att se f\u00e4rjetiderna f\u00f6r vald dag. Rutt Puttgarden \u21c4 R\u00f8dby Operat\u00f6r Scandlines \u00d6verfart cirka 45 minuter Avg\u00e5ngar ungef\u00e4r var 30:e minut F\u00e4rjetidtabell Puttgarden R\u00f8dby F\u00e4rjetidtabell R\u00f8dby Puttgarden Innan du v\u00e4ljer avg\u00e5ng \u00d6verfartstid F\u00e4rjan [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"footnotes":""},"class_list":["post-651","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.9 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Puttgarden R\u00f8dby tidtabell | F\u00e4rja avg\u00e5ngar &amp; tider<\/title>\n<meta name=\"description\" content=\"Kontrollera tidtabellen f\u00f6r Puttgarden-R\u00f8dby-f\u00e4rjan p\u00e5 PuttgardenRodby.com. Alla avg\u00e5ngstider f\u00f6r denna f\u00e4rje\u00f6verfart.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/puttgardenrodby.com\/se\/tidtabell\/\" \/>\n<meta property=\"og:locale\" content=\"sv_SE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Puttgarden R\u00f8dby tidtabell | F\u00e4rja avg\u00e5ngar &amp; tider\" \/>\n<meta property=\"og:description\" content=\"Kontrollera tidtabellen f\u00f6r Puttgarden-R\u00f8dby-f\u00e4rjan p\u00e5 PuttgardenRodby.com. Alla avg\u00e5ngstider f\u00f6r denna f\u00e4rje\u00f6verfart.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/puttgardenrodby.com\/se\/tidtabell\/\" \/>\n<meta property=\"og:site_name\" content=\"Puttgarden Rodby Svenska\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-24T12:46:01+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2026\/06\/scandlines-logo-e1781018744673.jpg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Ber\u00e4knad l\u00e4stid\" \/>\n\t<meta name=\"twitter:data1\" content=\"2 minuter\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/tidtabell\\\/\",\"url\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/tidtabell\\\/\",\"name\":\"Puttgarden R\u00f8dby tidtabell | F\u00e4rja avg\u00e5ngar & tider\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/tidtabell\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/tidtabell\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/06\\\/scandlines-logo-e1781018744673.jpg\",\"datePublished\":\"2023-05-11T11:56:09+00:00\",\"dateModified\":\"2026-06-24T12:46:01+00:00\",\"description\":\"Kontrollera tidtabellen f\u00f6r Puttgarden-R\u00f8dby-f\u00e4rjan p\u00e5 PuttgardenRodby.com. Alla avg\u00e5ngstider f\u00f6r denna f\u00e4rje\u00f6verfart.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/tidtabell\\\/#breadcrumb\"},\"inLanguage\":\"sv-SE\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/tidtabell\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"sv-SE\",\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/tidtabell\\\/#primaryimage\",\"url\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/06\\\/scandlines-logo-e1781018744673.jpg\",\"contentUrl\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/06\\\/scandlines-logo-e1781018744673.jpg\",\"width\":36,\"height\":36},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/tidtabell\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tidtabell\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/#website\",\"url\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/\",\"name\":\"Puttgarden Rodby Svenska\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"sv-SE\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/#organization\",\"name\":\"Puttgarden Rodby Svenska\",\"url\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"sv-SE\",\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2023\\\/05\\\/Puttgarden-Rodby-logo.png\",\"contentUrl\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2023\\\/05\\\/Puttgarden-Rodby-logo.png\",\"width\":1043,\"height\":347,\"caption\":\"Puttgarden Rodby Svenska\"},\"image\":{\"@id\":\"https:\\\/\\\/puttgardenrodby.com\\\/se\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Puttgarden R\u00f8dby tidtabell | F\u00e4rja avg\u00e5ngar & tider","description":"Kontrollera tidtabellen f\u00f6r Puttgarden-R\u00f8dby-f\u00e4rjan p\u00e5 PuttgardenRodby.com. Alla avg\u00e5ngstider f\u00f6r denna f\u00e4rje\u00f6verfart.","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:\/\/puttgardenrodby.com\/se\/tidtabell\/","og_locale":"sv_SE","og_type":"article","og_title":"Puttgarden R\u00f8dby tidtabell | F\u00e4rja avg\u00e5ngar & tider","og_description":"Kontrollera tidtabellen f\u00f6r Puttgarden-R\u00f8dby-f\u00e4rjan p\u00e5 PuttgardenRodby.com. Alla avg\u00e5ngstider f\u00f6r denna f\u00e4rje\u00f6verfart.","og_url":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/","og_site_name":"Puttgarden Rodby Svenska","article_modified_time":"2026-06-24T12:46:01+00:00","og_image":[{"url":"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2026\/06\/scandlines-logo-e1781018744673.jpg","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_misc":{"Ber\u00e4knad l\u00e4stid":"2 minuter"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/","url":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/","name":"Puttgarden R\u00f8dby tidtabell | F\u00e4rja avg\u00e5ngar & tider","isPartOf":{"@id":"https:\/\/puttgardenrodby.com\/se\/#website"},"primaryImageOfPage":{"@id":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/#primaryimage"},"image":{"@id":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/#primaryimage"},"thumbnailUrl":"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2026\/06\/scandlines-logo-e1781018744673.jpg","datePublished":"2023-05-11T11:56:09+00:00","dateModified":"2026-06-24T12:46:01+00:00","description":"Kontrollera tidtabellen f\u00f6r Puttgarden-R\u00f8dby-f\u00e4rjan p\u00e5 PuttgardenRodby.com. Alla avg\u00e5ngstider f\u00f6r denna f\u00e4rje\u00f6verfart.","breadcrumb":{"@id":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/#breadcrumb"},"inLanguage":"sv-SE","potentialAction":[{"@type":"ReadAction","target":["https:\/\/puttgardenrodby.com\/se\/tidtabell\/"]}]},{"@type":"ImageObject","inLanguage":"sv-SE","@id":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/#primaryimage","url":"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2026\/06\/scandlines-logo-e1781018744673.jpg","contentUrl":"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2026\/06\/scandlines-logo-e1781018744673.jpg","width":36,"height":36},{"@type":"BreadcrumbList","@id":"https:\/\/puttgardenrodby.com\/se\/tidtabell\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/puttgardenrodby.com\/se\/"},{"@type":"ListItem","position":2,"name":"Tidtabell"}]},{"@type":"WebSite","@id":"https:\/\/puttgardenrodby.com\/se\/#website","url":"https:\/\/puttgardenrodby.com\/se\/","name":"Puttgarden Rodby Svenska","description":"","publisher":{"@id":"https:\/\/puttgardenrodby.com\/se\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/puttgardenrodby.com\/se\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"sv-SE"},{"@type":"Organization","@id":"https:\/\/puttgardenrodby.com\/se\/#organization","name":"Puttgarden Rodby Svenska","url":"https:\/\/puttgardenrodby.com\/se\/","logo":{"@type":"ImageObject","inLanguage":"sv-SE","@id":"https:\/\/puttgardenrodby.com\/se\/#\/schema\/logo\/image\/","url":"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2023\/05\/Puttgarden-Rodby-logo.png","contentUrl":"https:\/\/puttgardenrodby.com\/se\/wp-content\/uploads\/sites\/2\/2023\/05\/Puttgarden-Rodby-logo.png","width":1043,"height":347,"caption":"Puttgarden Rodby Svenska"},"image":{"@id":"https:\/\/puttgardenrodby.com\/se\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/puttgardenrodby.com\/se\/wp-json\/wp\/v2\/pages\/651","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/puttgardenrodby.com\/se\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/puttgardenrodby.com\/se\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/puttgardenrodby.com\/se\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/puttgardenrodby.com\/se\/wp-json\/wp\/v2\/comments?post=651"}],"version-history":[{"count":44,"href":"https:\/\/puttgardenrodby.com\/se\/wp-json\/wp\/v2\/pages\/651\/revisions"}],"predecessor-version":[{"id":1294,"href":"https:\/\/puttgardenrodby.com\/se\/wp-json\/wp\/v2\/pages\/651\/revisions\/1294"}],"wp:attachment":[{"href":"https:\/\/puttgardenrodby.com\/se\/wp-json\/wp\/v2\/media?parent=651"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}