(function () {
// --- (1) 50Hertz-Schrift laden ---
document.head.insertAdjacentHTML(
'beforeend',
''
);
// --- (2) Minimal-CSS + Basisverankerung unten links ---
const style = document.createElement('style');
style.innerHTML = `
.hidden { display: none !important; }
/* Flash animation */
@keyframes flash {
0%, 14.28%, 28.57%, 42.86%, 57.14%, 71.43%, 85.71%, 100% { background-color: #ffffff; }
7.14%, 21.43%, 35.71%, 50%, 64.29%, 78.57%, 92.86% { background-color: #1f2937; }
}
/* Container: immer unten links; feintuning via JS (Reposition) */
#chat-widget-container {
position: fixed;
left: 16px; /* wird vom JS dynamisch angepasst */
bottom: 16px; /* wird vom JS dynamisch angepasst */
z-index: 2147483639; /* unterhalb UC-Dialoge (UC nutzt 2147483640+) */
display: flex;
flex-direction: column;
gap: 8px;
}
#chat-bubble {
width: 64px;
height: 64px;
background-color: #ffffff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background-color 0.3s ease;
color: #f06d1a;
box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px rgba(0, 0, 0, 0.14), 0px 1px 18px rgba(0, 0, 0, 0.12);
border: none;
padding: 0;
animation: flash 3s ease-in-out;
outline: none;
}
#chat-bubble:hover { background-color: #f5f5f5; }
#chat-bubble:focus { outline: none; }
/* Inner div inherits height from button (like Usercentrics pattern) */
#chat-bubble .sc-fqkvVR {
height: inherit;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
#chat-bubble svg {
width: 60%;
height: 60%;
color: #f06d1a;
}
/* Popup: erscheint oberhalb der Bubble, linksbündig zum Container */
#chat-popup {
position: absolute;
left: 0; /* statt zentriert */
bottom: 80px; /* oberhalb der Bubble */
width: 384px;
height: 70vh;
max-height: 70vh;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
display: flex;
flex-direction: column;
font-size: 14px;
transition: all .3s;
overflow: hidden;
}
/* Close-Button über dem iframe - OBEN RECHTS */
#close-popup {
position: absolute;
top: 8px;
right: 8px;
z-index: 10;
background: rgba(31, 41, 55, 0.8);
border: none;
color: white;
cursor: pointer;
padding: 6px;
border-radius: 4px;
transition: background-color 0.2s;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
}
#close-popup:hover { background: rgba(31, 41, 55, 0.9); }
#close-popup svg { width: 18px; height: 18px; }
#chat-messages {
flex: 1;
padding: 0;
border-radius: 8px;
overflow: hidden;
}
@media (max-width: 768px) {
#chat-popup {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 0;
}
#chat-bubble {
width: 44px;
height: 44px;
}
}
`;
document.head.appendChild(style);
// --- (3) Container erzeugen ---
const chatWidgetContainer = document.createElement('div');
chatWidgetContainer.id = 'chat-widget-container';
document.body.appendChild(chatWidgetContainer);
// --- (4) Markup injizieren ---
chatWidgetContainer.innerHTML = `
`;
// --- (4.5) Language override and iframe setup (after DOM insertion) ---
// Override der Browser-Language
Object.defineProperty(navigator, 'language', {
value: 'de-DE',
configurable: true
});
Object.defineProperty(navigator, 'languages', {
value: ['de-DE'],
configurable: true
});
// Fallback: Sprache per postMessage an den iFrame senden
setTimeout(() => {
const iframe = document.getElementById('copilotFrame');
if (iframe && iframe.contentWindow) {
try {
iframe.contentWindow.postMessage({ locale: 'de-DE' }, '*');
} catch (e) {
console.log('Could not send postMessage to iframe:', e);
}
}
}, 1000);
// --- (5) Events ---
const chatBubble = document.getElementById('chat-bubble');
const chatPopup = document.getElementById('chat-popup');
const closePopup = document.getElementById('close-popup');
chatBubble.addEventListener('click', togglePopup);
closePopup.addEventListener('click', togglePopup);
function togglePopup() { chatPopup.classList.toggle('hidden'); }
// --------------------------------------------------------------------------
// (6) >>> UC‑AWARE POSITIONIERUNG (immer unten links; außer UC ist dort → rechts daneben)
// --------------------------------------------------------------------------
// Konfiguration für die Position
const BASE_LEFT = 16; // px, wenn UC nicht unten links sitzt
const BASE_BOTTOM = 16; // px, wenn UC nicht unten links sitzt
const SPACING = 12; // px Abstand zwischen UC-Trigger und unserem Container
function getUcTrigger() {
const host = document.querySelector('#usercentrics-root');
const root = host && host.shadowRoot;
if (!root) return null;
// Bevorzugt: stabile Selektoren
let btn =
root.querySelector('button[data-testid*="privacy"]') ||
root.querySelector('button[aria-label*="Privacy" i]') ||
root.querySelector('button[aria-label*="Datenschutz" i]');
// Fallback-Heuristik: sichtbarer fixed-Button in einer Ecke
if (!btn) {
btn = Array.from(root.querySelectorAll('button')).find(el => {
const cs = getComputedStyle(el);
const fixed = cs.position === 'fixed';
const corner =
(parseInt(cs.bottom) >= 0 || parseInt(cs.top) >= 0) &&
(parseInt(cs.left) >= 0 || parseInt(cs.right) >= 0);
const visible = el.offsetWidth > 0 && el.offsetHeight > 0 &&
cs.visibility !== 'hidden' && cs.display !== 'none';
return fixed && corner && visible;
});
}
return btn || null;
}
function isBottomLeft(rect) {
const isLeft = rect.left < (window.innerWidth - rect.right);
const isBelow = (window.innerHeight - rect.bottom) < rect.top;
return isLeft && isBelow;
}
function overlaps(a, b, margin = 0) {
return !(
a.right + margin < b.left ||
a.left > b.right + margin ||
a.bottom + margin < b.top ||
a.top > b.bottom + margin
);
}
function setContainer(leftPx, bottomPx) {
chatWidgetContainer.style.left = Math.max(0, Math.round(leftPx)) + 'px';
chatWidgetContainer.style.right = ''; // sicherstellen, dass links verwendet wird
chatWidgetContainer.style.bottom = Math.max(0, Math.round(bottomPx)) + 'px';
chatWidgetContainer.style.top = '';
}
function reposition() {
// Default: unten links auf Basiswerte
setContainer(BASE_LEFT, BASE_BOTTOM);
const ucBtn = getUcTrigger();
if (!ucBtn) return;
const ucRect = ucBtn.getBoundingClientRect();
// Wenn der UC-Trigger unten links sitzt: rechts daneben, gleiche Höhe
if (isBottomLeft(ucRect)) {
const desiredLeft = ucRect.right + SPACING;
const desiredBottom = window.innerHeight - ucRect.bottom;
setContainer(desiredLeft, desiredBottom);
// Fallback, falls rechts daneben kein Platz (z.B. kleiner Viewport)
const myRect = chatWidgetContainer.getBoundingClientRect();
const noRoomRight = myRect.right > window.innerWidth - 4;
const collides = overlaps(myRect, ucRect, 4);
if (noRoomRight || collides) {
// dezent oberhalb stapeln, bündig zur linken UC-Kante
const newLeft = ucRect.left;
const newBottom = (window.innerHeight - ucRect.top) + SPACING;
setContainer(newLeft, newBottom);
}
}
}
// Initiale Positionierung
requestAnimationFrame(reposition);
// Auf UC‑DOM‑Änderungen reagieren (UC rendert im Shadow DOM)
function attachObservers() {
const host = document.querySelector('#usercentrics-root');
if (!host) return;
new MutationObserver(reposition)
.observe(host, { attributes: true, childList: true, subtree: true });
if (host.shadowRoot) {
new MutationObserver(reposition)
.observe(host.shadowRoot, { attributes: true, childList: true, subtree: true });
}
}
// Mehrfach versuchen, bis UC geladen ist
let tries = 0;
const t = setInterval(() => {
attachObservers();
reposition();
if (++tries > 20 || document.querySelector('#usercentrics-root')) clearInterval(t);
}, 250);
// Viewport-Änderungen berücksichtigen
window.addEventListener('resize', reposition);
window.addEventListener('orientationchange', reposition);
document.addEventListener('visibilitychange', () => { if (!document.hidden) setTimeout(reposition, 50); });
})();