// Palette, icons, image helpers, and content data — used by all pages.

// === Brand palette ===
const TNF = {
  green: '#2BD884',
  greenDk: '#16B26C',
  turq: '#5BC0DE',
  turqDk: '#3FA7C9',
  blue: '#1B6478',
  blueDk: '#0F4A5C',
  blueXdk: '#072A35',
  cream: '#FAF8F2',
  paper: '#F4F1EA',
  ink: '#0B2630',
  inkSoft: '#3A5560',
  line: 'rgba(11, 38, 48, 0.12)',
  lineSoft: 'rgba(11, 38, 48, 0.07)'
};
window.TNF = TNF;

// === Responsive breakpoint hook (inline-style sites can't use CSS media queries) ===
// mobile ≤ 640px · tablet 641–1024px · desktop ≥ 1025px
function tnfBP() {
  const w = typeof window !== 'undefined' ? window.innerWidth : 1280;
  return w <= 640 ? 'mobile' : w <= 1024 ? 'tablet' : 'desktop';
}
function useBP() {
  const [bp, setBp] = React.useState(tnfBP);
  React.useEffect(() => {
    let t;
    const on = () => { clearTimeout(t); t = setTimeout(() => setBp(tnfBP()), 80); };
    window.addEventListener('resize', on, { passive: true });
    window.addEventListener('orientationchange', on);
    return () => { window.removeEventListener('resize', on); window.removeEventListener('orientationchange', on); clearTimeout(t); };
  }, []);
  return bp;
}
window.useBP = useBP;
// pick a value by breakpoint: bpv(bp, mobileVal, tabletVal, desktopVal)
function bpv(bp, m, t, d) { return bp === 'mobile' ? m : bp === 'tablet' ? t : d; }
window.bpv = bpv;
// standard section padding per breakpoint — keeps rhythm consistent site-wide
function secPad(bp, v, h) {
  // v/h are the DESKTOP vertical/horizontal base (numbers, px)
  const vv = bpv(bp, Math.round(v * 0.62), Math.round(v * 0.8), v);
  const hh = bpv(bp, 20, 36, h);
  return `${vv}px ${hh}px`;
}
window.secPad = secPad;
const isTouchLike = (bp) => bp !== 'desktop';
window.isTouchLike = isTouchLike;

// === Input hardening (validation + sanitization) ===
// IMPORTANT: this is a static, client-only site — there is no server, database,
// OS shell, or file-upload endpoint, so SQL/command injection and unsafe file
// uploads cannot occur in this codebase. React also escapes all rendered text
// (no dangerouslySetInnerHTML / innerHTML / eval anywhere), which neutralises
// script injection. These helpers enforce strict input *types*, character
// allow-lists and length caps so the UI rejects malformed data and any future
// backend receives clean values. Client-side checks are NOT a security boundary —
// real SQLi / command-injection / upload defences must be enforced server-side.
const InputGuard = {
  // Strip control chars + angle brackets (markup/script), cap length.
  text(v, max = 500) {
    return String(v == null ? '' : v)
      .replace(/[\u0000-\u001F\u007F]/g, '') // control characters
      .replace(/[<>]/g, '')                   // angle brackets → no tag/markup injection
      .slice(0, max);
  },
  // Single-line free text (names, destinations): no line breaks/tabs, trimmed cap.
  line(v, max = 120) {
    return this.text(v, max).replace(/[\r\n\t]+/g, ' ');
  },
  // Email: drop whitespace + brackets; RFC-ish length cap.
  email(v) {
    return String(v == null ? '' : v).replace(/[\s<>]/g, '').slice(0, 254);
  },
  // Phone: digits and the few legal separators only.
  phone(v) {
    return String(v == null ? '' : v).replace(/[^\d+\-()\s]/g, '').slice(0, 24);
  },
  // Search query: text rules + tighter cap, single line.
  search(v) {
    return this.text(v, 64).replace(/[\r\n]+/g, ' ');
  },
  // Strict integer, clamped to [min,max]; falls back when not a number.
  int(v, min, max, fallback) {
    const n = parseInt(String(v == null ? '' : v).replace(/[^\d-]/g, ''), 10);
    if (!Number.isFinite(n)) return fallback;
    return Math.min(max, Math.max(min, n));
  },
  // Allow-list a value against known options (rejects anything unexpected).
  oneOf(v, allowed, fallback = '') {
    return allowed.includes(v) ? v : fallback;
  },
};
window.InputGuard = InputGuard;

// Validators — return boolean. Used to gate submission and reject invalid data.
const isEmail = (v) => /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(String(v == null ? '' : v).trim());
const isPhone = (v) => /^[+]?[\d\s\-()]{7,20}$/.test(String(v == null ? '' : v).trim());
const isFilledName = (v) => InputGuard.line(v).trim().length >= 2;
window.isEmail = isEmail;
window.isPhone = isPhone;
window.isFilledName = isFilledName;

// === Client-side abuse deterrents ===
// IMPORTANT: this is a static, client-only site — there is NO login, account
// creation, API, or AI endpoint, and no server. Real rate limiting and bot
// prevention (per-IP throttling, CAPTCHA, WAF, server tokens) MUST live on a
// backend; a script can bypass anything enforced only in the browser. The helpers
// below are front-end deterrents for the lead forms that DO exist (contact / quote
// / partner): a honeypot, a minimum fill time, and a per-window submit cap.
const AbuseGuard = {
  // Sliding-window submit cap, persisted per browser via localStorage.
  checkRate(key, { maxPerWindow = 3, windowMs = 60000 } = {}) {
    try {
      const now = Date.now();
      const sk = 'tnf_rl_' + key;
      const arr = JSON.parse(localStorage.getItem(sk) || '[]').filter(t => now - t < windowMs);
      if (arr.length >= maxPerWindow) return { ok: false, retryInMs: windowMs - (now - arr[0]) };
      return { ok: true };
    } catch (e) { return { ok: true }; }
  },
  record(key, { windowMs = 60000 } = {}) {
    try {
      const now = Date.now();
      const sk = 'tnf_rl_' + key;
      const arr = JSON.parse(localStorage.getItem(sk) || '[]').filter(t => now - t < Math.max(windowMs, 3600000));
      arr.push(now);
      localStorage.setItem(sk, JSON.stringify(arr));
    } catch (e) {}
  },
};
window.AbuseGuard = AbuseGuard;

// Hidden honeypot field — humans never see or fill it; bots that auto-fill inputs do.
function HoneypotField({ value, onChange }) {
  return (
    <div aria-hidden="true" style={{ position: 'absolute', left: '-9999px', top: 0, width: 1, height: 1, overflow: 'hidden', opacity: 0, pointerEvents: 'none' }}>
      <label>Company website (leave empty)
        <input type="text" tabIndex={-1} autoComplete="off" name="company_website" value={value} onChange={e => onChange(e.target.value)}/>
      </label>
    </div>
  );
}
window.HoneypotField = HoneypotField;

