1/* ============================================================================= 2 Qistas â site behaviour 3 Requires: jQuery 3.7 (loaded first), Bootstrap 5.3 bundle (components/utilities). 4 The site ships one page tree per language (en/ + ar/), so the interface language 5 is read once from <html lang> â there is no runtime string swapping. 6 ========================================================================== */ 7(function ($) { 8 'use strict'; 9 10 var LANG = document.documentElement.getAttribute('lang') === 'ar' ? 'ar' : 'en'; 11 var reduce = window.matchMedia && matchMedia('(prefers-reduced-motion:reduce)').matches; 12 13 /* ---------------------------------------------------------------- icon set */ 14 var I={ 15 search:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>', 16 chat:'<span class="pico pico-chat"></span>', 17 gavel:'<span class="pico pico-gavel"></span>', 18 doc:'<span class="pico pico-doc"></span>', 19 bank:'<span class="pico pico-bank"></span>', 20 bolt:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2L3 14h7l-1 8 10-12h-7z"/></svg>', 21 home:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11.5 12 4l8 7.5"/><path d="M6 10v8.5a1 1 0 0 0 1 1h3v-6h4v6h3a1 1 0 0 0 1-1V10"/></svg>', 22 globe:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>', 23 chevronDown:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>', 24 folder:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/></svg>', 25 clock:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>', 26 bell:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.268 21a2 2 0 0 0 3.464 0"/><path d="M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326"/></svg>', 27 mail:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>', 28 sun:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>', 29 userTop:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>', 30 31 sparkle:'<svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M12 3c.4 3.2 1 5.2 2 6.2S17 11 20 11c-3 .4-5 1-6 2s-1.6 2.8-2 6c-.4-3.2-1-5.2-2-6S6 11.4 4 11c3-.4 5-1 6-2s1.6-2.8 2-6Z"/></svg>', 32 crosshair:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="2" x2="5" y1="12" y2="12"/><line x1="19" x2="22" y1="12" y2="12"/><line x1="12" x2="12" y1="2" y2="5"/><line x1="12" x2="12" y1="19" y2="22"/><circle cx="12" cy="12" r="7"/><circle cx="12" cy="12" r="3"/></svg>', 33 key:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"/><circle cx="16.5" cy="7.5" r=".5" fill="currentColor"/></svg>', 34 sparklePlus:'<svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/><path d="M20 3v4"/><path d="M22 5h-4"/><path d="M4 17v2"/><path d="M5 18H3"/></svg>', 35 mic:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" x2="12" y1="19" y2="22"/></svg>', 36 wand:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M5 19 15.5 8.5"/><path d="M18 4l.7 1.8L20.5 6.5l-1.8.7L18 9l-.7-1.8-1.8-.7 1.8-.7Z"/>
36<path d="M6.5 14.5l.4 1 1 .4-1 .4-.4 1-.4-1-1-.4 1-.4Z"/></svg>', 37 docnav:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="3.5" width="12" height="17" rx="2"/><path d="M9 8h6M9 12h6M9 16h3.5"/></svg>', 38 book:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M4 5.5A2 2 0 016 4h6v16H6a2 2 0 01-2-1.5z"/><path d="M20 5.5A2 2 0 0018 4h-6v16h6a2 2 0 002-1.5z"/></svg>' 39 }; 40 41 /* --------------------------------------- research-home mockup copy (bilingual) */ 42 var RH={ 43 en:{hello:'Hello,',h:'What would you like to research today?',ph:'Search by document name, citation, keyword, or legal topic',go:'Search', 44 chips:['All Documents','Legislation','Cases','Treaties','Constitutional','Reports','Seminal Cases'], 45 tabs:['Legal News','Legal Updates','Legal Content','Practice Areas','Resource Centre','Our Solutions'], 46 news:[['New Federal Decree-Law on Commercial Companies Amendment','UAE · Corporate Law · March 2026','Enhanced corporate governance requirements introduced to the Commercial Companies Law.'], 47 ['Supreme Court Ruling on Digital Evidence Admissibility','UAE · Civil Law · March 2026','New standards established for accepting digital evidence in civil proceedings.'], 48 ['GCC Trade Agreement Updates, New Provisions','GCC · International Trade · March 2026','Member states ratify amendments affecting cross-border rules.'], 49 ['Amendments to Labour Law: Remote Work Provisions','UAE · Employment Law · Feb 2026','Updated provisions covering remote and hybrid working.']]}, 50 ar:{hello:'Ù Ø±ØØ¨Ø§ÙØ',h:'٠اذا ترÙÙÙØ¯ أ٠تبØÙÙØ« اÙÙÙÙÙÙ Ø',ph:'Ø§Ø¨ØØ« باس٠اÙÙ Ø³ØªÙØ¯ Ø£Ù Ø§ÙØ§Ø³ØªØ´Ùاد Ø£Ù ÙÙÙ Ø© Ù ÙØªØ§ØÙØ© Ø£Ù Ù ÙØ¶Ùع ÙØ§ÙÙÙÙ',go:'Ø¨ØØ«', 51 chips:['Ù٠اÙÙ Ø³ØªÙØ¯Ø§Øª','Ø§ÙØªØ´Ø±Ùعات','Ø§ÙØ£ØÙا٠','اÙÙ Ø¹Ø§ÙØ¯Ø§Øª','Ø§ÙØ¯Ø³ØªÙرÙ','Ø§ÙØªÙØ§Ø±ÙØ±','ÙØ¶Ø§Ùا Ù Ø±Ø¬Ø¹ÙØ©'], 52 tabs:['Ø§ÙØ£Ø®Ø¨Ø§Ø± اÙÙØ§ÙÙÙÙØ©','Ø§ÙØªØØ¯Ùثات اÙÙØ§ÙÙÙÙØ©','اÙÙ ØØªÙ٠اÙÙØ§ÙÙÙÙ','Ù Ø¬Ø§ÙØ§Øª اÙ٠٠ارسة','Ù Ø±ÙØ² اÙÙ ÙØ§Ø±Ø¯','ØÙÙÙÙØ§'], 53 news:[['٠رسÙÙ Ø¨ÙØ§ÙÙÙ Ø§ØªØØ§Ø¯Ù Ø¬Ø¯ÙØ¯ بتعدÙÙ ÙØ§ÙÙÙ Ø§ÙØ´Ø±Ùات Ø§ÙØªØ¬Ø§Ø±ÙØ©','Ø§ÙØ¥Ù ارات · ÙØ§ÙÙÙ Ø§ÙØ´Ø±Ùات · ٠ارس 2026','Ø¥Ø¯Ø®Ø§Ù Ù ØªØ·ÙØ¨Ø§Øª Ù Ø¹Ø²ÙØ²Ø© ÙÙØÙÙÙ Ø© اÙÙ Ø¤Ø³Ø³ÙØ© عÙÙ ÙØ§ÙÙÙ Ø§ÙØ´Ø±Ùات Ø§ÙØªØ¬Ø§Ø±ÙØ©.'], 54 ['ØÙ٠٠٠اÙÙ ØÙÙ Ø© Ø§ÙØ¹ÙÙØ§ Ø¨Ø´Ø£Ù ÙØ¨ÙÙ Ø§ÙØ£Ø¯ÙØ© Ø§ÙØ±ÙÙ ÙØ©','Ø§ÙØ¥Ù ارات · اÙÙØ§ÙÙ٠اÙ٠دÙ٠· ٠ارس 2026','إرساء ٠عاÙÙØ± Ø¬Ø¯ÙØ¯Ø© ÙÙØ¨ÙÙ Ø§ÙØ£Ø¯ÙØ© Ø§ÙØ±ÙÙ ÙØ© ÙÙ Ø§ÙØ¯Ø¹Ø§Ù٠اÙ٠دÙÙØ©.'], 55 ['ØªØØ¯Ùثات Ø§ØªÙØ§ÙÙØ© Ø§ÙØªØ¬Ø§Ø±Ø© Ø§ÙØ®ÙÙØ¬ÙØ©Ø Ø£ØÙØ§Ù Ø¬Ø¯ÙØ¯Ø©','دÙÙ Ø§ÙØ®ÙÙØ¬ · Ø§ÙØªØ¬Ø§Ø±Ø© Ø§ÙØ¯ÙÙÙØ© · ٠ارس 2026','Ù ØµØ§Ø¯ÙØ© Ø§ÙØ¯ÙÙ Ø§ÙØ£Ø¹Ø¶Ø§Ø¡ عÙ٠تعدÙÙØ§Øª ت٠س اÙÙÙØ§Ø¹Ø¯ Ø§ÙØ¹Ø§Ø¨Ø±Ø© ÙÙØØ¯ÙØ¯.'], 56 ['تعدÙÙØ§Øª عÙÙ ÙØ§ÙÙÙ Ø§ÙØ¹Ù Ù: Ø£ØÙØ§Ù Ø§ÙØ¹Ù Ù Ø¹Ù Ø¨ÙØ¹Ø¯','Ø§ÙØ¥Ù ارات · ÙØ§ÙÙÙ Ø§ÙØ¹Ù ٠· ÙØ¨Ø±Ø§Ùر 2026','Ø£ØÙØ§Ù Ù ØØ¯Ùثة ØªØºØ·Ù Ø§ÙØ¹Ù Ù Ø¹Ù Ø¨ÙØ¹Ø¯ ÙØ§Ùع٠٠اÙÙ Ø®ØªÙØ·.']]} 57 }; 58 59 var SIDE={en:{home:'Home',search:'Search',ai:'AI Assistants',drafting:'Drafting',documents:'Documents',library:'Library'}, 60 ar:{home:'Ø§ÙØ±Ø¦ÙØ³ÙØ©',search:'Ø¨ØØ«',ai:'اÙ٠ساعدÙÙ Ø§ÙØ£Ø°ÙÙØ§Ø¡',drafting:'Ø§ÙØµÙاغة',documents:'اÙÙ Ø³ØªÙØ¯Ø§Øª',library:'اÙÙ ÙØªØ¨Ø©'}}; 61 62 /* assistant verticals as they appear in the mockup sidebar */ 63 var ASST = [ 64 { key: 'research', ic: I.chat, tab: { en: 'Research', ar: 'Ø§ÙØ¨ØØ«' } }, 65 { key: 'litigation', ic: I.gavel, tab: { en: 'Litigation', ar: 'Ø§ÙØªÙاضÙ' } }, 66 { key: 'contracts', ic: I.doc, tab: { en: 'Contracts', ar: 'Ø§ÙØ¹ÙÙØ¯' } }, 67 { key: 'legislative', ic: I.bank, tab: { en: 'Legislative', ar: 'Ø§ÙØªØ´Ø±Ùع' } } 68 ]; 69 70 /* ------------------------------------------------------------- hero starfield */ 71 function seedStars(box, n, shoots, bright) { 72 var f = ''; 73 for (var i = 0; i < n; i++) { 74 var s = bright ? (Math.random() * 2.4 + 1.2).toFixed(2) : (Math.random() * 1.7 + 0.5).toFixed(2); 75 var x = (Math.random() * 100).toFixed(2), y = (Math.random() * 88).toFixed(2); 76 var dur = bright ? (Math.random() * 2.4 + 1.8).toFixed(2) : (Math.random() * 4 + 3).toFixed(2); 77 var del = (Math.random() * 5).toFixed(2); 78 var op = bright ? (Math.random() * .35 + .55).toFixed(2) : (Math.random() * .5 + .2).toFixed(2); 79 f += '<span class="star' + (bright ? ' bright' : '') + '" style="width:' + s + 'px;height:' + s + 'px;left:' + x + '%;top:' + y + '%;opacity:' + op + ';animation:' + (bright ? 'twb' : 'tw') + ' ' + dur + 's ease-in-out ' + del + 's infinite"></span>'; 80 } 81 for (var j = 0; j < shoots; j++) { 82 var st = (Math.random() * 30 + 3).toFixed(1), sl = (Math.random() * 76 + 3).toFixed(1); 83 var w = Math.round(54 + Math.random() * 30); 84 var sd = (18 + Math.random() * 12).toFixed(1), sdel = (Math.random() * 24).toFixed(1);
85 f += '<span class="shoot" style="top:' + st + '%;left:' + sl + '%;width:' + w + 'px;animation:shoot ' + sd + 's linear ' + sdel + 's infinite"></span>'; 86 } 87 box.innerHTML = f; 88 } 89 90 function initStars() { 91 var box = document.getElementById('stars'); 92 if (box) seedStars(box, window.innerWidth < 640 ? 30 : 52, 0); 93 ['assistants', 'cta'].forEach(function (id) { 94 var sec = document.getElementById(id); 95 if (!sec) return; 96 var b = document.createElement('div'); 97 b.className = 'stars'; 98 sec.insertBefore(b, sec.firstChild); 99 var isAsst = id === 'assistants', isCta = id === 'cta'; 100 seedStars(b, window.innerWidth < 640 ? (isAsst ? 12 : (isCta ? 20 : 16)) : (isAsst ? 18 : (isCta ? 30 : 26)), 1, isAsst || isCta); 101 }); 102 document.querySelectorAll('.page-head').forEach(function (sec) { 103 var b = document.createElement('div'); 104 b.className = 'stars'; 105 sec.insertBefore(b, sec.firstChild); 106 seedStars(b, window.innerWidth < 640 ? 9 : 14, 0, false); 107 }); 108 } 109 110 /* --------------------------------------------------------- reveal on scroll */ 111 var revIO = new IntersectionObserver(function (es) { 112 es.forEach(function (e) { if (e.isIntersecting) { e.target.classList.add('in'); revIO.unobserve(e.target); } }); 113 }, { threshold: .12 }); 114 var truleIO = new IntersectionObserver(function (es) { 115 es.forEach(function (e) { e.target.classList.toggle('in', e.isIntersecting); }); 116 }, { threshold: .2 }); 117 118 function armReveals() { $('.reveal').not('.in').each(function () { revIO.observe(this); }); } 119 function armTrules() { $('.trule').each(function () { truleIO.observe(this); }); } 120 /* failsafe: never leave an in-viewport reveal stuck hidden */ 121 function revealVisible() { 122 $('.reveal').not('.in').each(function () { 123 var r = this.getBoundingClientRect(); 124 if (r.top < innerHeight * 0.95 && r.bottom > 0) { this.classList.add('in'); revIO.unobserve(this); } 125 }); 126 } 127 128 /* ------------------------------------------------------------ number count-up */ 129 function initCounters() { 130 var tgt = document.querySelector('.cband'); 131 if (!tgt) return; 132 var fired = false; 133 function ease(t) { return 1 - Math.pow(1 - t, 3); } 134 function run() { 135 if (fired) return; 136 fired = true; 137 $('.cband .cnum').each(function () { 138 var el = this, 139 end = parseFloat(el.dataset.count), 140 dec = parseInt(el.dataset.dec || '0', 10), 141 suf = el.dataset.suffix || ''; 142 if (reduce) { el.textContent = end.toFixed(dec) + suf; return; } 143 var t0 = null, dur = 1500; 144 function step(ts) { 145 if (t0 === null) t0 = ts; 146 var p = Math.min((ts - t0) / dur, 1); 147 el.textContent = (end * ease(p)).toFixed(dec) + suf; 148 if (p < 1) requestAnimationFrame(step); else el.textContent = end.toFixed(dec) + suf; 149 } 150 requestAnimationFrame(step); 151 }); 152 } 153 if ('IntersectionObserver' in window) { 154 var io = new IntersectionObserver(function (es) { 155 es.forEach(function (e) { if (e.isIntersecting) { run(); io.disconnect(); } }); 156 }, { threshold: .35 }); 157 io.observe(tgt); 158 } else { run(); } 159 } 160 161 /* ------------------------------------------------------- rotating hero line */ 162 var PHRASES={en:['Purpose build for Arabic legal systems and critical practice areas','and grounded in verified legal content and research'], 163 ar:['٠ص٠ÙÙ Ø®ØµÙØµØ§Ù ÙÙØ£Ùظ٠ة اÙÙØ§ÙÙÙÙØ© Ø§ÙØ¹Ø±Ø¨ÙØ© ÙØ£ÙÙ Ù Ø¬Ø§ÙØ§Øª اÙ٠٠ارسة','ÙØ¨Ø§ÙØ§Ø³ØªÙØ§Ø¯ Ø¥ÙÙ Ù ØØªÙÙ ÙØ¨ØØ« ÙØ§ÙÙÙÙ Ù ÙØ«ÙÙ']}; 164 function startTyper() { 165 var rot = document.getElementById('rot'); 166 if (!rot) return; 167 var phrases = PHRASES[LANG], idx = 0, timer = 0; 168 rot.style.transition = 'opacity .5s'; 169 rot.style.opacity = 1; 170 rot.textContent = phrases[0]; 171 (function fade() { 172 timer = setTimeout(function () { 173 rot.style.opacity = 0; 174 timer = setTimeout(function () { 175 idx = (idx + 1) % phrases.length; 176 rot.textContent = phrases[idx]; 177 rot.style.opacity = 1; 178 fade(); 179 }, 500); 180 }, 2600); 181 })(); 182 } 183 184 /* ------------------------------------------------------------ client marquee */ 185 var firmsEN=[['<span class="cwm"><b>Clifford Chance</b></span>','<span class="cwm"><b>Linklaters</b></span>','<span class="cwm"><b>White & Case</b></span>','<span class="cwm"><b>A&O Shearman</b></span>','<span class="cwm"><b>Freshfields</b></span>','<span class="cwm"><b>Gibson Dunn</b></span>','<span class="cwm"><b>Kirkland & Ellis</b></span>','<span class="cwm"><b>Pinsent Masons</b></span>','<span class="cwm"><b>Eversheds Sutherland</b></span>','<span class="cwm"><b>Al Tamimi & Company</b></span>','<span class="cwm"><b>Hadef & Partners</b></span>','<span class="cwm"><b>Suhail Partners</b></span>','<span class="cwm"><b>Khalifeh & Partners</b></span>','<span class="cwm"><b>Obeidat, Tarawneh & Kurd</b></span>'],['<span class="cwm"><b>UAE Supreme Legislation Committee</b></span>','<span class="cwm"><b>UAE Ministry of Foreign Affairs</b></span>','<span class="cwm"><b>Central Bank of Jordan</b></span>','<span class="cwm"><b>Mubadala</b></span>','<span class="cwm"><b>Abu Dhabi Commercial Bank</b></span>','<span class="cwm"><b>Etihad Rail</b></span>','<span class="cwm"><b>Abu Dhabi Department of Finance</b></span>','<span class="cwm"><b>Executive Affairs Authority</b></span>','<span class="cwm"><b>Abu Dhabi Department of Health</b></span>','<span class="cwm"><b>UNHCR</b></span>','<span class="cwm"><b>EY</b></span>','<span class="cwm"><b>UAE University</b></span>']]; 186 var firmsAR=[['<span class="cwm" dir="ltr"><b>Clifford Chance</b></span>','<span class="cwm" dir="ltr"><b>Linklaters</b></span>','<span class="cwm" dir="ltr"><b>White & Case</b></span>','<span class="cwm" dir="ltr"><b>A&O Shearman</b></span>','<span class="cwm" dir="ltr"><b>Freshfields</b></span>','<span class="cwm" dir="ltr"><b>Gibson Dunn</b></span>','<span class="cwm" dir="ltr"><b>Kirkland & Ellis</b></span>','<span class="cwm" dir="ltr"><b>Pinsent Masons</b></span>','<span class="cwm" dir="ltr"><b>Eversheds Sutherland</b></span>','<span class="cwm"><b>Ø§ÙØªÙ ÙÙ Ù Ù٠شارÙÙÙ</b></span>','<span class="cwm"><b>ÙØ§Ø¯Ù ÙØ´Ø±ÙاÙ</b></span>','<span class="cwm"><b>Ø´Ø±ÙØ§Ø¡ سÙÙÙ</b></span>','<span class="cwm"><b>Ø®ÙÙÙØ© Ù٠شارÙÙÙ</b></span>','<span class="cwm"><b>
186Ø¹Ø¨ÙØ¯Ø§Øª ÙØ§ÙطراÙÙØ© ÙØ§ÙÙØ±Ø¯</b></span>'],['<span class="cwm"><b>اÙÙØ¬ÙØ© Ø§ÙØ¹ÙÙØ§ ÙÙØªØ´Ø±Ùعات</b></span>','<span class="cwm"><b>ÙØ²Ø§Ø±Ø© Ø§ÙØ®Ø§Ø±Ø¬ÙØ© Ø§ÙØ¥Ù Ø§Ø±Ø§ØªÙØ©</b></span>','<span class="cwm"><b>Ø§ÙØ¨Ù٠اÙÙ Ø±ÙØ²Ù Ø§ÙØ£Ø±Ø¯ÙÙ</b></span>','<span class="cwm"><b>Ù Ø¨Ø§Ø¯ÙØ©</b></span>','<span class="cwm"><b>بÙÙ Ø£Ø¨ÙØ¸Ø¨Ù Ø§ÙØªØ¬Ø§Ø±Ù</b></span>','<span class="cwm"><b>ÙØ·Ø§Ø±Ø§Øª Ø§ÙØ§ØªØØ§Ø¯</b></span>','<span class="cwm"><b>دائرة اÙ٠اÙÙØ© â Ø£Ø¨ÙظبÙ</b></span>','<span class="cwm"><b>Ø¬ÙØ§Ø² Ø§ÙØ´Ø¤ÙÙ Ø§ÙØªÙÙÙØ°ÙØ©</b></span>','<span class="cwm"><b>دائرة Ø§ÙØµØØ© â Ø£Ø¨ÙظبÙ</b></span>','<span class="cwm"><b>اÙÙ ÙÙØ¶ÙØ© Ø§ÙØ³Ø§Ù ÙØ© ÙÙØ£Ù ٠اÙÙ ØªØØ¯Ø© ÙØ´Ø¤Ù٠اÙÙØ§Ø¬Ø¦ÙÙ</b></span>','<span class="cwm" dir="ltr"><b>EY</b></span>','<span class="cwm"><b>جا٠عة Ø§ÙØ¥Ù ارات</b></span>']]; 187 function fillFirms() { 188 var f = LANG === 'ar' ? firmsAR : firmsEN; 189 $('.ctrack').each(function () { var r = f[+$(this).data('row') || 0]; $(this).html(r.concat(r).join('')); }); 190 } 191 192 /* ------------------------------------------------- platform mockup (research) */ 193 function LOGO() { 194 var el = document.querySelector(LANG === 'ar' ? '.nav .l-light-ar' : '.nav .l-light'); 195 return el ? el.getAttribute('src') : ''; 196 } 197 function topIcons() { 198 return '<span class="app-top-ic">' + I.folder + '</span><span class="app-top-ic">' + I.clock + '</span><span class="app-top-ic bell"><span class="dot"></span>' + I.bell + '</span><span class="app-top-ic">' + I.mail + '</span><span class="app-top-ic">' + I.sun + '</span><span class="app-top-ic user">' + I.userTop + '</span>'; 199 } 200 function sideList(active, expanded) { 201 var s = SIDE[LANG]; 202 return '<div class="side-item' + (!expanded ? ' on' : '') + '">' + I.home + '<span>' + s.home + '</span></div>' + 203 '<div class="side-item">' + I.search + '<span>' + s.search + '</span></div>' + 204 '<div class="side-sec">' + s.ai + '</div>' + 205 ASST.map(function (a) { 206 return '<div class="side-item' + (expanded && a.key === active ? ' on' : '') + '" data-go="' + a.key + '">' + a.ic + '<span>' + a.tab[LANG] + '</span></div>'; 207 }).join(''); 208 } 209 function rhomeInner() { 210 var d = RH[LANG]; 211 var blocks = '<span class="rbtool">' + I.crosshair + '</span><span class="rbar-div"></span><span class="rbtool-group"><span class="rbtool on">' + I.key + '</span><span class="rbtool">' + I.sparklePlus + '</span></span><span class="rbar-div"></span>'; 212 return '<div class="rhome-top"><div class="rgreet">' + d.hello + '</div><h4>' + d.h + '</h4>' + 213 '<div class="rbar"><span class="rbar-tools">' + blocks + '</span><span class="ph">' + d.ph + '</span><span style="flex:1"></span><span class="rbar-av">' + I.mic + '</span><span class="go"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg></span></div>' + 214 '<div class="rchips">' + d.chips.map(function (c, i) { return '<span' + (i === 0 ? ' class="on"' : '') + '>' + c + '</span>'; }).join('') + '</div></div>' + 215 '<div class="rlower"><div class="rtabs">' + d.tabs.map(function (t, i) { return '<a' + (i === 0 ? ' class="on"' : '') + '>' + t + '</a>'; }).join('') + '</div>' + 216 '<div class="rnews-head"><b>' + (LANG === 'ar' ? 'Ø£ØØ¯Ø« Ø§ÙØ£Ø®Ø¨Ø§Ø± اÙÙØ§ÙÙÙÙØ©' : 'Latest legal news') + '</b></div>' + 217 '<div class="rskel">' + [0, 1, 2, 3].map(function () { return '<div class="skcard"><span class="skb w1"></span><span class="skb w2"></span><span class="skb w3"></span></div>'; }).join('') + '</div></div>'; 218 } 219 function fillResearchMock() { 220 var $el = $('#mockResearch'); 221 if (!$el.length) return; 222 $el.html('<div class="app"><div class="app-top"><img class="brand" src="' + LOGO() + '" alt=""><span style="flex:1"></span><span class="jpill">' + I.globe + (LANG === 'ar' ? '9 دÙÙ Ø¹Ø±Ø¨ÙØ©' : '9 jurisdictions') + I.chevronDown + '</span><span class="tctl">' + LANG.toUpperCase() + I.chevronDown + '</span>' + topIcons() + '</div>' + 223 '<div class="app-flex"><aside class="app-side">' + sideList('research', false) + '</aside>' + 224 '<div style="flex:1;min-width:0">' + rhomeInner() + '</div></div></div>'); 225 } 226 227 /* ---------------------------------------------------- nav over the dark hero */ 228 function initNavDark() { 229 var nav = document.getElementById('nav'); 230 var hero = document.querySelector('.hero, .ab-hero'); 231 if (!nav) return; 232 if (!hero) { nav.classList.remove('on-dark'); return; }
233 function update() { 234 var r = hero.getBoundingClientRect(); 235 /* The transparent nav belongs to the resting hero only: as soon as the 236 visitor starts scrolling, the header takes its rgba(255,255,255,.9) 237 background (and with it the dark wordmark and link colours), even while 238 the dark hero is still passing underneath. */ 239 var atTop = (window.pageYOffset || document.documentElement.scrollTop || 0) <= 0; 240 nav.classList.toggle('on-dark', atTop && r.bottom > 70); 241 } 242 $(window).on('scroll', update); 243 update(); 244 } 245 246 /* ------------------------------------------------------------ sign-in menu */ 247 function initSignin() { 248 var $w = $('#signinWrap'), $b = $('#signinBtn'); 249 if (!$w.length) return; 250 $b.on('click', function (e) { 251 e.stopPropagation(); 252 var open = $w.toggleClass('open').hasClass('open'); 253 $b.attr('aria-expanded', open ? 'true' : 'false'); 254 }); 255 $(document).on('click', function (e) { 256 if (!$w[0].contains(e.target)) { $w.removeClass('open'); $b.attr('aria-expanded', 'false'); } 257 }); 258 $(document).on('keydown', function (e) { 259 if (e.key === 'Escape') { $w.removeClass('open'); $b.attr('aria-expanded', 'false'); } 260 }); 261 } 262 263 /* --------------------------------------------------------- mobile nav menu */ 264 function initHamburger() { 265 var $inner = $('#navInner'), $ham = $('#hamburgerBtn'); 266 if (!$inner.length || !$ham.length) return; 267 function close() { $inner.removeClass('menu-open'); $ham.attr('aria-expanded', 'false'); } 268 function open() { $inner.addClass('menu-open'); $ham.attr('aria-expanded', 'true'); } 269 $ham.on('click', function (e) { 270 e.stopPropagation(); 271 $inner.hasClass('menu-open') ? close() : open(); 272 }); 273 $inner.find('.nav-links a').on('click', close); 274 $(document).on('click', function (e) { if (!$inner[0].contains(e.target)) close(); }); 275 $(document).on('keydown', function (e) { if (e.key === 'Escape') close(); }); 276 $(window).on('resize', function () { if (window.innerWidth > 900) close(); }); 277 } 278 279 /* -------------------------------------------------------------- video modal */ 280 function initVideoModal() { 281 var $modal = $('#videoModal'), $open = $('#watchVideoBtn'); 282 if (!$modal.length || !$open.length) return; 283 function close() { $modal.removeClass('open'); } 284 $('#videoModalClose, #videoModalBackdrop, #videoModalCta').on('click', close); 285 $(document).on('keydown', function (e) { if (e.key === 'Escape') close(); }); 286 } 287 288 /* ------------------------------------------------ smooth in-page scrolling */ 289 /* jQuery's animated scrollTop fights the global `html{scroll-behavior:smooth}` 290 from the design drop â each frame re-queues a smooth scroll and the page 291 never moves. Use the native scroller, which also honours scroll-margin-top 292 on targets that sit under the sticky nav (e.g. #ctaForm). */ 293 function scrollToEl(el) { 294 if (!el) return; 295 el.scrollIntoView({ behavior: reduce ? 'auto' : 'smooth', block: 'start' }); 296 } 297 function initAnchors() { 298 $(document).on('click', 'a[href^="#"]', function (e) { 299 var id = $(this).attr('href').slice(1); 300 if (!id) return; 301 var el = document.getElementById(id); 302 if (!el) return; 303 e.preventDefault(); 304 scrollToEl(el); 305 }); 306 /* hero suite cards jump to the assistants section */ 307 $('.hcard[data-assistant]').on('click', function (e) { 308 e.preventDefault(); 309 scrollToEl(document.getElementById('assistants')); 310 }); 311 } 312 313 /* --------------------------------------------- about page: canvas starfield */ 314 function initAboutStarfield() { 315 var cv = document.getElementById('starfield'); 316 if (!cv) return; 317 var ctx = cv.getContext('2d'), stars = [], w, h; 318 function build() { 319 stars = []; 320 var n = Math.min(120, Math.floor(w * h / 22000)); 321 for (var i = 0; i < n; i++) stars.push({ 322 x: Math.random() * w, y: Math.random() * h, 323 r: (Math.random() * 1.1 + 0.25) * devicePixelRatio, 324 a: Math.random() * 6.28, tw: Math.random() * 0.012 + 0.003, 325 vy: (Math.random() * 0.03 + 0.01) * devicePixelRatio 326 }); 327 } 328 function size() { w = cv.width = cv.offsetWidth * devicePixelRatio; h = cv.height = cv.offsetHeight * devicePixelRatio; build(); } 329 function draw() { 330 ctx.clearRect(0, 0, w, h); 331 for (var i = 0; i < stars.length; i++) { 332 var s = stars[i]; 333 s.a += s.tw; 334 var al = 0.22 + Math.abs(Math.sin(s.a)) * 0.4; 335 if (!reduce) { s.y += s.vy; if (s.y > h) { s.y = 0; s.x = Math.random() * w; } } 336 ctx.beginPath(); 337 ctx.fillStyle = 'rgba(180,214,255,' + al + ')'; 338 ctx.arc(s.x, s.y, s.r, 0, 6.28); 339 ctx.fill(); 340 } 341 requestAnimationFrame(draw); 342 } 343 size(); 344 $(window).on('resize', size); 345 draw(); 346 } 347 348 /* ---------------------------------------------------------------- forms 349 Both forms post normally to the server endpoint in their action attribute 350 (wire this to your PHP/back-end handler). jQuery only guards double submits. */ 351 function initForms() { 352 $('form.qform').not('.crmWebToEntityForm').on('submit', function () { 353 var $b = $(this).find('button[type=submit]'); 354 $b.prop('disabled', true).text(LANG === 'ar' ? 'Ø¬Ø§Ø±Ù Ø§ÙØ¥Ø±Ø³Ø§Ùâ¦' : 'Sendingâ¦'); 355 }); 356 } 357 358 359 /* -------------------------------------------------------------- page loader 360 Fades the white loading screen out once the page is ready; the timeout is a 361 failsafe so a slow font or image can never leave it on screen. */ 362 function initLoader() { 363 var $l = $('#pageLoader'); 364 if (!$l.length) return; 365 var done = false;
366 function hide() { 367 if (done) return; 368 done = true; 369 $l.addClass('is-done'); 370 setTimeout(function () { $l.remove(); }, 450); 371 } 372 $(window).on('load', function () { setTimeout(hide, 150); }); 373 setTimeout(hide, 4000); 374 if (document.readyState === 'complete') setTimeout(hide, 150); 375 } 376 377 /* --------------------------------------------------------- enquiry routing 378 The contact form serves three arrivals. A partner or enterprise enquiry 379 cannot be assessed without the organisation details, so on those the form 380 says what it is for, shows the message field, and requires organisation, 381 size and country. Everything else keeps the short form. */ 382 function initEnquiry() { 383 var $form = $('#webform5021687000073835197'); 384 if (!$form.length) return; 385 var kind = new URLSearchParams(location.search).get('enquiry'); 386 if (kind !== 'partner' && kind !== 'enterprise') return; 387 var ar = LANG === 'ar'; 388 var T = { 389 partner: { 390 note: ar ? 'Ø·ÙØ¨ Ø´Ø±Ø§ÙØ© â ÙØ±Ø¬Ù تعبئة Ø¨ÙØ§Ùات اÙ٠ؤسسة ÙØ§ÙسÙÙ Ø§ÙØ°Ù تغطÙÙ.' 391 : 'Partnership enquiry â please complete your organisation details and the market you cover.', 392 msg: ar ? 'ÙØ´Ø§Ø·ÙÙ Ø§ÙØØ§ÙÙ ÙØ®Ø·ØªÙÙ ÙÙØªÙ Ø«ÙÙ *' : 'Your current activity and how you would represent Qistas *', 393 country: ar ? 'Ø§ÙØ¯ÙÙØ© / Ø§ÙØ³ÙÙ *' : 'Country / market *' 394 }, 395 enterprise: { 396 note: ar ? 'Ø§Ø³ØªÙØ³Ø§Ø± Ù Ø¤Ø³Ø³Ù â Ø£Ø®Ø¨Ø±Ùا ع٠٠ؤسستÙÙ ÙØØ¬Ù ÙØ§ ÙØ§ØØªÙاجÙÙ Ø ÙØ³ÙØªÙØ§ØµÙ ٠عÙÙ ÙØ±Ù٠اÙ٠ؤسسات.' 397 : 'Enterprise enquiry â tell us about your organisation, its size and what you need, and our enterprise team will get in touch.', 398 msg: ar ? 'Ø§ØØªÙاجÙÙ : Ø§ÙØªØ´ØºÙÙØ ÙØ§ÙØªÙØ§Ù ÙØ ÙØ¹Ø¯Ø¯ اÙ٠ستخد٠ÙÙØ ÙØ§ÙجدÙÙ Ø§ÙØ²Ù ÙÙ *' 399 : 'What you need: deployment, integrations, number of users, timeline *', 400 country: ar ? 'Ø§ÙØ¯ÙÙØ© *' : 'Country *' 401 } 402 }[kind]; 403 var COMPANY = ar ? 'اس٠اÙ٠ؤسسة *' : 'Organisation name *'; 404 var REQ = ar ? 'ÙØ±Ø¬Ù تعبئة Ø¨ÙØ§Ùات اÙ٠ؤسسة: Ø§ÙØ§Ø³Ù Ø ÙØ§ÙÙÙØ¹Ø ÙØ§ÙØØ¬Ù Ø ÙØ§ÙدÙÙØ©Ø ÙÙØµÙ Ø§ØØªÙاجÙÙ .' 405 : 'Please complete your organisation details: name, type, size, country, and a description of what you need.'; 406 407 $form.addClass('is-detailed').prepend('<p class="qf-note">' + T.note + '</p>'); 408 $('#Company').attr({ placeholder: COMPANY, 'aria-required': 'true' }); 409 $('#Country').attr({ placeholder: T.country, 'aria-required': 'true' }); 410 $('#LEADCF1').attr({ placeholder: T.msg, 'aria-required': 'true', rows: 6 }); 411 $('#LEADCF16, #LEADCF17').attr('aria-required', 'true'); 412 if (kind === 'enterprise') $('#LEADCF18').val('Full Qistas Suite'); 413 414 $form.on('submit', function (e) { 415 var missing = !$('#Company').val().trim() || !$('#Country').val().trim() || !$('#LEADCF1').val().trim() || 416 $('#LEADCF16').val() === '-None-' || $('#LEADCF17').val() === '-None-'; 417 if (missing) { e.preventDefault(); e.stopImmediatePropagation(); alert(REQ); return false; } 418 }); 419 } 420 421 /* ----------------------------------------------------------- policy dialog 422 "Read the privacy policy" opens the document over the page instead of 423 navigating away, so the visitor does not lose their place in the section. 424 The policy page itself is fetched once and cached; if the fetch cannot run 425 (opened from the filesystem, for instance) the link behaves normally. */ 426 function initPolicyModal() { 427 /* Laravel serves the page at /{locale}/privacy-policy â no .html suffix â 428 so the policy URL is read off the link itself rather than assumed. */ 429 var $links = $('.dep-note a[href$="privacy-policy.html"], .dep-note a[href$="/privacy-policy"]'); 430 if (!$links.length || !window.fetch) return; 431 var policyUrl = $links.first().attr('href'); 432 var ar = LANG === 'ar'; 433 var $m = $( 434 '<div class="doc-modal" id="policyModal" role="dialog" aria-modal="true" aria-label="' + 435 (ar ? 'Ø³ÙØ§Ø³Ø© Ø§ÙØ®ØµÙØµÙØ©' : 'Privacy Policy') + '">' + 436 '<div class="doc-modal-back"></div>' + 437 '<div class="doc-modal-panel">' + 438 '<div class="doc-modal-head">' + 439 '<b>' + (ar ? 'Ø³ÙØ§Ø³Ø© Ø§ÙØ®ØµÙØµÙØ©' : 'Privacy Policy') + '</b>' + 440 '<a class="doc-modal-full" href="' + policyUrl + '">' + (ar ? 'ÙØªØ Ø§ÙØµÙØØ©' : 'Open the page') + '</a>' + 441 '<button type="button" class="doc-modal-x" aria-label="' + (ar ? 'Ø¥ØºÙØ§Ù' : 'Close') + '">' + 442 '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M6 6l12 12M18 6 6 18"></path></svg>
442' + 443 '</button>' + 444 '</div>' + 445 '<div class="doc-modal-body legal"><p class="doc-modal-load">' + (ar ? 'Ø¬Ø§Ø±Ù Ø§ÙØªØÙ ÙÙâ¦' : 'Loadingâ¦') + '</p></div>' + 446 '</div>' + 447 '</div>'); 448 $('body').append($m); 449 450 var loaded = false, lastFocus = null; 451 function close() { 452 $m.removeClass('on'); 453 $('html').css('overflow', ''); 454 if (lastFocus) lastFocus.focus(); 455 } 456 function load() { 457 if (loaded) return; 458 loaded = true; 459 fetch(policyUrl) 460 .then(function (r) { return r.text(); }) 461 .then(function (html) { 462 var doc = new DOMParser().parseFromString(html, 'text/html'); 463 var body = doc.querySelector('main.legal .wrap'); 464 if (!body) throw new Error('policy body not found'); 465 $m.find('.doc-modal-body').html(body.innerHTML); 466 }) 467 .catch(function () { loaded = false; location.href = policyUrl; }); 468 } 469 470 $links.on('click', function (e) { 471 e.preventDefault(); 472 lastFocus = this; 473 load(); 474 $m.addClass('on'); 475 $('html').css('overflow', 'hidden'); 476 $m.find('.doc-modal-x').trigger('focus'); 477 }); 478 $m.on('click', '.doc-modal-back, .doc-modal-x', close); 479 $(document).on('keydown', function (e) { if (e.key === 'Escape') close(); }); 480 } 481 482 /* ------------------------------------------------------------- form dialog 483 Any link marked data-form-modal opens the contact form over the page rather 484 than navigating to it. The form is fetched from contact.html once, so there 485 is a single copy of it to maintain; if the fetch cannot run the link works 486 as an ordinary link. */ 487 function initFormModal() { 488 var $links = $('a[data-form-modal]'); 489 if (!$links.length || !window.fetch) return; 490 var ar = LANG === 'ar'; 491 var $m = $( 492 '<div class="doc-modal form-modal" id="formModal" role="dialog" aria-modal="true" aria-label="' + 493 (ar ? 'ØªÙØ§ØµÙ Ù Ø¹ÙØ§' : 'Contact us') + '">' + 494 '<div class="doc-modal-back"></div>' + 495 '<div class="doc-modal-panel">' + 496 '<div class="doc-modal-head">' + 497 '<b>' + (ar ? 'ØªÙØ§ØµÙ Ù Ø¹ÙØ§' : 'Contact us') + '</b>' + 498 '<button type="button" class="doc-modal-x" aria-label="' + (ar ? 'Ø¥ØºÙØ§Ù' : 'Close') + '">' + 499 '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M6 6l12 12M18 6 6 18"></path></svg>' + 500 '</button>' + 501 '</div>' + 502 '<div class="doc-modal-body"><p class="doc-modal-load">' + (ar ? 'Ø¬Ø§Ø±Ù Ø§ÙØªØÙ ÙÙâ¦' : 'Loadingâ¦') + '</p></div>' + 503 '</div>' + 504 '</div>'); 505 $('body').append($m); 506 507 var loaded = false, lastFocus = null; 508 function close() { 509 $m.removeClass('on'); 510 $('html').css('overflow', ''); 511 if (lastFocus) lastFocus.focus(); 512 } 513 function load(href) { 514 if (loaded) return; 515 loaded = true; 516 fetch(href.split('#')[0]) 517 .then(function (r) { return r.text(); }) 518 .then(function (html) { 519 var doc = new DOMParser().parseFromString(html, 'text/html'); 520 var form = doc.querySelector('form.qform.crmWebToEntityForm'); 521 if (!form) throw new Error('form not found'); 522 $m.find('.doc-modal-body').empty().append(form); 523 }) 524 .catch(function () { loaded = false; location.href = href; }); 525 } 526 527 $links.on('click', function (e) { 528 e.preventDefault(); 529 lastFocus = this; 530 load($(this).attr('href')); 531 $m.addClass('on'); 532 $('html').css('overflow', 'hidden'); 533 $m.find('.doc-modal-x').trigger('focus'); 534 }); 535 $m.on('click', '.doc-modal-back, .doc-modal-x', close); 536 $(document).on('keydown', function (e) { if (e.key === 'Escape') close(); }); 537 } 538 539 $(function () { 540 initLoader(); 541 initFormModal(); 542 initPolicyModal(); 543 initEnquiry(); 544 initStars(); 545 armReveals(); 546 armTrules(); 547 revealVisible(); 548 $(window).on('scroll', revealVisible); 549 $(window).on('load', revealVisible); 550 setTimeout(revealVisible, 600);
551 initCounters(); 552 startTyper(); 553 fillFirms(); 554 fillResearchMock(); 555 initNavDark(); 556 initSignin(); 557 initHamburger(); 558 initVideoModal(); 559 initAnchors(); 560 initAboutStarfield(); 561 initForms(); 562 }); 563})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.