Benvenuto nella sezione eventi di Fattore Famiglia. Qui trovi tutte le iniziative dedicate alle famiglie: appuntamenti speciali, attività per grandi e piccoli, esperienze pensate per stare insieme in modo autentico e significativo. Ogni evento nasce dalla convinzione che la famiglia meriti momenti di qualità, vissuti con cura e allegria.
/* ===== FF EVENTI v1 — stile pagina eventi (inizio) ===== */
#ffe{--r:#c8102e;--r2:#b14147;--rd:#9e0c24;--ink:#1a1a1a;--tx:#2b2b2b;--mu:#6b6b6b;--bg:#f6f6f6;--ln:#e6e6e6;font-family:Montserrat,sans-serif;color:var(--tx);margin:0 0 40px}
#ffe *{box-sizing:border-box}
#ffe h1,#ffe h2,#ffe h3{font-family:Montserrat,sans-serif;color:var(--ink);margin:0}
#ffe a{text-decoration:none}
#ffe svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:none}
.ffe-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border-radius:999px;padding:13px 24px;font-weight:700;font-size:15px;line-height:1.1;border:2px solid transparent;cursor:pointer;transition:transform .15s,background .15s,color .15s;font-family:inherit}
.ffe-btn:hover{transform:translateY(-2px)}
.ffe-btn-white{background:#fff;color:var(--r)!important}
.ffe-btn-ghost{border-color:rgba(255,255,255,.75);color:#fff!important;background:transparent}
.ffe-btn-ghost:hover{background:rgba(255,255,255,.12)}
.ffe-btn-red{background:var(--r);color:#fff!important}
.ffe-btn-red:hover{background:var(--rd)}
.ffe-btn-line{background:#fff;border-color:var(--ln);color:var(--ink)}
.ffe-btn-line:hover{border-color:var(--ink)}
.ffe-sm{padding:9px 18px;font-size:14px}
/* hero */
.ffe-hero{position:relative;overflow:hidden;border-radius:26px;background:linear-gradient(135deg,#c8102e 0%,#9e0c24 100%);color:#fff;padding:clamp(28px,5vw,56px);display:grid;grid-template-columns:1.6fr 1fr;gap:28px;align-items:center}
.ffe-hero:before,.ffe-hero:after{content:"";position:absolute;border-radius:50%;background:rgba(255,255,255,.08)}
.ffe-hero:before{width:380px;height:380px;right:-120px;top:-140px}
.ffe-hero:after{width:220px;height:220px;right:180px;bottom:-130px}
.ffe-hero>*{position:relative;z-index:1}
.ffe-kicker{display:inline-block;background:rgba(255,255,255,.16);border-radius:999px;padding:6px 14px;font-size:13px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
#ffe .ffe-hero h1{color:#fff;font-size:clamp(30px,4.6vw,52px);line-height:1.05;font-weight:800;margin:16px 0 14px;letter-spacing:-.02em}
.ffe-hero h1 span{display:block;color:#ffd9de}
.ffe-hero p{font-size:clamp(16px,1.2vw + 10px,19px);line-height:1.55;max-width:560px;margin:0 0 24px;opacity:.95}
.ffe-hero-cta{display:flex;flex-wrap:wrap;gap:12px}
.ffe-hero-stats{display:grid;gap:12px}
.ffe-hero-stats div{background:rgba(255,255,255,.12);backdrop-filter:blur(4px);border:1px solid rgba(255,255,255,.18);border-radius:18px;padding:14px 20px;display:flex;align-items:baseline;gap:12px}
.ffe-hero-stats b{font-size:34px;font-weight:800;line-height:1}
.ffe-hero-stats span{font-size:15px;font-weight:600;opacity:.92}
/* in evidenza */
.ffe-feat{margin:-34px clamp(10px,3vw,40px) 0;position:relative;z-index:2}
.ffe-feat-card{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.35fr);background:#fff;border-radius:24px;overflow:hidden;box-shadow:0 18px 50px rgba(0,0,0,.14)}
.ffe-feat-img{background:#2b2b2b center/cover no-repeat;min-height:280px;display:flex;align-items:center;justify-content:center}
.ffe-feat-img span{color:#fff;font-size:84px;font-weight:800;line-height:1;text-align:center}
.ffe-feat-img small{display:block;font-size:22px;text-transform:uppercase;letter-spacing:.12em}
.ffe-feat-body{padding:clamp(20px,3vw,36px)}
#ffe .ffe-feat-body h2{font-size:clamp(22px,2vw + 8px,32px);line-height:1.15;margin:12px 0 8px;font-weight:800}
.ffe-feat-body h2 a{color:var(--ink)}
.ffe-feat-meta{color:var(--mu);font-size:16px;margin:0 0 18px;text-transform:none}
.ffe-feat-meta b{color:var(--ink)}
.ffe-card-body .ffe-badge,.ffe-feat-body .ffe-badge{align-self:flex-start}
.ffe-cd{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:20px;max-width:440px}
.ffe-cd div{background:var(--ink);color:#fff;border-radius:14px;text-align:center;padding:12px 4px 10px}
.ffe-cd div:first-child{background:var(--r)}
.ffe-cd b{display:block;font-size:clamp(26px,3vw,38px);font-weight:800;line-height:1;font-variant-numeric:tabular-nums}
.ffe-cd span{font-size:11.5px;text-transform:uppercase;letter-spacing:.1em;opacity:.85;font-weight:600}
.ffe-live-msg{display:none;background:#e8f7ee;color:#11713a;border-radius:14px;padding:14px 18px;font-weight:700;margin-bottom:20px}
.is-live .ffe-cd{display:none}.is-live .ffe-live-msg{display:block}
.ffe-feat-act{display:flex;flex-wrap:wrap;gap:10px}
.ffe-empty-feat{background:#fff;border-radius:24px;padding:30px;box-shadow:0 18px 50px rgba(0,0,0,.12);text-align:center}
/* badge */
.ffe-badge{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:5px 12px;font-size:12.5px;font-weight:700;letter-spacing:.02em}
.ffe-b-ff{background:#fde8eb;color:var(--r)}
.ffe-b-terr{background:#ececec;color:#3a3a3a}
.ffe-dot{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:6px;vertical-align:middle}
.ffe-dot-ff{background:var(--r)}.ffe-dot-terr{background:#3a3a3a}
/* strumenti */
.ffe-tools{margin:38px 0 18px;display:grid;gap:12px}
.ffe-chips{display:flex;gap:8px;overflow-x:auto;padding-bottom:2px;scrollbar-width:none}
.ffe-chips::-webkit-scrollbar{display:none}
.ffe-chips button,.ffe-switch button,.ffe-near{flex:none;font-family:inherit;font-size:14.5px;font-weight:600;border:1.5px solid var(--ln);background:#fff;color:var(--ink);border-radius:999px;padding:9px 16px;cursor:pointer;transition:all .15s;display:inline-flex;align-items:center;gap:6px}
.ffe-chips button:hover,.ffe-near:hover{border-color:var(--ink)}
.ffe-chips button.on,.ffe-switch button.on,.ffe-near.on{background:var(--ink);border-color:var(--ink);color:#fff}
.ffe-chips button.on .ffe-dot-terr{background:#fff}
.ffe-row2{display:flex;gap:10px;flex-wrap:wrap}
.ffe-search{flex:1 1 260px;display:flex;align-items:center;gap:8px;border:1.5px solid var(--ln);border-radius:999px;padding:0 16px;background:#fff;margin:0}
.ffe-search:focus-within{border-color:var(--ink)}
.ffe-search input{border:0!important;outline:0;box-shadow:none!important;background:transparent!important;font:500 15px Montserrat,sans-serif;padding:11px 0!important;width:100%;height:auto!important;margin:0}
.ffe-eta{border:1.5px solid var(--ln)!important;border-radius:999px!important;padding:10px 38px 10px 16px!important;font:600 14.5px Montserrat,sans-serif!important;background-color:#fff;color:var(--ink);height:auto!important;width:auto!important;max-width:100%}
.ffe-near.loading{opacity:.6;pointer-events:none}
.ffe-switch{display:none;background:var(--bg);border-radius:999px;padding:4px;width:max-content}
.ffe-switch button{border:0;background:transparent;padding:9px 26px}
/* contenuto */
.ffe-main{display:grid;grid-template-columns:minmax(0,1fr) minmax(320px,42%);gap:28px;align-items:start}
.ffe-list{display:grid;gap:18px}
#ffe .ffe-month{font-size:15px;text-transform:uppercase;letter-spacing:.12em;color:var(--r);font-weight:800;margin:10px 0 -4px;display:flex;align-items:center;gap:12px}
.ffe-month:after{content:"";flex:1;height:1px;background:var(--ln)}
.ffe-card{display:grid;grid-template-columns:220px minmax(0,1fr);background:#fff;border:1px solid var(--ln);border-radius:20px;overflow:hidden;transition:box-shadow .2s,transform .2s}
.ffe-card:hover{box-shadow:0 12px 32px rgba(0,0,0,.09);transform:translateY(-2px)}
.ffe-card.is-ff{border-color:#f3c3cb;box-shadow:inset 5px 0 0 var(--r)}
.ffe-card-img{position:relative;display:block;min-height:190px;background:linear-gradient(135deg,#3a3a3a,#1a1a1a) center/cover no-repeat}
.ffe-card.is-ff .ffe-card-img:not([style]){background:linear-gradient(135deg,#c8102e,#9e0c24)}
.ffe-date{position:absolute;top:12px;left:12px;background:#fff;border-radius:14px;padding:8px 10px 6px;text-align:center;color:var(--r);font-weight:800;font-size:12px;text-transform:uppercase;letter-spacing:.08em;line-height:1;box-shadow:0 4px 14px rgba(0,0,0,.18);min-width:54px}
.ffe-date b{display:block;font-size:26px;color:var(--ink);letter-spacing:0;margin-bottom:2px}
.ffe-when{position:absolute;left:12px;bottom:12px;background:rgba(26,26,26,.85);color:#fff;font-size:12.5px;font-weight:700;border-radius:999px;padding:5px 11px}
.ffe-w-today,.ffe-w-soon{background:var(--r)}
.ffe-w-live{background:#11813f;animation:ffe-p 1.6s infinite}
@keyframes ffe-p{0%,100%{box-shadow:0 0 0 0 rgba(17,129,63,.6)}50%{box-shadow:0 0 0 7px rgba(17,129,63,0)}}
.ffe-card-body{padding:18px 20px 16px;display:flex;flex-direction:column;gap:9px}
#ffe .ffe-card h3{font-size:clamp(18px,.6vw + 14px,21px);line-height:1.25;font-weight:800}
.ffe-card h3 a{color:var(--ink)}
.ffe-card h3 a:hover{color:var(--r)}
.ffe-meta{list-style:none;margin:0;padding:0;display:grid;gap:5px;font-size:14.5px;color:var(--tx)}
.ffe-meta li{display:flex;gap:8px;align-items:flex-start;line-height:1.4;margin:0}
.ffe-meta li:first-letter{text-transform:uppercase}
.ffe-meta svg{color:var(--r);width:17px;height:17px;margin-top:1px}
.ffe-meta em{color:var(--r);font-style:normal;font-weight:700}
.ffe-intro{font-size:14.5px;line-height:1.55;color:var(--mu);margin:0}
.ffe-tags{display:flex;flex-wrap:wrap;gap:6px}
.ffe-tags:empty{display:none}
.ffe-tag{background:var(--bg);border-radius:8px;padding:4px 9px;font-size:12.5px;font-weight:600;color:#444}
.ffe-tag-cost{background:#e8f7ee;color:#11713a}
.ffe-act{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:4px}
.ffe-ico{width:40px;height:40px;border-radius:50%;border:1.5px solid var(--ln);background:#fff;color:var(--ink)!important;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:all .15s;padding:0}
.ffe-ico:hover{border-color:var(--r);color:var(--r)!important}
.ffe-wa:hover{border-color:#1faa53;color:#1faa53!important}
.ffe-link{font-size:14px;font-weight:700;color:var(--r)!important;margin-left:4px}
.ffe-empty{text-align:center;background:var(--bg);border-radius:20px;padding:44px 24px}
.ffe-empty-ico{font-size:44px}
#ffe .ffe-empty h3{margin:8px 0}
.ffe-empty p{color:var(--mu);max-width:420px;margin:0 auto 18px}
/* mappa */
.ffe-mapwrap{position:sticky;top:100px;border-radius:20px;overflow:hidden;border:1px solid var(--ln);background:var(--bg)}
#ffe-map{height:min(72vh,640px);width:100%;z-index:0}
.ffe-legend{display:flex;gap:16px;padding:10px 16px;font-size:13px;font-weight:600;background:#fff;border-top:1px solid var(--ln)}
.ffe-mk span{display:flex;flex-direction:column;align-items:center;justify-content:center;width:42px;height:42px;border-radius:50% 50% 50% 4px;transform:rotate(-45deg);background:#3a3a3a;color:#fff;font:800 15px/1 Montserrat,sans-serif;box-shadow:0 4px 12px rgba(0,0,0,.3);border:3px solid #fff}
.ffe-mk span>i{transform:rotate(45deg);display:flex;flex-direction:column;align-items:center;font-style:normal;line-height:1}
.ffe-mk span b{font-size:15px;font-weight:800}
.ffe-mk span small{font-size:8.5px;text-transform:uppercase;letter-spacing:.05em;margin-top:1px}
.ffe-mk{background:none;border:0}
.ffe-mk-ff span{background:#c8102e}
.ffe-pop{display:grid;gap:4px;font-family:Montserrat,sans-serif;font-size:13px}
.ffe-pop img{width:100%;height:110px;object-fit:cover;border-radius:10px;margin-bottom:4px}
.ffe-pop b{font-size:15px;line-height:1.25;color:#1a1a1a}
.ffe-pop a{color:#c8102e!important;font-weight:700}
.ffe-pop .ffe-badge{justify-self:start;padding:3px 9px;font-size:11px}
/* segnala */
.ffe-submit{margin-top:40px;border-radius:24px;background:#1a1a1a;color:#fff;padding:clamp(24px,4vw,44px);display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap}
#ffe .ffe-submit h2{color:#fff;font-size:clamp(22px,2vw + 10px,30px);font-weight:800;margin-bottom:8px}
.ffe-submit p{margin:0;max-width:640px;opacity:.85;line-height:1.55}
/* responsive */
@media (max-width:999px){
.ffe-hero{grid-template-columns:1fr}
.ffe-hero-stats{grid-template-columns:repeat(3,1fr)}
.ffe-hero-stats div{flex-direction:column;gap:4px;padding:12px}
.ffe-hero-stats b{font-size:26px}.ffe-hero-stats span{font-size:12.5px}
.ffe-feat{margin:-24px 8px 0}
.ffe-feat-card{grid-template-columns:1fr}
.ffe-feat-img{min-height:200px}
.ffe-switch{display:flex}
.ffe-main{grid-template-columns:1fr}
.ffe-main[data-view=list] .ffe-mapwrap{display:none}
.ffe-main[data-view=map] .ffe-list{display:none}
.ffe-mapwrap{position:relative;top:0}
#ffe-map{height:70vh}
}
@media (max-width:620px){
.ffe-hero{border-radius:20px}
.ffe-hero-cta .ffe-btn{flex:1 1 100%}
.ffe-card{grid-template-columns:1fr}
.ffe-card-img{min-height:170px}
.ffe-cd{gap:6px}
.ffe-feat-act .ffe-btn{flex:1 1 100%}
.ffe-submit .ffe-btn{width:100%}
}
/* in primo piano + archivio */
.ffe-ffnext,.ffe-past{margin-top:44px}
.ffe-sec-head{margin-bottom:18px}
.ffe-kicker2{display:inline-block;color:var(--r);font-weight:800;font-size:13px;letter-spacing:.1em;text-transform:uppercase}
#ffe .ffe-sec-head h2{font-size:clamp(22px,1.6vw + 12px,30px);font-weight:800;margin:6px 0 4px}
.ffe-sec-head p{color:var(--mu);margin:0;font-size:16px}
.ffe-mini-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:18px}
.ffe-mini{display:flex;flex-direction:column;background:#fff;border-radius:20px;overflow:hidden;border:1px solid var(--ln);color:var(--tx)!important;transition:transform .2s,box-shadow .2s}
.ffe-mini:hover{transform:translateY(-3px);box-shadow:0 14px 34px rgba(0,0,0,.1)}
.ffe-ffnext .ffe-mini{border:2px solid var(--r)}
.ffe-mini-img{position:relative;display:block;height:170px;background:linear-gradient(135deg,#c8102e,#9e0c24) center/cover no-repeat}
.ffe-mini-body{display:flex;flex-direction:column;gap:6px;padding:16px 18px 18px}
.ffe-mini-body b{font-size:17px;line-height:1.3;color:var(--ink)}
.ffe-mini-body small{font-size:14px;color:var(--mu)}
.ffe-mini-body em{font-style:normal;font-weight:700;color:var(--r);font-size:14px;margin-top:2px}
.ffe-more{text-align:center;margin-top:22px}
/* nel singolo articolo nascondo i campi tecnici */
.field-entry.coordinate,.field-entry.tipo-evento{display:none!important}
/* ===== FF EVENTI v1 (fine) ===== */
/* ===== FF EVENTI v1 — pagina eventi Fattore Famiglia (inizio) ===== */
(function () {
'use strict';
function boot() {
var blog = document.querySelector('.com-content-category-blog');
if (!blog) return;
var isEventi = document.getElementById('ff-eventi') || document.body.classList.contains('itemid-451');
if (!isEventi) return;
if (document.getElementById('ffe')) return;
var SUBMIT_URL = '/segnala-evento';
var MESI = ['gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'];
var MESI_L = ['gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'];
var GIORNI = ['domenica', 'lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato'];
function esc(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]; }); }
function pad(n) { return (n < 10 ? '0' : '') + n; }
function parseDate(t) {
if (!t) return null;
t = t.trim();
var m = t.match(/(\d{1,2})[-\/.](\d{1,2})[-\/.](\d{4})(?:[ T,]+(\d{1,2})[:.](\d{2}))?/);
if (m) return { d: new Date(+m[3], +m[2] - 1, +m[1], m[4] ? +m[4] : 0, m[5] ? +m[5] : 0), time: !!m[4] };
m = t.match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}))?/);
if (m) return { d: new Date(+m[1], +m[2] - 1, +m[3], m[4] ? +m[4] : 0, m[5] ? +m[5] : 0), time: !!m[4] };
return null;
}
function sameDay(a, b) { return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
function hhmm(d) { return pad(d.getHours()) + ':' + pad(d.getMinutes()); }
function store(k, v) { try { if (v === undefined) return JSON.parse(localStorage.getItem(k) || 'null'); localStorage.setItem(k, JSON.stringify(v)); } catch (e) { return null; } }
/* ---------- 1. Leggo gli eventi dall'elenco Joomla ---------- */
var arts = blog.querySelectorAll('.article-list .article, .blog-items .blog-item, .items-leading > div, .items-row .item');
var now = new Date();
var events = [];
Array.prototype.forEach.call(arts, function (a, i) {
var link = a.querySelector('.article-header a, h2 a, .page-header a');
if (!link) return;
var f = {};
a.querySelectorAll('.field-entry').forEach(function (li) {
var name = li.className.replace('field-entry', '').trim().split(/\s+/)[0];
var v = li.querySelector('.field-value');
if (name && v) f[name] = v;
});
var txt = function (k) { return f[k] ? f[k].textContent.replace(/\s+/g, ' ').trim() : ''; };
var href = function (k) { var x = f[k] && f[k].querySelector('a'); return x ? x.href : (txt(k).indexOf('http') === 0 ? txt(k) : ''); };
var st = parseDate(txt('data-evento'));
if (!st) return;
var en = parseDate(txt('data-fine'));
var start = st.d, end;
if (en && en.d > start) end = en.d;
else if (st.time && (st.d.getHours() || st.d.getMinutes())) end = new Date(start.getTime() + 3 * 3600e3);
else end = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 23, 59);
if (en && !en.time) end = new Date(en.d.getFullYear(), en.d.getMonth(), en.d.getDate(), 23, 59);
var past = end < now; // evento concluso: esce dall'agenda (se è di Fattore Famiglia va nell'archivio)
var img = a.querySelector('.article-intro-image img, .item-image img, img');
var introEl = a.querySelector('.article-introtext, .item-content, .article-intro');
var intro = '';
if (introEl) {
var c = introEl.cloneNode(true);
c.querySelectorAll('.readmore, .fields-container, script, style').forEach(function (n) { n.remove(); });
intro = c.textContent.replace(/\s+/g, ' ').trim();
}
var tipo = txt('tipo-evento').toLowerCase();
var coord = txt('coordinate').match(/(-?\d+(?:\.\d+)?)\s*[,; ]\s*(-?\d+(?:\.\d+)?)/);
var eta = txt('eta');
events.push({
id: 'e' + i, past: past,
title: link.textContent.replace(/\s+/g, ' ').trim(),
url: link.href,
img: img ? img.currentSrc || img.src : '',
intro: intro,
start: start, end: end, hasTime: st.time && (st.d.getHours() || st.d.getMinutes()),
ff: tipo ? tipo.indexOf('fattore') > -1 : !!(a.querySelector('.createdby') && a.querySelector('.createdby').textContent.trim()), // senza tipo: è FF se inserito dalla redazione
luogo: txt('luogo'), indirizzo: txt('indirizzo'),
lat: coord ? +coord[1] : null, lng: coord ? +coord[2] : null,
costo: txt('costo'), org: txt('organizzatore'),
info: href('link-info'), locandina: href('locandina-evento'),
eta: eta ? eta.split(/\s*,\s*/) : [],
etaRaw: eta.toLowerCase()
});
});
var pastFF = events.filter(function (e) { return e.past && e.ff; }).sort(function (x, y) { return y.start - x.start; });
events = events.filter(function (e) { return !e.past; });
events.sort(function (x, y) { var d = new Date(x.start.getFullYear(), x.start.getMonth(), x.start.getDate()) - new Date(y.start.getFullYear(), y.start.getMonth(), y.start.getDate()); return d || (y.ff - x.ff) || (x.start - y.start); });
/* ---------- 2. Costruisco la pagina ---------- */
var oldRow = blog.querySelector(':scope > .row');
var oldH1 = blog.querySelector(':scope > h1, :scope > .page-header');
var oldDesc = blog.querySelector(':scope > .category-desc');
var oldPag = blog.querySelector(':scope > .pagination, :scope > .com-content-category-blog__navigation, .pagination-wrapper');
[oldRow, oldH1, oldDesc, oldPag].forEach(function (n) { if (n) n.style.display = 'none'; });
var ffCount = events.filter(function (e) { return e.ff; }).length;
var root = document.createElement('div');
root.id = 'ffe';
root.innerHTML =
'<section class="ffe-hero">' +
'<div class="ffe-hero-txt">' +
'<span class="ffe-kicker">Agenda delle famiglie</span>' +
'<h1>Eventi per <span>tutta la famiglia</span></h1>' +
'<p>Gli appuntamenti di Fattore Famiglia e le migliori iniziative del territorio pensate per grandi e piccoli. Scegli, segna in calendario e… ci vediamo lì!</p>' +
'<div class="ffe-hero-cta">' +
'<a class="ffe-btn ffe-btn-white" href=\"#ffe-lista">Scopri gli eventi</a>' +
'<a class="ffe-btn ffe-btn-ghost" href=\"' + SUBMIT_URL + '">+ Segnala un evento</a>' +
'</div>' +
'</div>' +
'<div class="ffe-hero-stats">' +
'<div><b>' + events.length + '</b><span>eventi in arrivo</span></div>' +
'<div><b>' + ffCount + '</b><span>di Fattore Famiglia</span></div>' +
'<div><b>' + (events.length - ffCount) + '</b><span>dal territorio</span></div>' +
'</div>' +
'</section>' +
'<section class="ffe-feat" id="ffe-feat"></section>' +
'<section class="ffe-ffnext" id="ffe-ffnext"></section>' +
'<section class="ffe-tools" id="ffe-lista">' +
'<div class="ffe-chips" data-group="tipo">' +
'<button class="on" data-v="all">Tutti</button>' +
'<button data-v="ff"><i class="ffe-dot ffe-dot-ff"></i>Fattore Famiglia</button>' +
'<button data-v="terr"><i class="ffe-dot ffe-dot-terr"></i>Dal territorio</button>' +
'</div>' +
'<div class="ffe-chips" data-group="quando">' +
'<button class="on" data-v="all">Sempre</button>' +
'<button data-v="oggi">Oggi</button>' +
'<button data-v="weekend">Questo weekend</button>' +
'<button data-v="7">Prossimi 7 giorni</button>' +
'<button data-v="30">Prossimi 30 giorni</button>' +
'</div>' +
'<div class="ffe-row2">' +
'<label class="ffe-search"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg><input type="search" placeholder="Cerca evento, luogo, comune…" aria-label="Cerca"></label>' +
'<select class="ffe-eta" aria-label="Età dei bambini"><option value="">Tutte le età</option><option value="0-3">0-3 anni</option><option value="3-6">3-6 anni</option><option value="6-10">6-10 anni</option><option value="11-14">11-14 anni</option><option value="15+">Ragazzi 15+</option><option value="genitori">Genitori</option></select>' +
'<button class="ffe-near" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>Vicino a me</button>' +
'</div>' +
'<div class="ffe-switch" role="tablist"><button class="on" data-view="list">Elenco</button><button data-view="map">Mappa</button></div>' +
'</section>' +
'<section class="ffe-main" data-view="list">' +
'<div class="ffe-list" id="ffe-cards"></div>' +
'<div class="ffe-mapwrap"><div id="ffe-map" role="region" aria-label="Mappa degli eventi"></div><div class="ffe-legend"><span><i class="ffe-dot ffe-dot-ff"></i>Fattore Famiglia</span><span><i class="ffe-dot ffe-dot-terr"></i>Territorio</span></div></div>' +
'</section>' +
'<section class="ffe-past" id="ffe-past"></section>' +
'<section class="ffe-submit">' +
'<div><h2>Organizzi un evento per famiglie?</h2><p>Parrocchie, associazioni, comuni, scuole, biblioteche: segnalateci le vostre iniziative. Dopo una rapida verifica della redazione le pubblichiamo qui e sulla mappa, gratis.</p></div>' +
'<a class="ffe-btn ffe-btn-white" href=\"' + SUBMIT_URL + '">Segnala il tuo evento</a>' +
'</section>';
blog.insertBefore(root, blog.firstChild);
var $ = function (s) { return root.querySelector(s); };
var state = { tipo: 'all', quando: 'all', q: '', eta: '', pos: null, view: 'list' };
/* ---------- 3. Etichette tempo ---------- */
function whenLabel(e) {
var n = new Date();
if (e.start <= n && e.end >= n) return { cls: 'live', t: 'In corso adesso' };
var tom = new Date(n.getFullYear(), n.getMonth(), n.getDate() + 1);
if (sameDay(e.start, n)) return { cls: 'today', t: 'Oggi' + (e.hasTime ? ' alle ' + hhmm(e.start) : '') };
if (sameDay(e.start, tom)) return { cls: 'soon', t: 'Domani' + (e.hasTime ? ' alle ' + hhmm(e.start) : '') };
var days = Math.ceil((new Date(e.start.getFullYear(), e.start.getMonth(), e.start.getDate()) - new Date(n.getFullYear(), n.getMonth(), n.getDate())) / 864e5);
if (days <= 7) return { cls: 'soon', t: 'Tra ' + days + ' giorni' };
return { cls: '', t: 'Tra ' + days + ' giorni' };
}
function dateLong(e) {
var s = e.start, en = e.end;
var out = GIORNI[s.getDay()] + ' ' + s.getDate() + ' ' + MESI_L[s.getMonth()];
if (!sameDay(s, en) && (en - s) > 20 * 3600e3) out = 'dal ' + s.getDate() + (s.getMonth() !== en.getMonth() ? ' ' + MESI_L[s.getMonth()] : '') + ' al ' + en.getDate() + ' ' + MESI_L[en.getMonth()];
else if (e.hasTime) out += ', ore ' + hhmm(s) + (sameDay(s, en) && (en - s) !== 3 * 3600e3 ? '–' + hhmm(en) : '');
return out.charAt(0).toUpperCase() + out.slice(1);
}
/* ---------- 4. Evento in evidenza con countdown ---------- */
function renderFeat() {
var box = $('#ffe-feat');
var e = events.filter(function (x) { return x.ff; })[0] || events[0];
if (!e) {
box.innerHTML = '<div class="ffe-empty-feat"><h2>Nuovi eventi in arrivo!</h2><p>Stiamo preparando i prossimi appuntamenti. Iscriviti al nostro canale WhatsApp per non perderli.</p></div>';
return;
}
box.innerHTML =
'<div class="ffe-feat-card">' +
'<div class="ffe-feat-img"' + (e.img ? ' style="background-image:url(\'' + esc(e.img) + '\')"' : '') + '>' + (e.img ? '' : '<span>' + e.start.getDate() + '<small>' + MESI[e.start.getMonth()] + '</small></span>') + '</div>' +
'<div class="ffe-feat-body">' +
'<span class="ffe-badge ' + (e.ff ? 'ffe-b-ff' : 'ffe-b-terr') + '">' + (e.ff ? '★ Prossimo evento Fattore Famiglia' : 'Prossimo evento') + '</span>' +
'<h2><a href=\"' + esc(e.url) + '">' + esc(e.title) + '</a></h2>' +
'<p class="ffe-feat-meta"><b>' + esc(dateLong(e)) + '</b>' + (e.luogo || e.indirizzo ? ' · ' + esc(e.luogo || e.indirizzo) : '') + '</p>' +
'<div class="ffe-cd" aria-live="polite">' +
'<div><b data-u="d">0</b><span>giorni</span></div><div><b data-u="h">0</b><span>ore</span></div><div><b data-u="m">0</b><span>minuti</span></div><div><b data-u="s">0</b><span>secondi</span></div>' +
'</div>' +
'<div class="ffe-live-msg">🎉 L\'evento è in corso adesso: vi aspettiamo!</div>' +
'<div class="ffe-feat-act">' +
'<a class="ffe-btn ffe-btn-red" href=\"' + esc(e.url) + '">Tutti i dettagli</a>' +
'<button class="ffe-btn ffe-btn-line" data-ics="' + e.id + '">📅 Aggiungi al calendario</button>' +
'</div>' +
'</div>' +
'</div>';
var cd = box.querySelector('.ffe-cd'), card = box.querySelector('.ffe-feat-card');
function tick() {
var diff = e.start - new Date();
if (diff <= 0) { card.classList.add('is-live'); return; }
var d = Math.floor(diff / 864e5), h = Math.floor(diff % 864e5 / 36e5), m = Math.floor(diff % 36e5 / 6e4), s = Math.floor(diff % 6e4 / 1e3);
cd.querySelector('[data-u=d]').textContent = d;
cd.querySelector('[data-u=h]').textContent = pad(h);
cd.querySelector('[data-u=m]').textContent = pad(m);
cd.querySelector('[data-u=s]').textContent = pad(s);
}
tick(); setInterval(tick, 1000);
}
/* ---------- 4b. In primo piano (prossimi eventi FF) e archivio (eventi FF passati) ---------- */
function miniCard(e, past) {
var w = whenLabel(e);
return '<a class="ffe-mini' + (past ? ' is-past' : '') + '" href=\"' + esc(e.url) + '">' +
'<span class="ffe-mini-img"' + (e.img ? ' style="background-image:url(\'' + esc(e.img) + '\')"' : '') + '>' +
'<span class="ffe-date"><b>' + e.start.getDate() + '</b>' + MESI[e.start.getMonth()] + (past ? ' ' + e.start.getFullYear() : '') + '</span>' +
(past ? '' : '<span class="ffe-when ffe-w-' + w.cls + '">' + esc(w.t) + '</span>') +
'</span>' +
'<span class="ffe-mini-body"><b>' + esc(e.title) + '</b><small>' + esc(past ? dateLong({ start: e.start, end: e.end, hasTime: false }) : dateLong(e)) + (e.luogo ? ' · ' + esc(e.luogo) : '') + '</small><em>' + (past ? 'Guarda com\'è andata →' : 'Scopri e partecipa →') + '</em></span>' +
'</a>';
}
function renderFFNext() {
var box = $('#ffe-ffnext');
var list = events.filter(function (x) { return x.ff; }).slice(1);
if (!list.length) { box.innerHTML = ''; box.style.display = 'none'; return; }
box.style.display = '';
box.innerHTML = '<div class="ffe-sec-head"><span class="ffe-kicker2">★ In primo piano</span><h2>I prossimi appuntamenti di Fattore Famiglia</h2></div><div class="ffe-mini-grid">' + list.map(function (e) { return miniCard(e, false); }).join('') + '</div>';
}
function renderPast() {
var box = $('#ffe-past');
if (!pastFF.length) { box.innerHTML = ''; box.style.display = 'none'; return; }
box.style.display = '';
var all = box.getAttribute('data-all') === '1';
var list = all ? pastFF : pastFF.slice(0, 6);
box.innerHTML = '<div class="ffe-sec-head"><span class="ffe-kicker2">Archivio</span><h2>Rivivi gli eventi di Fattore Famiglia</h2><p>Gli appuntamenti che abbiamo già vissuto insieme: racconti, foto e ricordi.</p></div><div class="ffe-mini-grid">' + list.map(function (e) { return miniCard(e, true); }).join('') + '</div>' +
(pastFF.length > 6 && !all ? '<div class="ffe-more"><button class="ffe-btn ffe-btn-line" data-more="1">Mostra tutti (' + pastFF.length + ')</button></div>' : '');
}
/* ---------- 5. Filtri ---------- */
function inRange(e) {
var n = new Date(), t0 = new Date(n.getFullYear(), n.getMonth(), n.getDate());
if (state.quando === 'all') return true;
if (state.quando === 'oggi') return e.start < new Date(t0.getTime() + 864e5) && e.end >= n;
if (state.quando === 'weekend') {
var dow = n.getDay();
var sat = new Date(t0.getTime() + ((6 - dow + 7) % 7) * 864e5);
if (dow === 0) sat = new Date(t0.getTime() - 864e5);
var mon = new Date(sat.getTime() + 2 * 864e5);
return e.start < mon && e.end >= sat;
}
var lim = new Date(t0.getTime() + (+state.quando + 1) * 864e5);
return e.start < lim;
}
function filtered() {
var q = state.q.toLowerCase();
var list = events.filter(function (e) {
if (state.tipo === 'ff' && !e.ff) return false;
if (state.tipo === 'terr' && e.ff) return false;
if (!inRange(e)) return false;
if (state.eta && e.etaRaw && e.etaRaw.indexOf(state.eta) === -1 && e.etaRaw.indexOf('tutte') === -1) return false;
if (q && (e.title + ' ' + e.luogo + ' ' + e.indirizzo + ' ' + e.org + ' ' + e.intro).toLowerCase().indexOf(q) === -1) return false;
return true;
});
if (state.pos) list = list.slice().sort(function (a, b) { return (a.dist == null ? 1e9 : a.dist) - (b.dist == null ? 1e9 : b.dist); });
return list;
}
/* ---------- 6. Schede evento ---------- */
function card(e) {
var w = whenLabel(e);
var maps = 'https://www.google.com/maps/dir/?api=1&destination=' + encodeURIComponent(e.lat != null ? e.lat + ',' + e.lng : (e.luogo + ' ' + e.indirizzo));
var share = 'https://wa.me/?text=' + encodeURIComponent('👨👩👧👦 ' + e.title + '\n📅 ' + dateLong(e) + (e.luogo ? '\n📍 ' + e.luogo : '') + '\n' + e.url);
return '<article class="ffe-card' + (e.ff ? ' is-ff' : '') + '" data-id="' + e.id + '">' +
'<a class="ffe-card-img" href=\"' + esc(e.url) + '"' + (e.img ? ' style="background-image:url(\'' + esc(e.img) + '\')"' : '') + ' aria-label="' + esc(e.title) + '">' +
'<span class="ffe-date"><b>' + e.start.getDate() + '</b>' + MESI[e.start.getMonth()] + '</span>' +
'<span class="ffe-when ffe-w-' + w.cls + '">' + esc(w.t) + '</span>' +
'</a>' +
'<div class="ffe-card-body">' +
'<span class="ffe-badge ' + (e.ff ? 'ffe-b-ff' : 'ffe-b-terr') + '">' + (e.ff ? '★ Fattore Famiglia' : 'Dal territorio') + '</span>' +
'<h3><a href=\"' + esc(e.url) + '">' + esc(e.title) + '</a></h3>' +
'<ul class="ffe-meta">' +
'<li><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18M8 3v4M16 3v4"/></svg>' + esc(dateLong(e)) + '</li>' +
(e.luogo || e.indirizzo ? '<li><svg viewBox="0 0 24 24"><path d="M12 22s7-6.2 7-12a7 7 0 1 0-14 0c0 5.8 7 12 7 12z"/><circle cx="12" cy="10" r="2.5"/></svg>' + esc([e.luogo, e.indirizzo].filter(Boolean).join(' · ')) + (e.dist != null ? ' <em>· ' + (e.dist < 10 ? e.dist.toFixed(1) : Math.round(e.dist)) + ' km</em>' : '') + '</li>' : '') +
(e.org ? '<li><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6"/></svg>' + esc(e.org) + '</li>' : '') +
'</ul>' +
(e.intro ? '<p class="ffe-intro">' + esc(e.intro.length > 170 ? e.intro.slice(0, 165).replace(/\s\S*$/, '') + '…' : e.intro) + '</p>' : '') +
'<div class="ffe-tags">' +
(e.costo ? '<span class="ffe-tag ffe-tag-cost">' + esc(e.costo) + '</span>' : '') +
e.eta.map(function (x) { return '<span class="ffe-tag">' + esc(x) + '</span>'; }).join('') +
'</div>' +
'<div class="ffe-act">' +
'<a class="ffe-btn ffe-btn-red ffe-sm" href=\"' + esc(e.url) + '">Dettagli</a>' +
'<button class="ffe-ico" data-ics="' + e.id + '" title="Aggiungi al calendario" aria-label="Aggiungi al calendario"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18M8 3v4M16 3v4M12 13v5M9.5 15.5h5"/></svg></button>' +
'<a class="ffe-ico" href=\"' + esc(maps) + '" target="_blank" rel="noopener" title="Indicazioni stradali" aria-label="Indicazioni stradali"><svg viewBox="0 0 24 24"><path d="m3 11 18-8-8 18-2-8z"/></svg></a>' +
'<a class="ffe-ico ffe-wa" href=\"' + esc(share) + '" target="_blank" rel="noopener" title="Condividi su WhatsApp" aria-label="Condividi su WhatsApp"><svg viewBox="0 0 24 24"><path d="M4 20l1.3-3.9A8 8 0 1 1 8 19.1z"/><path d="M9 9.5c.3 2 2.5 4.6 5 5l1-1.2-1.6-.9-.7.7c-1-.4-2-1.4-2.4-2.4l.7-.7-.9-1.6z"/></svg></a>' +
((e.lat != null || e.geo) ? '<button class="ffe-ico ffe-pin" data-pin="' + e.id + '" title="Vedi sulla mappa" aria-label="Vedi sulla mappa"><svg viewBox="0 0 24 24"><path d="M9 4 3 6v14l6-2 6 2 6-2V4l-6 2z"/><path d="M9 4v14M15 6v14"/></svg></button>' : '') +
(e.info ? '<a class="ffe-link" href=\"' + esc(e.info) + '" target="_blank" rel="noopener">Info e iscrizioni ↗</a>' : '') +
'</div>' +
'</div>' +
'</article>';
}
function renderList() {
var list = filtered();
var box = $('#ffe-cards');
if (!list.length) {
box.innerHTML = '<div class="ffe-empty"><div class="ffe-empty-ico">🗓️</div><h3>Nessun evento con questi filtri</h3><p>Prova a cambiare periodo o tipo di evento, oppure segnalaci tu un\'iniziativa per famiglie.</p><a class="ffe-btn ffe-btn-red" href=\"' + SUBMIT_URL + '">Segnala un evento</a></div>';
} else {
var html = '', lastKey = '';
list.forEach(function (e) {
var key = state.pos ? '' : MESI_L[e.start.getMonth()] + ' ' + e.start.getFullYear();
if (key && key !== lastKey) { html += '<h2 class="ffe-month">' + key + '</h2>'; lastKey = key; }
html += card(e);
});
box.innerHTML = html;
}
renderMarkers(list);
}
/* ---------- 7. Mappa (Leaflet + OpenStreetMap) ---------- */
var map = null, layer = null, markers = {};
function loadLeaflet(cb) {
if (window.L) return cb();
var css = document.createElement('link');
css.rel = 'stylesheet'; css.href = 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css';
document.head.appendChild(css);
var s = document.createElement('script');
s.src = 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js';
s.onload = cb; document.head.appendChild(s);
}
function icon(e) {
return L.divIcon({ className: 'ffe-mk' + (e.ff ? ' ffe-mk-ff' : ''), html: '<span><i><b>' + e.start.getDate() + '</b><small>' + MESI[e.start.getMonth()] + '</small></i></span>', iconSize: [42, 50], iconAnchor: [21, 50], popupAnchor: [0, -46] });
}
function renderMarkers(list) {
if (!map) return;
layer.clearLayers(); markers = {};
var seen = {};
list.forEach(function (e) {
if (e.lat == null) return;
var k = e.lat.toFixed(4) + ',' + e.lng.toFixed(4), n = seen[k] = (seen[k] || 0) + 1;
var lat = e.lat + (n - 1) * 0.0004, lng = e.lng + (n - 1) * 0.0004;
var m = L.marker([lat, lng], { icon: icon(e), title: e.title, riseOnHover: true, zIndexOffset: e.ff ? 1000 : 0 })
.bindPopup('<div class="ffe-pop">' + (e.img ? '<img src=\"' + esc(e.img) + '" alt="">' : '') + '<span class="ffe-badge ' + (e.ff ? 'ffe-b-ff' : 'ffe-b-terr') + '">' + (e.ff ? '★ Fattore Famiglia' : 'Dal territorio') + '</span><b>' + esc(e.title) + '</b><span>' + esc(dateLong(e)) + '</span><span>' + esc(e.luogo || e.indirizzo) + '</span><a href=\"' + esc(e.url) + '">Vedi dettagli →</a></div>', { maxWidth: 260 });
m.addTo(layer); markers[e.id] = m;
});
}
function initMap() {
if (map) return;
loadLeaflet(function () {
map = L.map('ffe-map', { scrollWheelZoom: false, zoomControl: true }).setView([42.4, 12.6], 6);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map);
layer = L.layerGroup().addTo(map);
map.on('click', function () { map.scrollWheelZoom.enable(); });
renderMarkers(filtered());
geocodeMissing();
});
}
// Se mancano le coordinate le ricavo dall'indirizzo (una volta sola, poi restano in memoria nel browser)
function geocodeMissing() {
var cache = store('ffe-geo') || {};
var todo = events.filter(function (e) { return e.lat == null && (e.indirizzo || e.luogo); });
todo.forEach(function (e) {
var key = (e.indirizzo || e.luogo).toLowerCase();
if (cache[key]) { e.lat = cache[key][0]; e.lng = cache[key][1]; e.geo = 1; }
});
var rest = todo.filter(function (e) { return e.lat == null; });
if (!rest.length) { renderList(); return; }
var i = 0;
(function next() {
if (i >= rest.length) { store('ffe-geo', cache); renderList(); return; }
var e = rest[i++], q = (e.indirizzo || e.luogo);
fetch('https://nominatim.openstreetmap.org/search?format=json&limit=1&countrycodes=it&q=' + encodeURIComponent(q))
.then(function (r) { return r.json(); })
.then(function (j) { if (j && j[0]) { e.lat = +j[0].lat; e.lng = +j[0].lon; e.geo = 1; cache[q.toLowerCase()] = [e.lat, e.lng]; } })
.catch(function () {})
.then(function () { setTimeout(next, 1100); });
})();
}
var mapObs = new IntersectionObserver(function (en) { if (en[0].isIntersecting) { initMap(); mapObs.disconnect(); } }, { rootMargin: '300px' });
mapObs.observe($('#ffe-map'));
/* ---------- 8. Calendario (.ics) ---------- */
function ics(e) {
function f(d) { return d.getUTCFullYear() + pad(d.getUTCMonth() + 1) + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + pad(d.getUTCMinutes()) + '00Z'; }
var body = ['BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//Fattore Famiglia//Eventi//IT', 'BEGIN:VEVENT',
'UID:' + e.id + '-' + e.start.getTime() + '-fattorefamiglia-eventi', 'DTSTAMP:' + f(new Date()),
'DTSTART:' + f(e.start), 'DTEND:' + f(e.end), 'SUMMARY:' + e.title.replace(/[,;]/g, ' '),
'LOCATION:' + [e.luogo, e.indirizzo].filter(Boolean).join(' - ').replace(/[,;]/g, ' '),
'DESCRIPTION:' + (e.url), 'URL:' + e.url,
'BEGIN:VALARM', 'TRIGGER:-P1D', 'ACTION:DISPLAY', 'DESCRIPTION:Domani: ' + e.title.replace(/[,;]/g, ' '), 'END:VALARM',
'END:VEVENT', 'END:VCALENDAR'].join('\r\n');
var a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([body], { type: 'text/calendar;charset=utf-8' }));
a.download = e.title.replace(/[^\wàèéìòù ]+/gi, '').trim().replace(/\s+/g, '-').slice(0, 50) + '.ics';
document.body.appendChild(a); a.click(); setTimeout(function () { a.remove(); }, 500);
}
/* ---------- 9. Interazioni ---------- */
root.addEventListener('click', function (ev) {
var b = ev.target.closest('button');
if (!b) return;
if (b.hasAttribute('data-more')) { $('#ffe-past').setAttribute('data-all', '1'); renderPast(); return; }
var grp = b.parentElement.getAttribute('data-group');
if (grp) {
b.parentElement.querySelectorAll('button').forEach(function (x) { x.classList.toggle('on', x === b); });
state[grp] = b.getAttribute('data-v'); renderList(); return;
}
if (b.hasAttribute('data-view')) {
state.view = b.getAttribute('data-view');
b.parentElement.querySelectorAll('button').forEach(function (x) { x.classList.toggle('on', x === b); });
$('.ffe-main').setAttribute('data-view', state.view);
if (state.view === 'map') { initMap(); setTimeout(function () { map && map.invalidateSize(); }, 200); }
return;
}
if (b.hasAttribute('data-ics')) { var e = events.filter(function (x) { return x.id === b.getAttribute('data-ics'); })[0]; if (e) ics(e); return; }
if (b.hasAttribute('data-pin')) {
var id = b.getAttribute('data-pin');
if (window.matchMedia('(max-width: 999px)').matches) root.querySelector('.ffe-switch [data-view=map]').click();
initMap();
var go = function () { var m = markers[id]; if (!m) return; map.setView(m.getLatLng(), 14); m.openPopup(); $('.ffe-mapwrap').scrollIntoView({ behavior: 'smooth', block: 'center' }); };
if (map) go(); else setTimeout(go, 1200);
return;
}
if (b.classList.contains('ffe-near')) {
if (!navigator.geolocation) return;
b.classList.add('loading');
navigator.geolocation.getCurrentPosition(function (p) {
b.classList.remove('loading'); b.classList.add('on');
state.pos = [p.coords.latitude, p.coords.longitude];
events.forEach(function (e) {
if (e.lat == null) return;
var R = 6371, dLat = (e.lat - state.pos[0]) * Math.PI / 180, dLng = (e.lng - state.pos[1]) * Math.PI / 180;
var x = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(state.pos[0] * Math.PI / 180) * Math.cos(e.lat * Math.PI / 180) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
e.dist = R * 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));
});
renderList();
if (map) { map.setView(state.pos, 10); L.circleMarker(state.pos, { radius: 8, color: '#fff', weight: 3, fillColor: '#1a73e8', fillOpacity: 1 }).addTo(map).bindTooltip('Sei qui'); }
}, function () { b.classList.remove('loading'); alert('Non riesco a leggere la tua posizione. Controlla i permessi del browser.'); }, { timeout: 10000 });
}
});
var qt;
$('.ffe-search input').addEventListener('input', function (ev) { clearTimeout(qt); qt = setTimeout(function () { state.q = ev.target.value.trim(); renderList(); }, 200); });
$('.ffe-eta').addEventListener('change', function (ev) { state.eta = ev.target.value; renderList(); });
renderFeat();
renderFFNext();
renderPast();
renderList();
setInterval(function () { // aggiorna "tra X giorni / in corso" e toglie gli eventi appena terminati
var n = new Date(), before = events.length;
events = events.filter(function (e) { if (e.end < n && e.ff) pastFF.unshift(e); return e.end >= n; });
if (events.length !== before) { renderFeat(); renderFFNext(); renderPast(); }
renderList();
}, 60000);
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot); else boot();
})();
/* ===== FF EVENTI v1 (fine) ===== */