/* ExpertAims — "The Meridian" shared behaviours */
(function(){
'use strict';

/* theme: stored choice wins; else follow OS live */
var root=document.documentElement;
function applyTheme(t){
  if(t){root.setAttribute('data-theme',t);}else{root.removeAttribute('data-theme');}
  var dark = t==='dark' || (!t && window.matchMedia('(prefers-color-scheme: dark)').matches);
  var meta=document.querySelector('meta[name="theme-color"]');
  if(meta) meta.setAttribute('content', dark ? '#141011' : '#F6F4F2');
}
try{applyTheme(localStorage.getItem('ea-theme')||null);}catch(e){applyTheme(null);}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change',function(){
  var s=null;try{s=localStorage.getItem('ea-theme');}catch(e){}
  if(!s)applyTheme(null);
});
document.addEventListener('click',function(e){
  var b=e.target.closest('.thm');if(!b)return;
  /* read the stored choice first — data-theme lags behind during the
     view-transition's async apply, stored value never does */
  var cur=null;try{cur=localStorage.getItem('ea-theme');}catch(e0){}
  cur=cur||root.getAttribute('data-theme');
  var dark = cur==='dark' || (!cur && window.matchMedia('(prefers-color-scheme: dark)').matches);
  var next = dark?'light':'dark';
  try{localStorage.setItem('ea-theme',next);}catch(e2){}
  /* v8.1: the new theme floods outward from the toggle itself */
  if(document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches){
    var r=b.getBoundingClientRect();
    root.style.setProperty('--vtx',(r.left+r.width/2)+'px');
    root.style.setProperty('--vty',(r.top+r.height/2)+'px');
    root.classList.add('theming');
    var vt=document.startViewTransition(function(){applyTheme(next);});
    vt.finished.finally(function(){root.classList.remove('theming');});
  }else{
    applyTheme(next);
  }
});

/* year */
document.querySelectorAll('.yr').forEach(function(y){y.textContent=new Date().getFullYear();});

/* mega menus: hover only on true hover devices (touch fires mouseenter then
   click, which would open-and-instantly-close the panel); click always toggles */
var canHover=window.matchMedia('(hover: hover) and (pointer: fine)').matches;
document.querySelectorAll('.hd-item').forEach(function(it){
  var btn=it.querySelector('button.hd-lnk');if(!btn)return;
  if(canHover){
    it.addEventListener('mouseenter',function(){it.classList.add('open');btn.setAttribute('aria-expanded','true');});
    it.addEventListener('mouseleave',function(){it.classList.remove('open');btn.setAttribute('aria-expanded','false');});
  }
  btn.addEventListener('click',function(){
    var open=it.classList.toggle('open');
    btn.setAttribute('aria-expanded',open?'true':'false');
    document.querySelectorAll('.hd-item').forEach(function(o){if(o!==it){o.classList.remove('open');var b=o.querySelector('button.hd-lnk');if(b)b.setAttribute('aria-expanded','false');}});
  });
});
document.addEventListener('keydown',function(e){if(e.key==='Escape'){document.querySelectorAll('.hd-item.open').forEach(function(o){o.classList.remove('open');});setSheet(false);}});
document.addEventListener('click',function(e){
  if(!e.target.closest('.hd-item')){document.querySelectorAll('.hd-item.open').forEach(function(o){o.classList.remove('open');});}
});

/* mobile sheet */
var mbt=document.getElementById('mbt'),msh=document.getElementById('msh');
function setSheet(o){
  if(!mbt||!msh)return;
  mbt.classList.toggle('open',o);msh.classList.toggle('open',o);
  mbt.setAttribute('aria-expanded',o?'true':'false');
  document.body.style.overflow=o?'hidden':'';
}
if(mbt){mbt.addEventListener('click',function(){setSheet(!msh.classList.contains('open'));});}
if(msh){msh.addEventListener('click',function(e){if(e.target.closest('a'))setSheet(false);});}
window.addEventListener('resize',function(){if(window.innerWidth>1020)setSheet(false);});

/* reveal on scroll */
var rvs=document.querySelectorAll('.rv');
if('IntersectionObserver' in window){
  var rio=new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting){e.target.classList.add('in');rio.unobserve(e.target);}});},{threshold:.1});
  rvs.forEach(function(e){rio.observe(e);});
}else{rvs.forEach(function(e){e.classList.add('in');});}

/* signal compass: scroll-progress ring + station announcer */
(function(){
  var R=15,C=2*Math.PI*R;
  var cmp=document.createElement('div');
  cmp.className='cmp';
  cmp.innerHTML='<span class="vh" aria-live="polite"></span><button type="button" class="cmp-btn" aria-label="Scroll progress — back to top">'+
    '<svg viewBox="0 0 46 46" aria-hidden="true">'+
    '<circle class="tr" cx="23" cy="23" r="'+R+'" fill="none" stroke-width="2.5"/>'+
    '<circle class="pr" cx="23" cy="23" r="'+R+'" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-dasharray="'+C+'" stroke-dashoffset="'+C+'" transform="rotate(-90 23 23)"/>'+
    '<circle class="ad" cx="23" cy="23" r="4.5"/></svg></button>'+
    '<span class="cmp-lb" aria-hidden="true"></span>';
  document.body.appendChild(cmp);
  var pr=cmp.querySelector('.pr'),lb=cmp.querySelector('.cmp-lb'),vh=cmp.querySelector('.vh');
  var reduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  var stns=[].map.call(document.querySelectorAll('.stn-anchor'),function(a){
    var l=a.querySelector('.stn');
    return{el:a,txt:l?l.textContent.replace(/\s+/g,' ').trim():''};
  }).filter(function(s){return s.txt;});
  var cur=-1,sayT=null,tick=false;
  function upd(){
    tick=false;
    var h=document.documentElement.scrollHeight-window.innerHeight;
    var p=h>0?Math.min(window.scrollY/h,1):0;
    pr.style.strokeDashoffset=String(C*(1-p));
    cmp.classList.toggle('on',window.scrollY>140);
    var k=-1;
    for(var i=0;i<stns.length;i++){if(stns[i].el.getBoundingClientRect().top<window.innerHeight*.45)k=i;}
    if(k!==cur){
      cur=k;
      var t=k>=0?stns[k].txt:(document.title.split('—')[1]||'Top of the line').trim();
      lb.innerHTML='';
      t.split('·').forEach(function(part,n){
        if(n){var i2=document.createElement('i');i2.textContent=' · ';lb.appendChild(i2);}
        lb.appendChild(document.createTextNode(part.trim()));
      });
      if(vh&&cmp.contains(document.activeElement))vh.textContent=t;
      if(!reduce){
        cmp.classList.add('say');
        if(sayT)clearTimeout(sayT);
        sayT=setTimeout(function(){cmp.classList.remove('say');},1800);
      }
    }
  }
  window.addEventListener('scroll',function(){if(!tick){tick=true;requestAnimationFrame(upd);}},{passive:true});
  window.addEventListener('resize',upd);
  upd();
  var ftEl=document.querySelector('.ft'),waEl=document.querySelector('.wa');
  if(ftEl&&'IntersectionObserver' in window){
    new IntersectionObserver(function(es){es.forEach(function(en){
      cmp.classList.toggle('off',en.isIntersecting);
      if(waEl)waEl.classList.toggle('off',en.isIntersecting);
    });},{threshold:.08}).observe(ftEl);
  }
  /* v7 · the line map: the compass opens the whole page as a route */
  var btn=cmp.querySelector('.cmp-btn'),lm=null;
  function buildMap(){
    lm=document.createElement('div');lm.className='lm';lm.setAttribute('popover','');
    lm.setAttribute('aria-label','Stations on this page');
    var tt=document.createElement('p');tt.className='lm-tt';tt.textContent='Route — this page';
    lm.appendChild(tt);
    var rows=[{txt:'Top of the line',el:null}].concat(stns.map(function(s){return{txt:s.txt,el:s.el};}));
    rows.forEach(function(r){
      var b=document.createElement('button');b.type='button';b.className='lm-it';
      var d=document.createElement('span');d.className='ld';d.setAttribute('aria-hidden','true');
      b.appendChild(d);b.appendChild(document.createTextNode(r.txt));
      b.addEventListener('click',function(){
        lm.hidePopover();
        if(r.el)r.el.scrollIntoView({behavior:reduce?'auto':'smooth',block:'start'});
        else window.scrollTo({top:0,behavior:reduce?'auto':'smooth'});
      });
      lm.appendChild(b);
    });
    document.body.appendChild(lm);
  }
  if('togglePopover' in HTMLElement.prototype&&stns.length){
    btn.setAttribute('aria-haspopup','true');
    btn.setAttribute('aria-label','Route map — jump to any station');
    btn.addEventListener('click',function(){
      if(!lm)buildMap();
      var rows=lm.querySelectorAll('.lm-it');
      [].forEach.call(rows,function(b,i){
        b.classList.toggle('here',cur<0?i===0:i===cur+1);
        b.classList.toggle('past',i>0&&i-1<cur);
      });
      lm.togglePopover();
    });
  }else{
    btn.addEventListener('click',function(){
      window.scrollTo({top:0,behavior:reduce?'auto':'smooth'});
    });
  }
})();

/* rotating word (hero) */
var rot=document.getElementById('rot');
if(rot && !window.matchMedia('(prefers-reduced-motion: reduce)').matches){
  var words=JSON.parse(rot.getAttribute('data-words')||'[]'),wi=0;
  if(words.length>1){
    setInterval(function(){
      wi=(wi+1)%words.length;
      rot.style.opacity='0';rot.style.transform='translateY(8px)';
      setTimeout(function(){rot.textContent=words[wi];rot.style.opacity='1';rot.style.transform='none';},260);
    },2600);
    rot.style.transition='opacity .26s ease, transform .26s ease';
    rot.style.display='inline-block';
  }
}