// Hook: bundles honeypot state + min-fill timing + submit-cap + cooldown countdown.
// evaluate() → { ok } | { ok:false, bot } | { ok:false, reason:'too-fast'|'rate' }
function useFormGuard(key, opts = {}) {
  const minFillMs = opts.minFillMs == null ? 1500 : opts.minFillMs;
  const openedAt = React.useRef(Date.now());
  const [hp, setHp] = React.useState('');
  const [cooldown, setCooldown] = React.useState(0);
  React.useEffect(() => {
    if (cooldown <= 0) return;
    const id = setInterval(() => setCooldown(c => (c - 1 > 0 ? c - 1 : 0)), 1000);
    return () => clearInterval(id);
  }, [cooldown]);
  const evaluate = () => {
    if (hp.trim()) return { ok: false, bot: true };                       // honeypot tripped
    if (Date.now() - openedAt.current < minFillMs) return { ok: false, reason: 'too-fast' };
    if (cooldown > 0) return { ok: false, reason: 'rate', retryInMs: cooldown * 1000 };
    const r = AbuseGuard.checkRate(key, opts);
    if (!r.ok) { setCooldown(Math.ceil(r.retryInMs / 1000)); return { ok: false, reason: 'rate', retryInMs: r.retryInMs }; }
    return { ok: true };
  };
  const accept = () => AbuseGuard.record(key, opts);
  const reset = () => { openedAt.current = Date.now(); setHp(''); };
  return { hp, setHp, cooldown, evaluate, accept, reset };
}
window.useFormGuard = useFormGuard;

