Insight Journeys

There’s more to discover beyond Agra’s best-known sights. From historic monuments and local markets to temples and the wildlife along the Chambal River, there are many ways to experience the region. Choose a journey that catches your interest, and we’ll help you plan it.

Our journeys

el.querySelector(s); const $$ = (s, el = document) => [...el.querySelectorAll(s)]; const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches; const canHover = matchMedia('(hover: hover)').matches; const nav = $('#nav'), hero = $('#top'), route = $('.route'); /* ---- hero title: letters rise in (plain text stays in the markup as the no-JS fallback) ---- */ const wm = $('#wordmark'); let n = 0; const words = wm.textContent.trim().split(/\s+/); wm.textContent = ''; words.forEach((word, wi) => { if (wi) wm.append(' '); const w = document.createElement('span'); w.className = 'w'; w.setAttribute('aria-hidden', 'true'); for (const ch of word) { const l = document.createElement('span'); l.className = 'l'; l.style.setProperty('--i', n++); l.textContent = ch; w.append(l); } wm.append(w); }); /* ---- header logo: fall back to text if the image fails ---- */ const logo = $('.brand img', nav); const logoFailed = () => logo.parentNode.classList.add('no-logo'); logo.addEventListener('error', logoFailed); if (logo.complete && !logo.naturalWidth) logoFailed(); /* ---- scroll + pointer work, batched into one animation frame ---- */ let heroVisible = true, ticking = false, mx = 0, my = 0; const render = () => { ticking = false; nav.classList.toggle('solid', scrollY > 60); if (reduceMotion || !heroVisible) return; const sy = Math.min(scrollY * .12, 100); route.style.transform = `translate3d(${mx}px,${(sy + my).toFixed(1)}px,0)`; }; const requestRender = () => { if (!ticking) { ticking = true; requestAnimationFrame(render); } }; addEventListener('scroll', requestRender, { passive: true }); render(); if (canHover && !reduceMotion) { hero.addEventListener('pointermove', e => { mx = +((e.clientX / innerWidth - .5) * -20).toFixed(1); my = +((e.clientY / innerHeight - .5) * -14).toFixed(1); requestRender(); }, { passive: true }); hero.addEventListener('pointerleave', () => { mx = my = 0; requestRender(); }); } /* ---- pause the looping SVG pin while the hero is off-screen ---- */ if ('IntersectionObserver' in window && route.pauseAnimations) { new IntersectionObserver(([e]) => { heroVisible = e.isIntersecting; if (heroVisible && !reduceMotion) { route.unpauseAnimations(); requestRender(); } else route.pauseAnimations(); }).observe(hero); } /* ---- menu ---- */ const menu = $('#menu'), menuBtn = $('#menuBtn'), menuLabel = $('#menuLabel'); const firstLink = $('#menuLinks a'); const pageParts = [$('main'), $('.foot')]; const toggleMenu = open => { menu.classList.toggle('open', open); nav.classList.toggle('menu-open', open); menuBtn.setAttribute('aria-expanded', open); menuLabel.textContent = open ? 'Close' : 'Menu'; document.body.style.overflow = open ? 'hidden' : ''; pageParts.forEach(el => { el.inert = open; }); /* keep keyboard focus inside the open menu */ if (open) firstLink.focus({ preventScroll: true }); }; menuBtn.addEventListener('click', () => toggleMenu(!menu.classList.contains('open'))); menu.addEventListener('click', e => { if (e.target.closest('a') || e.target.id === 'menuScrim') toggleMenu(false); }); addEventListener('keydown', e => { if (e.key === 'Escape' && menu.classList.contains('open')) { toggleMenu(false); menuBtn.focus(); } }); /* ---- tour cards: reveal on scroll ---- */ const cards = $$('.tour'); if ('IntersectionObserver' in window) { const io = new IntersectionObserver(entries => entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } }), { rootMargin: '0px 0px -8% 0px' }); cards.forEach(c => io.observe(c)); } else { cards.forEach(c => c.classList.add('in')); } /* ---- tour cards: gentle tilt on mouse devices ---- */ if (canHover && !reduceMotion) { cards.forEach(card => { const box = $('.t-box', card); let raf = 0, x = 0, y = 0; card.addEventListener('pointermove', e => { x = e.clientX; y = e.clientY; if (raf) return; raf = requestAnimationFrame(() => { raf = 0; const r = card.getBoundingClientRect(); box.style.setProperty('--ry', ((x - r.left) / r.width - .5).toFixed(3)); box.style.setProperty('--rx', ((y - r.top) / r.height - .5).toFixed(3)); }); }, { passive: true }); card.addEventListener('pointerleave', () => { cancelAnimationFrame(raf); raf = 0; box.style.setProperty('--rx', 0); box.style.setProperty('--ry', 0); }); }); } })();