/* horizontal rails: drag + inertia + arrows + station-line progress (v7) */
document.querySelectorAll('.rail-wrap').forEach(function(w){
  var rail=w.querySelector('.rail');if(!rail)return;
  var bar=w.querySelector('.rail-bar i'),track=w.querySelector('.rail-bar');
  var railReduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  var cardCount=rail.children.length;
  if(track)track.style.setProperty('--n',cardCount);
  var thumbFrac=.2;
  function size(){
    thumbFrac=Math.max(rail.clientWidth/rail.scrollWidth,.08);
    if(bar)bar.style.setProperty('--tw',(thumbFrac*100)+'%');
    upd();
  }
  function upd(){
    var max=rail.scrollWidth-rail.clientWidth;
    var p=max>0?rail.scrollLeft/max:0;
    if(bar&&track)bar.style.transform='translateX('+(p*(track.clientWidth*(1-thumbFrac)))+'px)';
    w.classList.toggle('can-l',rail.scrollLeft>4);
    w.classList.toggle('can-r',rail.scrollLeft<max-4);
  }
  rail.addEventListener('scroll',function(){requestAnimationFrame(upd);},{passive:true});
  window.addEventListener('resize',size);size();
  var prev=w.querySelector('[data-rail="prev"]'),next=w.querySelector('[data-rail="next"]');
  var step=function(){var c=rail.querySelector(':scope>*');return c?c.getBoundingClientRect().width+18:320;};
  if(prev)prev.addEventListener('click',function(){rail.scrollBy({left:-step(),behavior:railReduce?'auto':'smooth'});});
  if(next)next.addEventListener('click',function(){rail.scrollBy({left:step(),behavior:railReduce?'auto':'smooth'});});
  /* keyboard: the rail itself is focusable and steerable */
  rail.tabIndex=0;
  rail.addEventListener('keydown',function(e){
    var b=railReduce?'auto':'smooth';
    if(e.key==='ArrowRight'){e.preventDefault();rail.scrollBy({left:step(),behavior:b});}
    else if(e.key==='ArrowLeft'){e.preventDefault();rail.scrollBy({left:-step(),behavior:b});}
    else if(e.key==='Home'){e.preventDefault();rail.scrollTo({left:0,behavior:b});}
    else if(e.key==='End'){e.preventDefault();rail.scrollTo({left:rail.scrollWidth,behavior:b});}
  });
  /* drag to scroll — click suppressed after real drags; mouse drags get
     inertia: velocity sampled over the last frames, decayed after release */
  var down=false,sx=0,sl=0,moved=0,samples=[],flying=null;
  function stopFling(){if(flying){cancelAnimationFrame(flying);flying=null;}}
  rail.addEventListener('pointerdown',function(e){
    stopFling();down=true;moved=0;sx=e.clientX;sl=rail.scrollLeft;samples=[];
    rail.classList.add('drag');
  });
  window.addEventListener('pointermove',function(e){
    if(!down)return;
    moved=Math.max(moved,Math.abs(e.clientX-sx));
    rail.scrollLeft=sl-(e.clientX-sx);
    samples.push({x:e.clientX,t:e.timeStamp});
    if(samples.length>6)samples.shift();
  });
  window.addEventListener('pointerup',function(e){
    if(!down)return;
    down=false;rail.classList.remove('drag');
    if(railReduce||e.pointerType!=='mouse'||samples.length<2)return;
    var a=samples[0],b2=samples[samples.length-1],dt=b2.t-a.t;
    if(dt<=0)return;
    var v=(b2.x-a.x)/dt*16.7; /* px per frame */
    if(Math.abs(v)<4)return;
    var last=performance.now();
    (function fling(now){
      var f=Math.min(((now||performance.now())-last)/16.7,2);last=now||performance.now();
      rail.scrollLeft-=v*f;v*=Math.pow(.94,f);
      if(Math.abs(v)>.4)flying=requestAnimationFrame(fling);
      else{flying=null;}
    })(last);
  });
  rail.addEventListener('click',function(e){if(moved>6){e.preventDefault();e.stopPropagation();}},true);
  /* v8.6 · velocity lean: cards take the pull of the scroll, spring back at rest */
  if(!railReduce){
    var lastSL=rail.scrollLeft,lv=0,leanAct=false;
    var leanFrame=function(){
      var d=rail.scrollLeft-lastSL;lastSL=rail.scrollLeft;
      var t=Math.max(-2.5,Math.min(2.5,d*.09));
      lv+=(t-lv)*.18;
      if(Math.abs(lv)<.02&&d===0){w.style.setProperty('--lean','0deg');leanAct=false;return;}
      w.style.setProperty('--lean',lv.toFixed(2)+'deg');
      requestAnimationFrame(leanFrame);
    };
    rail.addEventListener('scroll',function(){
      if(!leanAct){leanAct=true;requestAnimationFrame(leanFrame);}
    },{passive:true});
  }
});

/* testimonial slider — manual only: three quotes don't need autoplay,
   and auto-advance had no touch-reachable pause (WCAG 2.2.2) */
document.querySelectorAll('.tsl').forEach(function(t){
  var tr=t.querySelector('.tsl-t'),n=tr.children.length,i=0;
  var ui=t.querySelector('.tsl-ui');
  var tReduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  for(var d=0;d<n;d++){var b=document.createElement('button');b.className='tsl-d'+(d?'':' on');b.setAttribute('aria-label','Quote '+(d+1)+' of '+n);b.dataset.i=d;ui.appendChild(b);}
  var dots=ui.children;
  function go(k){
    i=(k+n)%n;tr.style.transform='translateX(-'+i*100+'%)';
    for(var d2=0;d2<n;d2++)dots[d2].classList.toggle('on',d2===i);
    if(!tReduce){var s=tr.children[i];s.classList.remove('rv2');void s.offsetWidth;s.classList.add('rv2');}
  }
  ui.addEventListener('click',function(e){var b2=e.target.closest('.tsl-d');if(b2)go(+b2.dataset.i);});
});

/* ── v8 · sector index: contact flood origin + boxes drive the register ── */
(function(){
  function aim(e){
    var b=e.target.closest('.sx');
    if(!b||(e.relatedTarget&&b.contains(e.relatedTarget)))return;
    var r=b.getBoundingClientRect();
    b.style.setProperty('--ox',(e.clientX-r.left).toFixed(1)+'px');
    b.style.setProperty('--oy',(e.clientY-r.top).toFixed(1)+'px');
    b.style.setProperty('--sxr',Math.hypot(r.width,r.height).toFixed(0)+'px');
  }
  if(window.matchMedia('(hover: hover) and (pointer: fine)').matches){
    document.addEventListener('pointerover',aim);
    document.addEventListener('pointerout',aim);
  }else{
    document.addEventListener('pointerdown',aim);
  }
})();
(function(){
  var grid=document.getElementById('pjGrid'),rgc=document.getElementById('rgCount');
  var rgx=document.getElementById('rgx'),btn=document.getElementById('rgxBtn');
  if(!grid||!rgx||!btn)return;
  var reduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  function setOpen(o){rgx.classList.toggle('open',o);btn.setAttribute('aria-expanded',o?'true':'false');}
  btn.addEventListener('click',function(){setOpen(!rgx.classList.contains('open'));});
  function filter(f,on){
    var shown=0;
    grid.querySelectorAll('[data-cat]').forEach(function(p){
      var hide=on&&p.getAttribute('data-cat')!==f;
      p.classList.toggle('hide',hide);
      if(!hide)shown++;
    });
    if(rgc)rgc.textContent=shown;
  }
  function press(b,on){
    document.querySelectorAll('.sx[data-f]').forEach(function(x){
      x.setAttribute('aria-pressed',String(x===b&&on));
    });
  }
  document.querySelectorAll('.sx[data-f]').forEach(function(b){
    b.addEventListener('click',function(){
      var on=b.getAttribute('aria-pressed')!=='true';
      press(b,on);
      if(b.hasAttribute('data-study')){
        filter('all',false);
        setOpen(true);
        var st=document.getElementById('rg-studies');
        if(st)setTimeout(function(){st.scrollIntoView({behavior:reduce?'auto':'smooth',block:'start'});},reduce?0:520);
        return;
      }
      filter(b.dataset.f,on);
      setOpen(true);
      btn.scrollIntoView({behavior:reduce?'auto':'smooth',block:'nearest'});
    });
  });
  /* deep links from the homepage chips: #rg-<sector> or #rg-studies.
     Whitelisted before use — a crafted hash must never reach querySelector */
  var h=(location.hash||'').replace('#rg-','');
  if(!/^[a-z-]{2,24}$/.test(h))h='';
  if(h){
    var target=document.querySelector('.sx[data-f="'+(h==='studies'?'study':h)+'"]');
    if(target)setTimeout(function(){target.click();target.scrollIntoView({behavior:'auto',block:'center'});},60);
  }
})();

/* article modal (news) */
var amod=document.getElementById('amod');
if(amod){
  var tagEl=amod.querySelector('.tag'),tEl=amod.querySelector('h3'),bEl=amod.querySelector('.bd');
  var last=null;
  function aOpen(card){
    tagEl.textContent=card.querySelector('.tag').textContent;
    tEl.textContent=card.querySelector('h3').textContent;
    bEl.innerHTML=card.querySelector('template').innerHTML;
    last=document.activeElement;
    amod.hidden=false;document.body.style.overflow='hidden';
    amod.querySelector('.amod-x').focus();
  }
  function aClose(){amod.hidden=true;document.body.style.overflow='';if(last)last.focus();}
  document.querySelectorAll('.nc[data-article]').forEach(function(c){
    c.addEventListener('click',function(){aOpen(c);});
  });
  amod.addEventListener('click',function(e){if(e.target.closest('[data-close]'))aClose();});
  amod.addEventListener('keydown',function(e){trapFocus(amod,e);});
  document.addEventListener('keydown',function(e){if(e.key==='Escape'&&!amod.hidden)aClose();});
}