// === Photos (stable Unsplash IDs) ===
const PHOTOS = {
  paris: { src: 'https://images.unsplash.com/photo-1431274172761-fca41d930114?auto=format&fit=crop&w=1400&q=80', alt: 'Eiffel Tower at dusk' },
  parisStreet: { src: 'https://images.unsplash.com/photo-1502602898657-3e91760cbb34?auto=format&fit=crop&w=1400&q=80', alt: 'Paris street' },
  swiss: { src: 'https://images.unsplash.com/photo-1527668752968-14dc70a27c95?auto=format&fit=crop&w=1400&q=80', alt: 'Swiss alpine valley' },
  swissTrain: { src: 'https://images.unsplash.com/photo-1530841377377-3ff06c0ca713?auto=format&fit=crop&w=1400&q=80', alt: 'Swiss train through mountains' },
  italy: { src: 'https://images.unsplash.com/photo-1516483638261-f4dbaf036963?auto=format&fit=crop&w=1400&q=80', alt: 'Amalfi coast Positano' },
  venice: { src: 'https://images.unsplash.com/photo-1514890547357-a9ee288728e0?auto=format&fit=crop&w=1400&q=80', alt: 'Venice canal' },
  tuscany: { src: 'https://images.unsplash.com/photo-1499678329028-101435549a4e?auto=format&fit=crop&w=1400&q=80', alt: 'Tuscany hills' },
  santorini: { src: 'https://images.unsplash.com/photo-1613395877344-13d4a8e0d49e?auto=format&fit=crop&w=1400&q=80', alt: 'Santorini blue domes' },
  maldives: { src: 'https://images.unsplash.com/photo-1514282401047-d79a71a590e8?auto=format&fit=crop&w=1400&q=80', alt: 'Maldives overwater villas' },
  bali: { src: 'https://images.unsplash.com/photo-1573790387438-4da905039392?auto=format&fit=crop&w=1400&q=80', alt: 'Tegalalang rice terraces, Ubud, Bali' },
  kashmir: { src: 'https://images.unsplash.com/photo-1595815771614-ade9d652a65d?auto=format&fit=crop&w=1400&q=80', alt: 'Kashmir Dal lake' },
  kerala: { src: 'https://images.unsplash.com/photo-1602216056096-3b40cc0c9944?auto=format&fit=crop&w=1400&q=80', alt: 'Kerala backwaters' },
  dubai: { src: 'https://images.unsplash.com/photo-1512453979798-5ea266f8880c?auto=format&fit=crop&w=1400&q=80', alt: 'Dubai skyline' },
  desert: { src: 'https://images.unsplash.com/photo-1473496169904-658ba7c44d8a?auto=format&fit=crop&w=1400&q=80', alt: 'Desert dunes at sunset' },
  oman: { src: 'assets/oman-bay.jpg', alt: 'Boats anchored in a turquoise bay along the Oman coast' },
  omanMuscat: { src: 'assets/oman-bay.jpg', alt: 'Boats anchored in a turquoise bay along the Oman coast' },
  omanCoast: { src: 'https://images.unsplash.com/photo-1473496169904-658ba7c44d8a?auto=format&fit=crop&w=1400&q=80', alt: 'Wadi / coast, Oman' },
  plane: { src: 'https://images.unsplash.com/photo-1436491865332-7a61a109cc05?auto=format&fit=crop&w=1400&q=80', alt: 'Plane wing above clouds' },
  couple: { src: 'https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?auto=format&fit=crop&w=1400&q=80', alt: 'Couple on a beach' },
  family: { src: 'https://images.unsplash.com/photo-1602002418082-a4443e081dd1?auto=format&fit=crop&w=1400&q=80', alt: 'Family on a trip' },
  passport: { src: 'https://images.unsplash.com/photo-1488646953014-85cb44e25828?auto=format&fit=crop&w=1400&q=80', alt: 'Passport and map' },
  rome: { src: 'https://images.unsplash.com/photo-1552832230-c0197dd311b5?auto=format&fit=crop&w=1400&q=80', alt: 'Rome colosseum' },
  honeymoon: { src: 'https://images.unsplash.com/photo-1506929562872-bb421503ef21?auto=format&fit=crop&w=1400&q=80', alt: 'Couple at the beach' },
  mountain: { src: 'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?auto=format&fit=crop&w=1400&q=80', alt: 'Mountain peak' },
  city: { src: 'https://images.unsplash.com/photo-1480714378408-67cf0d13bc1b?auto=format&fit=crop&w=1400&q=80', alt: 'New York City' },
  beach: { src: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&w=1400&q=80', alt: 'Tropical beach' },
  hotel: { src: 'https://images.unsplash.com/photo-1542314831-068cd1dbfeeb?auto=format&fit=crop&w=1400&q=80', alt: 'Boutique hotel pool' },
  team: { src: 'https://images.unsplash.com/photo-1521737711867-e3b97375f902?auto=format&fit=crop&w=1400&q=80', alt: 'Team in office' },
  desk: { src: 'https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?auto=format&fit=crop&w=1400&q=80', alt: 'Desk planning' },
  airport: { src: 'https://images.unsplash.com/photo-1530521954074-e64f6810b32d?auto=format&fit=crop&w=1400&q=80', alt: 'Airport departures' },
  airTicketing: { src: 'https://images.unsplash.com/photo-1436491865332-7a61a109cc05?auto=format&fit=crop&w=1400&q=80', alt: 'Boarding pass and departures' },
  cabService: { src: 'https://images.unsplash.com/photo-1502877338535-766e1452684a?auto=format&fit=crop&w=1400&q=80', alt: 'Chauffeur car service' },
  insuranceService: { src: 'https://images.unsplash.com/photo-1448375240586-882707db888b?auto=format&fit=crop&w=1400&q=80', alt: 'Family travel planning' },
  visaService: { src: 'https://images.unsplash.com/photo-1488646953014-85cb44e25828?auto=format&fit=crop&w=1400&q=80', alt: 'Passport and visa documents' },
  aboutHero: { src: 'https://images.unsplash.com/photo-1602216056096-3b40cc0c9944?auto=format&fit=crop&w=1400&q=80', alt: 'Kerala backwaters at golden hour' },
  globe: { src: 'https://images.unsplash.com/photo-1488646953014-85cb44e25828?auto=format&fit=crop&w=1400&q=80', alt: 'Globe and passport' },
  travelPrep: { src: 'https://images.unsplash.com/photo-1551918120-9739cb430c6d?auto=format&fit=crop&w=1400&q=80', alt: 'Suitcase travel prep' },
  founder: { src: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=800&q=80', alt: 'Founder portrait' },
  founder2: { src: 'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&w=800&q=80', alt: 'Co-founder portrait' },
  uk: { src: 'https://images.unsplash.com/photo-1513635269975-59663e0ac1ad?auto=format&fit=crop&w=1400&q=80', alt: 'London Big Ben and bridge' },
  spain: { src: 'https://images.unsplash.com/photo-1583422409516-2895a77efded?auto=format&fit=crop&w=1400&q=80', alt: 'Sagrada Familia, Barcelona' },
  turkey: { src: 'https://images.unsplash.com/photo-1524231757912-21f4fe3a7200?auto=format&fit=crop&w=1400&q=80', alt: 'Istanbul Hagia Sophia' },
  thailand: { src: 'https://images.unsplash.com/photo-1528181304800-259b08848526?auto=format&fit=crop&w=1400&q=80', alt: 'Thailand Phi Phi islands' },
  malaysia: { src: 'https://images.unsplash.com/photo-1596422846543-75c6fc197f07?auto=format&fit=crop&w=1400&q=80', alt: 'Petronas Towers, Kuala Lumpur, Malaysia' },
  singapore: { src: 'https://images.unsplash.com/photo-1525625293386-3f8f99389edd?auto=format&fit=crop&w=1400&q=80', alt: 'Singapore Marina Bay Sands' },
  vietnam: { src: 'https://images.unsplash.com/photo-1528127269322-539801943592?auto=format&fit=crop&w=1400&q=80', alt: 'Ha Long Bay Vietnam' },
  japan: { src: 'https://images.unsplash.com/photo-1545569341-9eb8b30979d9?auto=format&fit=crop&w=1400&q=80', alt: 'Japan torii gate' },
  korea: { src: 'https://images.unsplash.com/photo-1517154421773-0529f29ea451?auto=format&fit=crop&w=1400&q=80', alt: 'Seoul South Korea cityscape' },
  australia: { src: 'https://images.unsplash.com/photo-1523482580672-f109ba8cb9be?auto=format&fit=crop&w=1400&q=80', alt: 'Sydney Opera House' },
  nz: { src: 'https://images.unsplash.com/photo-1469521669194-babb45599def?auto=format&fit=crop&w=1400&q=80', alt: 'New Zealand mountains' },
  usa: { src: 'https://images.unsplash.com/photo-1485871981521-5b1fd3805eee?auto=format&fit=crop&w=1400&q=80', alt: 'New York City skyline' },
  egypt: { src: 'https://images.unsplash.com/photo-1539768942893-daf53e448371?auto=format&fit=crop&w=1400&q=80', alt: 'Egypt pyramids' },
  southAfrica: { src: 'https://images.unsplash.com/photo-1580060839134-75a5edca2e99?auto=format&fit=crop&w=1400&q=80', alt: 'Cape Town Table Mountain' },
  srilanka: { src: 'https://images.unsplash.com/photo-1586500036706-41963de24d8b?auto=format&fit=crop&w=1400&q=80', alt: 'Sri Lanka beach' },
  saudi: { src: 'https://images.unsplash.com/photo-1578895101408-1a36b834405b?auto=format&fit=crop&w=1400&q=80', alt: 'AlUla rock formations, Saudi Arabia' },
  qatar: { src: 'assets/qatar-lusail.jpg', alt: 'Katara Towers and the Lusail skyline, Qatar' },
  mecca: { src: 'https://images.unsplash.com/photo-1565019001609-0e34a6a22189?auto=format&fit=crop&w=1400&q=80', alt: 'Kaaba, Masjid al-Haram, Mecca' },
  uae: { src: 'https://images.unsplash.com/photo-1512453979798-5ea266f8880c?auto=format&fit=crop&w=1400&q=80', alt: 'UAE skyline — Dubai & Abu Dhabi' },
  mauritius: { src: 'https://images.unsplash.com/photo-1544551763-46a013bb70d5?auto=format&fit=crop&w=1400&q=80', alt: 'Le Morne Brabant, Mauritius' },
  iceland: { src: 'https://images.unsplash.com/photo-1531366936337-7c912a4589a7?auto=format&fit=crop&w=1400&q=80', alt: 'Northern lights over Iceland' },
  norway: { src: 'https://images.unsplash.com/photo-1601439678777-b2b3c56fa627?auto=format&fit=crop&w=1400&q=80', alt: 'Norway fjords' },
  goa: { src: 'https://images.unsplash.com/photo-1512343879784-a960bf40e7f2?auto=format&fit=crop&w=1400&q=80', alt: 'Goa beach' },
  rajasthan: { src: 'https://images.unsplash.com/photo-1599661046289-e31897846e41?auto=format&fit=crop&w=1400&q=80', alt: 'Jaipur Hawa Mahal' },
  ladakh: { src: 'assets/ladakh-pangong.jpg', alt: 'Pangong Tso lake, Ladakh' },
  andaman: { src: 'assets/andaman-coast.jpg', alt: 'Aerial view of the Andaman Islands coastline' },
  blog1: { src: 'https://images.unsplash.com/photo-1527668752968-14dc70a27c95?auto=format&fit=crop&w=1400&q=80', alt: 'Swiss alpine train through the Alps' },
  blog2: { src: 'https://images.unsplash.com/photo-1583422409516-2895a77efded?auto=format&fit=crop&w=1400&q=80', alt: 'Schengen documents' },
  blog3: { src: 'https://images.unsplash.com/photo-1488085061387-422e29b40080?auto=format&fit=crop&w=1400&q=80', alt: 'Hot air balloons over Cappadocia at sunrise' },
  blog4: { src: 'https://images.unsplash.com/photo-1551918120-9739cb430c6d?auto=format&fit=crop&w=1400&q=80', alt: 'Suitcase packing' },
  blog5: { src: 'https://images.unsplash.com/photo-1502602898657-3e91760cbb34?auto=format&fit=crop&w=1400&q=80', alt: 'Paris cafe' },
  blog6: { src: 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=1400&q=80', alt: 'Travel landscape' },
  blog7: { src: 'https://images.unsplash.com/photo-1497366216548-37526070297c?auto=format&fit=crop&w=1400&q=80', alt: 'Corporate meeting room' },

  // --- Local client photos (assets/) ---
  // Home hero polaroids
  omanPolaroid:   { src: 'assets/OmanPicture2.jpg', alt: 'Oman' },
  sgPolaroid:     { src: 'assets/Singaporepic1.jpg', alt: 'Singapore' },
  baliPolaroid:   { src: 'assets/balipic1.0.avif', alt: 'Bali' },
  qatarPolaroid:  { src: 'assets/Qatarpic2.jpg', alt: 'Qatar' },
  // Home region cards
  homeMiddleEast: { src: 'assets/MiddleEastPic.jpg', alt: 'Middle East' },
  homeIndianSub:  { src: 'assets/IndianSubcontinentpic.jpg', alt: 'Indian Subcontinent' },
  homeAsia:       { src: 'assets/MalaysiaPic2.jpg', alt: 'Asia' },
  // Page headers
  aboutHeader:    { src: 'assets/Omanpicture1.jpg', alt: 'Oman landscape' },
  destHeader:     { src: 'assets/thailandpic2.jpg', alt: 'Thailand' },
  blogHeader:     { src: 'assets/Ladakhpic2.jpg', alt: 'Ladakh' },
  // Destination cards
  baliDest:       { src: 'assets/Balipic2.jpg', alt: 'Bali' },
  maldivesDest:   { src: 'assets/Maldivespic2.jpg', alt: 'Maldives' },
  rajasthanDest:  { src: 'assets/RajasthanPic1.jpg', alt: 'Rajasthan' },
  ladakhDest:     { src: 'assets/Ladakhpic1.jpg', alt: 'Ladakh' },
  // Blog posts
  sgBlog:         { src: 'assets/Singaporepic2.jpg', alt: 'Singapore' },
  srilankaBlog:   { src: 'assets/SriLankapic1.jpg', alt: 'Sri Lanka' },
  // Services page
  svcHeader:      { src: 'assets/Andamanislandpic2.jpg', alt: 'Andaman Islands' },
  svcInbound:     { src: 'assets/keralapic4.avif', alt: 'Kerala' },
  svcOutbound:    { src: 'assets/Dubaipic2.jpg', alt: 'Dubai' },
  svcCab:         { src: 'assets/luxury-airport-transfer-mumbai.jpg', alt: 'Chauffeured airport transfer' },
  // Destination cards (additional)
  keralaDest:     { src: 'assets/Keralapic3.jpg', alt: 'Kerala' },
  omanDest:       { src: 'assets/OmanPicture4.jpeg', alt: 'Oman' },
  qatarDest:      { src: 'assets/Qatarpic1.jpg', alt: 'Qatar' }
};
window.PHOTOS = PHOTOS;

// === Icons (lightweight, single stroke weight) ===
const Icon = {
  plane: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M21 16v-2l-8-5V3.5a1.5 1.5 0 1 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5L21 16z" /></svg>,
  globe: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /></svg>,
  passport: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="5" y="3" width="14" height="18" rx="2" /><circle cx="12" cy="10" r="3" /><path d="M9 17h6" /></svg>,
  car: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M5 17h14M6 17v2M18 17v2M5 13l1.5-5a2 2 0 0 1 2-1.5h7a2 2 0 0 1 2 1.5L19 13M5 13h14M5 13v4h14v-4" /><circle cx="8" cy="14.5" r="1" /><circle cx="16" cy="14.5" r="1" /></svg>,
  shield: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 3l8 3v6a9 9 0 0 1-8 9 9 9 0 0 1-8-9V6l8-3z" /><path d="m9 12 2 2 4-4" /></svg>,
  briefcase: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="7" width="18" height="13" rx="2" /><path d="M8 7V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M3 13h18" /></svg>,
  pin: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 21s-7-6.5-7-12a7 7 0 1 1 14 0c0 5.5-7 12-7 12z" /><circle cx="12" cy="9" r="2.5" /></svg>,
  search: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" /></svg>,
  arrow: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M5 12h14M13 5l7 7-7 7" /></svg>,
  arrowDiag: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M7 17 17 7M9 7h8v8" /></svg>,
  calendar: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="5" width="18" height="16" rx="2" /><path d="M3 9h18M8 3v4M16 3v4" /></svg>,
  user: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="8" r="4" /><path d="M4 21c0-4 4-6 8-6s8 2 8 6" /></svg>,
  phone: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M22 16.92V21a1 1 0 0 1-1.11 1 19 19 0 0 1-8.27-3 19 19 0 0 1-6-6A19 19 0 0 1 3.62 4.13 1 1 0 0 1 4.6 3H8.7a1 1 0 0 1 1 .75c.12.96.34 1.9.65 2.81a1 1 0 0 1-.22 1L8.6 9.6a16 16 0 0 0 6 6l2.04-1.5a1 1 0 0 1 1-.22c.91.3 1.85.52 2.81.65a1 1 0 0 1 .75 1Z" /></svg>,
  mail: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="5" width="18" height="14" rx="2" /><path d="m3 7 9 6 9-6" /></svg>,
  chat: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M21 12a8 8 0 0 1-12.5 6.6L3 20l1.4-5.5A8 8 0 1 1 21 12z" /></svg>,
  whatsapp: (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M.057 24l1.687-6.163a11.867 11.867 0 0 1-1.587-5.946C.16 5.335 5.495 0 12.05 0a11.82 11.82 0 0 1 8.413 3.488 11.824 11.824 0 0 1 3.48 8.414c-.003 6.557-5.337 11.892-11.893 11.892a11.9 11.9 0 0 1-5.688-1.448L.057 24zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884a9.86 9.86 0 0 0 1.512 5.26l.36.572-1.001 3.66 3.748-.985zM17.422 14.382c-.074-.124-.272-.198-.57-.347-.297-.149-1.758-.868-2.03-.967-.273-.099-.471-.149-.67.149-.197.297-.768.967-.941 1.165-.173.198-.347.223-.644.074-.297-.149-1.255-.462-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.521.151-.172.2-.296.3-.495.099-.198.05-.372-.025-.521-.075-.149-.669-1.611-.916-2.206-.242-.579-.487-.501-.669-.51l-.57-.01c-.198 0-.52.074-.792.372s-1.04 1.016-1.04 2.479 1.065 2.876 1.213 3.074c.149.198 2.095 3.2 5.076 4.487.709.306 1.263.489 1.694.626.712.226 1.36.194 1.872.118.571-.085 1.758-.719 2.006-1.413.247-.694.247-1.289.173-1.413z" /></svg>,
  instagram: (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z" /></svg>,
  facebook: (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" /></svg>,
  star: (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p} style={{ width: "13px", opacity: "1" }}><path d="m12 2 3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" style={{ strokeWidth: "1px", opacity: "1" }} /></svg>,
  check: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m5 12 5 5L20 7" /></svg>,
  alert: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="9" /><path d="M12 8v4.5" /><circle cx="12" cy="16" r="0.6" fill="currentColor" stroke="none" /></svg>,
  chevR: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m9 6 6 6-6 6" /></svg>,
  chevL: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m15 6-6 6 6 6" /></svg>,
  x: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M6 6l12 12M18 6 6 18" /></svg>,
  menu: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 6h18M3 12h18M3 18h18" /></svg>,
  send: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z" /></svg>,
  hotel: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 21V8l9-5 9 5v13M3 21h18M9 21v-6h6v6M7 11h.01M11 11h.01M15 11h.01" /></svg>,
  clock: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" /></svg>,
  fb: (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M22 12a10 10 0 1 0-11.55 9.88v-7H7.9V12h2.55V9.79c0-2.52 1.5-3.91 3.79-3.91 1.1 0 2.25.2 2.25.2v2.47h-1.27c-1.25 0-1.64.78-1.64 1.57V12h2.78l-.44 2.88h-2.34v7A10 10 0 0 0 22 12z" /></svg>,
  ig: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="3" width="18" height="18" rx="5" /><circle cx="12" cy="12" r="4" /><circle cx="17.5" cy="6.5" r="0.6" fill="currentColor" /></svg>,
  yt: (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M23.5 6.2a3 3 0 0 0-2.1-2.1C19.5 3.5 12 3.5 12 3.5s-7.5 0-9.4.6A3 3 0 0 0 .5 6.2C0 8 0 12 0 12s0 4 .5 5.8a3 3 0 0 0 2.1 2.1C4.5 20.5 12 20.5 12 20.5s7.5 0 9.4-.6a3 3 0 0 0 2.1-2.1c.5-1.8.5-5.8.5-5.8s0-4-.5-5.8zM9.6 15.6V8.4l6.2 3.6-6.2 3.6z" /></svg>
};
window.Icon = Icon;

// === Image with graceful fallback ===
function Img({ photo, style = {}, alt, eager = false, ...rest }) {
  const [err, setErr] = React.useState(false);
  const key = typeof photo === 'string' ? photo : null;
  const p = typeof photo === 'string' ? PHOTOS[photo] : photo;
  if (!p || err) {
    return (
      <div style={{
        background: `linear-gradient(135deg, ${TNF.turq}, ${TNF.blue})`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        color: 'rgba(255,255,255,0.7)', fontFamily: 'monospace', fontSize: 12,
        ...style
      }}>{alt || p?.alt || 'image'}</div>);

  }
  const resolvedSrc = (key && typeof window !== 'undefined' && window.__resources && window.__resources[key]) ? window.__resources[key] : p.src;
  return (
    <img src={resolvedSrc} alt={alt || p.alt} loading={eager ? 'eager' : 'lazy'} onError={() => setErr(true)}
    style={{ objectFit: 'cover', display: 'block', ...style }} {...rest} />);

}
window.Img = Img;

// === Avatar (initials fallback) ===
function Avatar({ name, src, size = 40 }) {
  const initials = name.split(' ').map((s) => s[0]).join('').slice(0, 2).toUpperCase();
  const hue = name.charCodeAt(0) * 37 % 360;
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%',
      background: src ? `url(${src}) center/cover` : `linear-gradient(135deg, hsl(${hue} 35% 55%), hsl(${(hue + 30) % 360} 40% 40%))`,
      color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center',
      fontSize: size * 0.36, fontWeight: 600, letterSpacing: '0.02em',
      flex: '0 0 auto'
    }}>
      {!src && initials}
    </div>);

}
window.Avatar = Avatar;

// === Logo lockup ===
function Logo({ inverted = false, size = 36 }) {
  const text = inverted ? '#fff' : TNF.blue;
  const sub = inverted ? 'rgba(255,255,255,0.7)' : TNF.inkSoft;
  return (
    <a href="index.html" style={{ display: 'flex', alignItems: 'center', gap: 11, textDecoration: 'none' }}>
      <img src="assets/tnf-logo.png?v=2" alt="" width={size * 1.25} height={size}
        style={{ display: 'block', width: size * 1.25, height: size, objectFit: 'contain' }}/>
      <div style={{ lineHeight: 1, display: 'flex', flexDirection: 'column', gap: 3 }}>
        <span style={{ color: text, fontFamily: 'var(--tnf-logo-display)', fontWeight: 700, fontSize: size * 0.62, letterSpacing: '-0.01em', whiteSpace: 'nowrap' }}>
          Trips N Flys
        </span>
        <span style={{ color: sub, fontFamily: 'var(--tnf-logo-sans)', fontWeight: 500, fontSize: size * 0.26, letterSpacing: '0.22em', textTransform: 'uppercase', whiteSpace: 'nowrap' }}>
          Travel Solutions
        </span>
      </div>
    </a>);

}
window.Logo = Logo;

// === Reusable button styles ===
function btn(color, opts = {}) {
  return {
    background: color, color: opts.fg || '#fff', border: 'none',
    padding: opts.small ? '10px 18px' : '14px 26px', borderRadius: 999,
    fontWeight: 600, fontSize: opts.small ? 13 : 14, cursor: 'pointer',
    display: 'inline-flex', alignItems: 'center', gap: 10,
    fontFamily: 'inherit', textDecoration: 'none', whiteSpace: 'nowrap'
  };
}
function btnOutline(opts = {}) {
  return {
    background: opts.bg || '#fff', color: opts.fg || TNF.blueDk,
    border: `1.5px solid ${opts.border || TNF.line}`,
    padding: opts.small ? '8px 16px' : '12px 24px', borderRadius: 999,
    fontWeight: 500, fontSize: opts.small ? 13 : 14, cursor: 'pointer',
    fontFamily: 'inherit', display: 'inline-flex', alignItems: 'center', gap: 8,
    textDecoration: 'none', whiteSpace: 'nowrap'
  };
}
window.btn = btn;
window.btnOutline = btnOutline;

// === Content data ===
const SERVICES = [
{ id: 'inbound', label: 'Inbound Tourism', tag: 'Visitors to India', icon: 'globe', blurb: 'Curated itineraries for international travellers exploring Kerala, the Western Ghats, and beyond.', long: 'We design end-to-end experiences for international visitors — heritage trails, backwater stays, Ayurveda retreats and curated cultural immersions. Local guides, vetted accommodation, and seamless ground logistics.' },
{ id: 'outbound', label: 'Outbound Tourism', tag: 'Holidays worldwide', icon: 'plane', blurb: 'Tailored holiday packages — leisure, honeymoon, group tours — designed around you.', long: 'From Switzerland to Santorini, we plan trips that match your pace and budget. Honeymoons, family holidays, multi-country grand tours, group departures — all itemised, all flexible.' },
{ id: 'cab', label: 'Chauffeured Services', tag: 'Airport & city transfers', icon: 'car', blurb: 'Professionally driven transfers and intercity vehicles — airport, city or multi-day.', long: 'Vetted, uniformed chauffeurs in GPS-tracked vehicles, with transparent fares. Airport pickups, intercity transfers, multi-day tours with the same driver throughout — sedan, SUV or coach.' },
{ id: 'tickets', label: 'Air Ticketing', tag: 'Competitive airfares', icon: 'send', blurb: 'Domestic & international fares across major carriers. Multi-city, open-jaw, business class.', long: 'Direct relationships with airlines and consolidators mean we routinely match or beat OTA prices — plus a real person to handle reschedules, refunds and upgrade requests.' },
{ id: 'visa', label: 'Visa Consultancy', tag: 'End-to-end assistance', icon: 'passport', blurb: 'Documentation, applications, submission. Schengen, UK, US, GCC and more.', long: 'Visa processes are detail-heavy. We handle documentation, embassy appointments, biometrics scheduling, and submission. Schengen, UK, US, Canada, Australia, GCC — we cover most categories.' }];

window.SERVICES = SERVICES;

const DESTINATIONS = [
// Middle East
{ id: 'uae', name: 'United Arab Emirates', region: 'Middle East', photo: 'uae', blurb: 'Dubai skyline, Abu Dhabi mosques, desert dunes — long weekends, family holidays.', from: '₹  55,000', tag: 'City' },
{ id: 'oman', name: 'Oman', region: 'Middle East', photo: 'omanDest', blurb: 'Sultan Qaboos Grand Mosque, wadis, fjords — our founders\' second home.', from: '₹  65,000', tag: 'Adventure' },
{ id: 'saudi', name: 'Kingdom of Saudi Arabia', region: 'Middle East', photo: 'mecca', blurb: 'Umrah and Hajj pilgrimages, AlUla, Diriyah, Red Sea — the new tourist frontier.', from: '₹  75,000', tag: 'Cultural' },
{ id: 'qatar', name: 'Qatar', region: 'Middle East', photo: 'qatarDest', blurb: 'Doha skyline, Souq Waqif, desert weekends.', from: '₹  60,000', tag: 'City' },

// Southeast Asia
{ id: 'thailand', name: 'Thailand', region: 'Southeast Asia', photo: 'thailand', blurb: 'Bangkok buzz, Phuket beaches, Chiang Mai hills.', from: '₹  62,000', tag: 'Tropical' },
{ id: 'malaysia', name: 'Malaysia', region: 'Southeast Asia', photo: 'malaysia', blurb: 'Kuala Lumpur towers, Langkawi beaches, Penang street food.', from: '₹  58,000', tag: 'City' },
{ id: 'singapore', name: 'Singapore', region: 'Southeast Asia', photo: 'singapore', blurb: 'Marina Bay, Sentosa, the cleanest city stop.', from: '₹  75,000', tag: 'City' },
{ id: 'vietnam', name: 'Vietnam', region: 'Southeast Asia', photo: 'vietnam', blurb: 'Halong Bay, Hoi An lanterns, street-food trails.', from: '₹  78,000', tag: 'Cultural' },
{ id: 'bali', name: 'Bali (Indonesia)', region: 'Southeast Asia', photo: 'baliDest', blurb: 'Rice terraces, temple towns, surf and yoga.', from: '₹  85,000', tag: 'Tropical' },
{ id: 'srilanka', name: 'Sri Lanka', region: 'Southeast Asia', photo: 'srilanka', blurb: 'Tea hills, ancient cities, southern beaches.', from: '₹  48,000', tag: 'Cultural' },

// Indian Ocean
{ id: 'maldives', name: 'Maldives', region: 'Indian Ocean', photo: 'maldivesDest', blurb: 'Overwater villas, reef life, sunset seaplanes.', from: '₹1,25,000', tag: 'Beach' },

// India
{ id: 'kashmir', name: 'Kashmir', region: 'India', photo: 'kashmir', blurb: 'Dal Lake gondolas, Mughal gardens, Gulmarg snow.', from: '₹  42,000', tag: 'Adventure' },
{ id: 'kerala', name: 'Kerala', region: 'India', photo: 'keralaDest', blurb: 'Backwaters, spice country, beaches at home.', from: '₹  28,000', tag: 'Cultural' },
{ id: 'goa', name: 'Goa', region: 'India', photo: 'goa', blurb: 'Beaches, Portuguese heritage, sunset shacks.', from: '₹  24,000', tag: 'Beach' },
{ id: 'rajasthan', name: 'Rajasthan', region: 'India', photo: 'rajasthanDest', blurb: 'Pink, blue & golden cities — palaces and forts.', from: '₹  36,000', tag: 'Cultural' },
{ id: 'ladakh', name: 'Ladakh', region: 'India', photo: 'ladakhDest', blurb: 'High-altitude lakes, monasteries, biker country.', from: '₹  52,000', tag: 'Adventure' },
{ id: 'andaman', name: 'Andaman Islands', region: 'India', photo: 'andaman', blurb: 'Coral beaches, scuba diving, Havelock & Neil islands.', from: '₹  58,000', tag: 'Beach' }];

window.DESTINATIONS = DESTINATIONS;

const TESTIMONIALS = [
{ quote: 'Planning an international trip always felt overwhelming, but Trips N Flys made the entire process effortless. They took care of everything — from visa documentation to hotel bookings — and kept me informed at every step.', name: 'Reema A.', role: 'Family Holiday · Switzerland', rating: 5 },
{ quote: 'What impressed me most was how personal the service felt. It wasn’t just about selling a package — they genuinely wanted to understand what kind of trip we were looking for. That level of care is rare.', name: 'Arun & Priya', role: 'Honeymoon · Maldives', rating: 5 },
{ quote: 'As a business traveller with very specific needs, I need a partner who is responsive and reliable. Trips N Flys has never let me down. Quick turnarounds, great fares, and always available.', name: 'Hari Krishnan', role: 'Corporate · Multi-city', rating: 5 },
{ quote: 'The visa process I had been dreading was handled so smoothly by their team. Clear guidance, proper documentation, and the visa came through without any issues.', name: 'Fathima Shereen', role: 'Visa Consultancy · Schengen', rating: 5 }];

window.TESTIMONIALS = TESTIMONIALS;

const BLOG_POSTS = [
{ id: 'monsoon-kerala', title: 'Why the monsoon is the best time to visit Kerala (and how to pack for it)', cat: 'Destination', read: '6 min read', date: 'April 2026', photo: 'kerala', author: 'Anand Krishnan Nair', excerpt: 'Greener landscapes, half-price stays, and a few weather rules of thumb we share with international clients.', featured: true },
{ id: 'pack-light', title: 'Pack light, fly happy — the carry-on system we recommend to every client', cat: 'Travel tips', read: '4 min read', date: 'March 2026', photo: 'blog4', author: 'Devika Menon', excerpt: 'A repeatable packing method built for two-week trips with three climates and one carry-on.' },
{ id: 'corporate-2026', title: 'Five things corporate travellers are getting wrong in 2026', cat: 'Business travel', read: '6 min read', date: 'February 2026', photo: 'blog7', author: 'Amina Rahman', excerpt: 'Loyalty programs, fare classes, and the costly assumption that a single airline always wins.' },
{ id: 'oman-guide', title: 'Oman in five days — our founders’ second home, demystified', cat: 'Destination', read: '9 min read', date: 'January 2026', photo: 'omanMuscat', author: 'Faris Abdul Kareem', excerpt: 'Beyond the Muscat fort and the wadis: where locals eat, dive, and weekend.' },
{ id: 'bali-beyond', title: 'Bali beyond the beach clubs — the Ubud-and-east-coast itinerary we love', cat: 'Itinerary', read: '8 min read', date: 'May 2026', photo: 'bali', author: 'Mariam Joseph', excerpt: 'Rice-terrace mornings, a temple you’ll actually remember, and the quieter east coast most visitors skip.' },
{ id: 'rajasthan-roadtrip', title: 'Palaces, forts and the perfect Rajasthan road trip', cat: 'Itinerary', read: '10 min read', date: 'April 2026', photo: 'rajasthan', author: 'Thomas Varghese', excerpt: 'How to string Jaipur, Jodhpur and Udaipur together without spending your whole holiday in the car.' },
{ id: 'maldives-island', title: 'Choosing the right Maldives island for your budget', cat: 'Destination', read: '7 min read', date: 'March 2026', photo: 'maldives', author: 'Nandana Pillai', excerpt: 'Guesthouse islands, mid-range resorts, or overwater villas — how to match the atoll to your spend.' },
{ id: 'singapore-72h', title: '72 hours in Singapore with kids — a stopover that earns its airfare', cat: 'Itinerary', read: '6 min read', date: 'February 2026', photo: 'sgBlog', author: 'Muhammad Rafi P. K.', excerpt: 'Gardens, hawker centres and the one attraction worth pre-booking before you land.' },
{ id: 'srilanka-train', title: 'Sri Lanka by train — the hill-country route worth slowing down for', cat: 'Destination', read: '8 min read', date: 'January 2026', photo: 'srilankaBlog', author: 'Elizabeth Thomas', excerpt: 'Tea estates, viaducts and the Kandy-to-Ella leg that ends up everyone’s trip highlight.' },
{ id: 'ladakh-altitude', title: 'Acclimatising for Ladakh — the days most itineraries get wrong', cat: 'Travel tips', read: '5 min read', date: 'December 2025', photo: 'ladakh', author: 'Vishnu Prasad Namboothiri', excerpt: 'Why your first 48 hours in Leh decide the whole trip, and how we pace high-altitude clients.' }];

window.BLOG_POSTS = BLOG_POSTS;

// Full article bodies — strings are paragraphs, { h } objects are subheadings.
const BLOG_BODIES = {
  'monsoon-kerala': [
    'Most people are told to avoid Kerala in the monsoon. We tell our clients the opposite — if you can handle a few wet afternoons, June to September is when the state is at its most beautiful and its most affordable.',
    { h: 'The light changes everything' },
    'The hills behind Munnar turn an electric green you simply don’t see in the dry months. Waterfalls that are a trickle in March run full. The backwaters near Alleppey sit high and glassy, and the air smells of wet earth and cardamom. Photographers quietly consider this the best season of the year.',
    { h: 'What it costs — and saves' },
    'Houseboats and hill-station resorts drop their rates by a third or more between June and August. The same backwater cruise that books out in December is half-price and half-empty. For families travelling on school holidays, that difference funds an extra two nights almost everywhere.',
    { h: 'Packing for the rain' },
    'You don’t need much: a light rain shell, quick-dry footwear, and a dry-bag for your phone and camera. Showers tend to arrive in the afternoon and clear by evening, so we build mornings around the outdoor plans and leave afternoons for spice-garden visits, Ayurveda, or simply watching the rain from a veranda.',
    'If this is your first trip to the south, tell your consultant how you feel about weather. We’ll pace the itinerary around it rather than pretending the rain isn’t there.',
  ],
  'pack-light': [
    'Almost every problem we untangle for clients mid-trip — missed connections, baggage delays, the 5am scramble to repack — traces back to packing too much. Here’s the carry-on system we recommend to everyone, refined over a thousand itineraries.',
    { h: 'Pack for one week, not three' },
    'Whether you’re away for seven days or twenty-one, you only need about a week of clothing. Build a small palette where everything mixes, plan a single mid-trip laundry, and the bag stays the same size no matter how long the trip.',
    { h: 'The three-climate rule' },
    'For trips that cross climates — a hill station and a beach, say — pack layers rather than separate wardrobes. A merino base layer, one warm mid-layer and a packable shell cover almost any temperature you’ll meet, and they weigh almost nothing.',
    { h: 'Wear the bulk, bag the rest' },
    'On travel days, wear your heaviest shoes and jacket. Keep one change of clothes, all documents, medication and chargers in a small personal item — so even if a bag goes missing, your first 24 hours are unaffected.',
    'Do this once and you won’t go back. The freedom of walking straight past the baggage carousel is worth more than the third pair of shoes.',
  ],
  'corporate-2026': [
    'Corporate travel changed faster than most travel policies did. Here are the five mistakes we still see good companies making in 2026 — and what they quietly cost.',
    { h: '1. Booking the cheapest fare, not the cheapest trip' },
    'A fare that saves four thousand rupees but adds a self-transfer and a six-hour layover costs far more in a senior employee’s time and energy. We quote total trip cost, not just the ticket line.',
    { h: '2. Treating loyalty as a personal perk' },
    'When points sit in individual accounts, the company pays full price forever. A pooled corporate programme turns the same spend into measurable savings — and removes the temptation to route trips for personal miles.',
    { h: '3. Ignoring fare classes' },
    'Not all economy tickets are equal. The right fare class can mean free changes and full refunds for a small premium — exactly what business travel needs when plans shift at the last minute.',
    { h: '4. One airline, always' },
    'Standardising on a single carrier feels tidy but quietly inflates fares on routes where they don’t compete. We benchmark every route rather than assuming the incumbent wins.',
    { h: '5. No one owns the relationship' },
    'The biggest saving is having one consultant who knows your travellers, your approval chain and your priorities — so re-bookings happen in minutes, not email threads.',
  ],
  'oman-guide': [
    'Oman is our co-founder’s second home, and the country we send more curious travellers to than any other in the Gulf. Five days is enough to see why. Here’s how we structure it.',
    { h: 'Days one and two: Muscat' },
    'Start slow in the capital. The Sultan Qaboos Grand Mosque in the morning, the Mutrah corniche and souq in the late afternoon, and a seafood dinner where the fishing boats land. Muscat rewards an unhurried pace.',
    { h: 'Day three: the wadis' },
    'Drive inland to Wadi Shab or Wadi Bani Khalid — turquoise pools between sheer canyon walls, cool enough to swim even in the heat. This is the Oman that surprises first-timers.',
    { h: 'Days four and five: desert and coast' },
    'A night in the Wahiba Sands under more stars than you’ve ever seen, then back toward the coast for the fjords of Musandam if time allows. We match the exact route to your appetite for driving.',
    'Oman is safe, friendly and still uncrowded. Tell us whether you want adventure or ease, and we’ll build the five days around it.',
  ],
  'bali-beyond': [
    'Bali’s beach clubs get the attention, but the island we send honeymooners and families back to again and again is the one inland and to the east. Here’s the itinerary we love.',
    { h: 'Base in Ubud, not the south' },
    'Ubud trades nightclubs for rice terraces, river valleys and a genuinely good food scene. Mornings among the Tegalalang terraces before the crowds arrive are the Bali people remember.',
    { h: 'One temple, done properly' },
    'Rather than rushing six temples, we pick one — usually a sunrise or sunset visit — and let you actually be there. The difference between ticking it off and remembering it is the time of day.',
    { h: 'The quieter east coast' },
    'Amed and the east coast offer black-sand calm, easy snorkelling and a fraction of the traffic. It’s where we send couples who want the island to slow down for them.',
    'Bali rewards depth over breadth. Give us your pace and we’ll keep the days from blurring together.',
  ],
  'rajasthan-roadtrip': [
    'Rajasthan is built for a road trip, but the classic Jaipur–Jodhpur–Udaipur triangle can turn into more driving than holiday if you’re not careful. Here’s how we keep it joyful.',
    { h: 'Start pink, end blue' },
    'Begin in Jaipur for the forts and bazaars, move to Jodhpur for the staggering Mehrangarh and the blue old city, and finish in Udaipur — the lakes are the right note to end on.',
    { h: 'Break the long legs' },
    'The drives between cities are long. We build in a stop — a heritage hotel in the countryside, a stepwell, a rural lunch — so the transfer becomes part of the trip rather than a lost day.',
    { h: 'Sleep in the history' },
    'Rajasthan’s palace and haveli hotels are among the best heritage stays in the world. We choose two or three to splurge on and balance the rest, so the budget stretches without dulling the experience.',
    'Tell us how many hours a day you’re happy to drive, and we’ll shape the route to match.',
  ],
  'maldives-island': [
    'The Maldives isn’t one destination — it’s hundreds of islands at wildly different price points. Choosing the right one matters more than choosing the right month. Here’s how we guide it.',
    { h: 'Guesthouse islands' },
    'On local islands, family-run guesthouses put the Maldives within reach of almost any budget. You trade the private-island fantasy for real village life, shared house reefs and honest prices.',
    { h: 'Mid-range resorts' },
    'The sweet spot for most couples: a full-board resort a short speedboat from Malé, with a house reef good enough that you may never book an excursion. This is where we place most honeymooners.',
    { h: 'Overwater villas' },
    'The icon. Worth it for a special occasion, but we’re honest about which resorts justify the seaplane transfer and which simply charge for the photo.',
    'Give us your budget first and your dates second. In the Maldives, that order saves you the most.',
  ],
  'singapore-72h': [
    'Singapore is the rare stopover that earns its airfare. Three days is plenty to make it a holiday in its own right — especially with children. Here’s our 72-hour plan.',
    { h: 'Day one: gardens and the bay' },
    'Gardens by the Bay in the cooler morning, the waterfront in the afternoon, and the light show after dark. It’s the easiest possible introduction and it lands well with every age.',
    { h: 'Day two: hawker centres and the zoo' },
    'Eat your way through a hawker centre at lunch, then spend the afternoon at one of the world’s best zoos. The kids sleep well that night.',
    { h: 'Day three: Sentosa, pre-booked' },
    'Sentosa’s headline attraction sells out — we book it before you land. Build the rest of the day around it loosely and leave room to do nothing by the pool.',
    'Singapore is spotless, safe and effortless with children. Tell us their ages and we’ll tune the three days accordingly.',
  ],
  'srilanka-train': [
    'Sri Lanka is small, green and best seen slowly — and there’s no better way to slow down than the hill-country train. Here’s the route worth planning around.',
    { h: 'Kandy to Ella' },
    'The leg everyone remembers: tea estates, misty viaducts and open carriage doors as the train climbs through the highlands. We book reserved seats well ahead so you’re not standing for seven hours.',
    { h: 'Stop in the tea country' },
    'Break the journey at Nuwara Eliya or Haputale. A working tea-estate stay, a cool-climate walk and a factory tour turn the train ride into a proper few days rather than a single photo.',
    { h: 'Then come down to the coast' },
    'After the hills, the southern beaches around Mirissa and the old fort at Galle are the perfect contrast. We pace the descent so you arrive ready to stop moving.',
    'Sri Lanka packs a lot into a short flight. Tell us your timeframe and we’ll decide what to slow down for.',
  ],
  'ladakh-altitude': [
    'Ladakh is one of the most spectacular places we send travellers — and the one where itineraries most often go wrong. The mistake is almost always altitude. Here’s how we pace it.',
    { h: 'Your first 48 hours decide the trip' },
    'Leh sits at 3,500 metres. Fly in and you must rest — genuinely rest — for the first two days. Clients who try to sightsee on day one are the ones who lose day three to a headache and nausea.',
    { h: 'Climb high, sleep low' },
    'We build the route so you gain altitude gradually, visiting higher passes and lakes only after you’ve acclimatised. Pangong and the high passes are worth the patience; rushing them is not.',
    { h: 'The practical bits' },
    'Hydrate hard, skip alcohol the first few days, and keep the early itinerary flexible. We always leave a buffer day — bodies acclimatise at their own pace, and a good trip respects that.',
    'If you have any heart or breathing condition, tell us before we plan. Ladakh is for almost everyone, but only when it’s paced properly.',
  ],
};
window.BLOG_BODIES = BLOG_BODIES;

const FAQ = [
{ q: 'How early should I start planning my trip?', a: 'For international leisure trips, four to eight weeks is comfortable — it gives us time for visa processing, fare watching, and route optimisation. For peak-season travel (Dec, May, summer breaks), six to ten weeks is safer.' },
{ q: 'Do you charge a consultation fee?', a: 'No. Initial consultation, itinerary drafts, and quotes are always free. We only ask for a confirmation amount once you decide to book.' },
{ q: 'Are your prices negotiable?', a: 'Our pricing is itemised and transparent — flights, stay, transfers, visas, insurance and our planning fee are all shown separately. We’ll happily explain any line item, and there’s usually room to flex on stay categories or trip length.' },
{ q: 'What if something goes wrong during the trip?', a: 'A travel consultant is reachable on phone and WhatsApp 24/7 during your trip. Lost passport, missed connection, hotel issue — we step in, even from another time zone.' },
{ q: 'Do you handle group bookings?', a: 'Yes — family reunions, corporate offsites, educational trips and group tours of 8 to 60 travellers. We offer dedicated coordinators and consolidated billing for larger groups.' },
{ q: 'Can you handle just a visa, without the trip?', a: 'Absolutely. Visa-only consultancy is one of our most-used services — we’ll help with documentation, application, and appointment scheduling whether or not we’ve booked the trip.' }];

window.FAQ = FAQ;