
Celebrating Success
Culture isn’t just about the work we do, it’s about the connections we build. Our socials bring our people together, giving everyone the chance to relax, celebrate success, and enjoy celebrating our successes together.
%20(1)%20(1).jpg)
Industry Recognition
We proudly celebrate the great people and initiatives that drive our company forwards. In 2023/24, our Marketing Team was recognised at the prestigious ALF Awards, and we were named as one of the UK’s fastest-growing founder-led companies in the FEBE Growth 100.
.JPG)
Our Culture
From taking on challenges that push our people outside their comfort zones, to celebrating success together, giving back to our communities, and supporting our team in times of need - culture is what makes Outdo different.
(function () {
const AUTOPLAY_MS = 4000;
const DRAG_THRESHOLD = 12; // px before we treat it as a drag
const TAP_MAX_TIME = 350; // ms. if it ends quickly and under threshold, treat as tap
const S = {
component: ".timed-slider_component",
navButton: ".timed-slider_nav-button",
slidesWrap: ".timed-slider_slides",
slide: ".timed-slider_slide",
bar: ".timed-slider_progress-bar",
activeClass: "is--active",
};
document.querySelectorAll(S.component).forEach(initSlider);
function initSlider(root) {
const wrap = root.querySelector(S.slidesWrap);
const slides = Array.from(root.querySelectorAll(S.slide));
const buttons = Array.from(root.querySelectorAll(S.navButton));
const bars = buttons.map(b => b.querySelector(S.bar));
if (!wrap || slides.length === 0 || buttons.length !== slides.length) return;
const DEFAULT_TRANSITION = "transform .6s cubic-bezier(.22,.7,.26,1)";
if (!wrap.style.transition) {
wrap.style.display = "grid";
wrap.style.gridAutoFlow = "column";
wrap.style.gridAutoColumns = "100%";
wrap.style.willChange = "transform";
wrap.style.transition = DEFAULT_TRANSITION;
}
wrap.style.touchAction = "pan-y";
let index = Math.max(0, buttons.findIndex(b => b.classList.contains(S.activeClass)));
if (index === -1) index = 0;
let rafId = null;
let startTime = 0;
function go(i, resetProgress = true) {
index = (i + slides.length) % slides.length;
setActive(index);
wrap.style.transition = DEFAULT_TRANSITION;
wrap.style.transform = `translateX(${(-100 * index)}%)`;
if (resetProgress) startProgress();
}
function setActive(i) {
buttons.forEach((btn, bi) => {
btn.classList.toggle(S.activeClass, bi === i);
btn.setAttribute("aria-current", bi === i ? "true" : "false");
});
bars.forEach((bar) => {
if (!bar) return;
bar.style.width = "0%";
});
}
function startProgress() {
cancelAnimationFrame(rafId);
const bar = bars[index];
if (!bar) return;
startTime = performance.now();
function step(now) {
const t = Math.min(1, (now - startTime) / AUTOPLAY_MS);
bar.style.width = (t * 100).toFixed(3) + "%";
if (t >= 1) {
go(index + 1);
return;
}
rafId = requestAnimationFrame(step);
}
rafId = requestAnimationFrame(step);
}
buttons.forEach((btn, i) => {
btn.addEventListener("click", () => go(i));
});
// Drag and swipe with proper tap detection
let dragging = false;
let suppressNextClick = false;
let startX = 0;
let deltaX = 0;
let baseX = 0;
let pointerId = null;
let downAt = 0;
function slideWidth() {
return slides[0].getBoundingClientRect().width;
}
function isInteractive(el) {
if (!el) return false;
const tag = el.tagName;
if (["A", "BUTTON", "INPUT", "SELECT", "TEXTAREA", "LABEL"].includes(tag)) return true;
return el.closest("a,button,[role='button'],input,select,textarea,label") != null;
}
function onPointerDown(e) {
// Allow vertical scroll to start from slider, and allow taps on interactive items
pointerId = e.pointerId ?? null;
downAt = performance.now();
startX = e.clientX ?? (e.touches && e.touches[0].clientX) ?? 0;
baseX = -index * slideWidth();
deltaX = 0;
dragging = false; // we only flip to true after threshold
cancelAnimationFrame(rafId);
// We will capture only once drag starts, not immediately
window.addEventListener("pointermove", onPointerMove, { passive: true });
window.addEventListener("pointerup", onPointerUp, { once: true });
window.addEventListener("pointercancel", onPointerCancel, { once: true });
}
function onPointerMove(e) {
const x = e.clientX ?? (e.touches && e.touches[0].clientX) ?? startX;
deltaX = x - startX;
// Only start dragging after threshold and when the gesture is primarily horizontal
if (!dragging && Math.abs(deltaX) > DRAG_THRESHOLD) {
// If the press started on an interactive element, still allow drag once the user clearly drags
dragging = true;
suppressNextClick = true; // we will suppress the immediate click after a real drag
wrap.style.transition = "none";
try {
if (wrap.setPointerCapture && pointerId != null) wrap.setPointerCapture(pointerId);
} catch (_) {}
}
if (dragging) {
wrap.style.transform = `translateX(${baseX + deltaX}px)`;
}
}
function onPointerUp() {
window.removeEventListener("pointermove", onPointerMove);
const elapsed = performance.now() - downAt;
if (!dragging) {
// It was a tap. No suppression unless we barely crossed threshold extremely quickly.
const wasTinyMove = Math.abs(deltaX) <= DRAG_THRESHOLD;
const wasQuick = elapsed <= TAP_MAX_TIME;
suppressNextClick = !(wasTinyMove && wasQuick) ? false : false;
startProgress();
return;
}
// Snap if we were dragging
const width = slideWidth();
const threshold = width * 0.2;
let target = index;
if (deltaX <= -threshold) target = index + 1;
else if (deltaX >= threshold) target = index - 1;
go(target);
}
function onPointerCancel() {
window.removeEventListener("pointermove", onPointerMove);
dragging = false;
suppressNextClick = false;
startProgress();
}
// Only suppress clicks if a real drag happened
wrap.addEventListener(
"click",
function (e) {
if (!suppressNextClick) return;
// If user meant to click an interactive element but just dragged, block this one click
e.preventDefault();
e.stopPropagation();
suppressNextClick = false; // only consume once
},
true // capture to intercept before links fire
);
wrap.addEventListener("pointerdown", onPointerDown);
window.addEventListener("resize", () => {
wrap.style.transition = "none";
wrap.style.transform = `translateX(${(-100 * index)}%)`;
startProgress();
});
// Init
go(index);
}
})();