Bitte füllen Sie den Fragebogen aus, damit sich unser Team bestmöglich auf Ihren Termin vorbereiten kann. Im nächsten Schritt können Sie ein Datum und eine Uhrzeit für Ihr Gespräch auswählen.
Anfrageformular
„(Erforderlich)“ zeigt erforderliche Felder an
end (Custom Code) or enqueue in footer from a child theme.
===================================================================== */
(function () {
'use strict';
var STEP_DEFAULTS = [
{ at: 0.16, connector: 170, width: 480, shiftX: 0, side: 'above' },
{ at: 0.45, connector: 85, width: 640, shiftX: 0, side: 'below' },
{ at: 0.58, connector: 160, width: 460, shiftX: 0, side: 'above' }
];
var TRIGGER = 0.6;
var DESKTOP_START = 0.45;
var DESKTOP_FINISH = 0.1;
var DESKTOP_GATE = 0.8;
var uid = 0;
function mobileBreakpoint() {
try { return window.elementorFrontend.config.responsive.breakpoints.mobile.value; }
catch (e) { return 767; }
}
function isEditor() {
try { return !!window.elementorFrontend.isEditMode(); }
catch (e) { return false; }
}
function clamp01(v) { return Math.min(1, Math.max(0, v)); }
function uniquifyIds(svg, suffix) {
var nodes = svg.querySelectorAll('[id]');
for (var i = 0; i < nodes.length; i++) {
var oldId = nodes[i].id;
var newId = oldId + '-' + suffix;
nodes[i].id = newId;
var refs = svg.querySelectorAll(
'[fill*="#' + oldId + '"],[mask*="#' + oldId + '"],[href="#' + oldId + '"]'
);
for (var j = 0; j < refs.length; j++) {
['fill', 'mask', 'href'].forEach(function (a) {
var v = refs[j].getAttribute(a);
if (v && v.indexOf('#' + oldId) !== -1) {
refs[j].setAttribute(a, v.replace('#' + oldId, '#' + newId));
}
});
}
}
}
function cleanupDecorations(svg) {
var extras = svg.querySelectorAll('.jt__ghost');
for (var i = extras.length - 1; i >= 0; i--) extras[i].remove();
}
/* Inject and attach under-curve linear gradient fills with soft edge masks */
function ensureGradientsAndFills(svg, line, vb, suffix) {
var defs = svg.querySelector('defs');
if (!defs) {
defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
svg.insertBefore(defs, svg.firstChild);
}
var tealId = 'jt-grad-teal-' + suffix;
var orangeId = 'jt-grad-orange-' + suffix;
var maskFadeLeftId = 'jt-mask-fade-left-' + suffix;
var maskLeftId = 'jt-fade-left-' + suffix;
var maskFadeRightId = 'jt-mask-fade-right-' + suffix;
var maskRightId = 'jt-fade-right-' + suffix;
var gradHtml =
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'';
defs.insertAdjacentHTML('beforeend', gradHtml);
var total = line.getTotalLength();
var samples = 90;
// Left fill (Teal gradient under left curve with smooth right edge fade)
var fillLeft = svg.querySelector('.jt__fill--left, .jt__fill-left');
if (!fillLeft) {
fillLeft = document.createElementNS('http://www.w3.org/2000/svg', 'path');
fillLeft.setAttribute('class', 'jt__fill jt__fill--left');
var dLeft = 'M ' + vb.x + ' ' + (vb.y + vb.h);
for (var i = 0; i <= samples * 0.58; i++) {
var pt = line.getPointAtLength(total * (i / samples));
dLeft += ' L ' + pt.x.toFixed(1) + ' ' + pt.y.toFixed(1);
}
var midPt = line.getPointAtLength(total * 0.58);
dLeft += ' L ' + midPt.x.toFixed(1) + ' ' + (vb.y + vb.h) + ' Z';
fillLeft.setAttribute('d', dLeft);
line.parentNode.insertBefore(fillLeft, line);
}
fillLeft.setAttribute('fill', 'url(#' + tealId + ')');
fillLeft.setAttribute('mask', 'url(#' + maskLeftId + ')');
fillLeft.style.opacity = '0.16';
// Right fill (Orange gradient under right curve with smooth left edge fade)
var fillRight = svg.querySelector('.jt__fill--right, .jt__fill-right');
if (!fillRight) {
fillRight = document.createElementNS('http://www.w3.org/2000/svg', 'path');
fillRight.setAttribute('class', 'jt__fill jt__fill--right');
var startPt = line.getPointAtLength(total * 0.35);
var dRight = 'M ' + startPt.x.toFixed(1) + ' ' + (vb.y + vb.h);
for (var j = Math.floor(samples * 0.35); j <= samples; j++) {
var ptR = line.getPointAtLength(total * (j / samples));
dRight += ' L ' + ptR.x.toFixed(1) + ' ' + ptR.y.toFixed(1);
}
dRight += ' L ' + (vb.x + vb.w) + ' ' + (vb.y + vb.h) + ' Z';
fillRight.setAttribute('d', dRight);
line.parentNode.insertBefore(fillRight, line);
}
fillRight.setAttribute('fill', 'url(#' + orangeId + ')');
fillRight.setAttribute('mask', 'url(#' + maskRightId + ')');
fillRight.style.opacity = '0.32';
}
function ensureStrokeTrack(svg, line) {
var existingTrack = svg.querySelector('.jt__track');
if (existingTrack) {
existingTrack.setAttribute('stroke', '#229D9F');
existingTrack.setAttribute('stroke-opacity', '0.24');
existingTrack.setAttribute('stroke-width', '5');
existingTrack.setAttribute('stroke-linecap', 'round');
existingTrack.setAttribute('fill', 'none');
return;
}
var track = line.cloneNode(false);
track.removeAttribute('id');
track.setAttribute('class', 'jt__track');
track.setAttribute('stroke', '#229D9F');
track.setAttribute('stroke-opacity', '0.24');
track.setAttribute('stroke-width', '5');
track.setAttribute('stroke-linecap', 'round');
track.setAttribute('fill', 'none');
track.removeAttribute('stroke-dasharray');
track.removeAttribute('stroke-dashoffset');
track.style.removeProperty('stroke-dasharray');
track.style.removeProperty('stroke-dashoffset');
line.parentNode.insertBefore(track, line);
}
function initJourney(root) {
if (root.dataset.jtInit) return;
var svg = root.querySelector('.jt__svg svg');
var rail = root.querySelector('.jt__rail');
var steps = Array.prototype.slice.call(root.querySelectorAll('.jt__step'));
if (!svg || !steps.length) return;
var line = svg.querySelector('.jt__line, .animatable-line') ||
svg.querySelector('path[stroke]:not(.jt__track):not(.jt__fill)') ||
svg.querySelector('path:not(.jt__track):not(.jt__fill):not([fill])') ||
svg.querySelector('path:not(.jt__track):not(.jt__fill)');
if (!line) return;
line.classList.add('jt__line');
root.dataset.jtInit = '1';
var vbAttr = (svg.getAttribute('viewBox') || '0 0 1920 831')
.split(/[\s,]+/)
.map(Number);
var vb = { x: vbAttr[0], y: vbAttr[1], w: vbAttr[2], h: vbAttr[3] };
svg.setAttribute('preserveAspectRatio', 'none');
root.style.setProperty('--jt-ratio', vb.w + ' / ' + vb.h);
cleanupDecorations(svg);
ensureGradientsAndFills(svg, line, vb, ++uid);
ensureStrokeTrack(svg, line);
var total = line.getTotalLength();
// line.style.setProperty('--len', total);
line.style.setProperty('--len', total + 'px');
var trigger = TRIGGER;
var dStart = parseFloat(root.dataset.trigger) || DESKTOP_START;
var dFinish = parseFloat(root.dataset.finish);
if (isNaN(dFinish)) dFinish = DESKTOP_FINISH;
var dGate = parseFloat(root.dataset.gate);
if (isNaN(dGate)) dGate = DESKTOP_GATE;
var dotFrac = []; // each step's dot Y as a fraction of the section height
var mq = window.matchMedia('(max-width: ' + mobileBreakpoint() + 'px)');
var editor = isEditor();
/* Ensure background numbers are injected once per step */
steps.forEach(function (step, i) {
if (!step.querySelector('.jt__num')) {
var numEl = document.createElement('div');
numEl.className = 'jt__num';
numEl.setAttribute('aria-hidden', 'true');
numEl.textContent = step.dataset.step || (i + 1);
step.appendChild(numEl);
}
});
var cfg = steps.map(function (step, i) {
var d = STEP_DEFAULTS[i] || STEP_DEFAULTS[STEP_DEFAULTS.length - 1];
var classSide = step.classList.contains('jt__step--below')
? 'below'
: (step.classList.contains('jt__step--above') ? 'above' : '');
return {
at: parseFloat(step.dataset.at) || d.at,
connector: parseFloat(step.dataset.connector) || d.connector,
width: parseFloat(step.dataset.width) || d.width,
shiftX: parseFloat(step.dataset.shiftX || step.dataset.shiftx) || d.shiftX || 0,
side: step.dataset.side || classSide || d.side
};
});
/* ---------------- DESKTOP & TABLET ---------------- */
var desktopBound = false;
var desktopTicking = false;
function layoutDesktop() {
var rootRect = root.getBoundingClientRect();
var iconSize = parseFloat(getComputedStyle(root).getPropertyValue('--jt-icon')) || 80;
var scale = Math.min(1, Math.max(0.65, (rootRect.width || window.innerWidth) / 1600));
steps.forEach(function (step, i) {
var pt = line.getPointAtLength(total * cfg[i].at);
dotFrac[i] = (pt.y - vb.y) / vb.h;
var side = cfg[i].side === 'below' ? 'below' : 'above';
var baseConn = Math.round(cfg[i].connector * scale);
var cardW = Math.round(cfg[i].width * Math.min(1, Math.max(0.85, scale)));
step.classList.toggle('jt__step--above', side === 'above');
step.classList.toggle('jt__step--below', side === 'below');
step.style.setProperty('--x', ((pt.x - vb.x) / vb.w * 100) + '%');
step.style.setProperty('--y', ((pt.y - vb.y) / vb.h * 100) + '%');
step.style.setProperty('--card-w', cardW + 'px');
step.style.setProperty('--shift-x', cfg[i].shiftX + 'px');
step.style.setProperty('--connector', baseConn + 'px');
if (side === 'above') {
var safeConnector = Math.max(
baseConn,
Math.ceil(step.offsetHeight + (48 * scale) - iconSize)
);
step.style.setProperty('--connector', safeConnector + 'px');
}
});
}
/* Scroll-driven: progress 0 when the section top crosses the start line
(60% of viewport), 1 when the section top reaches the finish line
(15% of viewport) — or earlier, as soon as the section bottom is in
view. So the curve is always fully drawn while the whole section is
on screen. Each step activates when the drawn curve reaches its
data-at point AND its card or dot has scrolled above the gate line
(90% of viewport) AND the previous step is already active, so steps
always reveal in order and never light up off-screen.
Scrubs in both directions. */
function onScrollDesktop() {
if (desktopTicking) return;
desktopTicking = true;
requestAnimationFrame(function () {
desktopTicking = false;
var rect = root.getBoundingClientRect();
var vh = window.innerHeight;
var startTop = vh * dStart;
var endTop = Math.max(vh * dFinish, vh * 0.95 - rect.height);
endTop = Math.min(endTop, startTop - 120); // keep a usable scroll range
var progress = clamp01((startTop - rect.top) / (startTop - endTop));
root.style.setProperty('--curve', progress);
root.classList.toggle('jt--in', progress > 0);
var prevActive = true;
steps.forEach(function (step, i) {
var dotY = rect.top + (dotFrac[i] || 0) * rect.height;
var cardTop = step.getBoundingClientRect().top; // includes above/below transform
var inView = Math.min(dotY, cardTop) <= vh * dGate;
var active = prevActive && inView && progress >= cfg[i].at - 0.005;
step.classList.toggle('jt--active', active);
prevActive = active;
});
root.classList.toggle('jt--curve-done', progress >= 1);
});
}
function setupDesktop() {
layoutDesktop();
if (editor) {
root.classList.add('jt--static');
return;
}
onScrollDesktop();
if (desktopBound) return;
desktopBound = true;
window.addEventListener('scroll', onScrollDesktop, { passive: true });
}
function teardownDesktop() {
if (desktopBound) {
window.removeEventListener('scroll', onScrollDesktop);
desktopBound = false;
}
root.classList.remove('jt--in', 'jt--curve-done');
root.style.removeProperty('--curve');
steps.forEach(function (s) { s.classList.remove('jt--active'); });
}
/* ---------------- MOBILE ---------------- */
var railTop = 0;
var railH = 1;
var svgTopRel = 0;
var svgH = 1;
var iconYs = [];
var ticking = false;
function measureMobile() {
if (!rail) return;
var secRect = root.getBoundingClientRect();
var icons = steps.map(function (s) {
return s.querySelector('.jt__icon .elementor-icon-wrapper') ||
s.querySelector('.jt__icon .elementor-icon') ||
s.querySelector('.jt__icon') ||
s;
});
var iconH = icons[0].getBoundingClientRect().height || 64;
var centers = icons.map(function (ic) {
var rect = ic.getBoundingClientRect();
return rect.top - secRect.top + (rect.height || iconH) / 2;
});
var firstRect = icons[0].getBoundingClientRect();
var railX = firstRect.left - secRect.left + firstRect.width / 2;
var svgRect = svg.getBoundingClientRect();
var svgLeftRel = svgRect.left - secRect.left;
var railXInSvgPx = Math.min(
svgRect.width,
Math.max(0, railX - svgLeftRel)
);
var targetX = vb.x +
(railXInSvgPx / Math.max(1, svgRect.width)) * vb.w;
var best = line.getPointAtLength(0);
var bestDx = Infinity;
for (var p = 0; p <= 160; p++) {
var point = line.getPointAtLength(total * (p / 160));
var dx = Math.abs(point.x - targetX);
if (dx < bestDx) {
bestDx = dx;
best = point;
}
}
svgTopRel = svgRect.top - secRect.top;
svgH = Math.max(1, svgRect.height);
var curveY = svgTopRel + ((best.y - vb.y) / vb.h) * svgRect.height;
railTop = centers[0];
railH = Math.max(1, curveY - railTop);
rail.style.setProperty('--rail-x', railX + 'px');
rail.style.setProperty('--rail-top', railTop + 'px');
rail.style.setProperty('--rail-h', railH + 'px');
iconYs = centers.map(function (center) { return center - railTop; });
}
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(function () {
ticking = false;
var triggerPx = window.innerHeight * trigger;
var secTop = root.getBoundingClientRect().top;
var progress = 0;
if (rail) {
var reached = triggerPx - (secTop + railTop);
progress = clamp01(reached / railH);
rail.style.setProperty('--progress', progress);
rail.classList.toggle('is-started', progress > 0);
rail.classList.toggle('is-done', progress >= 1);
steps.forEach(function (step, i) {
step.classList.toggle('jt--active', reached >= iconYs[i] - 12);
});
} else {
steps.forEach(function (step) { step.classList.add('jt--active'); });
}
var curve = clamp01((triggerPx - (secTop + svgTopRel)) / svgH);
svg.style.setProperty('--curve', curve);
var revealed = steps.every(function (step) {
return step.classList.contains('jt--active');
});
root.classList.toggle(
'jt--curve-done',
revealed && (rail ? progress >= 1 : curve >= 1)
);
});
}
function setupMobile() {
if (editor) {
root.classList.add('jt--static');
steps.forEach(function (s) { s.classList.add('jt--active'); });
return;
}
measureMobile();
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
}
function teardownMobile() {
window.removeEventListener('scroll', onScroll);
root.classList.remove('jt--curve-done');
steps.forEach(function (s) { s.classList.remove('jt--active'); });
if (rail) rail.classList.remove('is-started', 'is-done');
svg.style.removeProperty('--curve');
}
function init() {
if (mq.matches) {
teardownDesktop();
setupMobile();
} else {
teardownMobile();
setupDesktop();
}
}
function refresh() {
if (editor) return;
if (mq.matches) {
measureMobile();
onScroll();
} else {
layoutDesktop();
onScrollDesktop();
}
}
init();
if (mq.addEventListener) mq.addEventListener('change', init);
else mq.addListener(init);
window.addEventListener('resize', function () {
if (editor && !mq.matches) { layoutDesktop(); return; }
refresh();
});
if (document.fonts && document.fonts.ready) {
document.fonts.ready.then(function () {
if (editor && !mq.matches) { layoutDesktop(); return; }
refresh();
});
}
}
function initAll(scope) {
var els = (scope || document).querySelectorAll('.jt');
for (var i = 0; i < els.length; i++) initJourney(els[i]);
}
if (window.jQuery) {
jQuery(window).on('elementor/frontend/init', function () {
elementorFrontend.hooks.addAction(
'frontend/element_ready/container',
function ($el) {
var el = $el[0];
if (el.classList.contains('jt')) {
initJourney(el);
} else {
var parent = el.closest('.jt');
if (parent) {
delete parent.dataset.jtInit;
initJourney(parent);
}
}
}
);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { initAll(); });
} else {
initAll();
}
})();