Terminez l’année autrement et réunissez votre équipe dans un cadre intime et exclusif. Une belle table, une cuisine raffinée et une expérience pensée dans les moindres détails pour prendre le temps d’échanger, de célébrer et de profiter ensemble.
Petit comitéTable privatiséeCuisine raffinéeExpérience sur mesure
Terminez l’année autrement et réunissez votre équipe dans un cadre intime
et exclusif. Une belle table, une cuisine raffinée et une expérience
pensée dans les moindres détails pour prendre le temps d’échanger,
de célébrer et de profiter ensemble.
Petit comitéTable privatiséeCuisine raffinéeExpérience sur mesure
/* ============================================================
BROCHURE — OUVERTURE POPUP + DONNÉES BROCHURE
Popup Elementor : 54912
============================================================ */
(function(){
var POPUP_ID = 54912;
function memoriserBrochure(lien){
var brochure =
lien.getAttribute('data-brochure') || '';
var url =
lien.getAttribute('data-brochure-url') || '';
try{
sessionStorage.setItem(
'tero_brochure',
brochure
);
sessionStorage.setItem(
'tero_brochure_url',
url
);
}catch(e){}
return {
brochure: brochure,
url: url
};
}
function definirValeur(champ, valeur){
if(!champ) return;
champ.value = valeur || '';
champ.dispatchEvent(
new Event('input', {
bubbles:true
})
);
champ.dispatchEvent(
new Event('change', {
bubbles:true
})
);
}
function remplirPopup(donnees){
if(!donnees) return;
/*
* CHAMP BROCHURE
*/
document.querySelectorAll(
'.elementor-popup-modal input[name="brochure"],' +
'.elementor-popup-modal select[name="brochure"],' +
'.elementor-popup-modal textarea[name="brochure"]'
).forEach(function(champ){
definirValeur(
champ,
donnees.brochure
);
});
/*
* CHAMP BROCHURE_URL
*/
document.querySelectorAll(
'.elementor-popup-modal input[name="brochure_url"],' +
'.elementor-popup-modal select[name="brochure_url"],' +
'.elementor-popup-modal textarea[name="brochure_url"]'
).forEach(function(champ){
definirValeur(
champ,
donnees.url
);
});
}
function ouvrirPopup(lien){
var donnees =
memoriserBrochure(lien);
if(
window.elementorProFrontend &&
elementorProFrontend.modules &&
elementorProFrontend.modules.popup
){
elementorProFrontend.modules.popup.showPopup({
id: POPUP_ID
});
/*
* Elementor injecte le popup dans le DOM
* après son ouverture, donc plusieurs essais.
*/
[150, 400, 800, 1200].forEach(
function(delai){
setTimeout(
function(){
remplirPopup(donnees);
},
delai
);
}
);
}
}
document.addEventListener(
'click',
function(e){
if(
!e.target ||
!e.target.closest
){
return;
}
var lien =
e.target.closest(
'.js-brochure-popup'
);
if(!lien){
return;
}
e.preventDefault();
ouvrirPopup(lien);
},
true
);
})();
/* ============================================================
CTA DEVIS — ROUTEUR INDÉPENDANT
============================================================ */
/* ============================================================
CTA DEVIS — ROUTEUR INDÉPENDANT
Placé en premier pour fonctionner même si un autre script plante.
============================================================ */
(function(){
function allerAuDevisDesktop(){
var scene = document.getElementById('scene');
if(!scene) return;
var debut =
scene.getBoundingClientRect().top +
window.pageYOffset;
var course = Math.max(
0,
scene.offsetHeight - window.innerHeight
);
/* 96 % = acte devis complètement affiché, mais avant la fin du sticky */
var cible = debut + course * 0.96;
window.scrollTo({
top: cible,
behavior: 'smooth'
});
}
function allerAuDevisMobile(){
var devis = document.getElementById('devis-mobile');
if(!devis) return;
var cible =
devis.getBoundingClientRect().top +
window.pageYOffset -
12;
window.scrollTo({
top: cible,
behavior: 'smooth'
});
}
document.addEventListener('click', function(e){
if(!e.target || !e.target.closest) return;
var lienMobile = e.target.closest('a[href="#devis-mobile"]');
var lienDesktop = e.target.closest('a[href="#devis"]');
if(!lienMobile && !lienDesktop) return;
e.preventDefault();
if(
lienMobile ||
window.matchMedia('(max-width:900px)').matches
){
allerAuDevisMobile();
}else{
allerAuDevisDesktop();
}
}, true);
})();
/* ---------- mesure automatique du bandeau haut ----------
On ne cherche pas par sélecteur : on regarde quel élément
occupe réellement le haut de l'écran et on remonte jusqu'à
son ancêtre fixe ou collant. Fonctionne quel que soit le
balisage du header. */
(function(){
var lp = document.getElementById('tero-lp');
if(!lp) return;
function ancetreFige(el){
while(el && el !== document.body){
var s = getComputedStyle(el);
if(s.position === 'fixed' || s.position === 'sticky') return el;
el = el.parentElement;
}
return null;
}
function hauteurHaut(){
var max = 0;
/* trois sondes horizontales, pour ne pas tomber sur un trou */
[0.15, 0.5, 0.85].forEach(function(f){
for(var y = 4; y <= 140; y += 12){
var el = document.elementFromPoint(Math.round(window.innerWidth * f), y);
if(!el || lp.contains(el)) continue;
var fige = ancetreFige(el);
if(!fige) continue;
var r = fige.getBoundingClientRect();
if(r.top <= 4 && r.bottom > max && r.bottom < 260) max = r.bottom;
}
});
return Math.round(max);
}
var dernier = -1;
function poser(){
var hh = hauteurHaut();
if(hh !== dernier){
dernier = hh;
lp.style.setProperty('--hauteur-header', hh + 'px');
}
}
poser();
window.addEventListener('load', poser);
window.addEventListener('resize', poser);
window.addEventListener('scroll', poser, {passive:true});
var n = 0;
var tic = setInterval(function(){ poser(); if(++n > 40) clearInterval(tic); }, 150);
})();
/* ---------- images : distant → local → couleur de repli ---------- */
(function(){
document.querySelectorAll('#tero-lp img[data-local]').forEach(function(im){
im.addEventListener('error',function(){
var local = im.getAttribute('data-local');
if(local && !im.dataset.essai){ im.dataset.essai='1'; im.src = local; return; }
im.style.visibility='hidden'; /* le dégradé de la couche prend le relais */
var hote = im.parentElement;
if(hote && hote.classList.contains('ph') && !hote.querySelector('.ph-note')){
var n=document.createElement('span');
n.className='ph-note';
n.textContent = im.getAttribute('alt') || 'Visual';
hote.appendChild(n);
}
});
});
})();
/* ---------- la séquence pilotée au scroll ---------- */
(function(){
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if(reduce) return;
/* Sur mobile, le scroll est entièrement natif via .mobile-story.
On ne lance surtout pas le moteur translateY/opacity piloté au pixel. */
if(window.matchMedia('(max-width:900px)').matches) return;
var scene = document.getElementById('scene');
var colle = document.getElementById('colle');
var cadre = document.getElementById('cadre');
var video = document.getElementById('video');
var cLieu = document.getElementById('cLieu');
var cTb = document.getElementById('cTb');
var cTraiteur = document.getElementById('cTraiteur');
var produit = document.getElementById('produit');
var b1 = document.getElementById('bloc1'), b2 = document.getElementById('bloc2'), b3 = document.getElementById('bloc3');
var trioTitre = document.getElementById('trioTitre');
var cta = document.getElementById('ctaFlottant');
var voile = scene.querySelector('.voile');
var acteDevis = document.getElementById('acteDevis');
var couches = [cLieu, cTraiteur, cTb];
var indice = document.getElementById('indice');
if(!scene) return;
/* interpole une valeur entre deux bornes de progression */
function seg(p,a,b){ return Math.min(1, Math.max(0, (p - a) / (b - a))); }
function adoucir(t){ return t<.5 ? 2*t*t : 1 - Math.pow(-2*t+2,2)/2; }
/* Translations arrondies au pixel entier et posées en 3D :
les valeurs décimales font scintiller le texte sur mobile
(rendu sub-pixel recalculé à chaque image). */
function poser(el, opacite, y){
el.style.opacity = opacite;
el.style.transform = 'translate3d(0,' + Math.round(y) + 'px,0)';
}
/* progression amortie : l'animation rattrape le scroll en douceur,
un coup de molette rapide ne fait plus tout défiler d'un bloc */
var pLisse = null;
var boucle = false;
var AMORTI = 0.085; /* plus bas = plus lent à rattraper */
/* La barre d'adresse mobile fait varier innerHeight pendant le scroll.
On fige une hauteur de référence, réévaluée seulement sur un vrai
changement (rotation, redimensionnement), pas à chaque pixel. */
function progressionBrute(){
var rect = scene.getBoundingClientRect();
var course = scene.offsetHeight - window.innerHeight;
return Math.min(1, Math.max(0, -rect.top / course));
}
function animer(){
var cible = progressionBrute();
if(pLisse === null) pLisse = cible;
pLisse += (cible - pLisse) * AMORTI;
var ecart = Math.abs(cible - pLisse);
if(ecart < 0.0004){ pLisse = cible; boucle = false; }
else { requestAnimationFrame(animer); }
dessiner(pLisse);
}
var enAttente = false;
function dessiner(p){
enAttente = false;
if(p === undefined) p = pLisse === null ? progressionBrute() : pLisse;
/* — le cadre s'élargit, puis se rétrécit tout à la fin —
sur mobile il est figé en plein écran : pas d'animation de taille */
var ouvre = adoucir(seg(p, 0, .08));
var ferme = adoucir(seg(p, .78, .88));
colle.style.setProperty('--e', (ouvre - ferme).toFixed(3));
/* bascule du contenu vers la citation, une fois le cadre ouvert */
var bascule = adoucir(seg(p, .06, .16));
colle.style.setProperty('--p', bascule.toFixed(3));
/* — acte 1 : le produit est là dès le départ, il ne fait que sortir — */
var pOut = adoucir(seg(p, .21, .28));
poser(produit, (1 - pOut).toFixed(3), (-60 * pOut).toFixed(1));
produit.style.pointerEvents = pOut > .5 ? 'none' : 'auto';
/* — la vidéo zoome en s'effaçant, le lieu arrive en dézoom — */
var vOut = adoucir(seg(p, .21, .33));
video.style.opacity = (1 - vOut).toFixed(3);
video.style.transform = 'scale(' + (1 + .22 * vOut).toFixed(3) + ')';
/* 1re couche : le lieu */
var lIn = adoucir(seg(p, .23, .33)), lOut = adoucir(seg(p, .41, .49));
cLieu.style.opacity = (lIn - lOut).toFixed(3);
cLieu.style.transform = 'scale(' + (1.14 - .14 * lIn + .14 * adoucir(seg(p, .33, .49))).toFixed(3) + ')';
/* 2e couche : le traiteur */
var tIn = adoucir(seg(p, .43, .50)), tOut = adoucir(seg(p, .58, .65));
cTraiteur.style.opacity = (tIn - tOut).toFixed(3);
cTraiteur.style.transform = 'scale(' + (1 + .14 * adoucir(seg(p, .43, .65))).toFixed(3) + ')';
/* 3e couche : l'activité, puis assombrissement pour le devis */
var rIn = adoucir(seg(p, .59, .66));
cTb.style.opacity = rIn.toFixed(3);
cTb.style.transform = 'scale(' + (1 + .14 * adoucir(seg(p, .59, .93))).toFixed(3) + ')';
/* — le trio de colonnes — */
var sortie = adoucir(seg(p, .72, .79));
var t1 = adoucir(seg(p, .31, .39));
var t2 = adoucir(seg(p, .47, .55));
var t3 = adoucir(seg(p, .63, .71));
if(trioTitre) poser(trioTitre, (t1 - sortie).toFixed(3), (18 * (1 - t1)).toFixed(1));
poser(b1, (t1 - sortie).toFixed(3), (22 * (1 - t1)).toFixed(1));
poser(b2, (t2 - sortie).toFixed(3), (22 * (1 - t2)).toFixed(1));
poser(b3, (t3 - sortie).toFixed(3), (22 * (1 - t3)).toFixed(1));
b2.classList.toggle('vu', t2 > .5);
b3.classList.toggle('vu', t3 > .5);
/* — le CTA réapparaît avec le premier texte, sort avec les colonnes — */
var cIn = adoucir(seg(p, .33, .41));
var ctaOp = cIn - sortie;
cta.style.opacity = ctaOp.toFixed(3);
cta.style.transform = 'translate3d(-50%,' + Math.round(18 * (1 - cIn)) + 'px,0)';
cta.style.pointerEvents = ctaOp > .5 ? 'auto' : 'none';
/* — les photos s'effacent : le cadre redevient bleu nuit — */
var nuit = adoucir(seg(p, .76, .86));
couches.forEach(function(c){
c.style.opacity = (parseFloat(c.style.opacity || 0) * (1 - nuit)).toFixed(3);
});
voile.style.opacity = (1 - nuit).toFixed(3);
/* — acte final : le devis, dans le cadre rétréci — */
var dIn = adoucir(seg(p, .86, .94));
acteDevis.style.opacity = dIn.toFixed(3);
acteDevis.classList.toggle('actif', dIn > .5);
colle.style.setProperty('--d', dIn.toFixed(3));
indice.style.opacity = (1 - adoucir(seg(p, 0, .06))).toFixed(3);
}
function auScroll(){
if(!boucle){ boucle = true; requestAnimationFrame(animer); }
}
/* capture:true pour capter aussi le défilement d'un conteneur parent (aperçu, iframe) */
window.addEventListener('scroll', auScroll, {passive:true, capture:true});
document.addEventListener('scroll', auScroll, {passive:true, capture:true});
window.addEventListener('resize', auScroll);
window.addEventListener('load', auScroll);
dessiner();
})();
/* ---------- aller à l'écran devis de la séquence + bouton flottant ---------- */
(function(){
var scene = document.getElementById('scene');
if(!scene) return;
var flottant = document.getElementById('btnFlottant');
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
/* champs de mapping Efficy : retirés de l'affichage mais toujours soumis */
function masquerMapping(){
['venues_all','activities_all','catering_all','tailor_made_all','travel_all']
.forEach(function(nom){
var champ = document.querySelector('#devis-source [name="'+nom+'"]');
if(!champ) return;
var ligne = champ.closest('.jet-form-builder-row') || champ.parentElement;
if(ligne && !ligne.dataset.masque){
ligne.dataset.masque = '1';
ligne.style.cssText = 'position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;margin:-1px;padding:0;border:0';
}
});
var t = document.querySelector('#devis-source .jet-form-builder h4');
if(t) t.style.display = 'none';
/* pré-sélection unique : cette page est consacrée à Gather.
On notifie JetFormBuilder pour que ses conditions se mettent à jour. */
var interet = document.querySelector('#devis-source [name="interested_in"]');
if(interet && !interet.dataset.prerempli){
interet.dataset.prerempli = '1';
interet.value = 'gather';
['input','change'].forEach(function(evt){
interet.dispatchEvent(new Event(evt, {bubbles:true}));
});
}
/* barre de progression et pagination « 1/2 » : style JFB par défaut,
trop présent dans le cadre. Le bouton « Suivant » suffit. */
['.jet-form-builder-progress-pages','.form-pagination']
.forEach(function(sel){
document.querySelectorAll('#devis-source ' + sel).forEach(function(el){
el.style.display = 'none';
});
});
}
/* ----------------------------------------------------------
LOCATION D'UN LIEU — masquer les champs conditionnels en double
Sur la page 2, JetFormBuilder peut afficher à nouveau :
- "Nombre de personnes" (parfois deux fois)
- "Votre budget"
alors que les valeurs principales (ex. 30 et 10000) sont déjà visibles.
On garde TOUJOURS la première occurrence visible et on masque
uniquement les occurrences suivantes. Les champs restent présents
dans le formulaire : on ne supprime aucune valeur ni aucune logique JFB.
---------------------------------------------------------- */
function masquerDoublonsLocation(){
var source = document.getElementById('devis-source');
if(!source) return;
function normaliser(txt){
return (txt || '')
.replace(/\*/g, '')
.replace(/\s+/g, ' ')
.trim()
.toLowerCase();
}
function visible(el){
if(!el) return false;
if(el.dataset.teroDoublonMasque === '1') return false;
var style = window.getComputedStyle(el);
if(style.display === 'none' || style.visibility === 'hidden') return false;
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
}
/* On ne travaille que dans la/les zone(s) actuellement visibles du formulaire.
Si JetFormBuilder utilise ses pages internes, cela évite qu'une occurrence
cachée de la page 1 influence le comptage de la page 2. */
var pages = Array.prototype.slice.call(
source.querySelectorAll('.jet-form-builder-page, .jet-form-builder__page')
).filter(visible);
var zones = pages.length ? pages : [source];
zones.forEach(function(zone){
var comptePersonnes = 0;
var compteBudget = 0;
zone.querySelectorAll('.jet-form-builder-row').forEach(function(ligne){
if(!visible(ligne)) return;
var label = ligne.querySelector(
'.jet-form-builder__label-text, .jet-form-builder__label, label'
);
if(!label) return;
var texte = normaliser(label.textContent);
if(texte.indexOf('number of people') === 0 || texte.indexOf('number of participants') === 0 || texte.indexOf('aantal personen') === 0 || texte.indexOf('nombre de personnes') === 0){
comptePersonnes++;
/* La première occurrence = la vraie valeur déjà saisie (ex. 30).
Toutes les suivantes sont les cadres conditionnels parasites. */
if(comptePersonnes > 1){
ligne.dataset.teroDoublonMasque = '1';
ligne.style.setProperty('display', 'none', 'important');
}
return;
}
if(texte.indexOf('your budget') === 0 || texte.indexOf('uw budget') === 0 || texte.indexOf('jouw budget') === 0 || texte.indexOf('votre budget') === 0){
compteBudget++;
/* La première occurrence = la vraie valeur déjà saisie (ex. 10000). */
if(compteBudget > 1){
ligne.dataset.teroDoublonMasque = '1';
ligne.style.setProperty('display', 'none', 'important');
}
}
});
});
}
var timerDoublons = null;
function programmerMasquageDoublons(){
clearTimeout(timerDoublons);
timerDoublons = setTimeout(masquerDoublonsLocation, 80);
}
/* on déplace le formulaire JetFormBuilder dans le cadre */
function rapatrier(){
var source = document.getElementById('devis-source');
var mobile = window.matchMedia('(max-width:900px)').matches;
var accueil = mobile
? document.getElementById('devisAccueilMobile')
: document.getElementById('devisAccueil');
if(source && accueil && !accueil.contains(source)){
accueil.appendChild(source);
source.style.display = 'block';
}
masquerMapping();
programmerMasquageDoublons();
}
rapatrier();
document.addEventListener('DOMContentLoaded', rapatrier);
window.addEventListener('load', rapatrier);
/* filet de sécurité : on réessaie pendant 3 s si Elementor charge en différé */
var essais = 0;
var tic = setInterval(function(){
rapatrier();
if(
++essais > 30 ||
document.querySelector('#devisAccueil #devis-source, #devisAccueilMobile #devis-source')
) clearInterval(tic);
}, 100);
/* JetFormBuilder affiche/masque ses champs conditionnels après un choix
(notamment "location d'un lieu") et après changement de page.
On relance donc le nettoyage après ces changements. */
document.addEventListener('change', function(e){
if(e.target && e.target.closest && e.target.closest('#devis-source')){
programmerMasquageDoublons();
}
}, true);
document.addEventListener('click', function(e){
if(!e.target || !e.target.closest) return;
var boutonPage = e.target.closest(
'#devis-source .jet-form-builder__next-page,' +
'#devis-source .jet-form-builder__prev-page,' +
'#devis-source .jet-form-builder__action-button'
);
if(boutonPage){
setTimeout(programmerMasquageDoublons, 120);
setTimeout(programmerMasquageDoublons, 350);
}
}, true);
/* Filet de sécurité pour les conditions JetFormBuilder injectées en AJAX/DOM. */
var sourceObservee = document.getElementById('devis-source');
if(sourceObservee && window.MutationObserver){
var observerDoublons = new MutationObserver(function(){
programmerMasquageDoublons();
});
observerDoublons.observe(sourceObservee, {
childList:true,
subtree:true,
attributes:true,
attributeFilter:['class','style']
});
}
programmerMasquageDoublons();
/* les CTA amènent à l'écran devis de la séquence */
function cible(){
var haut = scene.getBoundingClientRect().top + window.pageYOffset;
return haut + (scene.offsetHeight - window.innerHeight) * 0.96;
}
function allerAuDevis(e){
if(e) e.preventDefault();
window.scrollTo({top: cible(), behavior: reduce ? 'auto' : 'smooth'});
}
/* Les CTA sont gérés par le routeur indépendant placé au début du script. */
/* le bouton flottant apparaît une fois la bande logos dépassée */
if(!flottant) return;
function maj(){
var repere = document.querySelector('#tero-lp .bande-trusted') || scene;
var bas = repere.getBoundingClientRect().bottom;
flottant.classList.toggle('on', bas < window.innerHeight * 0.35);
}
window.addEventListener('scroll', maj, {passive:true, capture:true});
document.addEventListener('scroll', maj, {passive:true, capture:true});
window.addEventListener('resize', maj);
maj();
})();
Pourquoi Tero
Trois métiers, une seule équipe.
Lieux, table et activités sont gérés en interne, en Belgique et au Luxembourg. C'est ce qui nous permet de tout coordonner sans jamais vous renvoyer vers un prestataire.
Un seul interlocuteur, qui revient vers vous avec une proposition sur mesure et chiffrée.
3
On orchestre tout
Lieu, table et activité coordonnés par nos équipes. Le jour J, vous n'avez plus qu'à profiter.
Le groupe Tero
Vingt-cinq ans à organiser les moments qui comptent.
Lieux, activités et traiteur : trois métiers réunis sous une même équipe, en Belgique et au Luxembourg. C'est ce qui nous permet de tout coordonner sans jamais vous renvoyer vers un prestataire.
0+Années d'expérience
Du séminaire intime au gala de 400 personnes, en Belgique et au Luxembourg.
0Lieux uniques
Ardennes, Brabant wallon, côte belge et Luxembourg. De 14 à 400 personnes.
0Activités de cohésion
Indoor et outdoor, encadrées par nos animateurs, adaptées à tous les profils.
0+Événements par an
Une logistique rodée, un seul interlocuteur du devis à la dernière assiette.
Toutes nos formules
Et si votre fin d'année ressemblait à autre chose ?
L'intimate dinner n'est qu'une des façons de clôturer l'année. Selon ce que vous cherchez — célébrer, aligner, remercier ou simplement réunir — voici les autres formats.
Une journée
Teroir Traiteur
Célébrer · Remercier · Réunir
Parce que les plus belles conversations commencent à table, nos chefs viennent dresser et servir chez vous. Vous n'avez qu'à vous asseoir.
Lieu privatisé, nuit sur place, pension complète — vos équipes se concentrent sur l'essentiel, on orchestre le reste. Et le soir, les liens se tissent.