{"id":7261,"date":"2024-06-10T11:54:03","date_gmt":"2024-06-10T11:54:03","guid":{"rendered":"https:\/\/calais-dover.com\/?page_id=7261"},"modified":"2026-10-27T14:49:21","modified_gmt":"2026-10-27T14:49:21","slug":"orari","status":"publish","type":"page","link":"https:\/\/calais-dover.com\/it\/orari\/","title":{"rendered":"Orari traghetti Calais Dover"},"content":{"rendered":"\n<div class=\"wp-block-group cd-page is-layout-flow wp-block-group-is-layout-flow\">\n\n<p class=\"cd-intro wp-block-paragraph\"><strong>Secondo gli orari, il traghetto da Calais a Dover impiega circa 90 minuti. P&amp;O Ferries, DFDS e Irish Ferries partono insieme circa 40 volte al giorno, anche di notte. Le Shuttle nel tunnel della Manica impiega 35 minuti fino a Folkestone. Qui sotto trovi tutte le partenze di oggi.<\/strong><\/p>\n\n\n<p class=\"wp-block-paragraph\">Attenzione al fuso orario: in Inghilterra \u00e8 un&#8217;ora prima che in Francia e in Italia. Se parti da Calais alle 10.00 ora francese, arrivi a Dover verso le 10.30 ora inglese. Ritardo o cancellazione? Tutte le fonti ufficiali sono nella nostra pagina <a href=\"https:\/\/calais-dover.com\/it\/sailing-updates\/\">ritardi e cancellazioni<\/a>. Una panoramica di prezzi e compagnie \u00e8 nella nostra pagina <a href=\"https:\/\/calais-dover.com\/it\/\">traghetto Calais-Dover<\/a>.<\/p>\n\n\n<div class=\"wp-block-group alignfull cd-subnav is-layout-flow wp-block-group-is-layout-flow\">\n<ul class=\"wp-block-list\">\n<li><a href=\"#orari-calais-dover\">Traghetto Calais-Dover<\/a><\/li>\n\n<li><a href=\"#orari-dover-calais\">Traghetto Dover-Calais<\/a><\/li>\n\n<li><a href=\"#le-shuttle-calais-folkestone\">Le Shuttle Calais-Folkestone<\/a><\/li>\n\n<li><a href=\"#le-shuttle-folkestone-calais\">Le Shuttle Folkestone-Calais<\/a><\/li>\n\n<li><a href=\"#check-in\">Check-in<\/a><\/li>\n<\/ul>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"orari-calais-dover\">Orari traghetti Calais-Dover di oggi<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Qui sotto vedi le partenze da Calais e l&#8217;arrivo previsto a Dover. Mostriamo un giorno, ma puoi scegliere anche un&#8217;altra data. Come funziona la traversata con ogni compagnia lo leggi nelle nostre pagine su <a href=\"https:\/\/calais-dover.com\/it\/p-o-ferries\/\">P&amp;O Ferries<\/a>, <a href=\"https:\/\/calais-dover.com\/it\/dfds\/\">DFDS<\/a> e <a href=\"https:\/\/calais-dover.com\/it\/irish-ferries\/\">Irish Ferries<\/a>.<\/p>\n\n<div class=\"tp-wrap tp-theme-extended_cards tp-day-setup-modern\" data-config=\"{&quot;rest&quot;:&quot;https:\\\/\\\/calais-dover.com\\\/it\\\/wp-json\\\/timetables-pro\\\/v1\\\/timetables&quot;,&quot;route&quot;:97,&quot;days&quot;:1,&quot;autoload&quot;:true,&quot;theme&quot;:&quot;extended_cards&quot;,&quot;daySetup&quot;:&quot;modern&quot;,&quot;limit10&quot;:true,&quot;label&quot;:&quot;Calais - Dover&quot;,&quot;labels&quot;:{&quot;ui_date&quot;:&quot;Data&quot;,&quot;ui_days&quot;:&quot;Giorni&quot;,&quot;ui_button&quot;:&quot;Mostra partenze&quot;,&quot;status_idle&quot;:&quot;Scegli una data e clicca su Mostra partenze&quot;,&quot;status_loading&quot;:&quot;Caricamento...&quot;,&quot;status_empty&quot;:&quot;Nessuna partenza trovata&quot;,&quot;status_found&quot;:&quot;%d partenze trovate&quot;,&quot;th_date&quot;:&quot;Data&quot;,&quot;th_dep&quot;:&quot;Partenza&quot;,&quot;th_arr&quot;:&quot;Arrivo&quot;,&quot;th_dur&quot;:&quot;Durata&quot;,&quot;th_ship&quot;:&quot;Nave&quot;,&quot;th_op&quot;:&quot;Operatore&quot;,&quot;th_route&quot;:&quot;Rotta&quot;,&quot;wd_sun&quot;:&quot;DOM&quot;,&quot;wd_mon&quot;:&quot;LUN&quot;,&quot;wd_tue&quot;:&quot;MAR&quot;,&quot;wd_wed&quot;:&quot;MER&quot;,&quot;wd_thu&quot;:&quot;GIO&quot;,&quot;wd_fri&quot;:&quot;VEN&quot;,&quot;wd_sat&quot;:&quot;SAB&quot;,&quot;summary_footer_one&quot;:&quot;\\u00bb Controlla tutte le partenze %s nel nostro orario&quot;,&quot;summary_footer_two&quot;:&quot;\\u00bb Controlla altre partenze %1$s e %2$s nel nostro orario&quot;,&quot;summary_footer_generic&quot;:&quot;Consulta il nostro orario per altre partenze&quot;,&quot;summary_header&quot;:&quot;Le prossime due partenze:&quot;,&quot;summary_no_upcoming&quot;:&quot;Nessuna partenza imminente trovata&quot;,&quot;more_link&quot;:&quot;Altre partenze&quot;,&quot;more_departures_button&quot;:&quot;Mostra altre partenze&quot;,&quot;day_nav_previous&quot;:&quot;Mostra giorno precedente&quot;,&quot;day_nav_next&quot;:&quot;Mostra giorno successivo&quot;,&quot;day_nav_today&quot;:&quot;Mostra oggi&quot;,&quot;day_nav_tomorrow&quot;:&quot;Mostra domani&quot;,&quot;local_time_pair&quot;:&quot;Orario locale porto di partenza: %1$s \\\/ Orario locale porto di arrivo: %2$s&quot;,&quot;local_time_combined&quot;:&quot;Orario locale porto di partenza e arrivo: %s&quot;,&quot;tag_often_booked&quot;:&quot;\\u2b50 Spesso prenotato&quot;,&quot;tag_leaving_soon&quot;:&quot;\\ud83d\\udd34 In partenza presto&quot;,&quot;tag_currently_sailing&quot;:&quot;\\ud83d\\udfe2 In navigazione&quot;,&quot;tag_arrived&quot;:&quot;\\u26ab Arrivato&quot;,&quot;tag_overnight&quot;:&quot;Notturno&quot;},&quot;showLogo&quot;:true,&quot;activityBoosters&quot;:true,&quot;shipMap&quot;:{&quot;p&amp;o ferries&quot;:&quot;P&amp;O Ferries&quot;,&quot;dfds&quot;:&quot;DFDS&quot;,&quot;irish ferries&quot;:&quot;Irish Ferries&quot;,&quot;norfolk line&quot;:&quot;DFDS&quot;},&quot;shipLinks&quot;:[],&quot;showShip&quot;:true,&quot;departurePort&quot;:&quot;Calais&quot;,&quot;arrivalPort&quot;:&quot;Dover&quot;,&quot;departureTimezone&quot;:&quot;Europe\\\/Paris&quot;,&quot;arrivalTimezone&quot;:&quot;Europe\\\/London&quot;}\">\n  <div class=\"tp-controls\" role=\"group\" aria-label=\"Timetable controls\">\n    <div>\n      <label for=\"tp-date\">Data<\/label><br>\n      <input id=\"tp-date\" class=\"tp-date\" type=\"date\" aria-label=\"Data\">\n    <\/div>\n    <div class=\"tp-day-field\">\n      <label for=\"tp-range\">Giorni<\/label><br>\n      <select id=\"tp-range\" class=\"tp-range\" aria-label=\"Giorni\">\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\" class=\"tp-btn\">Mostra partenze<\/button><\/div>\n  <\/div>\n\n  <div class=\"tp-local-nav-row\">\n    <div class=\"tp-local-times\" id=\"tp-local-times\" aria-live=\"polite\"><\/div>\n    <div class=\"tp-day-nav-host\"><\/div>\n  <\/div>\n  <div id=\"tp-status\" class=\"tp-muted\" aria-live=\"polite\">Scegli una data e clicca su Mostra partenze<\/div>\n  <div id=\"tp-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\">Caricamento...<\/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');\n  const daysEl = wrap.querySelector('#tp-range');\n  const btn    = wrap.querySelector('#tp-load');\n  const status = wrap.querySelector('#tp-status');\n  const out    = wrap.querySelector('#tp-results');\n  const loader = wrap.querySelector('.tp-loader');\n  const controls = wrap.querySelector('.tp-controls');\n  const navHost = wrap.querySelector('.tp-day-nav-host');\n  const localTimesEl = wrap.querySelector('#tp-local-times');\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'}); } \/\/ short, no year\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      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.opId||''), String(+r.dep||0), String(+r.arr||0), String(r.ship||'')].join('|');\n  }\n\n  function pickFeaturedKey(rows, avoidKey){\n    if (!activityBoosters || !rows.length) return '';\n    const routeSeed = parseInt(cfg.route, 10) || 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((routeSeed + 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 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,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.op+'<\/th>');\n\n    let html = '<table class=\"tp-table\"><thead><tr>'+headCells.join('')+'<\/tr><\/thead><tbody>';\n\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 cells = [\n        '<td>'+dShort(r.dep)+' <span class=\"tp-day\">'+dow+'<\/span>'+boostersHtml(r, false)+'<\/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>'+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    const routeName = cfg.label || '';\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\">'+(showShip ? shipBadge(r.ship) : '')+'<\/div>'+\n          '<div class=\"rhs\"><\/div>'+\n        '<\/div>';\n      }\n\n      html +=\n        \/\/ Row 3: Operator + route label (no book button)\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\">'+opCell(r)+'<\/div>'+\n          (routeName ? ('<div class=\"rhs\"><span class=\"tp-route-ticket\">'+routeTicketHtml(routeName)+'<\/span><\/div>') : '<div class=\"rhs\"><\/div>')+\n        '<\/div>'+\n      '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  function renderExtendedCards(rows){\n    const routeName = cfg.label || '';\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        +   (routeName ? ('<div class=\"tp-ext-route\">'+routeName+'<\/div>') : '')\n        + '<\/div>'\n        + '<div class=\"tp-ext-right\">'+link+'<\/div>'\n        + '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  async function load(){\n    btn.disabled = true; setLoader(true); status.textContent = L.status_loading;\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 url = new URL(cfg.rest); url.searchParams.set('route', String(cfg.route));\n    url.searchParams.set('from', iso(start)); url.searchParams.set('to', iso(end));\n    try{\n      const res = await fetch(url.toString(), {credentials:'same-origin'});\n      if(!res.ok) throw new 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      let rows = list.map(t=>({\n        opId:t.operatorId||null, opName:t.operatorName||'', opLogo:t.operatorLogo||'', opLink:t.operatorLink||'',\n        dep:toLocal(t.departureTime), arr:toLocal(t.arrivalTime), min:t.durationInMinutes||0, ship:t.shipName||''\n      })).sort((a,b)=>a.dep-b.dep);\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      if(rows.length===0){ status.textContent = L.status_empty; clearStatusInline(); out.innerHTML=''; return; }\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      status.textContent = '';\n      setStatusInline(\n  (L.status_found || '%d sailings found').replace('%d', '<strong>'+rows.length+'<\/strong>')\n);\n      out.innerHTML = renderTable(visibleRows) + renderCards(visibleRows) + moreButtonHtml(hiddenCount);\n      bindRowLinks();\n      if (navHost) navHost.innerHTML = navHtml();\n    }catch(e){\n      status.textContent = 'Failed to load data'; out.innerHTML = '<pre>'+String(e.message||e)+'<\/pre>';\n    }finally{ setLoader(false); btn.disabled=false; }\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\n\n\n<h2 class=\"wp-block-heading\" id=\"orari-dover-calais\">Orari traghetti Dover-Calais<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Questa tabella mostra le partenze da Dover. All&#8217;arrivo in Francia \u00e8 un&#8217;ora pi\u00f9 tardi che in Inghilterra. Non sai ancora con quale compagnia? Abbiamo viaggiato con tutte e tre e le abbiamo valutate nel nostro <a href=\"https:\/\/calais-dover.com\/it\/conrontare\/\">confronto delle compagnie<\/a>.<\/p>\n\n<div class=\"tp-wrap tp-theme-extended_cards tp-day-setup-modern\" data-config=\"{&quot;rest&quot;:&quot;https:\\\/\\\/calais-dover.com\\\/it\\\/wp-json\\\/timetables-pro\\\/v1\\\/timetables&quot;,&quot;route&quot;:98,&quot;days&quot;:1,&quot;autoload&quot;:true,&quot;theme&quot;:&quot;extended_cards&quot;,&quot;daySetup&quot;:&quot;modern&quot;,&quot;limit10&quot;:true,&quot;label&quot;:&quot;Dover - Calais&quot;,&quot;labels&quot;:{&quot;ui_date&quot;:&quot;Data&quot;,&quot;ui_days&quot;:&quot;Giorni&quot;,&quot;ui_button&quot;:&quot;Mostra partenze&quot;,&quot;status_idle&quot;:&quot;Scegli una data e clicca su Mostra partenze&quot;,&quot;status_loading&quot;:&quot;Caricamento...&quot;,&quot;status_empty&quot;:&quot;Nessuna partenza trovata&quot;,&quot;status_found&quot;:&quot;%d partenze trovate&quot;,&quot;th_date&quot;:&quot;Data&quot;,&quot;th_dep&quot;:&quot;Partenza&quot;,&quot;th_arr&quot;:&quot;Arrivo&quot;,&quot;th_dur&quot;:&quot;Durata&quot;,&quot;th_ship&quot;:&quot;Nave&quot;,&quot;th_op&quot;:&quot;Operatore&quot;,&quot;th_route&quot;:&quot;Rotta&quot;,&quot;wd_sun&quot;:&quot;DOM&quot;,&quot;wd_mon&quot;:&quot;LUN&quot;,&quot;wd_tue&quot;:&quot;MAR&quot;,&quot;wd_wed&quot;:&quot;MER&quot;,&quot;wd_thu&quot;:&quot;GIO&quot;,&quot;wd_fri&quot;:&quot;VEN&quot;,&quot;wd_sat&quot;:&quot;SAB&quot;,&quot;summary_footer_one&quot;:&quot;\\u00bb Controlla tutte le partenze %s nel nostro orario&quot;,&quot;summary_footer_two&quot;:&quot;\\u00bb Controlla altre partenze %1$s e %2$s nel nostro orario&quot;,&quot;summary_footer_generic&quot;:&quot;Consulta il nostro orario per altre partenze&quot;,&quot;summary_header&quot;:&quot;Le prossime due partenze:&quot;,&quot;summary_no_upcoming&quot;:&quot;Nessuna partenza imminente trovata&quot;,&quot;more_link&quot;:&quot;Altre partenze&quot;,&quot;more_departures_button&quot;:&quot;Mostra altre partenze&quot;,&quot;day_nav_previous&quot;:&quot;Mostra giorno precedente&quot;,&quot;day_nav_next&quot;:&quot;Mostra giorno successivo&quot;,&quot;day_nav_today&quot;:&quot;Mostra oggi&quot;,&quot;day_nav_tomorrow&quot;:&quot;Mostra domani&quot;,&quot;local_time_pair&quot;:&quot;Orario locale porto di partenza: %1$s \\\/ Orario locale porto di arrivo: %2$s&quot;,&quot;local_time_combined&quot;:&quot;Orario locale porto di partenza e arrivo: %s&quot;,&quot;tag_often_booked&quot;:&quot;\\u2b50 Spesso prenotato&quot;,&quot;tag_leaving_soon&quot;:&quot;\\ud83d\\udd34 In partenza presto&quot;,&quot;tag_currently_sailing&quot;:&quot;\\ud83d\\udfe2 In navigazione&quot;,&quot;tag_arrived&quot;:&quot;\\u26ab Arrivato&quot;,&quot;tag_overnight&quot;:&quot;Notturno&quot;},&quot;showLogo&quot;:true,&quot;activityBoosters&quot;:true,&quot;shipMap&quot;:{&quot;p&amp;o ferries&quot;:&quot;P&amp;O Ferries&quot;,&quot;dfds&quot;:&quot;DFDS&quot;,&quot;irish ferries&quot;:&quot;Irish Ferries&quot;,&quot;norfolk line&quot;:&quot;DFDS&quot;},&quot;shipLinks&quot;:[],&quot;showShip&quot;:true,&quot;departurePort&quot;:&quot;Dover&quot;,&quot;arrivalPort&quot;:&quot;Calais&quot;,&quot;departureTimezone&quot;:&quot;Europe\\\/London&quot;,&quot;arrivalTimezone&quot;:&quot;Europe\\\/Paris&quot;}\">\n  <div class=\"tp-controls\" role=\"group\" aria-label=\"Timetable controls\">\n    <div>\n      <label for=\"tp-date\">Data<\/label><br>\n      <input id=\"tp-date\" class=\"tp-date\" type=\"date\" aria-label=\"Data\">\n    <\/div>\n    <div class=\"tp-day-field\">\n      <label for=\"tp-range\">Giorni<\/label><br>\n      <select id=\"tp-range\" class=\"tp-range\" aria-label=\"Giorni\">\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\" class=\"tp-btn\">Mostra partenze<\/button><\/div>\n  <\/div>\n\n  <div class=\"tp-local-nav-row\">\n    <div class=\"tp-local-times\" id=\"tp-local-times\" aria-live=\"polite\"><\/div>\n    <div class=\"tp-day-nav-host\"><\/div>\n  <\/div>\n  <div id=\"tp-status\" class=\"tp-muted\" aria-live=\"polite\">Scegli una data e clicca su Mostra partenze<\/div>\n  <div id=\"tp-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\">Caricamento...<\/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');\n  const daysEl = wrap.querySelector('#tp-range');\n  const btn    = wrap.querySelector('#tp-load');\n  const status = wrap.querySelector('#tp-status');\n  const out    = wrap.querySelector('#tp-results');\n  const loader = wrap.querySelector('.tp-loader');\n  const controls = wrap.querySelector('.tp-controls');\n  const navHost = wrap.querySelector('.tp-day-nav-host');\n  const localTimesEl = wrap.querySelector('#tp-local-times');\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'}); } \/\/ short, no year\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      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.opId||''), String(+r.dep||0), String(+r.arr||0), String(r.ship||'')].join('|');\n  }\n\n  function pickFeaturedKey(rows, avoidKey){\n    if (!activityBoosters || !rows.length) return '';\n    const routeSeed = parseInt(cfg.route, 10) || 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((routeSeed + 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 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,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.op+'<\/th>');\n\n    let html = '<table class=\"tp-table\"><thead><tr>'+headCells.join('')+'<\/tr><\/thead><tbody>';\n\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 cells = [\n        '<td>'+dShort(r.dep)+' <span class=\"tp-day\">'+dow+'<\/span>'+boostersHtml(r, false)+'<\/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>'+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    const routeName = cfg.label || '';\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\">'+(showShip ? shipBadge(r.ship) : '')+'<\/div>'+\n          '<div class=\"rhs\"><\/div>'+\n        '<\/div>';\n      }\n\n      html +=\n        \/\/ Row 3: Operator + route label (no book button)\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\">'+opCell(r)+'<\/div>'+\n          (routeName ? ('<div class=\"rhs\"><span class=\"tp-route-ticket\">'+routeTicketHtml(routeName)+'<\/span><\/div>') : '<div class=\"rhs\"><\/div>')+\n        '<\/div>'+\n      '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  function renderExtendedCards(rows){\n    const routeName = cfg.label || '';\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        +   (routeName ? ('<div class=\"tp-ext-route\">'+routeName+'<\/div>') : '')\n        + '<\/div>'\n        + '<div class=\"tp-ext-right\">'+link+'<\/div>'\n        + '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  async function load(){\n    btn.disabled = true; setLoader(true); status.textContent = L.status_loading;\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 url = new URL(cfg.rest); url.searchParams.set('route', String(cfg.route));\n    url.searchParams.set('from', iso(start)); url.searchParams.set('to', iso(end));\n    try{\n      const res = await fetch(url.toString(), {credentials:'same-origin'});\n      if(!res.ok) throw new 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      let rows = list.map(t=>({\n        opId:t.operatorId||null, opName:t.operatorName||'', opLogo:t.operatorLogo||'', opLink:t.operatorLink||'',\n        dep:toLocal(t.departureTime), arr:toLocal(t.arrivalTime), min:t.durationInMinutes||0, ship:t.shipName||''\n      })).sort((a,b)=>a.dep-b.dep);\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      if(rows.length===0){ status.textContent = L.status_empty; clearStatusInline(); out.innerHTML=''; return; }\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      status.textContent = '';\n      setStatusInline(\n  (L.status_found || '%d sailings found').replace('%d', '<strong>'+rows.length+'<\/strong>')\n);\n      out.innerHTML = renderTable(visibleRows) + renderCards(visibleRows) + moreButtonHtml(hiddenCount);\n      bindRowLinks();\n      if (navHost) navHost.innerHTML = navHtml();\n    }catch(e){\n      status.textContent = 'Failed to load data'; out.innerHTML = '<pre>'+String(e.message||e)+'<\/pre>';\n    }finally{ setLoader(false); btn.disabled=false; }\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\n\n\n<h2 class=\"wp-block-heading\" id=\"le-shuttle-calais-folkestone\">Le Shuttle Calais-Folkestone<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Qui vedi le partenze di <a href=\"https:\/\/calais-dover.com\/it\/tunnel-della-manica\/\">Le Shuttle nel tunnel della Manica<\/a> da Calais\/Coquelles a Folkestone. \u00c8 il collegamento pi\u00f9 veloce su questa rotta per auto, moto, camper e furgoni.<\/p>\n\n<div class=\"tp-wrap tp-theme-extended_cards tp-day-setup-modern\" data-config=\"{&quot;rest&quot;:&quot;https:\\\/\\\/calais-dover.com\\\/it\\\/wp-json\\\/timetables-pro\\\/v1\\\/timetables&quot;,&quot;route&quot;:8,&quot;days&quot;:1,&quot;autoload&quot;:true,&quot;theme&quot;:&quot;extended_cards&quot;,&quot;daySetup&quot;:&quot;modern&quot;,&quot;limit10&quot;:true,&quot;label&quot;:&quot;Calais - Folkestone&quot;,&quot;labels&quot;:{&quot;ui_date&quot;:&quot;Data&quot;,&quot;ui_days&quot;:&quot;Giorni&quot;,&quot;ui_button&quot;:&quot;Mostra partenze&quot;,&quot;status_idle&quot;:&quot;Scegli una data e clicca su Mostra partenze&quot;,&quot;status_loading&quot;:&quot;Caricamento...&quot;,&quot;status_empty&quot;:&quot;Nessuna partenza trovata&quot;,&quot;status_found&quot;:&quot;%d partenze trovate&quot;,&quot;th_date&quot;:&quot;Data&quot;,&quot;th_dep&quot;:&quot;Partenza&quot;,&quot;th_arr&quot;:&quot;Arrivo&quot;,&quot;th_dur&quot;:&quot;Durata&quot;,&quot;th_ship&quot;:&quot;Nave&quot;,&quot;th_op&quot;:&quot;Operatore&quot;,&quot;th_route&quot;:&quot;Rotta&quot;,&quot;wd_sun&quot;:&quot;DOM&quot;,&quot;wd_mon&quot;:&quot;LUN&quot;,&quot;wd_tue&quot;:&quot;MAR&quot;,&quot;wd_wed&quot;:&quot;MER&quot;,&quot;wd_thu&quot;:&quot;GIO&quot;,&quot;wd_fri&quot;:&quot;VEN&quot;,&quot;wd_sat&quot;:&quot;SAB&quot;,&quot;summary_footer_one&quot;:&quot;\\u00bb Controlla tutte le partenze %s nel nostro orario&quot;,&quot;summary_footer_two&quot;:&quot;\\u00bb Controlla altre partenze %1$s e %2$s nel nostro orario&quot;,&quot;summary_footer_generic&quot;:&quot;Consulta il nostro orario per altre partenze&quot;,&quot;summary_header&quot;:&quot;Le prossime due partenze:&quot;,&quot;summary_no_upcoming&quot;:&quot;Nessuna partenza imminente trovata&quot;,&quot;more_link&quot;:&quot;Altre partenze&quot;,&quot;more_departures_button&quot;:&quot;Mostra altre partenze&quot;,&quot;day_nav_previous&quot;:&quot;Mostra giorno precedente&quot;,&quot;day_nav_next&quot;:&quot;Mostra giorno successivo&quot;,&quot;day_nav_today&quot;:&quot;Mostra oggi&quot;,&quot;day_nav_tomorrow&quot;:&quot;Mostra domani&quot;,&quot;local_time_pair&quot;:&quot;Orario locale porto di partenza: %1$s \\\/ Orario locale porto di arrivo: %2$s&quot;,&quot;local_time_combined&quot;:&quot;Orario locale porto di partenza e arrivo: %s&quot;,&quot;tag_often_booked&quot;:&quot;\\u2b50 Spesso prenotato&quot;,&quot;tag_leaving_soon&quot;:&quot;\\ud83d\\udd34 In partenza presto&quot;,&quot;tag_currently_sailing&quot;:&quot;\\ud83d\\udfe2 In navigazione&quot;,&quot;tag_arrived&quot;:&quot;\\u26ab Arrivato&quot;,&quot;tag_overnight&quot;:&quot;Notturno&quot;},&quot;showLogo&quot;:true,&quot;activityBoosters&quot;:true,&quot;shipMap&quot;:{&quot;eurotunnel&quot;:&quot;Eurotunnel&quot;},&quot;shipLinks&quot;:[],&quot;showShip&quot;:false,&quot;departurePort&quot;:&quot;Calais&quot;,&quot;arrivalPort&quot;:&quot;Folkestone&quot;,&quot;departureTimezone&quot;:&quot;Europe\\\/Paris&quot;,&quot;arrivalTimezone&quot;:&quot;Europe\\\/London&quot;}\">\n  <div class=\"tp-controls\" role=\"group\" aria-label=\"Timetable controls\">\n    <div>\n      <label for=\"tp-date\">Data<\/label><br>\n      <input id=\"tp-date\" class=\"tp-date\" type=\"date\" aria-label=\"Data\">\n    <\/div>\n    <div class=\"tp-day-field\">\n      <label for=\"tp-range\">Giorni<\/label><br>\n      <select id=\"tp-range\" class=\"tp-range\" aria-label=\"Giorni\">\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\" class=\"tp-btn\">Mostra partenze<\/button><\/div>\n  <\/div>\n\n  <div class=\"tp-local-nav-row\">\n    <div class=\"tp-local-times\" id=\"tp-local-times\" aria-live=\"polite\"><\/div>\n    <div class=\"tp-day-nav-host\"><\/div>\n  <\/div>\n  <div id=\"tp-status\" class=\"tp-muted\" aria-live=\"polite\">Scegli una data e clicca su Mostra partenze<\/div>\n  <div id=\"tp-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\">Caricamento...<\/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');\n  const daysEl = wrap.querySelector('#tp-range');\n  const btn    = wrap.querySelector('#tp-load');\n  const status = wrap.querySelector('#tp-status');\n  const out    = wrap.querySelector('#tp-results');\n  const loader = wrap.querySelector('.tp-loader');\n  const controls = wrap.querySelector('.tp-controls');\n  const navHost = wrap.querySelector('.tp-day-nav-host');\n  const localTimesEl = wrap.querySelector('#tp-local-times');\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'}); } \/\/ short, no year\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      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.opId||''), String(+r.dep||0), String(+r.arr||0), String(r.ship||'')].join('|');\n  }\n\n  function pickFeaturedKey(rows, avoidKey){\n    if (!activityBoosters || !rows.length) return '';\n    const routeSeed = parseInt(cfg.route, 10) || 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((routeSeed + 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 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,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.op+'<\/th>');\n\n    let html = '<table class=\"tp-table\"><thead><tr>'+headCells.join('')+'<\/tr><\/thead><tbody>';\n\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 cells = [\n        '<td>'+dShort(r.dep)+' <span class=\"tp-day\">'+dow+'<\/span>'+boostersHtml(r, false)+'<\/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>'+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    const routeName = cfg.label || '';\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\">'+(showShip ? shipBadge(r.ship) : '')+'<\/div>'+\n          '<div class=\"rhs\"><\/div>'+\n        '<\/div>';\n      }\n\n      html +=\n        \/\/ Row 3: Operator + route label (no book button)\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\">'+opCell(r)+'<\/div>'+\n          (routeName ? ('<div class=\"rhs\"><span class=\"tp-route-ticket\">'+routeTicketHtml(routeName)+'<\/span><\/div>') : '<div class=\"rhs\"><\/div>')+\n        '<\/div>'+\n      '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  function renderExtendedCards(rows){\n    const routeName = cfg.label || '';\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        +   (routeName ? ('<div class=\"tp-ext-route\">'+routeName+'<\/div>') : '')\n        + '<\/div>'\n        + '<div class=\"tp-ext-right\">'+link+'<\/div>'\n        + '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  async function load(){\n    btn.disabled = true; setLoader(true); status.textContent = L.status_loading;\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 url = new URL(cfg.rest); url.searchParams.set('route', String(cfg.route));\n    url.searchParams.set('from', iso(start)); url.searchParams.set('to', iso(end));\n    try{\n      const res = await fetch(url.toString(), {credentials:'same-origin'});\n      if(!res.ok) throw new 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      let rows = list.map(t=>({\n        opId:t.operatorId||null, opName:t.operatorName||'', opLogo:t.operatorLogo||'', opLink:t.operatorLink||'',\n        dep:toLocal(t.departureTime), arr:toLocal(t.arrivalTime), min:t.durationInMinutes||0, ship:t.shipName||''\n      })).sort((a,b)=>a.dep-b.dep);\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      if(rows.length===0){ status.textContent = L.status_empty; clearStatusInline(); out.innerHTML=''; return; }\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      status.textContent = '';\n      setStatusInline(\n  (L.status_found || '%d sailings found').replace('%d', '<strong>'+rows.length+'<\/strong>')\n);\n      out.innerHTML = renderTable(visibleRows) + renderCards(visibleRows) + moreButtonHtml(hiddenCount);\n      bindRowLinks();\n      if (navHost) navHost.innerHTML = navHtml();\n    }catch(e){\n      status.textContent = 'Failed to load data'; out.innerHTML = '<pre>'+String(e.message||e)+'<\/pre>';\n    }finally{ setLoader(false); btn.disabled=false; }\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\n\n\n<h2 class=\"wp-block-heading\" id=\"le-shuttle-folkestone-calais\">Le Shuttle Folkestone-Calais<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Questi orari mostrano le partenze da Folkestone per Calais\/Coquelles. Quanto costano traghetto e treno lo leggi nella nostra pagina <a href=\"https:\/\/calais-dover.com\/it\/prezzi\/\">prezzi del traghetto Calais-Dover<\/a>.<\/p>\n\n<div class=\"tp-wrap tp-theme-extended_cards tp-day-setup-modern\" data-config=\"{&quot;rest&quot;:&quot;https:\\\/\\\/calais-dover.com\\\/it\\\/wp-json\\\/timetables-pro\\\/v1\\\/timetables&quot;,&quot;route&quot;:56,&quot;days&quot;:1,&quot;autoload&quot;:true,&quot;theme&quot;:&quot;extended_cards&quot;,&quot;daySetup&quot;:&quot;modern&quot;,&quot;limit10&quot;:true,&quot;label&quot;:&quot;Folkestone - Calais&quot;,&quot;labels&quot;:{&quot;ui_date&quot;:&quot;Data&quot;,&quot;ui_days&quot;:&quot;Giorni&quot;,&quot;ui_button&quot;:&quot;Mostra partenze&quot;,&quot;status_idle&quot;:&quot;Scegli una data e clicca su Mostra partenze&quot;,&quot;status_loading&quot;:&quot;Caricamento...&quot;,&quot;status_empty&quot;:&quot;Nessuna partenza trovata&quot;,&quot;status_found&quot;:&quot;%d partenze trovate&quot;,&quot;th_date&quot;:&quot;Data&quot;,&quot;th_dep&quot;:&quot;Partenza&quot;,&quot;th_arr&quot;:&quot;Arrivo&quot;,&quot;th_dur&quot;:&quot;Durata&quot;,&quot;th_ship&quot;:&quot;Nave&quot;,&quot;th_op&quot;:&quot;Operatore&quot;,&quot;th_route&quot;:&quot;Rotta&quot;,&quot;wd_sun&quot;:&quot;DOM&quot;,&quot;wd_mon&quot;:&quot;LUN&quot;,&quot;wd_tue&quot;:&quot;MAR&quot;,&quot;wd_wed&quot;:&quot;MER&quot;,&quot;wd_thu&quot;:&quot;GIO&quot;,&quot;wd_fri&quot;:&quot;VEN&quot;,&quot;wd_sat&quot;:&quot;SAB&quot;,&quot;summary_footer_one&quot;:&quot;\\u00bb Controlla tutte le partenze %s nel nostro orario&quot;,&quot;summary_footer_two&quot;:&quot;\\u00bb Controlla altre partenze %1$s e %2$s nel nostro orario&quot;,&quot;summary_footer_generic&quot;:&quot;Consulta il nostro orario per altre partenze&quot;,&quot;summary_header&quot;:&quot;Le prossime due partenze:&quot;,&quot;summary_no_upcoming&quot;:&quot;Nessuna partenza imminente trovata&quot;,&quot;more_link&quot;:&quot;Altre partenze&quot;,&quot;more_departures_button&quot;:&quot;Mostra altre partenze&quot;,&quot;day_nav_previous&quot;:&quot;Mostra giorno precedente&quot;,&quot;day_nav_next&quot;:&quot;Mostra giorno successivo&quot;,&quot;day_nav_today&quot;:&quot;Mostra oggi&quot;,&quot;day_nav_tomorrow&quot;:&quot;Mostra domani&quot;,&quot;local_time_pair&quot;:&quot;Orario locale porto di partenza: %1$s \\\/ Orario locale porto di arrivo: %2$s&quot;,&quot;local_time_combined&quot;:&quot;Orario locale porto di partenza e arrivo: %s&quot;,&quot;tag_often_booked&quot;:&quot;\\u2b50 Spesso prenotato&quot;,&quot;tag_leaving_soon&quot;:&quot;\\ud83d\\udd34 In partenza presto&quot;,&quot;tag_currently_sailing&quot;:&quot;\\ud83d\\udfe2 In navigazione&quot;,&quot;tag_arrived&quot;:&quot;\\u26ab Arrivato&quot;,&quot;tag_overnight&quot;:&quot;Notturno&quot;},&quot;showLogo&quot;:true,&quot;activityBoosters&quot;:true,&quot;shipMap&quot;:{&quot;eurotunnel&quot;:&quot;Eurotunnel&quot;},&quot;shipLinks&quot;:[],&quot;showShip&quot;:false,&quot;departurePort&quot;:&quot;Folkestone&quot;,&quot;arrivalPort&quot;:&quot;Calais&quot;,&quot;departureTimezone&quot;:&quot;Europe\\\/London&quot;,&quot;arrivalTimezone&quot;:&quot;Europe\\\/Paris&quot;}\">\n  <div class=\"tp-controls\" role=\"group\" aria-label=\"Timetable controls\">\n    <div>\n      <label for=\"tp-date\">Data<\/label><br>\n      <input id=\"tp-date\" class=\"tp-date\" type=\"date\" aria-label=\"Data\">\n    <\/div>\n    <div class=\"tp-day-field\">\n      <label for=\"tp-range\">Giorni<\/label><br>\n      <select id=\"tp-range\" class=\"tp-range\" aria-label=\"Giorni\">\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\" class=\"tp-btn\">Mostra partenze<\/button><\/div>\n  <\/div>\n\n  <div class=\"tp-local-nav-row\">\n    <div class=\"tp-local-times\" id=\"tp-local-times\" aria-live=\"polite\"><\/div>\n    <div class=\"tp-day-nav-host\"><\/div>\n  <\/div>\n  <div id=\"tp-status\" class=\"tp-muted\" aria-live=\"polite\">Scegli una data e clicca su Mostra partenze<\/div>\n  <div id=\"tp-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\">Caricamento...<\/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');\n  const daysEl = wrap.querySelector('#tp-range');\n  const btn    = wrap.querySelector('#tp-load');\n  const status = wrap.querySelector('#tp-status');\n  const out    = wrap.querySelector('#tp-results');\n  const loader = wrap.querySelector('.tp-loader');\n  const controls = wrap.querySelector('.tp-controls');\n  const navHost = wrap.querySelector('.tp-day-nav-host');\n  const localTimesEl = wrap.querySelector('#tp-local-times');\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'}); } \/\/ short, no year\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      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.opId||''), String(+r.dep||0), String(+r.arr||0), String(r.ship||'')].join('|');\n  }\n\n  function pickFeaturedKey(rows, avoidKey){\n    if (!activityBoosters || !rows.length) return '';\n    const routeSeed = parseInt(cfg.route, 10) || 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((routeSeed + 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 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,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.op+'<\/th>');\n\n    let html = '<table class=\"tp-table\"><thead><tr>'+headCells.join('')+'<\/tr><\/thead><tbody>';\n\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 cells = [\n        '<td>'+dShort(r.dep)+' <span class=\"tp-day\">'+dow+'<\/span>'+boostersHtml(r, false)+'<\/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>'+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    const routeName = cfg.label || '';\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\">'+(showShip ? shipBadge(r.ship) : '')+'<\/div>'+\n          '<div class=\"rhs\"><\/div>'+\n        '<\/div>';\n      }\n\n      html +=\n        \/\/ Row 3: Operator + route label (no book button)\n        '<div class=\"tp-mrow\">'+\n          '<div class=\"lhs\">'+opCell(r)+'<\/div>'+\n          (routeName ? ('<div class=\"rhs\"><span class=\"tp-route-ticket\">'+routeTicketHtml(routeName)+'<\/span><\/div>') : '<div class=\"rhs\"><\/div>')+\n        '<\/div>'+\n      '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  function renderExtendedCards(rows){\n    const routeName = cfg.label || '';\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        +   (routeName ? ('<div class=\"tp-ext-route\">'+routeName+'<\/div>') : '')\n        + '<\/div>'\n        + '<div class=\"tp-ext-right\">'+link+'<\/div>'\n        + '<\/div>';\n    });\n    html += '<\/div>';\n    return html;\n  }\n\n  async function load(){\n    btn.disabled = true; setLoader(true); status.textContent = L.status_loading;\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 url = new URL(cfg.rest); url.searchParams.set('route', String(cfg.route));\n    url.searchParams.set('from', iso(start)); url.searchParams.set('to', iso(end));\n    try{\n      const res = await fetch(url.toString(), {credentials:'same-origin'});\n      if(!res.ok) throw new 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      let rows = list.map(t=>({\n        opId:t.operatorId||null, opName:t.operatorName||'', opLogo:t.operatorLogo||'', opLink:t.operatorLink||'',\n        dep:toLocal(t.departureTime), arr:toLocal(t.arrivalTime), min:t.durationInMinutes||0, ship:t.shipName||''\n      })).sort((a,b)=>a.dep-b.dep);\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      if(rows.length===0){ status.textContent = L.status_empty; clearStatusInline(); out.innerHTML=''; return; }\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      status.textContent = '';\n      setStatusInline(\n  (L.status_found || '%d sailings found').replace('%d', '<strong>'+rows.length+'<\/strong>')\n);\n      out.innerHTML = renderTable(visibleRows) + renderCards(visibleRows) + moreButtonHtml(hiddenCount);\n      bindRowLinks();\n      if (navHost) navHost.innerHTML = navHtml();\n    }catch(e){\n      status.textContent = 'Failed to load data'; out.innerHTML = '<pre>'+String(e.message||e)+'<\/pre>';\n    }finally{ setLoader(false); btn.disabled=false; }\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\n\n\n<div class=\"wp-block-group alignfull cd-band-grey is-layout-flow wp-block-group-is-layout-flow\">\n<h2 class=\"wp-block-heading\">Durata e partenze per compagnia<\/h2>\n\n\n<ul class=\"wp-block-list\">\n<li><strong>P&amp;O Ferries:<\/strong> circa 90 minuti, <a href=\"https:\/\/calais-dover.com\/go\/in-text-poferries-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">fino a 15 partenze al giorno \u2197<\/a>. L&#8217;unica compagnia che ti imbarca <a href=\"https:\/\/calais-dover.com\/it\/passeggero-a-piedi\/\">come passeggero a piedi<\/a>.<\/li>\n\n<li><strong>DFDS:<\/strong> circa 90 minuti, <a href=\"https:\/\/calais-dover.com\/go\/in-text-dfds-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">fino a 30 traversate al giorno \u2197<\/a> nelle due direzioni insieme.<\/li>\n\n<li><strong>Irish Ferries:<\/strong> circa 90 minuti, <a href=\"https:\/\/calais-dover.com\/go\/in-text-irish-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">fino a 14 partenze al giorno \u2197<\/a>.<\/li>\n\n<li><strong>Le Shuttle:<\/strong> 35 minuti nel tunnel, diverse partenze all&#8217;ora.<\/li>\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\">Se una partenza manca nella tabella non \u00e8 per forza cancellata: spesso il prossimo orario non \u00e8 ancora pubblicato, soprattutto al cambio di stagione. Nei giorni affollati d&#8217;estate o con vento forte controlla anche gli <a href=\"https:\/\/calais-dover.com\/it\/sailing-updates\/\">avvisi aggiornati<\/a> della tua compagnia, perch\u00e9 la tabella a volte mostra le cancellazioni dell&#8217;ultimo minuto in ritardo. Il meteo lo vedi sulle nostre <a href=\"https:\/\/calais-dover.com\/it\/meteo-e-webcam\/\">webcam di Calais e Dover<\/a>, la posizione delle navi sul <a href=\"https:\/\/calais-dover.com\/it\/ferry-tracker\/\">tracker dei traghetti<\/a>.<\/p>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"check-in\">Check-in per compagnia<\/h2>\n\n\n<p class=\"wp-block-paragraph\"><em>Nota: gli orari di check-in di questa pagina sono indicativi, per stimare quanto tempo prevedere per il viaggio. Fanno sempre fede le informazioni della compagnia con cui viaggi o presso cui hai prenotato. Come funziona il check-in lo leggi nelle nostre pagine <a href=\"https:\/\/calais-dover.com\/it\/porto-di-calais\/\">porto di Calais<\/a> e <a href=\"https:\/\/calais-dover.com\/it\/porto-di-dover\/\">porto di Dover<\/a>.<\/em><\/p>\n\n\n<div class=\"cd-opgrid\">\n  <div class=\"cd-opcard\">\n    <div class=\"cd-opcard-head\"><img decoding=\"async\" src=\"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/dfds-logo-1-1.jpg\" alt=\"Logo di DFDS\" width=\"48\" height=\"48\" loading=\"lazy\"><div><strong>DFDS<\/strong><a class=\"cd-opcard-more\" href=\"https:\/\/calais-dover.com\/it\/dfds\/\">Tutto su DFDS<\/a><\/div><\/div>\n    <ul class=\"cd-checkin\">\n      <li><span>Essere al porto<\/span><b>60-90 min<\/b><\/li>\n      <li><span>Nei giorni di punta<\/span><b>90 min<\/b><\/li>\n    <\/ul>\n    <a class=\"cd-opcard-book\" href=\"https:\/\/calais-dover.com\/go\/in-text-dfds-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">Prenota con DFDS \u2197<\/a>\n  <\/div>\n  <div class=\"cd-opcard\">\n    <div class=\"cd-opcard-head\"><img decoding=\"async\" src=\"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/po-ferries-logo-1-1.jpg\" alt=\"Logo di P&amp;O Ferries\" width=\"48\" height=\"48\" loading=\"lazy\"><div><strong>P&amp;O Ferries<\/strong><a class=\"cd-opcard-more\" href=\"https:\/\/calais-dover.com\/it\/p-o-ferries\/\">Tutto su P&amp;O<\/a><\/div><\/div>\n    <ul class=\"cd-checkin\">\n      <li><span>Con veicolo<\/span><b>60 min<\/b><\/li>\n      <li><span>A piedi<\/span><b>90 min<\/b><\/li>\n    <\/ul>\n    <a class=\"cd-opcard-book\" href=\"https:\/\/calais-dover.com\/go\/in-text-poferries-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">Prenota con P&amp;O \u2197<\/a>\n  <\/div>\n  <div class=\"cd-opcard\">\n    <div class=\"cd-opcard-head\"><img decoding=\"async\" src=\"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/irish-ferries-logo-2-1.jpg\" alt=\"Logo di Irish Ferries\" width=\"48\" height=\"48\" loading=\"lazy\"><div><strong>Irish Ferries<\/strong><a class=\"cd-opcard-more\" href=\"https:\/\/calais-dover.com\/it\/irish-ferries\/\">Tutto su Irish Ferries<\/a><\/div><\/div>\n    <ul class=\"cd-checkin\">\n      <li><span>Con veicolo<\/span><b>60 min<\/b><\/li>\n      <li><span>Pullman<\/span><b>90 min<\/b><\/li>\n    <\/ul>\n    <a class=\"cd-opcard-book\" href=\"https:\/\/calais-dover.com\/go\/in-text-irish-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">Prenota con Irish Ferries \u2197<\/a>\n  <\/div>\n  <div class=\"cd-opcard\">\n    <div class=\"cd-opcard-head\"><img decoding=\"async\" src=\"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/eurotunnel-le-shuttle-2-1.jpg\" alt=\"Logo di Eurotunnel Le Shuttle\" width=\"48\" height=\"48\" loading=\"lazy\"><div><strong>Le Shuttle (treno)<\/strong><a class=\"cd-opcard-more\" href=\"https:\/\/calais-dover.com\/it\/tunnel-della-manica\/\">Tutto sul treno<\/a><\/div><\/div>\n    <ul class=\"cd-checkin\">\n      <li><span>Non prima di<\/span><b>2 ore<\/b><\/li>\n      <li><span>Al pi\u00f9 tardi<\/span><b>1 ora<\/b><\/li>\n    <\/ul>\n    <a class=\"cd-opcard-book\" href=\"https:\/\/calais-dover.com\/go\/in-text-leshuttle-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">Prenota Le Shuttle \u2197<\/a>\n  <\/div>\n<\/div>\n<p class=\"cd-checkin-note\">Tempo prima della partenza. Per le compagnie di traghetti \u00e8 la chiusura del check-in.<\/p>\n<style>\n.cd-opgrid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px}\n.cd-opcard{display:flex;flex-direction:column;background:#fff;border:1px solid #e3e9ed;border-radius:14px;padding:16px;box-shadow:0 8px 22px -16px rgba(0,49,78,.45)}\n.cd-opcard-head{display:flex;align-items:center;gap:12px;margin-bottom:12px}\n.cd-opcard-head img{width:48px;height:48px;border-radius:50%;object-fit:cover;flex:none;box-shadow:0 0 0 1px #e3e9ed}\n.cd-opcard-head strong{display:block;color:var(--cd-navy,#00314e);font-size:17px;line-height:1.3}\n.cd-opcard-more{font-size:13px;color:#5b6770!important}\n.cd-page ul.cd-checkin{list-style:none!important;margin:0 0 14px!important;padding:0!important;display:grid;gap:6px}\n.cd-page ul.cd-checkin li{margin:0;display:flex;justify-content:space-between;align-items:baseline;gap:8px;padding:7px 10px;border-radius:8px;background:#f2f6f8;font-size:14px;color:#5b6770}\n.cd-page ul.cd-checkin li b{color:var(--cd-navy,#00314e);font-weight:700;white-space:nowrap}\n.cd-opcard-book{margin-top:auto;display:block;text-align:center;padding:9px 12px;border-radius:20px;background:var(--cd-blue,#0077b6);color:#fff!important;text-decoration:none!important;font-weight:700;font-size:14px}\n.cd-opcard-book:hover{background:var(--cd-green,#14a37f)}\n.cd-page .cd-checkin-note{margin:10px 0 0!important;font-size:14px;color:#5b6770}\n@media (max-width:1024px){.cd-opgrid{grid-template-columns:repeat(2,minmax(0,1fr))}}\n@media (max-width:560px){.cd-opgrid{grid-template-columns:1fr}}\n<\/style>\n\n\n<div class=\"wp-block-group alignfull cd-band is-layout-flow wp-block-group-is-layout-flow\">\n<div class=\"wp-block-columns are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:62%\">\n<h3 class=\"wp-block-heading\">Trovato l&#8217;orario giusto?<\/h3>\n\n\n<p class=\"wp-block-paragraph\">Confronta in un colpo d&#8217;occhio partenze e prezzi attuali di P&amp;O Ferries, DFDS e Irish Ferries, oppure prenota il treno navetta. Altro nella nostra pagina <a href=\"https:\/\/calais-dover.com\/it\/calais-dover-in-macchina\/\">Calais-Dover in auto<\/a>.<\/p>\n<\/div>\n\n\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:38%\">\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button cd-btn cd-btn-solid\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/calais-dover.com\/go\/in-text-directferries-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">Confronta orari e prezzi \u2197<\/a><\/div>\n\n\n<div class=\"wp-block-button is-style-outline cd-btn is-style-outline--1\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/calais-dover.com\/go\/in-text-leshuttle-it\" target=\"_blank\" rel=\"nofollow sponsored noopener\">Prenota Le Shuttle \u2197<\/a><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Tutte le partenze di oggi tra Calais e Dover, traghetti e Le Shuttle.<\/p>\n","protected":false},"author":1,"featured_media":6442,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","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":"disabled","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":"default","ast-page-background-enabled":"default","ast-page-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":"","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-4)","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-4)","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-4)","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":""}},"cd_hero_tagline":"","footnotes":""},"class_list":["post-7261","page","type-page","status-publish","has-post-thumbnail","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Orari traghetti Calais Dover oggi: P&amp;O, DFDS e Irish Ferries<\/title>\n<meta name=\"description\" content=\"Orari dei traghetti Calais-Dover di oggi: tutte le partenze di P&amp;O Ferries, DFDS e Irish Ferries e di Le Shuttle, con durata e check-in per compagnia.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/calais-dover.com\/it\/orari\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Orari traghetti Calais Dover oggi: P&amp;O, DFDS e Irish Ferries\" \/>\n<meta property=\"og:description\" content=\"Orari dei traghetti Calais-Dover di oggi: tutte le partenze di P&amp;O Ferries, DFDS e Irish Ferries e di Le Shuttle, con durata e check-in per compagnia.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/calais-dover.com\/it\/orari\/\" \/>\n<meta property=\"og:site_name\" content=\"Calais-Dover.com\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-27T14:49:21+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/timetable-calais-dover.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"800\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data1\" content=\"3 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/orari\\\/\",\"url\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/orari\\\/\",\"name\":\"Orari traghetti Calais Dover oggi: P&O, DFDS e Irish Ferries\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/orari\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/orari\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/calais-dover.com\\\/wp-content\\\/uploads\\\/2024\\\/06\\\/timetable-calais-dover.jpg\",\"datePublished\":\"2024-06-10T11:54:03+00:00\",\"dateModified\":\"2026-10-27T14:49:21+00:00\",\"description\":\"Orari dei traghetti Calais-Dover di oggi: tutte le partenze di P&O Ferries, DFDS e Irish Ferries e di Le Shuttle, con durata e check-in per compagnia.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/orari\\\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/calais-dover.com\\\/it\\\/orari\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/orari\\\/#primaryimage\",\"url\":\"https:\\\/\\\/calais-dover.com\\\/wp-content\\\/uploads\\\/2024\\\/06\\\/timetable-calais-dover.jpg\",\"contentUrl\":\"https:\\\/\\\/calais-dover.com\\\/wp-content\\\/uploads\\\/2024\\\/06\\\/timetable-calais-dover.jpg\",\"width\":1200,\"height\":800,\"caption\":\"Orari Calais Dover DFDS\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/orari\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Calais-Dover.com\",\"item\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Orari traghetti Calais Dover\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/#website\",\"url\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/\",\"name\":\"Calais-Dover.com\",\"description\":\"From Dover to Calais\",\"publisher\":{\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/#organization\",\"name\":\"Calais-Dover.com\",\"url\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/calais-dover.com\\\/wp-content\\\/uploads\\\/2023\\\/07\\\/Calais-Dover-logo.png\",\"contentUrl\":\"https:\\\/\\\/calais-dover.com\\\/wp-content\\\/uploads\\\/2023\\\/07\\\/Calais-Dover-logo.png\",\"width\":450,\"height\":80,\"caption\":\"Calais-Dover.com\"},\"image\":{\"@id\":\"https:\\\/\\\/calais-dover.com\\\/it\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Orari traghetti Calais Dover oggi: P&O, DFDS e Irish Ferries","description":"Orari dei traghetti Calais-Dover di oggi: tutte le partenze di P&O Ferries, DFDS e Irish Ferries e di Le Shuttle, con durata e check-in per compagnia.","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:\/\/calais-dover.com\/it\/orari\/","og_locale":"it_IT","og_type":"article","og_title":"Orari traghetti Calais Dover oggi: P&O, DFDS e Irish Ferries","og_description":"Orari dei traghetti Calais-Dover di oggi: tutte le partenze di P&O Ferries, DFDS e Irish Ferries e di Le Shuttle, con durata e check-in per compagnia.","og_url":"https:\/\/calais-dover.com\/it\/orari\/","og_site_name":"Calais-Dover.com","article_modified_time":"2026-10-27T14:49:21+00:00","og_image":[{"width":1200,"height":800,"url":"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/timetable-calais-dover.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Tempo di lettura stimato":"3 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/calais-dover.com\/it\/orari\/","url":"https:\/\/calais-dover.com\/it\/orari\/","name":"Orari traghetti Calais Dover oggi: P&O, DFDS e Irish Ferries","isPartOf":{"@id":"https:\/\/calais-dover.com\/it\/#website"},"primaryImageOfPage":{"@id":"https:\/\/calais-dover.com\/it\/orari\/#primaryimage"},"image":{"@id":"https:\/\/calais-dover.com\/it\/orari\/#primaryimage"},"thumbnailUrl":"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/timetable-calais-dover.jpg","datePublished":"2024-06-10T11:54:03+00:00","dateModified":"2026-10-27T14:49:21+00:00","description":"Orari dei traghetti Calais-Dover di oggi: tutte le partenze di P&O Ferries, DFDS e Irish Ferries e di Le Shuttle, con durata e check-in per compagnia.","breadcrumb":{"@id":"https:\/\/calais-dover.com\/it\/orari\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/calais-dover.com\/it\/orari\/"]}]},{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/calais-dover.com\/it\/orari\/#primaryimage","url":"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/timetable-calais-dover.jpg","contentUrl":"https:\/\/calais-dover.com\/wp-content\/uploads\/2024\/06\/timetable-calais-dover.jpg","width":1200,"height":800,"caption":"Orari Calais Dover DFDS"},{"@type":"BreadcrumbList","@id":"https:\/\/calais-dover.com\/it\/orari\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Calais-Dover.com","item":"https:\/\/calais-dover.com\/it\/"},{"@type":"ListItem","position":2,"name":"Orari traghetti Calais Dover"}]},{"@type":"WebSite","@id":"https:\/\/calais-dover.com\/it\/#website","url":"https:\/\/calais-dover.com\/it\/","name":"Calais-Dover.com","description":"From Dover to Calais","publisher":{"@id":"https:\/\/calais-dover.com\/it\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/calais-dover.com\/it\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"it-IT"},{"@type":"Organization","@id":"https:\/\/calais-dover.com\/it\/#organization","name":"Calais-Dover.com","url":"https:\/\/calais-dover.com\/it\/","logo":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/calais-dover.com\/it\/#\/schema\/logo\/image\/","url":"https:\/\/calais-dover.com\/wp-content\/uploads\/2023\/07\/Calais-Dover-logo.png","contentUrl":"https:\/\/calais-dover.com\/wp-content\/uploads\/2023\/07\/Calais-Dover-logo.png","width":450,"height":80,"caption":"Calais-Dover.com"},"image":{"@id":"https:\/\/calais-dover.com\/it\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/pages\/7261","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/comments?post=7261"}],"version-history":[{"count":7,"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/pages\/7261\/revisions"}],"predecessor-version":[{"id":11814,"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/pages\/7261\/revisions\/11814"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/media\/6442"}],"wp:attachment":[{"href":"https:\/\/calais-dover.com\/it\/wp-json\/wp\/v2\/media?parent=7261"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}