/* enquiry forms -> pre-filled email drafts */
document.querySelectorAll('form[data-mailto]').forEach(function(f){
  var note=f.querySelector('.frm-note');
  if(note){note.setAttribute('role','alert');}
  f.addEventListener('submit',function(e){
    e.preventDefault();
    var ok=true;
    f.querySelectorAll('.ff').forEach(function(w){
      var i=w.querySelector('input,textarea,select');if(!i)return;
      var v=i.value.trim();
      var bad=(i.required&&!v)||(i.type==='email'&&v&&!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v));
      w.classList.toggle('bad',bad);if(i.required||i.type==='email')i.setAttribute('aria-invalid',bad?'true':'false');if(bad)ok=false;
    });
    if(!ok){if(note){note.textContent='Please complete the highlighted fields.';note.style.color='var(--err)';}return;}
    function v(n){var el=f.querySelector('[name='+n+']');return el?el.value.trim():'';}
    var to=f.getAttribute('data-to')||'info@expertaims.com';
    var subject=(f.getAttribute('data-subject')||'Enquiry')+' — '+v('name')+(v('company')?' ('+v('company')+')':'');
    var body='Name: '+v('name')+'\nEmail: '+v('email')+(v('phone')?'\nPhone: '+v('phone'):'')+(v('company')?'\nRole: '+v('company'):'')+(v('msg2')?'\nLink: '+v('msg2'):'')+'\n';
    var cv=f.querySelector('input[type=file]');
    if(cv&&cv.files&&cv.files.length){body+='CV to attach: '+cv.files[0].name+' (please attach this file before sending)\n';}
    body+='\n'+v('msg');
    window.location.href='mailto:'+to+'?subject='+encodeURIComponent(subject)+'&body='+encodeURIComponent(body);
    /* success state: swap the form for a confirmation panel */
    var career=to.indexOf('careers')===0;
    var ok2=f.parentNode.querySelector('.frm-ok');
    if(!ok2){
      ok2=document.createElement('div');ok2.className='frm-ok';ok2.setAttribute('role','status');
      f.parentNode.appendChild(ok2);
    }
    ok2.innerHTML='<span class="frm-ok-mk" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></span>'+
      '<b>'+(career?'Application ready':'Message ready')+'</b>'+
      '<p>We&#8217;ve opened a pre-filled email to '+to+'. '+(career?'Attach your CV and hit send &#8212; a person replies within a week, including the noes.':'Review it and hit send &#8212; we reply within one working day.')+'</p>'+
      '<p class="frm-ok-alt">Nothing opened? Email <a href="mailto:'+to+'">'+to+'</a> or WhatsApp <a href="https://wa.me/96590908625" target="_blank" rel="noopener">+965 9090 8625</a> directly.</p>'+
      '<button type="button" class="tx frm-again">'+(career?'Apply for another role':'Send another message')+'</button>';
    f.hidden=true;ok2.hidden=false;
    var again=ok2.querySelector('.frm-again');
    if(again)again.addEventListener('click',function(){
      f.reset();f.querySelectorAll('.ff.bad').forEach(function(w){w.classList.remove('bad');});
      if(note){note.textContent='This opens a pre-filled draft — review and send it.';note.style.color='';}
      ok2.hidden=true;f.hidden=false;
      var first=f.querySelector('input,textarea,select');if(first)first.focus();
    });
    ok2.scrollIntoView({behavior:window.matchMedia('(prefers-reduced-motion: reduce)').matches?'auto':'smooth',block:'center'});
  });
});

/* ── v9.7 · careers: "Apply" opens the application modal, role preset ── */
(function(){
  var mod=document.getElementById('appmod');if(!mod)return;
  var form=mod.querySelector('form[data-mailto]');if(!form)return;
  var roleEl=document.getElementById('appRole'),companyEl=form.querySelector('[name=company]');
  var lastFocus=null;
  function openMod(role){
    lastFocus=document.activeElement;
    if(role){if(roleEl)roleEl.textContent=role;if(companyEl)companyEl.value=role;}
    var ok=form.parentNode.querySelector('.frm-ok');
    if(ok&&!ok.hidden){ok.hidden=true;form.hidden=false;}
    mod.hidden=false;document.body.style.overflow='hidden';
    var nm=form.querySelector('[name=name]');if(nm)setTimeout(function(){nm.focus();},40);
  }
  function closeMod(){mod.hidden=true;document.body.style.overflow='';if(lastFocus&&lastFocus.focus)lastFocus.focus();}
  document.querySelectorAll('.job-apply').forEach(function(b){
    b.addEventListener('click',function(){openMod(b.getAttribute('data-role')||'Open application');});
  });
  mod.addEventListener('click',function(e){if(e.target.closest('[data-close]'))closeMod();});
  mod.addEventListener('keydown',function(e){trapFocus(mod,e);});
  document.addEventListener('keydown',function(e){if(e.key==='Escape'&&!mod.hidden)closeMod();});
})();

/* ── v5.1 · signal draw on page entry ── */
if(!window.matchMedia('(prefers-reduced-motion: reduce)').matches){
  var sig=document.createElement('div');
  sig.className='sig-load';sig.setAttribute('aria-hidden','true');
  document.body.appendChild(sig);
  sig.addEventListener('animationend',function(){sig.remove();});
}

/* ── v5.1 · pointer spotlight on cards ── */
if(window.matchMedia('(hover: hover) and (pointer: fine)').matches){
  document.addEventListener('pointermove',function(e){
    var c=e.target.closest('.pj');if(!c)return;
    var host=c.querySelector('.pj-art')||c;
    var r=host.getBoundingClientRect();
    host.style.setProperty('--mx',((e.clientX-r.left)/r.width*100).toFixed(1)+'%');
    host.style.setProperty('--my',((e.clientY-r.top)/r.height*100).toFixed(1)+'%');
  },{passive:true});
}

/* v11.4 · header logo is static — the traveling "ai" light effect was
   removed at the client's request (they disliked it). No replacement. */

/* ── v6.1 · header logo expands on scroll ── */
(function(){
  var hd=document.querySelector('.hd');if(!hd)return;
  var tick=false;
  function upd(){hd.classList.toggle('exp',window.scrollY>90);tick=false;}
  window.addEventListener('scroll',function(){if(!tick){tick=true;requestAnimationFrame(upd);}},{passive:true});
  upd();
})();

/* ── v6.1 · back to top ── */
document.addEventListener('click',function(e){
  if(!e.target.closest('[data-top]'))return;
  var reduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  window.scrollTo({top:0,behavior:reduce?'auto':'smooth'});
});

/* ── v5.3 · hero banner slider ── */
var hb=document.querySelector('.hb');
if(hb){
  var hbT=hb.querySelector('.hb-t'),hbS=[].slice.call(hbT.children);
  var hbDots=hb.querySelector('.hb-dots'),hbN=hb.querySelector('.hb-n');
  var hbReduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  var HB_MS=9000,hbI=0,hbTimer=null;
  hb.style.setProperty('--hb-ms',HB_MS+'ms');
  hbS.forEach(function(s,i){
    var d=document.createElement('button');
    d.className='hb-d';d.type='button';
    d.setAttribute('aria-label','Slide '+(i+1)+' of '+hbS.length);
    d.innerHTML='<i></i>';d.dataset.i=i;
    hbDots.appendChild(d);
  });
  var hbD=[].slice.call(hbDots.children);
  function hbAcc(s,on){
    s.setAttribute('aria-hidden',on?'false':'true');
    s.querySelectorAll('a,button').forEach(function(f){f.tabIndex=on?0:-1;});
  }
  var hbInit=false,hbWipeT=null,hbWipeId=0;
  function hbGo(k){
    var prev=hbI;
    hbI=(k+hbS.length)%hbS.length;
    /* meridian wipe: incoming slide reveals over the old one, led by the
       signal line. Cleanup is triple-guarded — animationend, animationcancel
       and a timeout — and token-guarded, so an interrupted or throttled
       animation can never leave two slides stacked, and a stale event can
       never cut a newer wipe short. */
    if(hbInit&&!hbReduce&&prev!==hbI){
      var n=hbS.length,fwd=((hbI-prev+n)%n)<=n/2;
      hb.dataset.dir=fwd?'fwd':'rev';
      if(hbWipeT){clearTimeout(hbWipeT);hbWipeT=null;}
      hbS.forEach(function(s){s.classList.remove('in','out');});
      var myId=++hbWipeId;
      var inn=hbS[hbI];
      hbS[prev].classList.add('out');
      inn.classList.add('in');
      var done=function(e){
        if(e&&e.animationName&&e.animationName.indexOf('tl-wipe')!==0)return;
        inn.removeEventListener('animationend',done);
        inn.removeEventListener('animationcancel',done);
        if(myId!==hbWipeId)return; /* stale transition — leave the current one alone */
        if(hbWipeT){clearTimeout(hbWipeT);hbWipeT=null;}
        hbS.forEach(function(s){s.classList.remove('in','out');});
      };
      inn.addEventListener('animationend',done);
      inn.addEventListener('animationcancel',done);
      hbWipeT=setTimeout(done,850);
    }
    hbS.forEach(function(s,i){s.classList.toggle('on',i===hbI);hbAcc(s,i===hbI);});
    hbD.forEach(function(d,i){
      d.classList.remove('on');
      if(i===hbI){void d.offsetWidth;d.classList.add('on');}
    });
    if(hbN)hbN.textContent=('0'+(hbI+1)).slice(-2)+' / '+('0'+hbS.length).slice(-2);
    hbInit=true;
    hbPlay();
  }
  function hbPlay(){
    if(hbTimer)clearTimeout(hbTimer);
    if(hbReduce||hb.classList.contains('paused'))return;
    hbTimer=setTimeout(function(){hbGo(hbI+1);},HB_MS);
  }
  var hbUserPaused=false;
  hb.addEventListener('click',function(e){
    var pp=e.target.closest('[data-hb-pp]');
    if(pp){
      hbUserPaused=!hbUserPaused;
      pp.setAttribute('aria-pressed',hbUserPaused?'true':'false');
      pp.setAttribute('aria-label',hbUserPaused?'Play slides':'Pause slides');
      pp.innerHTML=hbUserPaused
        ?'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.5 2.8v10.4c0 .8.9 1.3 1.6.9l8-5.2c.6-.4.6-1.4 0-1.8l-8-5.2c-.7-.4-1.6.1-1.6.9Z"/></svg>'
        :'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="3" y="2.5" width="3.4" height="11" rx="1"/><rect x="9.6" y="2.5" width="3.4" height="11" rx="1"/></svg>';
      hbPause(hbUserPaused);return;
    }
    var ar=e.target.closest('[data-hb]');
    if(ar){hbGo(hbI+(ar.dataset.hb==='next'?1:-1));return;}
    var d=e.target.closest('.hb-d');
    if(d)hbGo(+d.dataset.i);
  });
  function hbPause(p){p=p||hbUserPaused;hb.classList.toggle('paused',p);if(p){if(hbTimer)clearTimeout(hbTimer);}else hbPlay();}
  hb.addEventListener('mouseenter',function(){hbPause(true);});
  hb.addEventListener('mouseleave',function(){hbPause(false);});
  hb.addEventListener('focusin',function(){hbPause(true);});
  hb.addEventListener('focusout',function(e){if(!hb.contains(e.relatedTarget))hbPause(false);});
  document.addEventListener('visibilitychange',function(){hbPause(document.hidden);});
  hb.addEventListener('keydown',function(e){
    if(e.key==='ArrowRight'){e.preventDefault();hbGo(hbI+1);}
    if(e.key==='ArrowLeft'){e.preventDefault();hbGo(hbI-1);}
  });
  /* swipe — horizontal intent only, so diagonal page scrolling never flips slides */
  var hx=null,hy=null;
  hbT.addEventListener('pointerdown',function(e){if(!e.target.closest('a,button')){hx=e.clientX;hy=e.clientY;}});
  window.addEventListener('pointerup',function(e){
    if(hx===null)return;
    var dx=e.clientX-hx,dy=e.clientY-hy;hx=hy=null;
    if(Math.abs(dx)>56&&Math.abs(dx)>Math.abs(dy)*1.4)hbGo(hbI+(dx<0?1:-1));
  });
  hbGo(0);
}

