/* ==========================================================================
   APP — orchestrates the 3D world: scroll-driven arrival camera, portal
   fly-through, museum-wing halls, HUD, sound, tweaks.
   ========================================================================== */
const { useState:useS, useEffect:useE, useRef:useR } = React;

/* ---- camera keyframes along the arrival (scroll 0..1) ----
   z decreases (camera moves forward / deeper into the building).        */
const ARR = [
  { p:0.00, x:0, y:-20, z:2600, ry:0, rx:1 },   // far outside, facade framed
  { p:0.44, x:0, y:-10, z:-560, ry:0, rx:0 },   // at the doors
  { p:0.72, x:0, y:-10, z:-1000,ry:0, rx:0 },   // just inside the atrium
  { p:1.00, x:0, y:-10, z:-1200,ry:0, rx:0 },   // resting in the atrium
];
const ARR_SCROLL_VH = 520;     // length of the arrival scroll

/* The MB door's location within exterior.webp, as fractions of the image.
   Center seam at x=0.5; the round MB emblem straddles it. */
const IMG_AR = 1280/854;
const DOOR_BOX = { x0:0.404, x1:0.596, y0:0.30, y1:0.795 };

const lerp=(a,b,t)=>a+(b-a)*t;
const clamp=(v,a,b)=>Math.max(a,Math.min(b,v));
function sampleArr(p){
  p = clamp(p,0,1);
  for(let i=0;i<ARR.length-1;i++){
    const a=ARR[i], b=ARR[i+1];
    if(p>=a.p && p<=b.p){
      const t=(p-a.p)/(b.p-a.p);
      const e=t*t*(3-2*t); // smoothstep
      return { x:lerp(a.x,b.x,e), y:lerp(a.y,b.y,e), z:lerp(a.z,b.z,e), ry:lerp(a.ry,b.ry,e), rx:lerp(a.rx,b.rx,e) };
    }
  }
  return ARR[ARR.length-1];
}

const REST = (()=>{ const a=ARR[ARR.length-1]; return { x:a.x, y:a.y, z:a.z, ry:a.ry, rx:a.rx }; })();

const t = { mood:"goldcyan", grain:true };   // fixed look (Tweaks panel removed)

