/*! trentpower.fr · /app.js · generated · signed via /integrity.json */
var I18N=window.I18N||{};var LANG_CYCLE=['en','fr','it','es','de'];
(function () {
'use strict';
try { document.documentElement.classList.add('js'); } catch (_) {}
function _markEnhanced() {
try { document.documentElement.classList.add('enhanced'); } catch (_) {}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', _markEnhanced, { once: true });
} else {
_markEnhanced();
}
function _safeScriptURL(s) {
if (typeof s !== 'string') {
throw new TypeError('tp-i18n: script URL must be a string');
}
if (s.charAt(0) !== '/' || s.charAt(1) === '/') {
throw new Error('tp-i18n: only absolute same-origin paths allowed: ' + s);
}
var bareNoQuery = s.split('?')[0].split('#')[0];
if (!/\.(js|mjs)$/.test(bareNoQuery)) {
throw new Error('tp-i18n: script URL extension not allowed: ' + s);
}
var ALLOWED_PREFIXES = ['/sw.js', '/app.js', '/app-enhance.', '/cite.js', '/i18n-core.js', '/i18n/', '/verify/'];
var ok = ALLOWED_PREFIXES.some(function (p) {
return bareNoQuery === p || bareNoQuery.indexOf(p) === 0;
});
if (!ok) {
throw new Error('tp-i18n: script URL not in allowlist: ' + s);
}
return s;
}
var ttPolicy = (typeof window !== 'undefined' && window.trustedTypes &&
typeof window.trustedTypes.createPolicy === 'function')
? window.trustedTypes.createPolicy('tp-i18n', {
createHTML: function (s) { return s; },
createScriptURL: _safeScriptURL
})
: null;
function setTrustedHTML(el, value) {
el.innerHTML = ttPolicy ? ttPolicy.createHTML(value) : value;
}
function trustedScriptURL(value) {
return ttPolicy ? ttPolicy.createScriptURL(value) : value;
}
function getVal(obj, key) {
return key.split('.').reduce(function (o, k) { return o ? o[k] : undefined; }, obj);
}
var CORE_LANGS = { en: 1, fr: 1 };
var FALLBACK_LANG = 'en';
var I18N_VTAG = '2026-05-09.fceaf1e4';
function normaliseLang(value) {
var l = String(value || '').trim().toLowerCase().slice(0, 2);
if (CORE_LANGS[l]) return l;
return FALLBACK_LANG;
}
function loadOptionalLang(lang) {
return Promise.resolve(true);
}
function updateLangControls(lang) {
document.querySelectorAll('button[data-lang], a[data-lang]').forEach(function (control) {
var l = control.getAttribute('data-lang');
control.setAttribute('aria-pressed', l === lang ? 'true' : 'false');
});
}
function renderLanguage(lang) {
var t = I18N[lang];
if (!t) return false;
var page = document.body && document.body.getAttribute('data-page') || 'home';
document.documentElement.lang = lang;
document.documentElement.setAttribute('data-lang', lang);
if (t.meta && t.meta[page]) {
document.title = t.meta[page].title;
var md = document.querySelector('meta[name="description"]');
if (md) md.setAttribute('content', t.meta[page].description);
}
if (page === 'home' && t.meta && t.meta.home) {
var ot = document.querySelector('meta[property="og:title"]');
var od = document.querySelector('meta[property="og:description"]');
if (ot) ot.setAttribute('content', t.meta.home.og_title);
if (od) od.setAttribute('content', t.meta.home.og_description);
}
var idMap = {
'p-mission': t.hero && t.hero.statement,
'p-role': t.hero && t.hero.body,
'p-growth': t.approach && t.approach.growth_title,
'p-growth-detail': t.approach && t.approach.growth_body,
'p-adoption': t.approach && t.approach.adoption_title,
'p-adoption-detail': t.approach && t.approach.adoption_body,
'p-ai': t.approach && t.approach.ai_title,
'p-ai-detail': t.approach && t.approach.ai_body,
'p-governance': t.approach && t.approach.governance_title,
'p-governance-detail': t.approach && t.approach.governance_body,
'p-taste': t.approach && t.approach.taste_title,
'p-taste-detail': t.approach && t.approach.taste_body,
'p-project-paris': t.projects && t.projects.paris_desc
};
Object.keys(idMap).forEach(function (id) {
var text = idMap[id];
if (!text) return;
var el = document.getElementById(id);
if (el) el.textContent = text;
});
document.querySelectorAll('[data-i18n]').forEach(function (el) {
var value = getVal(t, el.getAttribute('data-i18n'));
if (value !== undefined) el.textContent = value;
});
document.querySelectorAll('[data-i18n-html]').forEach(function (el) {
var value = getVal(t, el.getAttribute('data-i18n-html'));
if (value !== undefined) setTrustedHTML(el, value);
});
document.querySelectorAll('[data-i18n-aria-label]').forEach(function (el) {
var value = getVal(t, el.getAttribute('data-i18n-aria-label'));
if (value !== undefined) el.setAttribute('aria-label', value);
});
document.querySelectorAll('[data-i18n-list]').forEach(function (el) {
var key = el.getAttribute('data-i18n-list');
var value = getVal(t, key);
if (!value) return;
var html = value.split('\n').map(function (item) {
return '<li>' + item + '</li>';
}).join('');
setTrustedHTML(el, html);
});
var copyBtn = document.querySelector('.code-copy');
if (copyBtn) {
var _ct = I18N[lang] || I18N['en'];
var _copiedLabel = (_ct.integrity && _ct.integrity.copy_button_done) || 'Copied';
if (copyBtn.textContent !== _copiedLabel) {
copyBtn.textContent = (_ct.integrity && _ct.integrity.copy_button) || 'Copy';
}
}
var pic = document.querySelector('picture[data-arch-base]');
if (pic) {
var base = pic.dataset.archBase;
var src = pic.querySelector('source[media]');
var img = pic.querySelector('img');
if (src) src.srcset = '/images/architecture/' + base + '-mobile.' + lang + '.svg';
if (img) img.src = '/images/architecture/' + base + '.' + lang + '.svg';
}
return true;
}
function applyLanguage(lang) {
var target = normaliseLang(lang);
return loadOptionalLang(target).then(function (ok) {
var applied = ok && renderLanguage(target);
if (applied) {
try { localStorage.setItem('tp-lang', target); } catch (_) {}
updateLangControls(target);
return target;
}
return document.documentElement.getAttribute('data-lang') || FALLBACK_LANG;
});
}
function bootLanguage() {
var stored;
try { stored = localStorage.getItem('tp-lang'); } catch (_) { stored = null; }
var nav = /^fr\b/i.test((navigator.languages && navigator.languages[0]) || navigator.language || 'en') ? 'fr' : 'en';
var pref = stored ? normaliseLang(stored) : nav;
if (pref === 'en' && document.documentElement.lang === 'en') {
document.documentElement.setAttribute('data-lang', 'en');
updateLangControls('en');
return;
}
renderLanguage(pref);
updateLangControls(pref);
}
bootLanguage();
(function () {
function getViewportAnchor() {
var navOffset = 64;
var candidates = document.querySelectorAll(
'main, section[id], .hero, .principle, .trajectory-item, ' +
'.project-card, .page, .site-footer'
);
var best = null;
var bestDistance = Infinity;
for (var i = 0; i < candidates.length; i++) {
var el = candidates[i];
var rect = el.getBoundingClientRect();
if (rect.bottom < navOffset) continue;
if (rect.top > window.innerHeight) continue;
var distance = Math.abs(rect.top - navOffset);
if (distance < bestDistance) {
best = el;
bestDistance = distance;
}
}
return best || document.querySelector('main') || document.body;
}
function switchLanguage(nextLang, trigger) {
var root = document.documentElement;
var anchor = getViewportAnchor();
var beforeTop = anchor.getBoundingClientRect().top;
root.classList.add('is-language-switching');
applyLanguage(nextLang).then(function () {
requestAnimationFrame(function () {
requestAnimationFrame(function () {
var afterTop = anchor.getBoundingClientRect().top;
var delta = afterTop - beforeTop;
if (Math.abs(delta) > 1) {
window.scrollTo({
top: window.scrollY + delta,
behavior: 'auto'
});
}
if (trigger && typeof trigger.focus === 'function') {
try {
trigger.focus({ preventScroll: true });
} catch (_) {
trigger.focus();
}
}
root.classList.remove('is-language-switching');
var langRow = trigger && trigger.closest
? trigger.closest('.site-footer__language')
: document.querySelector('.site-footer__language');
if (langRow) {
langRow.classList.remove('language-updated');
void langRow.offsetWidth;
langRow.classList.add('language-updated');
setTimeout(function () {
langRow.classList.remove('language-updated');
}, 320);
}
});
});
});
}
document.addEventListener('click', function (event) {
var trigger = event.target && event.target.closest
? event.target.closest('[data-lang]')
: null;
if (!trigger) return;
var nextLang = trigger.getAttribute('data-lang');
if (!nextLang) return;
var tag = trigger.tagName;
if (tag !== 'BUTTON' && tag !== 'A') return;
event.preventDefault();
switchLanguage(nextLang, trigger);
});
})();
if ('serviceWorker' in navigator && location.protocol === 'https:') {
var swDebug = location.search.indexOf('debug-sw=1') !== -1;
window.addEventListener('load', function () {
try {
navigator.serviceWorker.register(trustedScriptURL('/sw.js'), { scope: '/' })
.then(function (reg) {
if (swDebug) {
try { console.info('[tp] service worker registered', reg && reg.scope); } catch (_) {}
}
})
.catch(function (err) {
if (swDebug) {
try { console.warn('[tp] service worker registration skipped', err); } catch (_) {}
}
});
} catch (err) {
if (swDebug) {
try { console.warn('[tp] service worker registration unavailable', err); } catch (_) {}
}
}
}, { once: true });
}
var prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
function _deferEnhancements() {
var revealEls = document.querySelectorAll('.principle, .trajectory-item, .project-card');
if (!prefersReducedMotion && 'IntersectionObserver' in window) {
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.15, rootMargin: '0px 0px -40px 0px' });
revealEls.forEach(function (el, i) {
el.style.transitionDelay = (i % 5 * 80) + 'ms';
observer.observe(el);
});
} else {
revealEls.forEach(function (el) {
el.classList.add('visible');
});
}
var emailLinks = document.querySelectorAll('[data-contact]');
emailLinks.forEach(function (el) {
var existingHref = el.getAttribute('href') || '';
if (existingHref.indexOf('mailto:') === 0) return;
var user = el.getAttribute('data-contact');
var domain = el.getAttribute('data-domain');
if (!user || !domain) return;
var addr = user + '@' + domain;
var href = 'mailto:' + addr;
var subject = el.getAttribute('data-contact-subject');
if (subject) href += '?subject=' + encodeURIComponent(subject);
el.setAttribute('href', href);
var firstChild = el.firstElementChild;
if (firstChild) {
el.insertBefore(document.createTextNode(addr + ' '), firstChild);
} else {
el.textContent = addr;
}
});
}
if ('requestIdleCallback' in window) {
requestIdleCallback(_deferEnhancements, { timeout: 2000 });
} else {
setTimeout(_deferEnhancements, 200);
}
window.I18N = I18N;
window.LANG_CYCLE = LANG_CYCLE;
function _tpLoadEnhance() {
if (window.__tpEnhanceLoaded || window.TP_OVERLAY) return;
window.__tpEnhanceLoaded = true;
try {
var s = document.createElement('script'); s.src = trustedScriptURL('/app-enhance.2026-05-09.fceaf1e4.js'); s.defer = true;
document.head.appendChild(s);
} catch (_) { }
}
if ('requestIdleCallback' in window) {
requestIdleCallback(_tpLoadEnhance, { timeout: 1500 });
} else {
setTimeout(_tpLoadEnhance, 500);
}
})();