/* ── v5.3 · service card icons + outlined numerals ── */
(function(){
  var IC={
    s1:'<rect x="8" y="8" width="32" height="12" rx="2.5"/><rect x="8" y="26" width="32" height="12" rx="2.5"/><circle cx="14.5" cy="14" r="1.6"/><circle cx="14.5" cy="32" r="1.6"/><path d="M22 14h12M22 32h12"/><circle class="dt" cx="40" cy="8" r="2.6"/>',
    s2:'<path d="M14 32a7.5 7.5 0 0 1-1-14.9A10.5 10.5 0 0 1 33.6 19 8 8 0 0 1 33 35H16"/><path d="M24 38V24m0 0-5 5m5-5 5 5"/><circle class="dt" cx="38" cy="12" r="2.6"/>',
    s3:'<path d="M24 6 38 11v11c0 9.5-6 15.6-14 20-8-4.4-14-10.5-14-20V11Z"/><path d="m17 23 5 5 9.5-10"/><circle class="dt" cx="38" cy="9" r="2.6"/>',
    s4:'<rect x="6" y="9" width="36" height="28" rx="3"/><path d="M6 17h36"/><circle cx="11.5" cy="13" r="1.3"/><circle cx="16.5" cy="13" r="1.3"/><path d="m19 30 -5-4.5 5-4.5M29 21l5 4.5-5 4.5"/><circle class="dt" cx="40" cy="13" r="2.6"/>',
    s5:'<path d="M8 38V22m10 16V14m10 24V26m10 12V8"/><path d="M30 8h8v8"/><circle class="dt" cx="38" cy="8" r="2.6"/>',
    s7:'<path d="M38 24a14 14 0 1 1-4.1-9.9M38 24v-8m0 8h-8"/><path d="M19 24l4 4 7-8"/><circle class="dt" cx="38" cy="10" r="2.6"/>',
    s6:'<path d="M24 8 42 16l-18 8L6 16Z"/><path d="M13 20v10c0 3 5 6 11 6s11-3 11-6V20"/><path d="M42 16v10"/><circle class="dt" cx="42" cy="28.5" r="2.4"/>'
  };
  window.__IC=IC;
  /* pathLength=1 lets the strokes draw themselves on hover (v7) */
  function drawable(frag){return frag.replace(/<(path|rect|circle)(?![^>]*class="dt")/g,'<$1 pathLength="1"');}
  document.querySelectorAll('a.svc').forEach(function(c){
    var m=(c.getAttribute('href')||'').match(/#(s[1-7])/);
    if(!m||!IC[m[1]])return;
    var ic=document.createElement('span');
    ic.className='ic';ic.setAttribute('aria-hidden','true');
    ic.innerHTML='<svg viewBox="0 0 48 48">'+drawable(IC[m[1]])+'</svg>';
    c.appendChild(ic);
    var num=c.querySelector('.num');
    if(num){
      var bn=document.createElement('span');
      bn.className='bignum';bn.setAttribute('aria-hidden','true');
      bn.textContent=(num.textContent.match(/\d+/)||[''])[0];
      c.appendChild(bn);
    }
  });
})();

/* ── v5.3 · project card motifs by category ── */
(function(){
  var IC=window.__IC;if(!IC)return;
  document.querySelectorAll('.mega a.mg').forEach(function(a){
    var m=(a.getAttribute('href')||'').match(/#(s[1-7])/);
    if(!m||!IC[m[1]])return;
    var ic=document.createElement('span');
    ic.className='mg-ic';ic.setAttribute('aria-hidden','true');
    ic.innerHTML='<svg viewBox="0 0 48 48">'+IC[m[1]]+'</svg>';
    a.appendChild(ic);
  });
})();

(function(){
  var MT={
    websites:'<svg viewBox="0 0 120 90"><rect x="4" y="6" width="112" height="78" rx="6"/><path d="M4 22h112"/><circle cx="13" cy="14" r="2"/><circle cx="21" cy="14" r="2"/><circle cx="29" cy="14" r="2"/><path d="M16 38h48M16 50h64M16 62h40"/><rect x="88" y="34" width="18" height="32" rx="3"/></svg>',
    apps:'<svg viewBox="0 0 70 110"><rect x="6" y="4" width="58" height="102" rx="10"/><path d="M26 12h18"/><circle cx="35" cy="94" r="4"/><rect x="16" y="26" width="16" height="16" rx="3"/><rect x="38" y="26" width="16" height="16" rx="3"/><rect x="16" y="48" width="16" height="16" rx="3"/><rect x="38" y="48" width="16" height="16" rx="3"/></svg>',
    logos:'<svg viewBox="0 0 110 110"><path d="M20 90C20 50 50 20 90 20"/><circle cx="20" cy="90" r="5"/><circle cx="90" cy="20" r="5"/><path d="M20 90 55 55m35-35L55 55" stroke-dasharray="3 6"/><circle cx="55" cy="55" r="3"/><rect x="47" y="14" width="12" height="12" rx="2"/><rect x="14" y="84" width="12" height="12" rx="2" transform="rotate(0)"/></svg>',
    brands:'<svg viewBox="0 0 120 100"><path d="M14 62V38l52-24v72L14 62Z"/><path d="M66 30c14 0 24 8 24 20"/><path d="M20 62v18c0 4 3 6 7 6h6V64"/><path d="M98 26l10-8M100 50h14M96 68l10 8"/></svg>'
  };
  document.querySelectorAll('.pj').forEach(function(p){
    var art=p.querySelector('.pj-art');
    var cat=p.getAttribute('data-cat');
    if(!art||!MT[cat]||art.querySelector('.mt'))return;
    var mt=document.createElement('span');
    mt.className='mt';mt.setAttribute('aria-hidden','true');
    mt.innerHTML=MT[cat];
    art.insertBefore(mt,art.firstChild);
  });
})();

/* focus trap shared by all dialogs */
function trapFocus(box,e){
  if(e.key!=='Tab')return;
  var f=box.querySelectorAll('a[href],button:not([disabled]),input,textarea,select,[tabindex]:not([tabindex="-1"])');
  if(!f.length)return;
  var first=f[0],last=f[f.length-1];
  if(e.shiftKey&&document.activeElement===first){e.preventDefault();last.focus();}
  else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();first.focus();}
}

/* ── v6.0 · case reader ── */
var cmod=document.getElementById('cmod');
if(cmod){
  var cHero=cmod.querySelector('.cs-hero'),cTag=cmod.querySelector('.tag'),cT=cmod.querySelector('h3'),cBd=cmod.querySelector('.bd');
  var cLast=null;
  function cOpen(card){
    cHero.innerHTML='';var cSvg=card.querySelector('.cs-ill-svg');if(cSvg)cHero.appendChild(cSvg.cloneNode(true));
    cTag.textContent=card.querySelector('.cs-cover .tag').textContent;
    cT.textContent=card.querySelector('.cs-b b').textContent;
    cBd.innerHTML=card.querySelector('template').innerHTML;
    cLast=document.activeElement;
    cmod.hidden=false;document.body.style.overflow='hidden';
    cmod.querySelector('.amod-x').focus();
  }
  function cClose(){cmod.hidden=true;document.body.style.overflow='';if(cLast)cLast.focus();}
  document.querySelectorAll('.cs[data-case]').forEach(function(c){c.addEventListener('click',function(){cOpen(c);});});
  cmod.addEventListener('click',function(e){if(e.target.closest('[data-close]'))cClose();});
  cmod.addEventListener('keydown',function(e){trapFocus(cmod,e);});
  document.addEventListener('keydown',function(e){if(e.key==='Escape'&&!cmod.hidden)cClose();});
}

/* ── v6.0 · pointer tilt on plates and case covers ── */
if(window.matchMedia('(hover: hover) and (pointer: fine)').matches && !window.matchMedia('(prefers-reduced-motion: reduce)').matches){
  document.querySelectorAll('.hb-art .plate,.cs-cover').forEach(function(el){el.setAttribute('data-tilt','');});
  document.addEventListener('pointermove',function(e){
    var host=e.target.closest('.hb-s.on,.cs');if(!host)return;
    var el=host.querySelector('[data-tilt]');if(!el)return;
    var r=host.getBoundingClientRect();
    var rx=((e.clientY-r.top)/r.height-.5)*-4.5;
    var ry=((e.clientX-r.left)/r.width-.5)*5.5;
    el.style.transform=(el.classList.contains('plate')?'translateY(-54%) ':'')+'perspective(900px) rotateX('+rx.toFixed(2)+'deg) rotateY('+ry.toFixed(2)+'deg)';
  },{passive:true});
  document.addEventListener('pointerout',function(e){
    var host=e.target.closest('.hb-s,.cs');if(!host||host.contains(e.relatedTarget))return;
    var el=host.querySelector('[data-tilt]');if(el)el.style.transform='';
  });
}

/* ── v5.1 · Signal Search (command palette) ── */
(function(){
  var INDEX=[
    {t:'Home',d:'The line begins here',u:'index.html',g:'page',k:'home start meridian'},
    {t:'Services — all seven practices',d:'Run · Move · Protect · Build · Grow · Enable · Transform',u:'services.html',g:'page',k:'services practices what we do'},
    {t:'IT Infrastructure & AMC',d:'Networks, servers, maintenance contracts',u:'services.html#s1',g:'service',k:'network servers helpdesk amc hardware infrastructure support'},
    {t:'Cloud, Email & Hosting',d:'Google Workspace, Microsoft 365 & Zoho — and the hosting under it',u:'services.html#s2',g:'service',k:'cloud m365 office email migration google workspace zoho hosting domain server'},
    {t:'Cybersecurity & Backup',d:'Endpoint, email security, tested backups',u:'services.html#s3',g:'service',k:'security ransomware endpoint backup recovery protect'},
    {t:'Websites, E-commerce & Apps',d:'Built to convert, handed over documented',u:'services.html#s4',g:'service',k:'website ecommerce app store development build design'},
    {t:'SEO, Branding & Marketing',d:'Found first, remembered longer',u:'services.html#s5',g:'service',k:'seo brand logo marketing social media growth'},
    {t:'Training & Workshops',d:'Your team, upskilled on your stack',u:'services.html#s6',g:'service',k:'training workshops learning enable'},
    {t:'Digital Transformation & AI',d:'Workflows digitised, AI integrated in your sector',u:'services.html#s7',g:'service',k:'digital transformation automation workflow erp crm integration ai paperless consultancy artificial intelligence'},
    {t:'Projects & case studies',d:'The sector index and the full delivery register',u:'projects.html',g:'page',k:'portfolio work case studies proof websites apps register fintech healthcare government'},
    {t:'About ExpertAims',d:'Vision, mission, how we work since 2012',u:'about.html',g:'page',k:'company story values respect responsibility ownership'},
    {t:'Clients & industries',d:'Who trusts us, by sector',u:'clients.html',g:'page',k:'customers industries sectors trust'},
    {t:'News & insights',d:'Practice notes from the field',u:'news.html',g:'page',k:'articles blog insights reading'},
    {t:'Innovation & Capability Atlas',d:'Frontier practices, interactive map',u:'innovation.html',g:'page',k:'ai automation atlas future frontier'},
    {t:'Contact — three offices',d:'Kuwait · India · Malaysia',u:'contact.html',g:'page',k:'contact reach address phone kuwait india malaysia office faq'},
    {t:'Careers — the open application',d:'We hire for the bench, not the vacancy',u:'careers.html',g:'page',k:'careers jobs hiring join work vacancy cv apply bench'},
    {t:'Our companies',d:'ExpertAims & IrrigAims — one discipline, several companies',u:'aims-group.html',g:'page',k:'group subsidiaries irrigaims agritech irrigation aims agriculture ventures'},
    {t:'WhatsApp us',d:'+965 9090 8625 · fastest reply',u:'https://wa.me/96590908625',g:'action',k:'whatsapp chat message call now'},
    {t:'Email info@expertaims.com',d:'Start an enquiry',u:'mailto:info@expertaims.com',g:'action',k:'email mail enquiry write'},
    {t:'Switch light / dark theme',d:'Follows your OS until you choose',g:'action',k:'theme dark light mode appearance',a:'theme'}
  ];
  var acts=document.querySelector('.hd-acts'),thm=document.querySelector('.thm');
  var mac=/Mac|iPhone|iPad/.test(navigator.platform||'');
  if(acts&&thm){
    var btn=document.createElement('button');
    btn.type='button';btn.className='cpb';btn.setAttribute('aria-label','Search the site (keyboard: '+(mac?'Command':'Control')+' K)');
    btn.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.8-3.8"/></svg><span class="cpb-t">Search</span><kbd>'+(mac?'⌘':'Ctrl')+' K</kbd>';
    acts.insertBefore(btn,thm);
  }
  var cp,inp,ls,items=[],sel=0,lastFocus=null;
  function build(){
    cp=document.createElement('div');
    cp.className='cp';cp.hidden=true;
    cp.setAttribute('role','dialog');cp.setAttribute('aria-modal','true');cp.setAttribute('aria-label','Site search');
    cp.innerHTML='<div class="cp-bg" data-close></div>'+
      '<div class="cp-box"><div class="cp-hd">'+
      '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.8-3.8"/></svg>'+
      '<input type="text" placeholder="Search pages, services, actions…" aria-label="Search" role="combobox" aria-expanded="true" aria-controls="cp-ls" autocomplete="off" spellcheck="false">'+
      '<kbd data-close role="button" tabindex="0" aria-label="Close search">ESC</kbd></div>'+
      '<div class="cp-ls" id="cp-ls" role="listbox" aria-label="Results"></div><div class="vh" aria-live="polite"></div>'+
      '<div class="cp-ft"><span><kbd>↑↓</kbd>navigate</span><span><kbd>↵</kbd>open</span><span><kbd>esc</kbd>close</span></div></div>';
    document.body.appendChild(cp);
    inp=cp.querySelector('input');ls=cp.querySelector('.cp-ls');
    inp.addEventListener('input',function(){render(inp.value);});
    cp.addEventListener('click',function(e){
      if(e.target.closest('[data-close]')){close();return;}
      var it=e.target.closest('.cp-it');if(it){e.preventDefault();go(+it.dataset.i);}
    });
    cp.addEventListener('keydown',function(e){
      trapFocus(cp,e);
      if(e.key==='ArrowDown'){e.preventDefault();move(1);}
      else if(e.key==='ArrowUp'){e.preventDefault();move(-1);}
      else if(e.key==='Enter'){e.preventDefault();if(items[sel])go(+items[sel].dataset.i);}
    });
  }
  function score(it,q){
    var hay=(it.t+' '+it.d+' '+it.k).toLowerCase(),s=0;
    var terms=q.toLowerCase().split(/\s+/).filter(Boolean);
    for(var i=0;i<terms.length;i++){
      var w=terms[i];
      if(it.t.toLowerCase().indexOf(w)===0)s+=5;
      else if(it.t.toLowerCase().indexOf(w)>-1)s+=3;
      else if(hay.indexOf(w)>-1)s+=1;
      else return 0;
    }
    return s||1;
  }
  function render(q){
    var res=q.trim()
      ? INDEX.map(function(it,i){return{it:it,i:i,s:score(it,q)};}).filter(function(r){return r.s>0;}).sort(function(a,b){return b.s-a.s;})
      : INDEX.map(function(it,i){return{it:it,i:i};});
    ls.innerHTML='';items=[];sel=0;
    var live=cp.querySelector('.vh');
    if(live)live.textContent=res.length?res.length+' results':'No results';
    if(!res.length)inp.removeAttribute('aria-activedescendant');
    if(!res.length){ls.innerHTML='<p class="cp-mt">No match — try “backup”, “website” or “WhatsApp”.</p>';return;}
    res.forEach(function(r,n){
      var el=document.createElement(r.it.u?'a':'button');
      el.className='cp-it'+(n===0?' on':'');
      el.setAttribute('role','option');el.id='cp-opt-'+n;el.dataset.i=r.i;
      if(r.it.u){el.href=r.it.u;}else{el.type='button';}
      el.innerHTML='<span class="dot" aria-hidden="true"></span><span><b></b><span></span></span><span class="k"></span>';
      el.querySelector('b').textContent=r.it.t;
      el.querySelector('span span').textContent=r.it.d;
      el.querySelector('.k').textContent=r.it.g;
      ls.appendChild(el);items.push(el);
    });
    if(items[0])inp.setAttribute('aria-activedescendant',items[0].id);
  }
  function move(d){
    if(!items.length)return;
    items[sel].classList.remove('on');
    sel=(sel+d+items.length)%items.length;
    items[sel].classList.add('on');
    inp.setAttribute('aria-activedescendant',items[sel].id);
    items[sel].scrollIntoView({block:'nearest'});
  }
  function go(i){
    var it=INDEX[i];
    if(it.a==='theme'){close();var t=document.querySelector('.thm');if(t)t.click();return;}
    close();window.location.href=it.u;
  }
  function open(){
    if(!cp)build();
    lastFocus=document.activeElement;
    cp.hidden=false;document.body.style.overflow='hidden';
    inp.value='';render('');inp.focus();
  }
  function close(){
    if(!cp||cp.hidden)return;
    cp.hidden=true;document.body.style.overflow='';
    if(lastFocus&&lastFocus.focus)lastFocus.focus();
  }
  document.addEventListener('click',function(e){if(e.target.closest('.cpb'))open();});
  document.addEventListener('keydown',function(e){
    if((e.metaKey||e.ctrlKey)&&(e.key==='k'||e.key==='K')){e.preventDefault();cp&&!cp.hidden?close():open();return;}
    if(e.key==='Escape')close();
    if(e.key==='/'&&!e.metaKey&&!e.ctrlKey&&!e.altKey){
      var t=e.target;
      if(t&&(t.tagName==='INPUT'||t.tagName==='TEXTAREA'||t.tagName==='SELECT'||t.isContentEditable))return;
      e.preventDefault();open();
    }
  });
})();

/* ── v7 · header: one shared underline gliding between links ── */
(function(){
  var nav=document.querySelector('.hd-nav');if(!nav)return;
  if(!window.matchMedia('(hover: hover) and (pointer: fine)').matches)return;
  var rail=document.createElement('span');
  rail.className='hd-rail';rail.setAttribute('aria-hidden','true');
  nav.appendChild(rail);nav.classList.add('railed');
  var home=nav.querySelector('.hd-lnk.on');
  function place(el){
    if(!el){rail.style.opacity='0';return;}
    var r=el.getBoundingClientRect(),n=nav.getBoundingClientRect();
    rail.style.opacity='';
    rail.style.transform='translateX('+(r.left-n.left+15)+'px) scaleX('+Math.max((r.width-30)/40,.2)+')';
  }
  nav.querySelectorAll('.hd-lnk').forEach(function(l){
    l.addEventListener('mouseenter',function(){place(l);});
    l.addEventListener('focus',function(){place(l);});
  });
  nav.addEventListener('mouseleave',function(){place(home);});
  nav.addEventListener('focusout',function(e){if(!nav.contains(e.relatedTarget))place(home);});
  window.addEventListener('resize',function(){place(home);});
  place(home);
})();

/* ── v7 · the through-line: the aim-dot rides the page with you ──
   Fine pointers, wide viewports, full-motion only. Every anchor is a
   static .aim dot in the markup, so nothing depends on this running. */
(function(){
  return; /* v11.18 · roaming aim-dot disabled — client found the dot travelling across the page on scroll distracting. Static .aim heading dots stay; Station 04 map still emanates flow from the E-mark. */
  if(!window.matchMedia('(hover: hover) and (pointer: fine)').matches)return;
  if(window.matchMedia('(prefers-reduced-motion: reduce)').matches)return;
  if(window.innerWidth<=720)return;
  var anchors=[].slice.call(document.querySelectorAll('.hb-h .aim, .sec-hd .d2 .aim, .ft-tag .d1 .aim'));
  if(anchors.length<2)return;
  var dot=document.createElement('div');
  dot.className='tl-dot';dot.setAttribute('aria-hidden','true');
  document.body.appendChild(dot);
  var band=document.querySelector('.band'),bandY=null;
  var pts=[],px=0,py=0,ps=1,active=false,lastScroll=0,dockedAt=-1,pinged={};
  function measure(){
    pts=anchors.map(function(a){
      var r=a.getBoundingClientRect();
      return {x:r.left+r.width/2+window.scrollX,y:r.top+r.height/2+window.scrollY,s:Math.max(r.width,7)/10};
    });
    if(band){var b=band.getBoundingClientRect();bandY=[b.top+window.scrollY,b.bottom+window.scrollY];}
  }
  function state(){
    var focal=window.scrollY+window.innerHeight*.45;
    var i=0;
    while(i<pts.length-2&&focal>pts[i+1].y)i++;
    var a=pts[i],b=pts[i+1];
    var t=(focal-a.y)/Math.max(b.y-a.y,1);t=Math.max(0,Math.min(1,t));
    return {i:i,t:t,a:a,b:b};
  }
  function dock(idx){
    if(dockedAt===idx)return;
    dockedAt=idx;
    dot.classList.remove('fly');
    anchors.forEach(function(el){el.classList.remove('hushed');});
    if(idx>=0&&!pinged[idx]){
      pinged[idx]=1;
      var el=anchors[idx];
      el.classList.add('pinged');
      setTimeout(function(){el.classList.remove('pinged');},420);
    }
  }
  function fly(i){
    if(dockedAt!==-1){dockedAt=-1;dot.classList.add('fly');}
    anchors.forEach(function(el,k){el.classList.toggle('hushed',k===i||k===i+1);});
  }
  function frame(){
    var s=state();
    var tx,ty,ts;
    if(s.t<.04){tx=s.a.x;ty=s.a.y;ts=s.a.s;dock(s.i);}
    else if(s.t>.96){tx=s.b.x;ty=s.b.y;ts=s.b.s;dock(s.i+1);}
    else{
      tx=s.a.x+(s.b.x-s.a.x)*s.t;
      ty=s.a.y+(s.b.y-s.a.y)*s.t;
      ts=(s.a.s+(s.b.s-s.a.s)*s.t)*(1+.5*Math.sin(Math.PI*s.t));
      fly(s.i);
    }
    px+=(tx-px)*.14;py+=(ty-py)*.14;ps+=(ts-ps)*.14;
    dot.style.transform='translate3d('+(px-window.scrollX-5)+'px,'+(py-window.scrollY-5)+'px,0) scale('+ps.toFixed(3)+')';
    if(bandY)dot.classList.toggle('on-band',py>bandY[0]&&py<bandY[1]);
    var settled=Math.abs(tx-px)<.4&&Math.abs(ty-py)<.4;
    if(!settled||performance.now()-lastScroll<300){requestAnimationFrame(frame);}
    else active=false;
  }
  function wake(){
    lastScroll=performance.now();
    if(!active){active=true;requestAnimationFrame(frame);}
  }
  measure();
  var s0=state();
  px=s0.t>.5?s0.b.x:s0.a.x;py=s0.t>.5?s0.b.y:s0.a.y;ps=s0.t>.5?s0.b.s:s0.a.s;
  dockedAt=s0.t>.5?s0.i+1:s0.i;pinged[dockedAt]=1;
  frame();
  window.addEventListener('scroll',wake,{passive:true});
  var rsT=null;
  function remeasure(){clearTimeout(rsT);rsT=setTimeout(function(){measure();wake();},150);}
  window.addEventListener('resize',remeasure);
  if('ResizeObserver' in window)new ResizeObserver(remeasure).observe(document.body);
})();

/* ── v7.1 · client logo river: pause/play control ── */
(function(){
  var lgr=document.querySelector('.lgr'),pp=document.querySelector('.lgr-pp');
  if(!lgr||!pp)return;
  if(window.matchMedia('(prefers-reduced-motion: reduce)').matches){pp.style.display='none';return;}
  var paused=false;
  pp.addEventListener('click',function(){
    paused=!paused;
    lgr.classList.toggle('paused',paused);
    pp.setAttribute('aria-pressed',paused?'true':'false');
    pp.setAttribute('aria-label',paused?'Play logo scroll':'Pause logo scroll');
    pp.innerHTML=paused
      ?'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.5 2.8v10.4c0 .8.9 1.3 1.6.9l8-5.2c.6-.4.6-1.4 0-1.8l-8-5.2c-.7-.4-1.6.1-1.6.9Z"/></svg>'
      :'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="3" y="2.5" width="3.4" height="11" rx="1"/><rect x="9.6" y="2.5" width="3.4" height="11" rx="1"/></svg>';
  });
})();

/* ── v7 · WhatsApp concierge: one honest nudge per visit ── */
(function(){
  var wa=document.querySelector('.wa');if(!wa)return;
  var lb=document.createElement('span');
  lb.className='wa-lb';lb.setAttribute('aria-hidden','true');
  lb.textContent='Replies within one working day';
  wa.appendChild(lb);
  if(window.matchMedia('(prefers-reduced-motion: reduce)').matches)return;
  var seen=false;try{seen=sessionStorage.getItem('ea-wa-nudge')==='1';}catch(e){}
  if(seen)return;
  setTimeout(function(){
    if(wa.classList.contains('off'))return;
    wa.classList.add('say');
    try{sessionStorage.setItem('ea-wa-nudge','1');}catch(e){}
    setTimeout(function(){wa.classList.remove('say');},4000);
  },12000);
})();

/* ── v8.6 · hero pointer parallax: two depth planes around the crosshair.
   The Ken Burns drift is retired; the visitor's pointer IS the aim-dot,
   and the hero world shifts around it. Desktop fine-pointer, full-motion. ── */
(function(){
  var hbEl=document.querySelector('.hb');if(!hbEl)return;
  if(!window.matchMedia('(hover: hover) and (pointer: fine)').matches)return;
  if(window.matchMedia('(prefers-reduced-motion: reduce)').matches)return;
  if(window.innerWidth<=1020)return;
  hbEl.classList.add('px');
  var slideRef=null,imgs=[],gg=null;
  var nx=0,ny=0,tx=0,ty=0,act=false,lastMove=0;
  function cache(){
    var on=hbEl.querySelector('.hb-s.on');
    if(on===slideRef)return;
    imgs.forEach(function(i){i.style.transform='';});
    if(gg)gg.style.transform='';
    slideRef=on;
    imgs=on?[].slice.call(on.querySelectorAll('.hb-art .bg img')):[];
    gg=on?on.querySelector('.hb-art .gg'):null;
  }
  function frame(){
    cache();
    nx+=(tx-nx)*.12;ny+=(ty-ny)*.12;
    var bx=(nx*-28).toFixed(1),by=(ny*-20).toFixed(1);
    var gx=(nx*52).toFixed(1),gy=(ny*32).toFixed(1);
    imgs.forEach(function(i){i.style.transform='translate3d('+bx+'px,'+by+'px,0) scale(1.05)';});
    if(gg)gg.style.transform='translate3d('+gx+'px,'+gy+'px,0)';
    var settled=Math.abs(tx-nx)<.002&&Math.abs(ty-ny)<.002;
    if(!settled||performance.now()-lastMove<300)requestAnimationFrame(frame);
    else act=false;
  }
  hbEl.addEventListener('pointermove',function(e){
    var r=hbEl.getBoundingClientRect();
    tx=(e.clientX-r.left)/r.width-.5;
    ty=(e.clientY-r.top)/r.height-.5;
    lastMove=performance.now();
    if(!act){act=true;requestAnimationFrame(frame);}
  },{passive:true});
  hbEl.addEventListener('pointerleave',function(){
    tx=0;ty=0;lastMove=performance.now();
    if(!act){act=true;requestAnimationFrame(frame);}
  });
})();

/* ── v8.6 · logo-river screenshot peek: three living chips answer with
   the real site under your cursor. Anonymity-vetted — no chip whose
   screenshot doubles as an anonymous case cover carries a peek. ── */
(function(){
  if(!window.matchMedia('(hover: hover) and (pointer: fine)').matches)return;
  var chips=document.querySelectorAll('.lgr .has-peek');if(!chips.length)return;
  var reduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  var card=document.createElement('div');
  card.className='lgp';card.setAttribute('aria-hidden','true');
  card.innerHTML='<img alt="" width="300" height="188"><span class="lgp-c"></span>';
  document.body.appendChild(card);
  var img=card.querySelector('img'),cap=card.querySelector('.lgp-c');
  var px=0,py=0,tx=0,ty=0,act=false,over=null,pre=false;
  function place(x,y){
    var W=card.offsetWidth||300,H=card.offsetHeight||225;
    var cx=Math.min(Math.max(x+18,12),window.innerWidth-W-12);
    var cy=y+16;if(cy+H>window.innerHeight-12)cy=y-H-14;
    return [cx,cy];
  }
  function frame(){
    px+=(tx-px)*.18;py+=(ty-py)*.18;
    card.style.transform='translate3d('+px.toFixed(1)+'px,'+py.toFixed(1)+'px,0)';
    if(over&&(Math.abs(tx-px)>.5||Math.abs(ty-py)>.5))requestAnimationFrame(frame);
    else act=false;
  }
  document.addEventListener('pointerover',function(e){
    var c=e.target.closest('.has-peek');if(!c)return;
    if(!pre){pre=true;chips.forEach(function(x){var i=new Image();i.src='assets/img/projects/'+x.dataset.peek;});}
    over=c;
    img.src='assets/img/projects/'+c.dataset.peek;
    cap.textContent=(c.getAttribute('title')||'')+' · live build';
    var p=place(e.clientX,e.clientY);
    px=tx=p[0];py=ty=p[1]+(reduce?0:8);ty=p[1];
    card.style.transform='translate3d('+px+'px,'+py+'px,0)';
    card.classList.add('on');
    if(!reduce&&!act){act=true;requestAnimationFrame(frame);}
  });
  document.addEventListener('pointermove',function(e){
    if(!over||!e.target.closest('.has-peek'))return;
    var p=place(e.clientX,e.clientY);tx=p[0];ty=p[1];
    if(reduce){px=tx;py=ty;card.style.transform='translate3d('+px+'px,'+py+'px,0)';}
    else if(!act){act=true;requestAnimationFrame(frame);}
  },{passive:true});
  document.addEventListener('pointerout',function(e){
    var c=e.target.closest('.has-peek');
    if(!c||(e.relatedTarget&&c.contains(e.relatedTarget)))return;
    over=null;card.classList.remove('on');
  });
})();

/* ── v8.8 · the engagement router: three taps end in a prefilled
   WhatsApp line — a router, not a chatbot, and it says so. ── */
(function(){
  var rt=document.getElementById('rt');if(!rt)return;
  var steps=[].slice.call(rt.querySelectorAll('.rt-q')),result=rt.querySelector('.rt-r');
  var trail=document.getElementById('rtTrail'),msgEl=document.getElementById('rtMsg');
  var wa=document.getElementById('rtWa'),mail=document.getElementById('rtMail');
  var picks=[];
  function chip(v){
    var c=document.createElement('span');c.textContent=v;trail.appendChild(c);
  }
  function show(i){
    steps.forEach(function(s,k){s.hidden=k!==i;});
    result.hidden=i!==-1?true:false;
    if(i>=0&&i<steps.length){var k=steps[i].querySelector('.rt-k');if(k)k.focus();}
  }
  function finish(){
    steps.forEach(function(s){s.hidden=true;});
    var msg='Hello ExpertAims — I need '+picks[0]+'. Timing: '+picks[1]+
      '. I’d prefer '+picks[2]+'. (Sent from the site router.)';
    msgEl.textContent=msg;
    wa.href='https://wa.me/96590908625?text='+encodeURIComponent(msg);
    mail.href='mailto:info@expertaims.com?subject='+encodeURIComponent('Enquiry via the site router')+
      '&body='+encodeURIComponent(msg);
    result.hidden=false;
    var k=result.querySelector('.rt-k');if(k)k.focus();
  }
  rt.addEventListener('click',function(e){
    var b=e.target.closest('.rt-o button');
    if(b){
      picks.push(b.getAttribute('data-v'));
      chip(b.textContent.trim());
      picks.length<3?show(picks.length):finish();
      return;
    }
    if(e.target.closest('#rtReset')){
      picks=[];trail.textContent='';result.hidden=true;show(0);
    }
  });
})();

/* ── v9.3 · the accountability map: Station 04's six reasons orbit one
   accountable core — the atlas pattern, re-set on the crimson platform.
   Desktop only; mobile and no-JS keep the cells. ── */
(function(){
  var band=document.querySelector('.band-platform');if(!band)return;
  var wm=document.getElementById('whyMap'),svg=document.getElementById('wmSvg');
  var cells=band.querySelectorAll('.cell');
  if(!wm||!svg||cells.length<3)return;
  if(window.innerWidth<=880)return;
  var data=[].map.call(cells,function(c){
    return {k:(c.querySelector('.mono')||{}).textContent||'',
            t:(c.querySelector('h3')||{}).textContent||'',
            p:(c.querySelector('p')||{}).textContent||''};
  });
  var NS='http://www.w3.org/2000/svg';
  function el(n,at){var e=document.createElementNS(NS,n);for(var k in at)e.setAttribute(k,at[k]);return e;}
  var reduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  var CX=320,CY=280,R=205,n=data.length;
  var EX=CX+19.2,EY=CY-19.2;/* v11.20 · effects emanate from the E-mark's aim-dot (upper-right of the core logo), not the core centre */
  var spokes=[],nodes=[],pos=[];
  data.forEach(function(d,i){
    var a=-Math.PI/2+i*(2*Math.PI/n);
    var x=CX+R*Math.cos(a),y=CY+R*Math.sin(a);
    pos.push({x:x,y:y});
    var sp=el('line',{x1:CX,y1:CY,x2:x,y2:y,'class':'spoke',style:'--i:'+i});
    svg.appendChild(sp);spokes.push(sp);
    var g=el('g',{'class':'nd',tabindex:'0',role:'button','aria-label':d.t,style:'--i:'+i});
    g.appendChild(el('circle',{cx:x,cy:y,r:30,'class':'halo'}));
    g.appendChild(el('circle',{cx:x,cy:y,r:24,'class':'ring'}));
    g.appendChild(el('circle',{cx:x,cy:y,r:5,'class':'dot'}));
    var above=y<CY-10,side=Math.abs(x-CX)>40?(x>CX?1:-1):0;
    var tx=el('text',{x:x+side*34,y:above?y-34:y+44,
      'text-anchor':side>0?'start':(side<0?'end':'middle')});
    tx.textContent=d.k.replace('/','').trim();
    g.appendChild(tx);
    svg.appendChild(g);nodes.push(g);
    function pick(){select(i);}
    g.addEventListener('click',pick);
    g.addEventListener('keydown',function(e){
      if(e.key==='Enter'||e.key===' '){e.preventDefault();pick();}
    });
    if(window.matchMedia('(hover: hover)').matches)g.addEventListener('pointerenter',pick);
  });
  var core=el('g',{'class':'core'});
  core.appendChild(el('circle',{cx:CX,cy:CY,r:42,'class':'c1'}));
  core.appendChild(el('circle',{cx:CX,cy:CY,r:12,'class':'pulse'}));
  /* the short E-mark sits at the accountable core — the all-light
     platform variant so it stays visible on the crimson background */
  var img=el('image',{x:CX-26,y:CY-26,width:52,height:52,'class':'core-logo'});
  img.setAttributeNS('http://www.w3.org/1999/xlink','href','assets/brand/logo-e-platform.svg?v=11');
  img.setAttribute('href','assets/brand/logo-e-platform.svg?v=11');
  core.appendChild(img);
  var ct=el('text',{x:CX,y:CY+64,'text-anchor':'middle'});
  ct.textContent='one accountable team';
  core.appendChild(ct);
  svg.appendChild(core);
  /* ambient life: the core continuously feeds every reason — small
     signal sparks flow outward along all spokes, staggered */
  var flowsG=el('g',{'class':'flows','aria-hidden':'true'});
  pos.forEach(function(p,i){
    flowsG.appendChild(el('circle',{cx:EX,cy:EY,r:2.5,'class':'flow',
      style:'--dx:'+(p.x-EX).toFixed(1)+'px;--dy:'+(p.y-EY).toFixed(1)+'px;animation-delay:'+(i*0.42).toFixed(2)+'s'}));
  });
  svg.appendChild(flowsG);
  /* the signal: a bright dot the core sends out along the chosen spoke */
  var sig=el('circle',{cx:EX,cy:EY,r:4.5,'class':'sig'});
  svg.appendChild(sig);
  var kEl=document.getElementById('wmK'),tEl=document.getElementById('wmT'),pEl=document.getElementById('wmP');
  var detail=wm.querySelector('.wm-detail');
  var sigRAF=null,cur=-1;
  function pulse(i){
    if(reduce||!svg.classList.contains('go'))return;
    if(sigRAF)cancelAnimationFrame(sigRAF);
    var t0=null,dur=460,p=pos[i];
    sig.classList.add('on');
    (function step(ts){
      if(!t0)t0=ts;var k=Math.min((ts-t0)/dur,1),e=1-Math.pow(1-k,3);
      sig.setAttribute('cx',EX+(p.x-EX)*e);sig.setAttribute('cy',EY+(p.y-EY)*e);
      if(k<1){sigRAF=requestAnimationFrame(step);}
      else{sig.classList.remove('on');}
    })();
  }
  function select(i){
    if(i===cur)return;cur=i;
    nodes.forEach(function(g,k){g.classList.toggle('on',k===i);});
    spokes.forEach(function(s,k){s.classList.toggle('on',k===i);});
    kEl.textContent=data[i].k;tEl.textContent=data[i].t;pEl.textContent=data[i].p;
    if(detail&&!reduce){detail.classList.remove('wm-anim');void detail.offsetWidth;detail.classList.add('wm-anim');}
    pulse(i);
  }
  nodes.forEach(function(g,k){g.classList.toggle('on',k===0);});
  spokes.forEach(function(s,k){s.classList.toggle('on',k===0);});
  kEl.textContent=data[0].k;tEl.textContent=data[0].t;pEl.textContent=data[0].p;cur=0;
  wm.hidden=false;
  band.classList.add('mapped');
  /* assemble on entry: spokes draw, nodes pop, first signal fires */
  if(!reduce&&'IntersectionObserver' in window){
    var io=new IntersectionObserver(function(es){
      es.forEach(function(en){
        if(!en.isIntersecting)return;io.disconnect();
        svg.classList.add('go');
        setTimeout(function(){pulse(0);},900);
      });
    },{threshold:.35});
    io.observe(svg);
  }else{svg.classList.add('go');}
})();

/* ── v9.7 · page-to-top: a floating up icon that appears once you've
   scrolled, stacked above the WhatsApp fab; hidden at top and at footer ── */
(function(){
  var reduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  var btn=document.createElement('button');
  btn.type='button';btn.className='totop';btn.setAttribute('aria-label','Back to top');
  btn.innerHTML='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 19V5m0 0-6 6m6-6 6 6"/></svg>';
  document.body.appendChild(btn);
  btn.addEventListener('click',function(){window.scrollTo({top:0,behavior:reduce?'auto':'smooth'});});
  var tick=false,atFooter=false;
  function upd(){tick=false;btn.classList.toggle('on',window.scrollY>700&&!atFooter);}
  window.addEventListener('scroll',function(){if(!tick){tick=true;requestAnimationFrame(upd);}},{passive:true});
  var ft=document.querySelector('.ft');
  if(ft&&'IntersectionObserver' in window){
    new IntersectionObserver(function(es){es.forEach(function(en){atFooter=en.isIntersecting;upd();});},{threshold:.05}).observe(ft);
  }
  upd();
})();

/* ── v9 · cookie notice: honest, once, dismissible. This site sets no
   tracking cookies — the notice says exactly that. ── */
(function(){
  var seen=false;try{seen=localStorage.getItem('ea-cc')==='1';}catch(e){}
  if(seen)return;
  var bar=document.createElement('div');
  bar.className='cc';bar.setAttribute('role','region');bar.setAttribute('aria-label','Privacy notice');
  bar.innerHTML='<p>No tracking cookies here. Your theme choice stays on your device, and fonts load from Google Fonts — that&#8217;s the whole list.</p>'+
    '<button type="button" class="btn btn-acc cc-ok">Understood</button>';
  document.body.appendChild(bar);
  requestAnimationFrame(function(){bar.classList.add('on');});
  bar.querySelector('.cc-ok').addEventListener('click',function(){
    try{localStorage.setItem('ea-cc','1');}catch(e){}
    bar.classList.remove('on');
    setTimeout(function(){bar.remove();},350);
  });
})();

/* ── v8.9 · the deal: "How the work actually lands" shuffles on every
   visit — four of six cases dealt in random order, sector chips
   reshuffled too. No-JS shows all six in authored order. ── */
(function(){
  function shuffle(a){
    for(var i=a.length-1;i>0;i--){
      var j=Math.floor(Math.random()*(i+1)),t=a[i];a[i]=a[j];a[j]=t;
    }
    return a;
  }
  var grid=document.querySelector('.cs-grid[data-deal]')||document.querySelector('.cs-grid.cs-4');
  if(grid){
    var n=parseInt(grid.getAttribute('data-deal'),10)||4;
    var cards=shuffle([].slice.call(grid.children));
    cards.forEach(function(c,i){
      grid.appendChild(c);
      c.style.display=i<n?'':'none';
    });
  }
  var chips=document.querySelector('.sxc');
  if(chips){
    var tx=chips.querySelector('.tx');
    var links=shuffle([].slice.call(chips.querySelectorAll('a:not(.tx)')));
    links.forEach(function(a){chips.appendChild(a);});
    if(tx)chips.appendChild(tx); /* the index link always deals last */
  }
})();

/* ── v8.8 · presence clocks: the offices, ticking in real local time.
   Times only — no staffed-hours claims until the client provides them. ── */
(function(){
  var els=document.querySelectorAll('.fclk i[data-tz], i.ct-clock[data-tz]');if(!els.length)return;
  function tick(){
    els.forEach(function(el){
      try{
        el.textContent=new Intl.DateTimeFormat('en-GB',
          {hour:'2-digit',minute:'2-digit',hour12:false,timeZone:el.getAttribute('data-tz')})
          .format(new Date());
      }catch(e){el.textContent='';}
    });
  }
  tick();
  setInterval(tick,30000);
})();

/* ── v8.6 · the index survey: the line drops down the Innovation Index
   and ignites each entry — Station 02's dots come alive on arrival. ── */
(function(){
  var ix=document.querySelector('.fx-ix');if(!ix)return;
  if(!('IntersectionObserver' in window)){ix.classList.add('go');return;}
  var io=new IntersectionObserver(function(es){
    es.forEach(function(en){
      if(!en.isIntersecting)return;
      io.disconnect();ix.classList.add('go');
    });
  },{threshold:.4});
  io.observe(ix);
})();

/* ── v8.1 · the branch line: Station 03 draws a metro branch across
   the case cards — one vertical drop in the left gutter, a rail above
   the cards, and a station dot stamped over each case. ── */
(function(){
  var grid=document.querySelector('.cs-grid.cs-4');if(!grid)return;
  if(window.innerWidth<=1020)return;
  var reduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  var wrap=grid.closest('.wrap');if(!wrap)return;
  var stn=wrap.querySelector('.sec-hd .stn');if(!stn)return;
  wrap.style.position='relative';
  var NS='http://www.w3.org/2000/svg';
  var svg=document.createElementNS(NS,'svg');
  svg.setAttribute('class','brl');svg.setAttribute('aria-hidden','true');
  var path=document.createElementNS(NS,'path');
  svg.appendChild(path);
  wrap.insertBefore(svg,wrap.firstChild);
  function build(){
    var w=wrap.getBoundingClientRect();
    svg.setAttribute('width',w.width);svg.setAttribute('height',w.height);
    svg.setAttribute('viewBox','0 0 '+w.width+' '+w.height);
    var pad=parseFloat(getComputedStyle(wrap).paddingLeft)||0;
    var gx=Math.max(pad-16,6);
    var h=stn.getBoundingClientRect();
    var y0=h.top-w.top+h.height/2;
    var cards=[].slice.call(grid.children).filter(function(c){return c.offsetParent!==null;});
    var pts=cards.map(function(c){var r=c.getBoundingClientRect();return r.left-w.left+r.width/2;});
    var railY=grid.getBoundingClientRect().top-w.top-14;
    path.setAttribute('d','M'+gx+' '+y0+' V'+railY+' H'+pts[pts.length-1]);
    [].slice.call(svg.querySelectorAll('circle')).forEach(function(c){c.remove();});
    pts.forEach(function(x){
      var c=document.createElementNS(NS,'circle');
      c.setAttribute('cx',x);c.setAttribute('cy',railY);c.setAttribute('r','4');
      c.setAttribute('class','brl-d');svg.appendChild(c);
    });
    var L=path.getTotalLength();
    path.style.strokeDasharray=L;
    path.style.strokeDashoffset=(reduce||svg.classList.contains('go'))?0:L;
  }
  build();
  if(!reduce&&'IntersectionObserver' in window){
    var io=new IntersectionObserver(function(es){
      es.forEach(function(en){
        if(!en.isIntersecting)return;
        io.disconnect();
        svg.classList.add('go');
        path.style.transition='stroke-dashoffset .9s cubic-bezier(.65,0,.35,1)';
        path.style.strokeDashoffset=0;
      });
    },{threshold:.3});
    io.observe(grid);
  }else{
    svg.classList.add('go');
    path.style.strokeDashoffset=0;
  }
  var rT;
  window.addEventListener('resize',function(){clearTimeout(rT);rT=setTimeout(build,180);});
})();
})();