function App(){
  const D = window.MBDATA;

  const worldRef = useR(null);
  const extRef = useR(null);
  const extDoorRef = useR(null);
  const holoRef = useR(null);     // dedicated 2D hologram layer (outside the 3D space)
  const holoStageRef = useR(null);
  const [phase, setPhase] = useS("arrival");     // arrival → atrium → wing
  const phaseRef = useR("arrival");
  const [wing, setWing] = useS(null);            // active room object
  const [soundOn, setSoundOn] = useS(false);
  const [coord, setCoord] = useS("EXTERIOR · APPROACH");
  const [imgReady, setImgReady] = useS({});      // room.id -> true once its image is decoded
  const arrivedRef = useR(false);
  const bloomRef = useR(null);

  /* bind camera to #world */
  useE(()=>{ if(worldRef.current){ window.MBCamera.bind(worldRef.current); } },[]);

  /* tweaks → html */
  useE(()=>{ document.documentElement.dataset.mood = (t.mood==="goldcyan")?"":t.mood; },[t.mood]);

  /* loader — preload ONLY the critical arrival assets (exterior + portrait),
     then stream the 5 room images one at a time so the atrium never stalls. */
  useE(()=>{
    const critical=["assets/exterior.webp","assets/portrait.webp"];
    let left=critical.length;
    const hideLoader=()=>{ const l=document.getElementById("loader"); if(l){ l.classList.add("hide"); setTimeout(()=>l&&l.remove(),900);} };
    const done=()=>{ if(--left<=0){ hideLoader(); streamRooms(); } };
    critical.forEach(s=>{ const im=new Image(); im.onload=done; im.onerror=done; im.src=s; });
    const fb=setTimeout(()=>{ hideLoader(); streamRooms(); },3500);

    // sequential, low-priority prefetch of room images (one after another)
    function streamRooms(){
      const queue=D.rooms.filter(r=>r.img);
      let i=0;
      const next=()=>{
        if(i>=queue.length) return;
        const r=queue[i++];
        const im=new Image();
        im.decoding="async";
        im.onload=im.onerror=()=>{ setImgReady(s=>({...s,[r.id]:true})); setTimeout(next,120); };
        im.src=r.img;
      };
      next();
    }
    return ()=>clearTimeout(fb);
  },[]);

  /* sound */
  useE(()=>{ if(soundOn) window.MBAudio.enable(); else window.MBAudio.disable(); },[soundOn]);

  /* ---------- lay out the two door halves by slicing the building image ---------- */
  useE(()=>{
    const layout=()=>{
      const door=extDoorRef.current; if(!door) return;
      const vw=window.innerWidth, vh=window.innerHeight, vAR=vw/vh;
      let rW,rH,oX,oY;                                  // cover-rendered image size + offset
      if(vAR>IMG_AR){ rW=vw; rH=vw/IMG_AR; oX=0; oY=(vh-rH)/2; }
      else { rH=vh; rW=vh*IMG_AR; oY=0; oX=(vw-rW)/2; }
      const px=f=>oX+f*rW, py=f=>oY+f*rH;
      const xL=px(DOOR_BOX.x0), xR=px(DOOR_BOX.x1), xC=px(0.5);
      const yT=py(DOOR_BOX.y0), yB=py(DOOR_BOX.y1);
      const hH=yB-yT;
      const bg="url(assets/exterior.webp)";
      const place=(el,left,w)=>{
        if(!el) return;
        el.style.left=left+"px"; el.style.top=yT+"px"; el.style.width=w+"px"; el.style.height=hH+"px";
        el.style.backgroundImage=bg; el.style.backgroundSize=rW+"px "+rH+"px";
        el.style.backgroundPosition=(oX-left)+"px "+(oY-yT)+"px";
      };
      place(door.querySelector(".exd-leaf.l"), xL, xC-xL);
      place(door.querySelector(".exd-leaf.r"), xC, xR-xC);
      const light=door.querySelector(".exd-light");
      const parts=door.querySelector(".exd-particles");
      [light,parts].forEach(el=>{ if(!el) return; el.style.left=xL+"px"; el.style.top=yT+"px"; el.style.width=(xR-xL)+"px"; el.style.height=hH+"px"; });
    };
    layout();
    window.addEventListener("resize", layout);
    return ()=>window.removeEventListener("resize", layout);
  },[phase]);

  /* ---------- ARRIVAL SCROLL ENGINE ---------- */
  useE(()=>{
    phaseRef.current = phase;
    if(worldRef.current) worldRef.current.classList.toggle("in-building", phase!=="arrival");
    // pause all atrium animations whenever we're not actually standing in the atrium
    document.body.classList.toggle("anims-paused", phase!=="atrium");
    // the hologram lives on its own 2D layer — only show it in the atrium
    if(holoRef.current) holoRef.current.classList.toggle("show", phase==="atrium");
    const driver = document.getElementById("scroll-driver");
    const html = document.documentElement;
    if(phase==="arrival"){
      if(driver) driver.style.height = ARR_SCROLL_VH+"vh";   // creates scrollable height
      html.classList.remove("locked");                        // ALLOW page scroll
      arrivedRef.current=false;
    } else {
      if(driver) driver.style.height = "1px";
      html.classList.add("locked");                           // lock during atrium/wing
      window.scrollTo(0,0);
    }
  },[phase]);

  useE(()=>{
    let raf=0, ticking=false;
    const apply=()=>{
      ticking=false;
      if(phaseRef.current!=="arrival") return;
      const max=(ARR_SCROLL_VH-100)/100*window.innerHeight;
      const p=clamp(window.scrollY/Math.max(1,max),0,1);
      window.MBCamera.set(sampleArr(p));

      // building facade scales toward the entrance; stays opaque until we cross
      const baseScale = 1 + p*2.4;
      const ex=extRef.current;
      if(ex){ ex.style.transform=`scale(${baseScale.toFixed(3)})`; ex.style.opacity=String(clamp(1-(p-0.86)/0.12, 0, 1)); }

      // THE MB ENTRANCE — the building's own door halves slide apart; we pass through
      const door=extDoorRef.current;
      if(door){
        const appear = clamp((p-0.46)/0.12, 0, 1);          // door halves become active
        const open   = clamp((p-0.58)/0.24, 0, 1);          // halves slide apart
        const glow   = clamp((p-0.56)/0.30, 0, 1);          // warm light + particles behind
        const push   = 1 + clamp((p-0.84)/0.16, 0, 1)*2.8;  // camera passes through
        door.style.opacity = String(appear);
        door.style.transform = `scale(${(baseScale*push).toFixed(3)})`;   // tracks the facade scale
        door.style.setProperty("--open", open.toFixed(3));
        door.style.setProperty("--glow", glow.toFixed(3));
      }

      // keep the atrium hidden behind the facade until we actually cross the threshold
      if(worldRef.current) worldRef.current.classList.toggle("hide-interior", p<0.9);

      // title + atmosphere
      const title=document.querySelector(".arr-title");
      if(title){ title.style.opacity=String(clamp(1-p/0.34,0,1)); title.style.transform=`translateY(${-50-p*40}%)`; title.style.filter=`blur(${p*3}px)`; }
      const streaks=document.querySelector(".ext-streaks");
      if(streaks) streaks.style.opacity=String(clamp(p*1.2,0,1)*0.6);

      if(p<0.4) setCoord("EXTERIOR · APPROACH");
      else if(p<0.58) setCoord("THE GRAND DOORS");
      else if(p<0.84) setCoord("THE DOORS OPEN");
      else setCoord("CROSSING THE THRESHOLD");

      if(p>0.985 && !arrivedRef.current){ arrivedRef.current=true; setPhase("atrium"); }
    };
    const onScroll=()=>{ if(!ticking){ ticking=true; raf=requestAnimationFrame(apply); } };
    window.addEventListener("scroll", onScroll, {passive:true});
    window.addEventListener("resize", onScroll);
    apply();
    return ()=>{ cancelAnimationFrame(raf); window.removeEventListener("scroll",onScroll); window.removeEventListener("resize",onScroll); };
  },[]);

  /* ---------- ATRIUM GEOMETRY (mirrors world.jsx) ---------- */
  const ATR_R = 2150, ATR_CAMZ = -1200;
  const SLOT_AZ = { L2:57, L1:29, R1:-29, R2:-57, END:0 };
  const doorPos = (room)=>{
    const az = SLOT_AZ[room.slot]; const rad = az*Math.PI/180;
    if(room.slot==="END") return { x:0, z:ATR_CAMZ-3050, az:0 };
    return { x:-ATR_R*Math.sin(rad), z:ATR_CAMZ-ATR_R*Math.cos(rad), az };
  };

  const lookRef = useR(0);        // target look azimuth (deg)
  const openingRef = useR(false);

  /* when entering atrium, settle camera at rest + reset look */
  useE(()=>{
    if(phase==="atrium"){
      window.scrollTo(0,0);
      if(worldRef.current) worldRef.current.classList.remove("hide-interior");
      openingRef.current=false; lookRef.current=0;
      window.MBCamera.to({x:0,y:-10,z:ATR_CAMZ,ry:0,rx:0},{duration:1.1});
      setCoord("LOOK AROUND · CHOOSE A DOOR");
    }
  },[phase]);

  /* ---------- LOOK AROUND : drag / arrows / wheel rotate the camera ---------- */
  useE(()=>{
    let raf, dragging=false, lastX=0;
    const CLAMP=72;
    const onDown=(e)=>{ if(phaseRef.current!=="atrium"||openingRef.current) return; if(e.target.closest(".tweaks-panel,.hud-btn,.atrium-nav,button")) return; dragging=true; lastX=(e.touches?e.touches[0].clientX:e.clientX); document.body.style.cursor="grabbing"; };
    const onMove=(e)=>{ if(!dragging) return; const x=(e.touches?e.touches[0].clientX:e.clientX); const dx=x-lastX; lastX=x; lookRef.current=clamp(lookRef.current + dx*0.13, -CLAMP, CLAMP); };
    const onUp=()=>{ dragging=false; document.body.style.cursor=""; };
    const onWheel=(e)=>{ if(phaseRef.current!=="atrium"||openingRef.current) return; const d=Math.abs(e.deltaX)>Math.abs(e.deltaY)?e.deltaX:e.deltaY; lookRef.current=clamp(lookRef.current - d*0.06, -CLAMP, CLAMP); };
    const onKey=(e)=>{ if(phaseRef.current!=="atrium"||openingRef.current) return;
      if(e.key==="ArrowLeft")  lookRef.current=clamp(lookRef.current+11,-CLAMP,CLAMP);
      if(e.key==="ArrowRight") lookRef.current=clamp(lookRef.current-11,-CLAMP,CLAMP);
    };
    window.addEventListener("pointerdown",onDown); window.addEventListener("pointermove",onMove); window.addEventListener("pointerup",onUp);
    window.addEventListener("wheel",onWheel,{passive:true}); window.addEventListener("keydown",onKey);
    const tick=()=>{
      const c=window.MBCamera.get();
      let ny=c.ry;
      if(phaseRef.current==="atrium" && !openingRef.current){
        ny=c.ry + (lookRef.current - c.ry)*0.10;
        if(Math.abs(ny-c.ry)>0.002){ window.MBCamera.set({ry:ny}); }
        // highlight nearest + CULL doors that rotate out of view (avoids 3D singularity artifacts)
        let best=null,bd=1e9;
        D.rooms.forEach(r=>{ const az=SLOT_AZ[r.slot]; const diff=Math.abs(az-ny); if(diff<bd){bd=diff;best=r;} });
        D.rooms.forEach(r=>{
          const el=document.querySelector(`.door3d[data-portal-id="${r.id}"]`); if(!el) return;
          const off=Math.abs(SLOT_AZ[r.slot]-ny);
          el.classList.toggle("behind", off>74 && r.slot!=="END");
          el.classList.toggle("near", best && r.id===best.id && bd<16);
        });
      }
      // PARALLAX the dedicated hologram layer from the camera yaw so it feels
      // anchored at the atrium centre — but it lives on its own 2D z-plane,
      // so it can never 3D-intersect / slice through the door portals.
      if(phaseRef.current==="atrium" && holoStageRef.current){
        const rad = ny*Math.PI/180;
        const tx = Math.sin(rad) * window.innerWidth * 0.52;   // slide opposite to the turn
        const op = clamp(1.12 - Math.abs(ny)/52, 0, 1);        // fade as it nears a side door
        holoStageRef.current.style.transform = `translate(${tx.toFixed(1)}px, 5vh)`;
        holoStageRef.current.style.opacity = op.toFixed(3);
      }
      raf=requestAnimationFrame(tick);
    };
    raf=requestAnimationFrame(tick);
    return ()=>{ cancelAnimationFrame(raf); window.removeEventListener("pointerdown",onDown); window.removeEventListener("pointermove",onMove); window.removeEventListener("pointerup",onUp); window.removeEventListener("wheel",onWheel); window.removeEventListener("keydown",onKey); };
  },[]);

  /* ---------- DOOR OPEN SEQUENCE : rotate → zoom → split → light → enter ---------- */
  const openPortal = (room, el)=>{
    if(phaseRef.current!=="atrium" || openingRef.current) return;
    openingRef.current = true;
    if(soundOn) window.MBAudio.portal();
    const index = D.rooms.findIndex(r=>r.id===room.id);
    const pos = doorPos(room);
    el = el || document.querySelector(`.door3d[data-portal-id="${room.id}"]`);
    if(el) el.classList.add("arming");           // gold light intensifies
    setCoord("ENTERING · "+room.label);

    // 1) rotate the camera to face the door
    window.MBCamera.to({ ry: pos.az, rx:0 }, { duration:1.1, ease:"power2.inOut", onComplete:()=>{
      // 2) the glass doors split open
      if(el) el.classList.add("open");
      if(soundOn) setTimeout(()=>window.MBAudio.enter(), 120);
      // 3) after doors begin opening, dolly slowly THROUGH the doorway
      setTimeout(()=>{
        const rad = pos.az*Math.PI/180;
        const nx = pos.x + Math.sin(rad)*240;     // stop just inside the threshold
        const nz = pos.z + Math.cos(rad)*240;
        window.MBCamera.to({ x:nx, z:nz, ry:pos.az }, { duration:1.7, ease:"power2.in" });
        // 4) warm light blooms and fills the view as we cross in
        const bloom=bloomRef.current; const accent=`oklch(0.9 0.12 ${room.hue})`;
        if(bloom){ bloom.style.transition="opacity 1.1s ease"; bloom.style.background=`radial-gradient(circle at 50% 52%, #fff7e6 0%, ${accent} 26%, transparent 74%)`; }
        setTimeout(()=>{ if(bloom) bloom.style.opacity="1"; }, 900);
        // 5) enter the room
        setTimeout(()=>{
          setWing({ room, index });
          setPhase("wing");
          if(bloom){ bloom.style.transition="opacity 1.1s ease"; bloom.style.opacity="0"; }
        }, 1700);
      }, 650);
    }});
  };

  const exitWing = ()=>{
    if(soundOn) window.MBAudio.click();
    const bloom=bloomRef.current;
    if(bloom){ bloom.style.transition="opacity .5s"; bloom.style.background="radial-gradient(circle at 50% 50%, #fff 0%, var(--gold-hi) 18%, transparent 72%)"; bloom.style.opacity="0.92"; }
    setTimeout(()=>{
      setPhase("atrium"); setWing(null);
      document.querySelectorAll(".door3d").forEach(p=>p.classList.remove("open","arming"));
      window.MBCamera.set({x:0,y:-10,z:ATR_CAMZ,ry:0,rx:0});
      openingRef.current=false; lookRef.current=0;
      if(bloom){ bloom.style.transition="opacity .8s"; bloom.style.opacity="0"; }
    }, 420);
  };

  const backToExterior = ()=>{
    setPhase("arrival"); setWing(null);
    document.querySelectorAll(".door3d").forEach(p=>p.classList.remove("open","arming"));
    openingRef.current=false;
    requestAnimationFrame(()=>{ window.scrollTo(0,0); window.MBCamera.set(ARR[0]);
      if(extRef.current){ extRef.current.style.opacity="1"; extRef.current.style.transform="scale(1)"; }
      if(extDoorRef.current){ extDoorRef.current.style.opacity="0"; extDoorRef.current.style.setProperty("--open","0"); extDoorRef.current.style.setProperty("--glow","0"); }
    });
  };

  /* keyboard: 1-5 open wings; Esc exits */
  useE(()=>{
    const onKey=(e)=>{
      if(phaseRef.current==="wing" && e.key==="Escape"){ exitWing(); return; }
      if(phaseRef.current==="atrium"){
        const n=parseInt(e.key,10);
        if(n>=1&&n<=5){ const room=D.rooms[n-1]; openPortal(room, document.querySelector(`.door3d[data-portal-id="${room.id}"]`)); }
      }
    };
    window.addEventListener("keydown",onKey);
    return ()=>window.removeEventListener("keydown",onKey);
  },[soundOn]);

  return (
    <React.Fragment>
      <div id="skydome" />

      <div id="viewport">
        <div id="world" ref={worldRef}>
          <Atrium onPortal={openPortal} imgReady={imgReady} />
        </div>
      </div>

      {/* DEDICATED HOLOGRAM LAYER — its own 2D z-plane, never in the doors' 3D space */}
      <div id="holo-layer" ref={holoRef}>
        <div className="holo-stage" ref={holoStageRef}>
          <div className="holo-rings">
            <div className="ring spin" />
            <div className="ring r2 spin rev" />
            <div className="ring r3 spin" />
          </div>
          <div className="holo-beam" />
          <div className="holo-disc" />
          <div className="holo-particles">
            {Array.from({length:10}).map((_,i)=>(
              <i key={i} style={{ left:(8+i*9)+"%", "--d":(5.5+(i%5))+"s", "--dl":(i*0.6)+"s" }} />
            ))}
          </div>
          <div className="holo-portrait">
            <img src="assets/portrait.webp" alt="Meriem Bembli" />
            <div className="htint" />
            <div className="hscan" />
          </div>
          <div className="holo-name">
            <b>MERIEM BEMBLI</b>
            <span>Digital Twin · AI Founder</span>
          </div>
        </div>
      </div>

      {/* full-screen exterior approach layer */}
      {phase==="arrival" && <div className="ext-screen" ref={extRef} />}

      {/* THE MB ENTRANCE — the building's own door, cut into two halves that slide apart */}
      {phase==="arrival" && (
        <div className="ext-door" ref={extDoorRef}>
          <div className="exd-light" />
          <div className="exd-particles">
            {Array.from({length:14}).map((_,i)=>(
              <i key={i} style={{ left:(8+i*6.2)+"%", "--pd":(3.2+(i%5)*0.6)+"s", "--pdl":(i*0.3)+"s" }} />
            ))}
          </div>
          <div className="exd-leaf l" />
          <div className="exd-leaf r" />
        </div>
      )}

      {/* atmosphere — light streaks only during the approach */}
      {phase==="arrival" && (
        <div className="ext-streaks">
          {Array.from({length:10}).map((_,i)=>(
            <span key={i} className="streak" style={{ left:(6+i*9)+"%", animationDelay:(i*0.3)+"s", animationDuration:(2.8+(i%4)*0.5)+"s" }} />
          ))}
        </div>
      )}
      <div id="vignette" />
      {t.grain && <div className="grain" />}
      <div id="bloom" ref={bloomRef} />

      {/* arrival title */}
      {phase==="arrival" && (
        <div className="arr-title">
          <div className="eyebrow">Headquarters · Est. 2023</div>
          <h1>MERIEM<br/><span className="amp">BEMBLI</span></h1>
          <div className="tagline">{D.identity.taglineParts.map((s,i)=>(<span key={i}>{s}</span>))}</div>
          <div className="arr-cta">
            {window.CVActions ? React.createElement(window.CVActions, { source:"cv_download_hero" }) : null}
          </div>
        </div>
      )}

      {/* HUD */}
      <div id="hud">
        <div className="hud-brand">
          <div className="hud-seal">{D.identity.initials}</div>
          <div className="hud-name">MERIEM BEMBLI<small>HEADQUARTERS</small></div>
        </div>
        <div className="hud-tools">
          {phase!=="arrival" && (
            <button className="hud-btn" title="Back to exterior" onClick={backToExterior}>
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M3 12h13M9 6l-6 6 6 6M21 5v14"/></svg>
            </button>
          )}
          <button className="hud-btn" title={soundOn?"Mute":"Sound"} onClick={()=>{ const n=!soundOn; setSoundOn(n); if(n) setTimeout(()=>window.MBAudio.click(),80); }}>
            {soundOn
              ? <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M11 5L6 9H3v6h3l5 4V5z"/><path d="M16 9a4 4 0 010 6M19 7a8 8 0 010 10"/></svg>
              : <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M11 5L6 9H3v6h3l5 4V5z"/><path d="M22 9l-6 6M16 9l6 6"/></svg>}
          </button>
        </div>
        <div className="hud-coord">{coord}</div>
        {phase==="arrival" && <button className="skip-intro" onClick={()=>{ const max=(ARR_SCROLL_VH-100)/100*window.innerHeight; window.scrollTo({top:max,behavior:"smooth"}); }}>Skip to atrium ▸</button>}
        {phase==="atrium" && (
          <React.Fragment>
            <div className="look-hint"><span className="lh-arrow">‹</span><span>drag &nbsp;·&nbsp; ← → &nbsp;·&nbsp; click a door to enter</span><span className="lh-arrow">›</span></div>
            <nav className="atrium-nav">
              {D.rooms.map((r,i)=>(
                <button key={r.id} style={{ "--rh":r.hue }} onClick={()=>openPortal(r, document.querySelector(`.door3d[data-portal-id="${r.id}"]`))}>
                  <span className="dot" /> {r.sub}
                </button>
              ))}
            </nav>
          </React.Fragment>
        )}
      </div>

      {phase==="wing" && wing && (
        <Wing room={wing.room} index={wing.index} onExit={exitWing} />
      )}
    </React.Fragment>
  );
}

/* =====================================================================
   FAILSAFE — never crash, never blank. If the 3D world throws (WebKit
   memory pressure, GPU compositing, etc.) we drop to the 2D showroom.
   ===================================================================== */
class ErrorBoundary extends React.Component{
  constructor(p){ super(p); this.state={ failed:false }; }
  static getDerivedStateFromError(){ return { failed:true }; }
  componentDidCatch(err){ try{ console.warn("[failsafe] 3D world error → 2D showroom:", err); document.documentElement.classList.add("is-mobile"); }catch(e){} }
  render(){
    if(this.state.failed){
      const Fallback = window.MobileApp;
      return Fallback ? React.createElement(Fallback) : React.createElement("div",{style:{padding:"40px",color:"#efe6d6",fontFamily:"sans-serif"}},"Meriem Bembli — Headquarters");
    }
    return this.props.children;
  }
}

/* Route: phones / small / low-memory devices → elegant 2D showroom (never
   mounts the heavy 3D stack). Desktop → full cinematic 3D, wrapped in the
   failsafe so any runtime error degrades gracefully instead of crashing. */
function Root(){
  if(window.MB_MOBILE && window.MobileApp){ return React.createElement(window.MobileApp); }
  return React.createElement(ErrorBoundary, null, React.createElement(App));
}

ReactDOM.createRoot(document.getElementById("root")).render(<Root/>);