/* ── v11.2 · contact intent router — the chips preset the enquiry subject
   and swap in a context-specific prompt, so the message lands pre-sorted. ── */
(function(){
  var form=document.querySelector('.ct-form');if(!form)return;
  var chips=form.querySelectorAll('.ct-chip');if(!chips.length)return;
  var ta=form.querySelector('textarea[name=msg]');
  chips.forEach(function(c){
    c.setAttribute('aria-pressed',c.classList.contains('on')?'true':'false');
    c.addEventListener('click',function(){
      chips.forEach(function(x){x.classList.remove('on');x.setAttribute('aria-pressed','false');});
      c.classList.add('on');c.setAttribute('aria-pressed','true');
      form.setAttribute('data-subject',c.getAttribute('data-subject')||'Consultation request');
      var hint=c.getAttribute('data-hint');
      if(ta&&hint&&!ta.value.trim())ta.setAttribute('placeholder',hint);
    });
  });
})();

/* ── v11.10 · home case modal — "Read the case" shows a short project writeup.
   Progressive enhancement: no-JS the cards still link to projects.html. ── */
(function(){
  var mod=document.getElementById('caseMod');if(!mod)return;
  var ill=document.getElementById('cmodIll'),tag=document.getElementById('cmodTag'),
      ttl=document.getElementById('cmodTitle'),txt=document.getElementById('cmodText');
  var last=null;
  function open(card){
    last=card;
    ill.innerHTML='';var svg=card.querySelector('.cs-ill-svg');if(svg)ill.appendChild(svg.cloneNode(true));
    var t=card.querySelector('.tag');tag.textContent=t?t.textContent:'';
    var b=card.querySelector('.cs-b b');ttl.textContent=b?b.textContent:'';
    txt.innerHTML=card.getAttribute('data-detail')||(card.querySelector('.cs-b>span')||{}).textContent||'';
    mod.hidden=false;document.body.style.overflow='hidden';
    var x=mod.querySelector('.cmod-x');if(x)x.focus();
  }
  function close(){mod.hidden=true;document.body.style.overflow='';if(last){try{last.focus();}catch(e){}}}
  document.querySelectorAll('.cs-ill-grid .cs[data-detail]').forEach(function(c){
    c.addEventListener('click',function(e){e.preventDefault();open(c);});
  });
  mod.querySelectorAll('[data-cmod-close]').forEach(function(el){el.addEventListener('click',close);});
  document.addEventListener('keydown',function(e){if(e.key==='Escape'&&!mod.hidden)close();});
})();


/* ── v11.15 · hero scroll-down cue → smooth scroll past the banner ── */
(function(){
  var b=document.querySelector('[data-hb-scroll]');if(!b)return;
  b.addEventListener('click',function(){
    var hb=document.querySelector('.hb'),next=hb&&hb.nextElementSibling;
    if(next)next.scrollIntoView({behavior:window.matchMedia('(prefers-reduced-motion: reduce)').matches?'auto':'smooth',block:'start'});
  });
})();


/* ── v11.26 · certifications carousel — arrows only when the certs overflow (scales as more are added) ── */
(function(){
  var car=document.querySelector('.cert-carousel');if(!car)return;
  var track=car.querySelector('.cert-track'),prev=car.querySelector('.cert-prev'),next=car.querySelector('.cert-next');
  function upd(){
    var over=track.scrollWidth-track.clientWidth>4;
    car.classList.toggle('scrollable',over);
    if(prev)prev.disabled=track.scrollLeft<=2;
    if(next)next.disabled=track.scrollLeft>=track.scrollWidth-track.clientWidth-2;
  }
  function step(dir){var card=track.querySelector('.cert-item');var w=card?card.offsetWidth+18:280;track.scrollBy({left:dir*w*(track.clientWidth>640?2:1),behavior:'smooth'});}
  if(prev)prev.addEventListener('click',function(){step(-1);});
  if(next)next.addEventListener('click',function(){step(1);});
  track.addEventListener('scroll',upd,{passive:true});
  window.addEventListener('resize',upd);
  upd();
})();
