/* Curio — Scan Tab, Museum Map, Visit Planner, Object Catalog */
const {useState:usePMState, useEffect:usePMEffect, useRef:usePMRef, useCallback:usePMCallback} = React;

function MapNavLegend({de, showObjects}){
  return <div className="cu-map-legend">
    <span><i style={{background:'#34C759'}}></i>{de?'Erledigt':'Done'}</span>
    <span><i style={{background:'var(--ink)',clipPath:'polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%)',borderRadius:0}}></i>{de?'Nächster Stop':'Next stop'}</span>
    <span><i style={{background:'rgba(255,255,255,.85)',boxShadow:'inset 0 0 0 1px #C5C0D8'}}></i>{de?'Kommend':'Upcoming'}</span>
    {showObjects&&<span><i style={{background:'#E0B25A'}}></i>{de?'Highlight':'Highlight'}</span>}
  </div>;
}

function MapPinDetail({pin, q, lang, nav, onClose, de, prog}){
  const L=v=>pick(v,lang);
  if(!pin||!q) return null;
  const stop=pin.type==='stop'?q.stops[pin.index]:null;
  const obj=pin.type==='object'?pin.obj:null;
  const activeIdx=prog?(prog.completed?q.stops.length:prog.stop):-1;
  const isActive=pin.type==='stop'&&pin.index===activeIdx&&!(prog&&prog.completed);
  const title=stop?L(stop):obj?L(obj.name):'';
  const where=stop&&stop.where?L(stop.where):null;
  const img=stop?stop.img:obj?obj.img:null;
  const look=stop&&stop.look?L(stop.look):obj&&obj.blurb?L(obj.blurb):null;
  return <div className="cu-map-pin-detail cu-rise">
    <div style={{display:'flex',gap:12,alignItems:'flex-start',marginBottom:12}}>
      {img&&<Thumb src={img} alt="" size={64} radius={12}/>}
      <div style={{flex:1,minWidth:0}}>
        <div style={{display:'flex',alignItems:'center',gap:8,marginBottom:4}}>
          {isActive&&<Chip label={de?'Nächster Stop':'Next stop'} kind="ink"/>}
          {pin.type==='object'&&<Chip label={de?'Highlight':'Highlight'} kind="gold"/>}
        </div>
        <div style={{color:T.text,fontSize:fz(16),fontWeight:800,fontFamily:F,lineHeight:1.25}}>{title}</div>
        {where&&<div style={{color:T.muted,fontSize:fz(13),fontFamily:F,marginTop:4,display:'flex',gap:4,alignItems:'center'}}><Ic k="location" size={13} color={T.muted}/>{where}</div>}
        {look&&<p style={{color:T.sub,fontSize:fz(13),fontFamily:F,lineHeight:1.5,margin:'8px 0 0'}}>{look}</p>}
      </div>
      <button type="button" onClick={onClose} aria-label={de?'Schließen':'Close'} className="cu-press" style={{width:32,height:32,borderRadius:16,border:'none',background:T.cardAlt,cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}><Ic k="x" size={16}/></button>
    </div>
    <div style={{display:'flex',gap:8}}>
      {stop&&nav&&<Btn label={de?'Details':'View details'} variant="secondary" sm onClick={()=>nav.push('object-detail',{questId:q.id,stopIndex:pin.index})} style={{flex:1}}/>}
      {isActive&&nav&&<Btn label={de?'Scannen':'Scan'} icon={<Ic k="scan" size={16}/>} sm onClick={()=>nav.push('ar-scan',{questId:q.id})} style={{flex:1}}/>}
      {!stop&&obj&&nav&&<Btn label={de?'Objekt ansehen':'View object'} variant="secondary" sm onClick={()=>{const si=q.stops.findIndex(s=>s.id===obj.stopId); nav.push('object-detail',{questId:q.id,stopIndex:si>=0?si:0});}} style={{flex:1}}/>}
    </div>
  </div>;
}

function NavPin({x,y,i,done,active,upcoming,selected,onSelect,de}){
  const label=i+1;
  if(active){
    return <g className="cu-map-pin" role="button" tabIndex={0} onClick={()=>onSelect({type:'stop',index:i})} onKeyDown={e=>{if(e.key==='Enter'||e.key===' ')onSelect({type:'stop',index:i});}} style={{cursor:'pointer'}}>
      <circle cx={x} cy={y} r={7} fill="rgba(109,90,208,.18)"><animate attributeName="r" values="5;9;5" dur="2s" repeatCount="indefinite"/></circle>
      <path d={`M${x} ${y-5.5} L${x+3.8} ${y+1.2} L${x} ${y+5.5} L${x-3.8} ${y+1.2} Z`} fill="var(--ink)" stroke="#fff" strokeWidth={1.3} filter={selected?'url(#pinGlow)':undefined}/>
      <text x={x} y={y+1.4} textAnchor="middle" fontSize={2.8} fill="#fff" fontFamily="system-ui" fontWeight="800">{label}</text>
    </g>;
  }
  const col=done?'#34C759':upcoming?'rgba(255,255,255,.88)':'#C5C0D8';
  const tc=done?'#fff':upcoming?'#5746B3':'#fff';
  return <g className="cu-map-pin" role="button" tabIndex={0} onClick={()=>onSelect({type:'stop',index:i})} onKeyDown={e=>{if(e.key==='Enter'||e.key===' ')onSelect({type:'stop',index:i});}} style={{cursor:'pointer',opacity:selected?1:done?0.85:0.72}}>
    <circle cx={x} cy={y} r={done?3.4:3} fill={col} stroke="#fff" strokeWidth={1.1}/>
    {!done&&<text x={x} y={y+1.1} textAnchor="middle" fontSize={2.4} fill={tc} fontFamily="system-ui" fontWeight="800">{label}</text>}
    {done&&<text x={x} y={y+1.2} textAnchor="middle" fontSize={2.2} fill="#fff" fontFamily="system-ui" fontWeight="800">✓</text>}
  </g>;
}

/* Golestan Palace complex map — uses Figma-sourced floor plan image */
function GolestanMapContent({q, prog, lang, nav, hideStops, compact, showObjects, nextLabel, interactive, hideNext}){
  const L = v => pick(v, lang);
  const de = lang === 'de';
  const isInteractive = interactive !== false && !!nav;
  const [selectedPin, setSelectedPin] = usePMState(null);
  const activeIdx = prog ? (prog.completed ? (q ? q.stops.length : -1) : prog.stop) : -1;
  const PINS = q ? q.stops.map((s,i)=>({
    si:i,
    x:[72,44,54,28,40][i]||50,
    y:[22,34,52,44,68][i]||50,
    label:L(s).split('(')[0].trim(),
  })) : [];
  const you = PINS.find(p=>p.si===activeIdx) || PINS[0];
  const nextStop = q && activeIdx >= 0 && activeIdx < q.stops.length ? q.stops[activeIdx] : null;
  const objects = showObjects && q ? window.DATA.objectsForQuest(q.id) : [];

  function handlePinSelect(pin){
    if(!isInteractive) return;
    setSelectedPin(p=>p&&p.type===pin.type&&p.index===pin.index&&(!pin.obj||p.obj?.id===pin.obj?.id)?null:pin);
  }

  return (
    <div>
      {isInteractive&&<MapNavLegend de={de} showObjects={showObjects&&objects.length>0}/>}
      {nextStop && !hideNext && (
        <div style={{padding: compact ? '0 0 12px' : `0 ${SP.safe}px 12px`}}>
          <div style={{padding:'12px 14px', borderRadius:14, background:tint(8), border:`1.5px solid ${tint(24)}`, display:'flex', gap:12, alignItems:'center'}}>
            <span style={{width:36,height:36,borderRadius:10,background:'var(--ink)',display:'inline-flex',alignItems:'center',justifyContent:'center',flexShrink:0,clipPath:'polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%)'}}><Ic k="location" size={18} color="#fff"/></span>
            <Thumb src={nextStop.img} alt="" size={48} radius={12}/>
            <div style={{flex:1, minWidth:0}}>
              <div style={{color:T.muted, fontSize:fz(11), fontWeight:800, fontFamily:F, textTransform:'uppercase', letterSpacing:'.5px', marginBottom:3}}>{nextLabel || (de?'Nächster Stop':'Next stop')}</div>
              <div style={{color:T.text, fontSize:fz(15), fontWeight:700, fontFamily:F, lineHeight:1.3}}>{L(nextStop)}</div>
              {nextStop.where && <div style={{color:T.muted, fontSize:fz(12.5), fontFamily:F, marginTop:3}}>{L(nextStop.where)}</div>}
            </div>
            {isInteractive&&nav&&<IconBtn k="chevR" onClick={()=>nav.push('object-detail',{questId:q.id,stopIndex:activeIdx})} ariaLabel={de?'Details':'Details'}/>}
          </div>
        </div>
      )}
      <div style={{padding: compact ? '0' : `0 ${SP.safe}px ${SP.sm}px`}}>
        <div style={{position:'relative', borderRadius: compact?14:20, overflow:'hidden', border:`0.5px solid ${T.line}`, boxShadow:SH}}>
          <img src="img/golestan/palace-map.jpg" alt="" style={{width:'100%', display:'block', aspectRatio:'16/10', objectFit:'cover'}}/>
          <svg viewBox="0 0 100 62" style={{position:'absolute', inset:0, width:'100%', height:'100%'}}>
            <defs><filter id="pinGlow"><feDropShadow dx="0" dy="0" stdDeviation="1.2" floodColor="#6D5AD0" floodOpacity="0.8"/></filter></defs>
            {PINS.map((p,i)=>{
              const done = i < activeIdx || (prog && prog.completed);
              const active = i === activeIdx && !(prog && prog.completed);
              const upcoming = i > activeIdx && !(prog && prog.completed);
              const sel = selectedPin?.type==='stop'&&selectedPin.index===i;
              return <NavPin key={i} x={p.x} y={p.y} i={i} done={done} active={active} upcoming={upcoming} selected={sel} onSelect={handlePinSelect} de={de}/>;
            })}
            {objects.length > 0 && objects.map(obj=>{
              const si = q.stops.findIndex(s=>s.id===obj.stopId);
              const pin = PINS[si];
              if(!pin) return null;
              const sel = selectedPin?.type==='object'&&selectedPin.obj?.id===obj.id;
              return (
                <g key={obj.id} className="cu-map-pin" role="button" tabIndex={0} onClick={()=>handlePinSelect({type:'object',index:si,obj})} style={{cursor:isInteractive?'pointer':'default'}}>
                  <circle cx={pin.x+4} cy={pin.y-4} r={sel?3.2:2.4} fill="#E0B25A" stroke="#fff" strokeWidth={0.9}/>
                </g>
              );
            })}
            {you && (
              <g>
                <circle cx={you.x} cy={you.y} r={7} fill="rgba(52,199,89,.18)"><animate attributeName="r" values="5;9;5" dur="2.2s" repeatCount="indefinite"/></circle>
                <circle cx={you.x} cy={you.y} r={2.8} fill="#34C759" stroke="#fff" strokeWidth={1.4}/>
              </g>
            )}
          </svg>
          <div style={{position:'absolute', bottom:10, left:10, right:10, display:'flex', gap:8, flexWrap:'wrap'}}>
            <span style={{display:'inline-flex', alignItems:'center', gap:5, padding:'5px 10px', borderRadius:100, background:'rgba(255,255,255,.82)', backdropFilter:GLASS_SOFT, WebkitBackdropFilter:GLASS_SOFT, border:'1px solid rgba(255,255,255,.6)', fontSize:fz(11), fontWeight:700, fontFamily:F, color:T.text}}>
              <span style={{width:8, height:8, borderRadius:'50%', background:'#34C759', boxShadow:'0 0 0 2px rgba(52,199,89,.3)'}}></span>
              {de?'Dein Standort':'Your location'}
            </span>
            {q && prog && <span style={{display:'inline-flex', alignItems:'center', gap:5, padding:'5px 10px', borderRadius:100, background:'rgba(255,255,255,.82)', backdropFilter:GLASS_SOFT, WebkitBackdropFilter:GLASS_SOFT, border:'1px solid rgba(255,255,255,.6)', fontSize:fz(11), fontWeight:700, fontFamily:F, color:T.text}}>
              {Math.min(activeIdx+1, prog.total)}/{prog.total} {de?'Stops':'stops'}
            </span>}
            {showObjects && objects.length > 0 && <span style={{display:'inline-flex', alignItems:'center', gap:5, padding:'5px 10px', borderRadius:100, background:'rgba(251,241,222,.92)', border:'1px solid rgba(234,206,155,.55)', fontSize:fz(11), fontWeight:700, fontFamily:F, color:T.gold}}>
              <span style={{width:8, height:8, borderRadius:'50%', background:'#E0B25A'}}></span>
              {de?'Highlights':'Highlights'}
            </span>}
          </div>
        </div>
      </div>
      {isInteractive&&selectedPin&&<MapPinDetail pin={selectedPin} q={q} lang={lang} nav={nav} onClose={()=>setSelectedPin(null)} de={de} prog={prog}/>}
      {showObjects && objects.length > 0 && !hideStops && (
        <div style={{padding:`0 ${SP.safe}px 12px`}}>
          <div style={{color:T.muted, fontSize:fz(11), fontWeight:800, fontFamily:F, textTransform:'uppercase', letterSpacing:'.5px', marginBottom:8}}>{de?'Wichtige Objekte':'Important objects'}</div>
          <div style={{display:'flex', gap:8, flexWrap:'wrap'}}>
            {objects.map(obj=><Chip key={obj.id} label={`${obj.emoji} ${L(obj.name)}`} kind="gold"/>)}
          </div>
        </div>
      )}
      {q && !hideStops && !compact && (
        <>
          <div style={{padding:`${SP.md}px ${SP.safe}px ${SP.sm}px`}}>
            <h2 style={{color:T.text, fontSize:fz(17), fontWeight:700, fontFamily:FD, margin:0}}>{L(q.title)}</h2>
          </div>
          <div style={{padding:`0 ${SP.safe}px`, display:'flex', flexDirection:'column', gap:10}}>
            {q.stops.map((stop,i)=>{
              const done = i < activeIdx || (prog && prog.completed);
              const active = i === activeIdx && !(prog && prog.completed);
              const Row = nav ? 'button' : 'div';
              return (
                <Row key={i} type={nav?'button':undefined} onClick={nav?()=>nav.push('object-detail',{questId:q.id,stopIndex:i}):undefined} className={nav?'cu-press':undefined} style={{display:'flex', gap:12, alignItems:'center', padding:'14px 16px', borderRadius:14, background:active?tint(8):T.card, border:`0.5px solid ${active?tint(36):T.line}`, boxShadow:SH, width:'100%', textAlign:'left', cursor:nav?'pointer':'default'}}>
                  <Thumb src={stop.img} alt="" size={44} radius={12}/>
                  <div style={{flex:1, minWidth:0}}>
                    <div style={{color:active?T.text:T.sub, fontSize:fz(15), fontWeight:active?700:500, fontFamily:F}}>{L(stop)}</div>
                    {stop.where && active && <div style={{color:T.muted, fontSize:fz(13), fontFamily:F, marginTop:4, display:'flex', gap:4, alignItems:'center'}}><Ic k="location" size={12} color={T.muted}/>{L(stop.where)}</div>}
                  </div>
                  {done ? <Ic k="check" size={18} color={T.green} stroke={2.5}/> : active ? <Chip label={de?'Jetzt':'Now'} kind="ink"/> : nav ? <Ic k="chevR" size={16} color={T.muted}/> : null}
                </Row>
              );
            })}
          </div>
          <Gap n={24}/>
        </>
      )}
    </div>
  );
}

function MuseumMapContent({q, prog, lang, nav, hideStops, compact, showObjects, nextLabel, interactive, hideNext}){
  if (q && q.id === 'golestan') return <GolestanMapContent q={q} prog={prog} lang={lang} nav={nav} hideStops={hideStops} compact={compact} showObjects={showObjects} nextLabel={nextLabel} interactive={interactive} hideNext={hideNext}/>;
  const L = v => pick(v, lang);
  const de = lang === 'de';
  const isInteractive = interactive !== false && !!nav;
  const [floor, setFloor] = usePMState(0);
  const [selectedPin, setSelectedPin] = usePMState(null);

  const FLOORS = [
    { label: de?'EG':'Ground', rooms:[
      {x:4,  y:6,  w:42, h:24, name:de?'Kraft-\nmaschinen':'Power\nMachinery', si:0},
      {x:4,  y:32, w:28, h:17, name:de?'Schiff-\nfahrt':'Marine\nNav.', si:2},
      {x:34, y:32, w:12, h:17, name:de?'Energie\n(\u2193)':'Energy\n(\u2193)', si:null},
      {x:48, y:6,  w:28, h:20, name:de?'Aus-\nstellungen':'Exhibits', si:null},
      {x:48, y:28, w:28, h:21, name:de?'Werk-\nst\u00e4tten':'Work-\nshops', si:null},
      {x:78, y:6,  w:18, h:43, name:de?'Wissen-\nschaft':'Science\nWing', si:null},
    ]},
    { label: de?'1.OG':'1st Fl.', rooms:[
      {x:4,  y:6,  w:42, h:24, name:de?'Luft-\nfahrt':'Aviation\nGallery', si:3},
      {x:4,  y:32, w:28, h:17, name:de?'Physik':'Physics', si:null},
      {x:34, y:32, w:12, h:17, name:de?'Chemie':'Chem.', si:null},
      {x:48, y:6,  w:28, h:20, name:de?'Instru-\nmente':'Instru-\nments', si:null},
      {x:48, y:28, w:28, h:21, name:de?'Technik':'Tech.', si:null},
      {x:78, y:6,  w:18, h:43, name:de?'Ostfl\u00fcgel':'East\nWing', si:null},
    ]},
    { label: de?'OG':'Top', rooms:[
      {x:4,  y:6,  w:42, h:24, name:de?'Astro-\nnomie':'Astro-\nnomy', si:4},
      {x:4,  y:32, w:28, h:17, name:de?'Biblio-\nthek':'Library', si:null},
      {x:34, y:32, w:62, h:17, name:de?'Dach-\nterrasse':'Rooftop\nTerrace', si:null},
      {x:48, y:6,  w:48, h:24, name:de?'Plane-\ntarium':'Plane-\ntarium', si:null},
    ]},
  ];

  const activeIdx = prog ? (prog.completed ? (q ? q.stops.length : -1) : prog.stop) : -1;
  const nextStop = q && activeIdx >= 0 && activeIdx < q.stops.length ? q.stops[activeIdx] : null;
  const objects = showObjects && q ? window.DATA.objectsForQuest(q.id) : [];

  function stopColor(si){
    if (si === null || si === undefined || !q) return null;
    if (prog && prog.completed) return '#34C759';
    if (si < activeIdx) return '#34C759';
    if (si === activeIdx) return 'var(--ink)';
    return '#C5C0D8';
  }

  function handlePinSelect(pin){
    if(!isInteractive) return;
    setSelectedPin(p=>p&&p.type===pin.type&&p.index===pin.index?null:pin);
    if(pin.type==='stop'&&pin.index!=null&&FLOORS.some(f=>f.rooms.some(r=>r.si===pin.index))){
      const fi=FLOORS.findIndex(f=>f.rooms.some(r=>r.si===pin.index));
      if(fi>=0) setFloor(fi);
    }
  }

  return (
    <div>
      {isInteractive&&<MapNavLegend de={de} showObjects={showObjects&&objects.length>0}/>}
      {nextStop && !hideNext && (
        <div style={{padding:`0 ${SP.safe}px 12px`}}>
          <div style={{padding:'12px 14px', borderRadius:14, background:tint(8), border:`1.5px solid ${tint(24)}`, display:'flex', gap:12, alignItems:'center'}}>
            <span style={{width:36,height:36,borderRadius:10,background:'var(--ink)',display:'inline-flex',alignItems:'center',justifyContent:'center',flexShrink:0,clipPath:'polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%)'}}><Ic k="location" size={18} color="#fff"/></span>
            <Thumb src={nextStop.img} alt="" size={48} radius={12}/>
            <div style={{flex:1, minWidth:0}}>
              <div style={{color:T.muted, fontSize:fz(11), fontWeight:800, fontFamily:F, textTransform:'uppercase', letterSpacing:'.5px', marginBottom:3}}>{nextLabel || (de?'Nächster Stop':'Next stop')}</div>
              <div style={{color:T.text, fontSize:fz(15), fontWeight:700, fontFamily:F, lineHeight:1.3}}>{L(nextStop)}</div>
              {nextStop.where && <div style={{color:T.muted, fontSize:fz(12.5), fontFamily:F, marginTop:3}}>{L(nextStop.where)}</div>}
            </div>
            {isInteractive&&nav&&<IconBtn k="chevR" onClick={()=>nav.push('object-detail',{questId:q.id,stopIndex:activeIdx})} ariaLabel={de?'Details':'Details'}/>}
          </div>
        </div>
      )}
      <div style={{padding:`0 ${SP.safe}px ${SP.md}px`}}>
        <div style={{display:'flex', background:T.cardAlt, borderRadius:12, padding:3, gap:3}}>
          {FLOORS.map((f,i) => (
            <button key={i} type="button" onClick={()=>setFloor(i)} className="cu-press" style={{flex:1, minHeight:38, border:'none', borderRadius:9, background:i===floor?T.card:'transparent', cursor:'pointer', color:i===floor?T.text:T.muted, fontSize:fz(13), fontWeight:600, fontFamily:F, boxShadow:i===floor?SH:'none', transition:`all .18s ${EASE}`}}>{f.label}</button>
          ))}
        </div>
      </div>

      <div style={{padding:`0 ${SP.safe}px ${SP.md}px`}}>
        <div style={{borderRadius:20, background:'#EDEAF6', border:`0.5px solid ${T.line}`, overflow:'hidden', boxShadow:SH}}>
          <svg viewBox="0 0 100 52" style={{width:'100%', display:'block'}}>
            <rect x={0} y={0} width={100} height={52} fill="#EDEAF6"/>
            <rect x={2} y={3} width={96} height={47} rx={2} fill="#F8F7FC" stroke="#D0CCE6" strokeWidth={0.5}/>
            <line x1={46} y1={3} x2={46} y2={50} stroke="#D0CCE6" strokeWidth={0.4} strokeDasharray="2,2"/>
            <line x1={76} y1={3} x2={76} y2={50} stroke="#D0CCE6" strokeWidth={0.4} strokeDasharray="2,2"/>
            {FLOORS[floor].rooms.map((r,i) => {
              const col = stopColor(r.si);
              const isActive = r.si === activeIdx && q && !(prog && prog.completed);
              const isDone = col === '#34C759';
              const isStop = r.si != null;
              const sel = selectedPin?.type==='stop'&&selectedPin.index===r.si;
              return (
                <g key={i} className={isStop&&isInteractive?'cu-map-pin':undefined} role={isStop&&isInteractive?'button':undefined} tabIndex={isStop&&isInteractive?0:undefined} onClick={isStop&&isInteractive?()=>handlePinSelect({type:'stop',index:r.si}):undefined} style={{cursor:isStop&&isInteractive?'pointer':'default'}}>
                  <rect x={r.x} y={r.y} width={r.w} height={r.h} rx={2}
                    fill={isActive?'rgba(109,90,208,.11)':isDone?'rgba(52,199,89,.07)':sel?'rgba(109,90,208,.08)':'#F3F1FA'}
                    stroke={isActive?'rgba(109,90,208,.5)':isDone?'rgba(52,199,89,.35)':sel?'rgba(109,90,208,.4)':'#CCC8E4'}
                    strokeWidth={isActive?.9:.5}/>
                  {r.name.split('\n').map((line,li,arr) => (
                    <text key={li} x={r.x+r.w/2} y={r.y+r.h/2+(li-(arr.length-1)/2)*4}
                      textAnchor="middle" fontSize={2.7}
                      fill={isActive?'#5746B3':isDone?'#187A48':'#8B8499'}
                      fontFamily="system-ui" fontWeight={col?'700':'400'}>{line}</text>
                  ))}
                  {col && isActive ? (
                    <g>
                      <circle cx={r.x+r.w-5} cy={r.y+5.5} r={5} fill="rgba(109,90,208,.18)"><animate attributeName="r" values="3.5;6;3.5" dur="2s" repeatCount="indefinite"/></circle>
                      <path d={`M${r.x+r.w-5} ${r.y+2} L${r.x+r.w-1.2} ${r.y+6.5} L${r.x+r.w-5} ${r.y+10} L${r.x+r.w-8.8} ${r.y+6.5} Z`} fill="var(--ink)" stroke="#fff" strokeWidth={0.9}/>
                      <text x={r.x+r.w-5} y={r.y+7.2} textAnchor="middle" fontSize={2.6} fill="#fff" fontFamily="system-ui" fontWeight="800">{(r.si||0)+1}</text>
                    </g>
                  ) : col ? (
                    <g>
                      <circle cx={r.x+r.w-5} cy={r.y+5.5} r={3.6} fill={col}/>
                      <text x={r.x+r.w-5} y={r.y+7.1} textAnchor="middle" fontSize={2.8} fill="#fff" fontFamily="system-ui" fontWeight="800">{isDone?'✓':(r.si||0)+1}</text>
                    </g>
                  ) : null}
                </g>
              );
            })}
            {showObjects && objects.length > 0 && objects.map(obj=>{
              const si = q.stops.findIndex(s=>s.id===obj.stopId);
              const room = FLOORS.flatMap(f=>f.rooms).find(r=>r.si===si);
              if(!room) return null;
              return (
                <g key={obj.id}>
                  <circle cx={room.x+room.w-3} cy={room.y+3} r={2.2} fill="#E0B25A" stroke="#fff" strokeWidth={0.8}/>
                </g>
              );
            })}
            {floor === 0 && (
              <g>
                <circle cx={25} cy={18} r={6} fill="rgba(109,90,208,.13)">
                  <animate attributeName="r" values="4;8;4" dur="2s" repeatCount="indefinite"/>
                </circle>
                <circle cx={25} cy={18} r={2.6} fill="var(--ink)" stroke="white" strokeWidth={1.2}/>
              </g>
            )}
          </svg>
        </div>
      </div>
      {isInteractive&&selectedPin&&q&&<MapPinDetail pin={selectedPin} q={q} lang={lang} nav={nav} onClose={()=>setSelectedPin(null)} de={de} prog={prog}/>}
      {showObjects && objects.length > 0 && !hideStops && (
        <div style={{padding:`0 ${SP.safe}px 12px`}}>
          <div style={{color:T.muted, fontSize:fz(11), fontWeight:800, fontFamily:F, textTransform:'uppercase', letterSpacing:'.5px', marginBottom:8}}>{de?'Wichtige Objekte':'Important objects'}</div>
          <div style={{display:'flex', gap:8, flexWrap:'wrap'}}>
            {objects.map(obj=><Chip key={obj.id} label={`${obj.emoji} ${L(obj.name)}`} kind="gold"/>)}
          </div>
        </div>
      )}

      {q ? (<>
        {!hideStops && <>
        <div style={{padding:`${SP.md}px ${SP.safe}px ${SP.sm}px`, display:'flex', justifyContent:'space-between', alignItems:'center'}}>
          <h2 style={{color:T.text, fontSize:fz(17), fontWeight:700, fontFamily:FD, margin:0}}>{L(q.title)}</h2>
          <Chip label={`${Math.min(activeIdx, prog.total)}/${prog.total}`} kind="ink"/>
        </div>
        <div style={{padding:`0 ${SP.safe}px`, display:'flex', flexDirection:'column', gap:10}}>
          {q.stops.map((stop,i) => {
            const done = i < activeIdx || (prog && prog.completed);
            const active = i === activeIdx && !(prog && prog.completed);
            const Row = nav ? 'button' : 'div';
            return (
              <Row key={i} type={nav?'button':undefined} onClick={nav?()=>nav.push('object-detail',{questId:q.id,stopIndex:i}):undefined} className={nav?'cu-press':undefined} style={{display:'flex', gap:12, alignItems:'center', padding:'14px 16px', borderRadius:14, background:active?tint(8):T.card, border:`0.5px solid ${active?tint(36):T.line}`, boxShadow:SH, width:'100%', textAlign:'left', cursor:nav?'pointer':'default'}}>
                <div style={{width:28, height:28, borderRadius:'50%', flexShrink:0, display:'flex', alignItems:'center', justifyContent:'center', background:active?'var(--ink)':done?T.greenBg:T.cardAlt, color:active?'#fff':done?T.green:T.muted, fontSize:fz(12), fontWeight:700, fontFamily:F}}>{done?'✓':i+1}</div>
                <div style={{flex:1, minWidth:0}}>
                  <div style={{color:active?T.text:T.sub, fontSize:fz(15), fontWeight:active?700:500, fontFamily:F}}>{L(stop)}</div>
                  {stop.where && active && <div style={{color:T.muted, fontSize:fz(13), fontFamily:F, marginTop:4, display:'flex', gap:4, alignItems:'center'}}><Ic k="location" size={12} color={T.muted}/>{L(stop.where)}</div>}
                </div>
                {active ? <Chip label={de?'Jetzt':'Now'} kind="ink"/> : nav ? <Ic k="chevR" size={16} color={T.muted}/> : null}
              </Row>
            );
          })}
        </div>
        <Gap n={32}/>
        </>}
      </>) : (
        <div style={{padding:`0 ${SP.safe}px`}}>
          <div style={{padding:20, borderRadius:16, background:tint(8), border:`0.5px solid ${tint(24)}`, textAlign:'center', marginTop:SP.md}}>
            <p style={{color:'var(--ink-deep)', fontSize:fz(15), fontFamily:F, margin:'0 0 16px', lineHeight:1.55}}>{de?'Starte eine Quest, um deine Stops auf der Karte zu sehen.':'Start a quest to see your stops on the map.'}</p>
            {nav && <Btn label={de?'Quests erkunden':'Explore quests'} sm onClick={()=>nav.goTab('explore')}/>}
          </div>
          <Gap n={32}/>
        </div>
      )}
    </div>
  );
}

/* ── Google-Maps-style bottom sheet ──
   Three snap points (peek / half / full). Peek height auto-fits the header +
   footer, drag the grabber or header with velocity snapping, body scrolls at
   half/full. A floating glass pill above the sheet toggles the map — the same
   sheet + FAB pattern Google Maps uses. */
function ScanSheet({detent, onDetentChange, header, mapSection, expandedSection, footer, fabLabel, navBelow=true, mapTitle}){
  const hostRef = usePMRef(null);
  const handleRef = usePMRef(null);
  const headRef = usePMRef(null);
  const footRef = usePMRef(null);
  const dragRef = usePMRef(null);
  const suppressTap = usePMRef(false);
  const [dragH, setDragH] = usePMState(null);
  const [boxH, setBoxH] = usePMState(()=> typeof window !== 'undefined' ? Math.round(window.innerHeight * 0.72) : 560);
  const [peekH, setPeekH] = usePMState(224);

  usePMEffect(()=>{
    function measure(){
      const p = hostRef.current && hostRef.current.parentElement;
      if (p && p.clientHeight) setBoxH(p.clientHeight);
      const hh = (handleRef.current?.offsetHeight||24) + (headRef.current?.offsetHeight||110) + (footRef.current?.offsetHeight||0) + 2;
      setPeekH(prev => Math.abs(prev-hh) > 1 ? hh : prev);
    }
    measure();
    window.addEventListener('resize', measure);
    return ()=> window.removeEventListener('resize', measure);
  });

  const D = {
    peek: Math.min(peekH, Math.round(boxH * 0.55)),
    half: Math.max(Math.min(Math.round(boxH * 0.62), 560), Math.min(peekH, Math.round(boxH*0.55)) + 120),
    full: Math.round(boxH * 0.92),
  };
  const restH = D[detent] || D.peek;
  const dragging = !!(dragRef.current && dragRef.current.active);
  const h = dragH != null ? dragH : restH;
  /* continuous content reveal, tracks the finger during a drag */
  const revealMap = Math.max(0, Math.min(1, (h - D.peek) / Math.max(1, D.half - D.peek)));

  function clampRubber(raw){
    if (raw < D.peek) return D.peek - (D.peek - raw) * 0.25;
    if (raw > D.full) return D.full + (raw - D.full) * 0.15;
    return raw;
  }
  function startDrag(e){
    const y = e.touches ? e.touches[0].clientY : e.clientY;
    /* start from the rendered height so grabbing mid-animation doesn't jump */
    const liveH = hostRef.current ? hostRef.current.offsetHeight : restH;
    dragRef.current = {active:true, moved:false, startY:y, lastY:y, lastT:performance.now(), startH:liveH, curH:liveH, vy:0};
  }
  function moveDrag(e){
    const d = dragRef.current;
    if (!d || !d.active) return;
    const y = e.touches ? e.touches[0].clientY : e.clientY;
    const now = performance.now();
    const dt = Math.max(1, now - d.lastT);
    d.vy = d.vy * 0.4 + (((d.lastY - y) / dt) * 1000) * 0.6;
    d.lastY = y; d.lastT = now;
    const dy = d.startY - y;
    if (Math.abs(dy) > 6) d.moved = true;
    if (d.moved){
      d.curH = clampRubber(d.startH + dy);
      setDragH(d.curH);
    }
  }
  function endDrag(){
    const d = dragRef.current;
    if (!d || !d.active) return;
    d.active = false;
    dragRef.current = null;
    if (!d.moved){ setDragH(null); return; }
    suppressTap.current = true;
    setTimeout(()=>{ suppressTap.current = false; }, 80);
    /* project momentum, snap to the closest detent */
    const projected = d.curH + d.vy * 0.18;
    let best = 'peek', bestDist = Infinity;
    ['peek','half','full'].forEach(k=>{
      const dist = Math.abs(D[k] - projected);
      if (dist < bestDist){ best = k; bestDist = dist; }
    });
    setDragH(null);
    if (best !== detent) onDetentChange(best);
  }
  function handleTap(){
    if (suppressTap.current) return;
    onDetentChange(detent==='peek' ? 'half' : detent==='half' ? 'full' : 'peek');
  }

  usePMEffect(()=>{
    function mm(e){ moveDrag(e); }
    function mu(){ endDrag(); }
    window.addEventListener('mousemove', mm);
    window.addEventListener('mouseup', mu);
    window.addEventListener('touchend', mu);
    window.addEventListener('touchcancel', mu);
    return ()=>{
      window.removeEventListener('mousemove', mm);
      window.removeEventListener('mouseup', mu);
      window.removeEventListener('touchend', mu);
      window.removeEventListener('touchcancel', mu);
    };
  });

  const de = (window.__curioLang||'en') === 'de';
  return (
    <div ref={hostRef} className="cu-scan-sheet" style={{
      position:'absolute', left:0, right:0, bottom:0, zIndex:10,
      height:h,
      display:'flex', flexDirection:'column',
      background:'rgba(252,251,255,.66)',
      borderTop:'1px solid rgba(255,255,255,.65)',
      borderRadius:'22px 22px 0 0',
      boxShadow:'0 -10px 40px rgba(11,8,20,.25)',
      transition: dragging ? 'none' : `height .32s ${EASE}`,
      willChange:'height',
      overflow:'visible',
    }}>
      {fabLabel && mapSection && detent !== 'full' && (
        <button type="button" onClick={()=>onDetentChange(detent==='peek'?'half':'peek')} className="cu-press" style={{
          position:'absolute', top:-54, right:14, zIndex:11,
          display:'inline-flex', alignItems:'center', gap:6, padding:'0 15px', minHeight:42,
          borderRadius:100, border:'1px solid rgba(255,255,255,.6)',
          background:'rgba(252,251,255,.88)', backdropFilter:GLASS, WebkitBackdropFilter:GLASS,
          boxShadow:SHmd, color:T.text, fontSize:fz(13), fontWeight:700, fontFamily:F, cursor:'pointer',
        }}>
          <Ic k={detent==='peek'?'map':'chevD'} size={16} color="var(--ink-deep)"/>
          {detent==='peek' ? fabLabel : (de?'Karte schließen':'Hide map')}
        </button>
      )}
      <div ref={handleRef} role="button" tabIndex={0}
        aria-label={detent==='peek' ? (de?'Karte aufziehen':'Pull up for map') : (de?'Einklappen':'Collapse sheet')}
        onMouseDown={startDrag} onTouchStart={startDrag} onTouchMove={moveDrag}
        onClick={handleTap}
        onKeyDown={e=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); handleTap(); } }}
        style={{flexShrink:0, padding:'11px 0 7px', cursor:'grab', touchAction:'none'}}>
        <div aria-hidden="true" style={{width:38, height:5, borderRadius:5, background:'rgba(60,60,67,.3)', margin:'0 auto'}}></div>
      </div>
      <div ref={headRef} onMouseDown={startDrag} onTouchStart={startDrag} onTouchMove={moveDrag}
        style={{flexShrink:0, padding:`0 ${SP.md}px`, touchAction:'none'}}>
        {header}
      </div>
      {/* content stays mounted and reveals continuously as the sheet is dragged — no pop-in */}
      <div className="cu-scroll" style={{flex:1, minHeight:0, overflowY: detent==='peek'?'hidden':'auto', WebkitOverflowScrolling:'touch', overscrollBehavior:'contain', padding:`0 ${SP.md}px`}}>
        {mapSection && (
          <div aria-hidden={revealMap===0} style={{padding:'14px 0 4px', opacity:0.1+0.9*revealMap, transform:`translateY(${(1-revealMap)*10}px)`, transition:dragging?'none':`opacity .3s ${EASE}, transform .3s ${EASE}`, pointerEvents:revealMap>0.5?'auto':'none'}}>
            {mapTitle && <div style={{color:T.muted, fontSize:fz(11), fontWeight:800, fontFamily:F, textTransform:'uppercase', letterSpacing:'.5px', margin:'0 2px 10px'}}>{mapTitle}</div>}
            {mapSection}
          </div>
        )}
        {expandedSection && (
          <div aria-hidden={revealMap===0} style={{padding:'10px 0 16px', opacity:0.1+0.9*revealMap, transform:`translateY(${(1-revealMap)*10}px)`, transition:dragging?'none':`opacity .3s ${EASE}, transform .3s ${EASE}`, pointerEvents:revealMap>0.5?'auto':'none'}}>
            {expandedSection}
          </div>
        )}
      </div>
      {footer && (
        <div ref={footRef} style={{flexShrink:0, padding:`8px ${SP.md}px ${navBelow?'10px':'calc(12px + var(--cu-safe-bottom))'}`}}>
          {footer}
        </div>
      )}
    </div>
  );
}

function MapOverlay({q, prog, lang, nav, onClose}){
  const de = lang === 'de';
  return (
    <div style={{position:'absolute', inset:0, zIndex:88, display:'flex', flexDirection:'column', justifyContent:'flex-end', pointerEvents:'none'}}>
      <button type="button" aria-label={de?'Schlie\u00dfen':'Close'} onClick={onClose} style={{position:'absolute', inset:0, background:'rgba(11,8,20,.45)', backdropFilter:'blur(3px)', WebkitBackdropFilter:'blur(3px)', border:'none', cursor:'pointer', pointerEvents:'auto'}}></button>
      <div className="cu-map-in" style={{position:'relative', maxHeight:'88%', background:T.card, backdropFilter:GLASS, WebkitBackdropFilter:GLASS, borderRadius:'24px 24px 0 0', borderTop:'1px solid rgba(255,255,255,.65)', boxShadow:'0 -16px 48px rgba(11,8,20,.28)', overflow:'hidden', display:'flex', flexDirection:'column', pointerEvents:'auto'}}>
        <div style={{flexShrink:0, borderBottom:`0.5px solid ${T.line}`}}>
          <div aria-hidden="true" style={{width:44, height:5, borderRadius:5, background:T.lineMd, margin:'12px auto 8px'}}></div>
          <div style={{display:'flex', alignItems:'center', gap:4, padding:`4px ${SP.safe}px 14px`}}>
            <h1 style={{color:T.text, fontSize:fz(17), fontWeight:700, fontFamily:FD, margin:0, flex:1}}>{de?'Museumsplan':'Museum Map'}</h1>
            {q && <Chip label={`${Math.min(prog&&prog.stop||0, prog&&prog.total||0)}/${prog&&prog.total||0}`} kind="ink"/>}
            <button type="button" onClick={onClose} aria-label={de?'Schlie\u00dfen':'Close'} className="cu-press" style={{width:40, height:40, borderRadius:20, background:tintGlass(12), border:`1px solid ${T.lineMd}`, color:T.text, cursor:'pointer', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0}}>
              <Ic k="x" size={20}/>
            </button>
          </div>
        </div>
        <div style={{flex:1, overflowY:'auto', paddingBottom:16}}>
          <MuseumMapContent q={q} prog={prog} lang={lang} nav={nav}/>
        </div>
        <div style={{flexShrink:0, padding:`12px ${SP.safe}px max(16px, env(safe-area-inset-bottom))`, borderTop:`0.5px solid ${T.line}`, background:'rgba(255,255,255,.55)', backdropFilter:GLASS_SOFT, WebkitBackdropFilter:GLASS_SOFT}}>
          <Btn label={de?'Zur\u00fcck zum Scannen':'Back to scan'} icon={<Ic k="scan" size={18}/>} onClick={onClose}/>
        </div>
      </div>
    </div>
  );
}

/* ── SCAN TAB ── camera-first; map + item list live in the snap-point sheet.
   Three modes: quest (next quest stop), visit (next planned stop), and free
   scan — no session, just scannable objects near your (simulated) location. */
function ScanTabScreen(){
  const {lang, state, nav, t, actions} = useApp();
  window.__curioLang = lang;
  const L = v => pick(v, lang);
  const de = lang === 'de';

  const [found, setFound] = usePMState(false);
  const [detent, setDetent] = usePMState('peek');
  const [showHintImg, setShowHintImg] = usePMState(false);
  const [confirmEnd, setConfirmEnd] = usePMState(false);

  const q = state.activeQuestId ? window.DATA.questById(state.activeQuestId) : null;
  const prog = q ? (state.questProgress[q.id] || {stop:0, total:q.stops.length}) : null;
  const inQuest = !!(q && prog && !prog.completed && prog.stop < q.stops.length);
  const visit = !inQuest ? state.activeVisit : null;
  const vq = visit ? window.DATA.questById(visit.questId) : null;
  const inVisit = !!(visit && vq && (visit.currentStop||0) < visit.stops.length);
  const vCur = inVisit ? Math.min(visit.currentStop||0, visit.stops.length-1) : 0;
  const vStop = inVisit ? visit.stops[vCur] : null;
  const vQuestStop = inVisit ? vq.stops[vCur] : null;

  const activeStop = inQuest ? q.stops[Math.min(prog.stop, q.stops.length-1)] : null;

  /* free mode — scannable objects near you, sorted by (simulated) distance */
  const nearby = (!inQuest && !inVisit) ? window.DATA.QUESTS.flatMap((qq,qi)=>
    qq.stops.map((s,i)=>({q:qq, stop:s, stopIndex:i, dist: qi===0 ? (15+i*40) : (420+i*90)}))
  ).sort((a,b)=>a.dist-b.dist) : [];
  const nearest = nearby[0];
  const distLabel = d => d>=1000 ? `${(d/1000).toFixed(1)} km` : `${d} m`;

  const hintImg = inQuest ? activeStop?.img : inVisit ? (vQuestStop?.img||vq.img) : nearest?.stop.img;
  const hintAlt = inQuest ? L(activeStop) : inVisit ? (vStop?.name||'') : (nearest?L(nearest.stop):'');
  const fallback = hintImg || 'img/golestan/shams-hero.jpg';

  function handleFound(){
    setFound(true);
    showToast(t('niceFind'), {icon:<Ic k="check" size={15} color="#34C759"/>});
  }

  function handleReveal(){
    if (inQuest){ nav.push('clue-found', {questId:q.id}); return; }
    if (inVisit){
      if (vCur+1 >= visit.stops.length){ actions.endVisit(); showToast(de?'Besuch abgeschlossen':'Visit complete',{icon:<Ic k="check" size={15} color="#34C759"/>}); nav.goTab('home'); }
      else { actions.advanceVisitStop(); setFound(false); showToast(de?'Nächster Stop':'Next stop',{icon:<Ic k="location" size={15} color="var(--ink-deep)"/>}); }
      return;
    }
    /* free scan → identify the nearest object */
    if (nearest){
      const obj = window.DATA.OBJECTS.find(o=>o.questId===nearest.q.id && o.stopId===nearest.stop.id);
      nav.push('object-result', obj ? {objectId:obj.id} : {questId:nearest.q.id, stopIndex:nearest.stopIndex});
    } else nav.push('object-catalog');
  }

  /* header (peek) — one compact card per mode */
  const headerCard = (label, img, title, whereText) => (
    <div style={{background:'rgba(255,255,255,.5)', border:'1px solid rgba(255,255,255,.55)', borderRadius:16, padding:'12px'}}>
      <div style={{display:'flex', gap:12, alignItems:'center'}}>
        <button type="button" onClick={()=>setShowHintImg(true)} className="cu-press" style={{border:'none', padding:0, cursor:'pointer', flexShrink:0}}>
          <Thumb src={img} alt="" size={62} radius={13}/>
        </button>
        <div style={{flex:1, minWidth:0}}>
          <div style={{color:T.muted, fontSize:fz(11), fontWeight:700, fontFamily:F, textTransform:'uppercase', letterSpacing:'.4px', marginBottom:4}}>{label}</div>
          <div style={{color:T.text, fontSize:fz(15.5), fontWeight:700, fontFamily:F, lineHeight:1.25, marginBottom:4, overflow:'hidden', textOverflow:'ellipsis', display:'-webkit-box', WebkitLineClamp:2, WebkitBoxOrient:'vertical'}}>{title}</div>
          {whereText && <button type="button" onClick={()=>setDetent(d=>d==='peek'?'half':d)} style={{display:'flex', gap:4, alignItems:'center', maxWidth:'100%', border:'none', background:'transparent', padding:0, cursor:'pointer', color:'var(--ink-deep)', fontSize:fz(12.5), fontWeight:600, fontFamily:F}}>
            <Ic k="location" size={13} color="var(--ink-deep)" style={{flexShrink:0}}/><span style={{overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', textDecoration:'underline', textUnderlineOffset:2}}>{whereText}</span>
          </button>}
        </div>
      </div>
    </div>
  );

  const header = inQuest
    ? headerCard(`${t('lookForLabel')} · ${prog.stop+1}/${prog.total}`, activeStop.img, L(activeStop), activeStop.where?L(activeStop.where):null)
    : inVisit
    ? headerCard(`${de?'Nächster Stop':'Next stop'} · ${vCur+1}/${visit.stops.length}`, vQuestStop?.img||vq.img, vStop?.name||L(vQuestStop), vStop?.where||null)
    : nearest
    ? headerCard(`${de?'Nächstes Objekt':'Nearest to you'} · ${distLabel(nearest.dist)}`, nearest.stop.img, L(nearest.stop), nearest.stop.where?L(nearest.stop.where):null)
    : (
      <div style={{background:'rgba(255,255,255,.5)', border:'1px solid rgba(255,255,255,.55)', borderRadius:16, padding:'14px', textAlign:'center'}}>
        <p style={{color:T.sub, fontSize:fz(14), fontFamily:F, lineHeight:1.5, margin:0}}>{de?'Richte die Kamera auf ein Exponat.':'Point your camera at an exhibit.'}</p>
      </div>
    );

  /* map (half) */
  const mapQ = inQuest ? q : inVisit ? vq : nearest ? nearest.q : null;
  const mapProg = inQuest ? prog : inVisit ? {stop:vCur, total:visit.stops.length, completed:false} : null;
  const mapSection = mapQ ? (
    <MuseumMapContent q={mapQ} prog={mapProg} lang={lang} nav={nav} hideStops compact hideNext showObjects={!inQuest && !inVisit}/>
  ) : null;

  /* list (full) — quest stops, visit route, or everything scannable near you */
  const listRowStyle = (isCurrent, dim) => ({display:'flex', gap:10, alignItems:'center', padding:'8px 10px', borderRadius:12, border:`0.5px solid ${isCurrent?tint(32):T.line}`, background:isCurrent?tint(6):'rgba(255,255,255,.4)', opacity:dim?0.55:1, cursor:'pointer', width:'100%', textAlign:'left'});
  const listTitle = s => ({color:T.text, fontSize:fz(14), fontWeight:600, fontFamily:F, flex:1, minWidth:0, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', ...s});

  const expandedSection = inQuest ? (
    <div>
      <div style={{color:T.muted, fontSize:fz(11), fontWeight:800, fontFamily:F, textTransform:'uppercase', letterSpacing:'.5px', margin:'0 2px 10px'}}>{de?'Alle scanbaren Objekte':'All scannable objects'}</div>
      <div style={{display:'flex', flexDirection:'column', gap:8}}>
        {q.stops.map((stop,i) => (
          <button key={i} type="button" onClick={()=>nav.push('object-detail',{questId:q.id,stopIndex:i})} className="cu-press" style={listRowStyle(i===prog.stop, i<prog.stop)}>
            <Thumb src={stop.img} alt="" size={40} radius={10}/>
            <span style={listTitle({fontWeight:i===prog.stop?700:500, color:i===prog.stop?T.text:T.sub})}>{L(stop)}</span>
            {i<prog.stop && <Ic k="check" size={16} color={T.green} stroke={2.5} style={{flexShrink:0}}/>}
            {i===prog.stop && <Chip label={de?'Aktuell':'Current'} kind="ink"/>}
            {i>prog.stop && <Ic k="chevR" size={14} color={T.muted} style={{flexShrink:0}}/>}
          </button>
        ))}
      </div>
      <Btn label={de?'Quest verlassen':'Exit quest'} variant="ghost" sm icon={<Ic k="x" size={15}/>} onClick={()=>setConfirmEnd(true)} style={{marginTop:10, color:T.muted}}/>
    </div>
  ) : inVisit ? (
    <div>
      <div style={{color:T.muted, fontSize:fz(11), fontWeight:800, fontFamily:F, textTransform:'uppercase', letterSpacing:'.5px', margin:'0 2px 10px'}}>{de?'Deine Route':'Your route'}</div>
      <div style={{display:'flex', flexDirection:'column', gap:8}}>
        {visit.stops.map((stop,i) => (
          <button key={i} type="button" onClick={()=>nav.push('object-detail',{questId:vq.id,stopIndex:i})} className="cu-press" style={listRowStyle(i===vCur, i<vCur)}>
            <Thumb src={vq.stops[i]?.img||vq.img} alt="" size={40} radius={10}/>
            <span style={listTitle({fontWeight:i===vCur?700:500, color:i===vCur?T.text:T.sub})}>{stop.name}</span>
            {i<vCur && <Ic k="check" size={16} color={T.green} stroke={2.5} style={{flexShrink:0}}/>}
            {i===vCur && <Chip label={de?'Jetzt':'Now'} kind="ink"/>}
            {i>vCur && <Ic k="chevR" size={14} color={T.muted} style={{flexShrink:0}}/>}
          </button>
        ))}
      </div>
      <Btn label={de?'Besuch beenden':'End visit'} variant="ghost" sm icon={<Ic k="x" size={15}/>} onClick={()=>setConfirmEnd(true)} style={{marginTop:10, color:T.muted}}/>
    </div>
  ) : nearby.length ? (
    <div>
      <div style={{color:T.muted, fontSize:fz(11), fontWeight:800, fontFamily:F, textTransform:'uppercase', letterSpacing:'.5px', margin:'0 2px 10px'}}>{de?'Scanbar in deiner Nähe':'Scannable near you'}</div>
      <div style={{display:'flex', flexDirection:'column', gap:8}}>
        {nearby.map((it,i) => (
          <button key={it.q.id+it.stop.id} type="button" onClick={()=>nav.push('object-detail',{questId:it.q.id,stopIndex:it.stopIndex})} className="cu-press" style={listRowStyle(i===0, false)}>
            <Thumb src={it.stop.img} alt="" size={40} radius={10}/>
            <span style={{flex:1, minWidth:0}}>
              <span style={listTitle({display:'block', fontWeight:i===0?700:500})}>{L(it.stop)}</span>
              <span style={{display:'block', color:T.muted, fontSize:fz(11.5), fontFamily:F, marginTop:1, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{it.q.venue}</span>
            </span>
            <Chip label={distLabel(it.dist)} kind={i===0?'ink':'neutral'}/>
          </button>
        ))}
      </div>
    </div>
  ) : null;

  const scanFooter = !found ? (
    <Btn label={t('iFoundIt')} icon={<Ic k={inQuest||inVisit?'check':'scan'} size={18}/>} onClick={handleFound}/>
  ) : inQuest ? (
    <Btn label={t('revealClue')} variant="gold" icon={<Ic k="sparkle" size={18} fill/>} onClick={handleReveal}/>
  ) : inVisit ? (
    <Btn label={vCur+1>=visit.stops.length ? (de?'Besuch abschließen':'Finish visit') : (de?'Angekommen — weiter':'Arrived — next stop')} variant="gold" icon={<Ic k="check" size={18}/>} onClick={handleReveal}/>
  ) : (
    <Btn label={de?'Objekt identifizieren':'Identify object'} variant="gold" icon={<Ic k="sparkle" size={18} fill/>} onClick={handleReveal}/>
  );

  const topChip = inQuest ? (
    <button type="button" onClick={()=>nav.push('group-board',{questId:q.id})} style={{position:'absolute', top:'calc(8px + var(--cu-safe-top))', left:16, right:16, display:'flex', justifyContent:'center', zIndex:6, border:'none', background:'transparent', padding:0, cursor:'pointer', fontFamily:F}}>
      <Chip label={<span style={{display:'flex',alignItems:'center',gap:5,overflow:'hidden'}}><span style={{overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',maxWidth:180}}>{L(q.title)}</span><span style={{flexShrink:0,opacity:.8}}>· {prog.stop+1}/{prog.total}</span></span>} kind="goldOnDark"/>
    </button>
  ) : inVisit ? (
    <button type="button" onClick={()=>nav.push('visit-hub')} style={{position:'absolute', top:'calc(8px + var(--cu-safe-top))', left:16, right:16, display:'flex', justifyContent:'center', zIndex:6, border:'none', background:'transparent', padding:0, cursor:'pointer', fontFamily:F}}>
      <Chip label={<span style={{display:'flex',alignItems:'center',gap:5,overflow:'hidden'}}><span style={{overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',maxWidth:180}}>{vq.venue}</span><span style={{flexShrink:0,opacity:.8}}>· {vCur+1}/{visit.stops.length}</span></span>} kind="goldOnDark"/>
    </button>
  ) : nearby.length ? (
    <button type="button" onClick={()=>setDetent('full')} style={{position:'absolute', top:'calc(8px + var(--cu-safe-top))', left:16, right:16, display:'flex', justifyContent:'center', zIndex:6, border:'none', background:'transparent', padding:0, cursor:'pointer', fontFamily:F}}>
      <Chip label={`📍 ${nearby.length} ${de?'Objekte in der Nähe':'objects near you'}`} kind="onDark"/>
    </button>
  ) : null;

  return (
    <div data-screen-label="Scan" style={{flex:1, display:'flex', flexDirection:'column', position:'relative', overflow:'hidden', background:'#0B0814'}}>
      <div style={{position:'absolute', inset:0}}>
        <CameraView fallback={fallback}/>
      </div>
      <div aria-hidden="true" style={{position:'absolute', inset:0, background:'linear-gradient(180deg,rgba(11,8,20,.5),rgba(11,8,20,.12) 38%,rgba(11,8,20,.82))'}}></div>

      {topChip}

      <div aria-hidden={detent!=='peek'} style={{flex:1, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', position:'relative', zIndex:4, paddingTop:40, paddingBottom:190, opacity:detent==='peek'?1:0, transition:`opacity .25s ${EASE}`, pointerEvents:'none'}}>
        <ScanCorners size={210} sweep={!found && detent==='peek'}/>
        <p style={{color:'rgba(255,255,255,.95)', fontSize:fz(17), fontWeight:700, fontFamily:F, margin:'20px 0 6px', textAlign:'center', letterSpacing:'-0.3px'}}>
          {found ? t('objectFound') : (inQuest||inVisit ? pick({en:'Place your camera in front of this object',de:'Richte die Kamera auf dieses Objekt'}, lang) : t('pointAtArtifact'))}
        </p>
        {!found && <p style={{color:'rgba(255,255,255,.55)', fontSize:fz(14), fontFamily:F, margin:0, textAlign:'center'}}>{t('holdSteady')}</p>}
      </div>

      <ScanSheet detent={detent} onDetentChange={setDetent}
        header={header} mapSection={mapSection} expandedSection={expandedSection} footer={scanFooter}
        fabLabel={de?'Karte':'Map'} mapTitle={inQuest||inVisit ? (de?'Standort im Museum':'Where you are') : (de?'In deiner Nähe':'Near you')}/>

      {showHintImg && hintImg && <ImageViewer src={hintImg} alt={hintAlt} onClose={()=>setShowHintImg(false)}/>}

      {confirmEnd && (inQuest||inVisit) && <Sheet onClose={()=>setConfirmEnd(false)}>
        <h2 style={{color:T.text, fontSize:fz(20), fontWeight:800, fontFamily:FD, margin:'0 0 8px'}}>{inQuest ? (de?'Quest verlassen?':'Exit this quest?') : (de?'Besuch beenden?':'End this visit?')}</h2>
        <p style={{color:T.muted, fontSize:fz(14), fontFamily:F, lineHeight:1.55, margin:'0 0 20px'}}>{inQuest
          ? (de?'Dein Fortschritt bleibt gespeichert — du kannst jederzeit weitermachen.':'Your progress is saved — you can pick it up again anytime from the quest page.')
          : (de?'Dein Besuchsfortschritt geht verloren. Du kannst jederzeit einen neuen Plan erstellen.':'Your visit progress will be cleared. You can always plan a new one.')}</p>
        <div style={{display:'flex', flexDirection:'column', gap:10}}>
          {inQuest && <Btn label={de?'Quest verlassen':'Exit quest'} variant="secondary" onClick={()=>{actions.update({activeQuestId:null}); setConfirmEnd(false); setFound(false); showToast(de?'Quest pausiert':'Quest exited — progress saved');}}/>}
          {inQuest && <Btn label={de?'Fortschritt löschen & beenden':'Delete progress & exit'} variant="secondary" style={{color:'#C0392B'}} onClick={()=>{actions.update(s=>{const qp={...s.questProgress}; delete qp[q.id]; return {...s, questProgress:qp, activeQuestId:null};}); setConfirmEnd(false); setFound(false); showToast(de?'Quest gelöscht':'Quest progress deleted');}}/>}
          {inVisit && <Btn label={de?'Besuch beenden':'End visit'} variant="secondary" style={{color:'#C0392B'}} onClick={()=>{actions.endVisit(); setConfirmEnd(false); setFound(false); showToast(de?'Besuch beendet':'Visit ended');}}/>}
          <Btn label={t('cancel')} variant="tonal" onClick={()=>setConfirmEnd(false)}/>
        </div>
      </Sheet>}
    </div>
  );
}

function VisitPlannerScreen(){
  const {t, lang, state, nav, actions} = useApp();
  const L = v => pick(v, lang);
  const de = lang === 'de';
  const [minutes, setMinutes] = usePMState(120);
  const [venueId, setVenueId] = usePMState((state && state.activeQuestId) || 'golestan');
  const [step, setStep] = usePMState(0);
  const [plan, setPlan] = usePMState(null);
  const scrollRef = usePMRef(null);
  const resultRef = usePMRef(null);
  const timeOpts = [{v:30,l:'30 min'},{v:60,l:de?'1 Std.':'1 hr'},{v:90,l:de?'1,5 Std.':'1.5 hrs'},{v:120,l:de?'2 Std.':'2 hrs'},{v:180,l:de?'3+ Std.':'3+ hrs'}];
  const venues = [...new Map(window.DATA.QUESTS.map(q=>[q.id,q])).values()];

  function build(mins, vid){
    const q = window.DATA.QUESTS.find(x=>x.id===vid) || window.DATA.QUESTS[0];
    const maxStops = Math.max(1, Math.min(q.stops.length, Math.floor(mins/13)));
    const base = Math.round(mins / maxStops);
    const stops = q.stops.slice(0, maxStops).map((s,i)=>({name:L(s), where:s.where?L(s.where):null, time:Math.min(30,i===0?Math.round(base*1.15):Math.round(base*.9)), priority:i===0?'must-see':i<3?'recommended':'optional'}));
    const used = stops.reduce((a,s)=>a+s.time,0);
    return {quest:q, stops, used, buffer:Math.max(0,mins-used)};
  }

  function scrollToResult(){
    requestAnimationFrame(()=>{
      requestAnimationFrame(()=>{
        if(resultRef.current) resultRef.current.scrollIntoView({behavior:'smooth', block:'start'});
        else if(scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
      });
    });
  }

  function showPlan(mins, vid){
    const p = build(mins, vid);
    setPlan(p);
    setStep(2);
    setTimeout(scrollToResult, 80);
  }

  function pickTime(v){
    setMinutes(v);
    if(step === 0){
      setTimeout(()=>setStep(1), 220);
    } else if(step >= 1){
      showPlan(v, venueId);
    }
  }

  function pickVenue(vid){
    setVenueId(vid);
    showPlan(minutes, vid);
  }

  usePMEffect(()=>{
    if(step === 2 && plan) scrollToResult();
  }, [step, plan]);

  const PS = {'must-see':{bg:'#FBF1DE',bd:'#EACE9B',tc:T.gold,lbl:de?'Pflicht':'Must-see'},'recommended':{bg:tint(8),bd:tint(24),tc:'var(--ink-deep)',lbl:de?'Empfohlen':'Recommended'},'optional':{bg:T.cardAlt,bd:T.line,tc:T.muted,lbl:de?'Optional':'Optional'}};
  const stepLabels = [t('availableTime'), t('chooseMuseum'), t('yourPlan')];

  const footer = step === 0
    ? <Btn label={t('next')} icon={<Ic k="arrowR" size={18}/>} onClick={()=>setStep(1)}/>
    : step === 1
    ? <Btn label={t('back')} variant="secondary" onClick={()=>setStep(0)}/>
    : plan
    ? <>
        <Btn label={de?'Besuch starten':'Start visit'} onClick={()=>{actions.startVisit({quest:plan.quest,stops:plan.stops,minutes}); nav.replace('visit-hub');}} style={{flex:2}}/>
        <Btn label={de?'Katalog':'Catalog'} variant="secondary" icon={<Ic k="search" size={17}/>} onClick={()=>nav.push('object-catalog',{questId:plan.quest.id})} full={false} style={{flex:1}}/>
      </>
    : null;

  return (
    <StepShell label="Visit Planner"
      header={<><BackRow title={t('visitPlanner')}/><Gap n={8}/></>}
      footer={footer}>
      <div ref={scrollRef} style={{padding:`0 ${SP.safe}px 20px`}}>
        <p style={{color:T.muted, fontSize:fz(15), fontFamily:F, margin:'0 0 18px', lineHeight:1.6}}>{t('visitPlannerSub')}</p>
        <div style={{display:'flex', gap:8, marginBottom:22, alignItems:'center'}} aria-label="Progress">
          {stepLabels.map((lbl,i)=>(
            <React.Fragment key={lbl}>
              <div style={{flex:1, minWidth:0}}>
                <div style={{height:4, borderRadius:2, background:i<=step?'var(--ink)':T.lineMd, transition:'background .25s'}}/>
                <div style={{color:i===step?'var(--ink-deep)':T.muted, fontSize:fz(11), fontWeight:700, fontFamily:F, marginTop:6, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{i+1}. {lbl}</div>
              </div>
              {i<2&&<span style={{width:6, flexShrink:0}}/>}
            </React.Fragment>
          ))}
        </div>

        {step < 2 && <>
          {step === 0 && <>
            <h2 style={{color:T.text, fontSize:fz(17), fontWeight:700, fontFamily:FD, margin:'0 0 16px'}}>{t('availableTime')}</h2>
            <div style={{display:'flex', gap:8, marginBottom:8, flexWrap:'wrap'}}>
              {timeOpts.map(o => (<button key={o.v} type="button" onClick={()=>pickTime(o.v)} className="cu-press" style={{minHeight:44, padding:'10px 16px', borderRadius:100, border:`0.5px solid ${o.v===minutes?'var(--ink)':T.lineMd}`, background:o.v===minutes?'var(--ink)':T.card, color:o.v===minutes?'#fff':T.sub, fontSize:fz(14), fontWeight:600, fontFamily:F, cursor:'pointer'}}>{o.l}</button>))}
            </div>
          </>}

          {step === 1 && <>
            <h2 style={{color:T.text, fontSize:fz(17), fontWeight:700, fontFamily:FD, margin:'0 0 16px'}}>{t('chooseMuseum')}</h2>
            <div style={{display:'flex', flexDirection:'column', gap:10, marginBottom:16}}>
              {venues.map(v => (
                <button key={v.id} type="button" onClick={()=>pickVenue(v.id)} className="cu-press" style={{display:'flex', gap:12, alignItems:'center', padding:'14px 16px', borderRadius:14, border:`0.5px solid ${v.id===venueId?tint(40):T.line}`, background:v.id===venueId?tint(8):T.card, cursor:'pointer', textAlign:'left', boxShadow:SH}}>
                  <Thumb src={v.img} alt="" size={48} radius={12}/>
                  <div style={{flex:1, minWidth:0}}>
                    <div style={{color:T.text, fontSize:fz(15), fontWeight:700, fontFamily:F, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{v.venue}</div>
                    <div style={{color:T.muted, fontSize:fz(13), fontFamily:F, marginTop:4}}>{v.dur} min · {v.stops.length} {de?'Stops':'stops'}</div>
                  </div>
                  <Ic k="chevR" size={18} color={T.muted} style={{flexShrink:0}}/>
                </button>
              ))}
            </div>
            <p style={{color:T.muted, fontSize:fz(13), fontFamily:F, margin:0, lineHeight:1.5, textAlign:'center'}}>{de?'Tippe ein Museum — dein Plan erscheint sofort.':'Tap a museum — your plan appears instantly.'}</p>
          </>}
        </>}

        {step === 2 && plan && (
          <div ref={resultRef} style={{scrollMarginTop:12}} className="cu-rise">
            <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:16}}>
              <h2 style={{color:T.text, fontSize:fz(17), fontWeight:700, fontFamily:FD, margin:0}}>{t('yourPlan')}</h2>
              <button type="button" onClick={()=>setStep(1)} className="cu-press" style={{background:'transparent', border:'none', color:'var(--ink-deep)', fontSize:fz(13), fontWeight:700, fontFamily:F, cursor:'pointer', padding:'8px 4px'}}>{t('editPlan')}</button>
            </div>
            <div style={{padding:'16px', borderRadius:16, background:tint(8), border:`0.5px solid ${tint(24)}`, marginBottom:20, display:'flex', gap:12, alignItems:'center'}}>
              <Thumb src={plan.quest.img} alt="" size={56} radius={14}/>
              <div style={{flex:1, minWidth:0}}>
                <div style={{color:'var(--ink-deep)', fontSize:fz(15), fontWeight:700, fontFamily:F, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{L(plan.quest.title)}</div>
                <div style={{color:T.muted, fontSize:fz(13), fontFamily:F, marginTop:4}}>{plan.stops.length} {de?'Stops':'stops'} · ~{plan.used} {de?'Min.':'min'} · {minutes} {de?'geplant':'planned'}</div>
              </div>
            </div>
            <h3 style={{color:T.text, fontSize:fz(15), fontWeight:700, fontFamily:FD, margin:'0 0 10px'}}>{t('liveMap')}</h3>
            <div style={{margin:'0 -20px 22px'}}>
              <MuseumMapContent q={plan.quest} prog={{stop:0, total:plan.stops.length, completed:false}} lang={lang} nav={null} hideStops showObjects nextLabel={t('nextStop')}/>
            </div>
            <div style={{display:'flex', flexDirection:'column', gap:10}}>
              {plan.stops.map((stop,i) => { const ps=PS[stop.priority]; return (
                <button key={i} type="button" onClick={()=>nav.push('object-detail',{questId:plan.quest.id,stopIndex:i})} className="cu-press" style={{display:'flex', gap:12, padding:'14px 16px', borderRadius:14, background:ps.bg, border:`0.5px solid ${ps.bd}`, boxShadow:SH, width:'100%', textAlign:'left', cursor:'pointer'}}>
                  <div style={{width:28, height:28, borderRadius:9, flexShrink:0, display:'flex', alignItems:'center', justifyContent:'center', background:'rgba(255,255,255,.75)', color:ps.tc, fontSize:fz(13), fontWeight:700, fontFamily:F}}>{i+1}</div>
                  <div style={{flex:1, minWidth:0}}>
                    <div style={{color:T.text, fontSize:fz(15), fontWeight:700, fontFamily:F, marginBottom:4}}>{stop.name}</div>
                    {stop.where && <div style={{color:T.muted, fontSize:fz(13), fontFamily:F, marginBottom:8}}>{stop.where}</div>}
                    <Chip label={`~${stop.time} min`} kind="neutral"/>
                  </div>
                  <Ic k="chevR" size={16} color={T.muted} style={{flexShrink:0,alignSelf:'center'}}/>
                </button>);})}
            </div>
          </div>
        )}
      </div>
    </StepShell>
  );
}

function VisitHubScreen(){
  const{t,lang,state,nav,actions}=useApp();
  const L=v=>pick(v,lang);
  const de=lang==='de';
  const visit=state.activeVisit;
  const[tab,setTab]=usePMState('map');
  const[confirmEnd,setConfirmEnd]=usePMState(false);
  usePMEffect(()=>{if(!visit) nav.replace('home');},[visit]);
  if(!visit) return null;
  const q=window.DATA.questById(visit.questId);
  const cur=visit.currentStop||0;
  const total=visit.stops.length;
  const done=cur>=total;
  const prog={stop:cur,total,completed:done};
  const currentStop=q?.stops[cur];
  const visitStop=visit.stops[cur];
  const HUB_TABS=[
    {id:'map',label:de?'Karte':'Map',icon:'map'},
    {id:'route',label:de?'Route':'Route',icon:'location'},
    {id:'highlights',label:de?'Highlights':'Highlights',icon:'sparkle'},
  ];
  function handleArrived(){
    if(cur+1>=total){ actions.endVisit(); showToast(de?'Besuch abgeschlossen':'Visit complete',{icon:<Ic k="check" size={15} color="#34C759"/>}); nav.goTab('home'); }
    else{ actions.advanceVisitStop(); showToast(de?'Nächster Stop':'Next stop',{icon:<Ic k="location" size={15} color="var(--ink-deep)"/>}); }
  }
  return <div data-screen-label="Visit Hub" className="cu-step-shell">
    <div style={{flexShrink:0,padding:`calc(8px + var(--cu-safe-top)) 20px 14px`,background:T.bg,borderBottom:`1px solid ${T.line}`}}>
      <div style={{display:'flex',alignItems:'center',gap:10,marginBottom:14}}>
        <IconBtn k="arrowL" onClick={()=>nav.goTab('home')} ariaLabel={t('back')}/>
        <div style={{flex:1,minWidth:0}}>
          <div style={{color:T.text,fontSize:fz(17),fontWeight:800,fontFamily:FD,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{q?.venue||de?'Besuch':'Visit'}</div>
          <div style={{color:T.muted,fontSize:fz(12.5),fontFamily:F,marginTop:2}}>{de?'Stop':'Stop'} {Math.min(cur+1,total)}/{total} · ~{visit.minutes} {de?'Min.':'min'}</div>
        </div>
        <IconBtn k="settings" onClick={()=>setConfirmEnd(true)} ariaLabel={t('sessionSettings')}/>
      </div>
      <PBar val={total?cur/total*100:0} grad label={de?'Besuchsfortschritt':'Visit progress'}/>
    </div>
    <div style={{flexShrink:0,display:'flex',gap:6,padding:'10px 20px',background:T.bg,borderBottom:`1px solid ${T.line}`}}>
      {HUB_TABS.map(tb=><button key={tb.id} type="button" onClick={()=>setTab(tb.id)} className="cu-press" style={{flex:1,minHeight:44,borderRadius:12,border:'none',cursor:'pointer',background:tab===tb.id?tint(12):T.cardAlt,color:tab===tb.id?'var(--ink-deep)':T.muted,fontSize:fz(11.5),fontWeight:700,fontFamily:F,boxShadow:tab===tb.id?`inset 0 0 0 1.5px ${tint(32)}`:'none',display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',gap:4}}>
        <Ic k={tb.icon} size={16} color={tab===tb.id?'var(--ink-deep)':T.muted}/>
        {tb.label}
      </button>)}
    </div>
    <div className="cu-step-body" style={{background:T.bg}}>
      <div style={{padding:'20px'}}>
        {tab==='map'&&q&&<div style={{margin:'0 -20px'}}><MuseumMapContent q={q} prog={prog} lang={lang} nav={nav} hideStops showObjects nextLabel={t('nextStop')}/></div>}
        {tab==='route'&&(
          <div style={{display:'flex',flexDirection:'column',gap:10}}>
            {visit.stops.map((stop,i)=>{
              const active=i===cur&&!done;
              const completed=i<cur;
              return <button key={i} type="button" onClick={()=>nav.push('object-detail',{questId:visit.questId,stopIndex:i})} className="cu-press" style={{display:'flex',gap:12,alignItems:'center',padding:'14px 16px',borderRadius:14,background:active?tint(8):T.card,border:`0.5px solid ${active?tint(36):T.line}`,boxShadow:SH,width:'100%',textAlign:'left',cursor:'pointer',opacity:completed?0.65:1}}>
                <div style={{width:28,height:28,borderRadius:'50%',flexShrink:0,display:'flex',alignItems:'center',justifyContent:'center',background:active?'var(--ink)':completed?T.greenBg:T.cardAlt,color:active?'#fff':completed?T.green:T.muted,fontSize:fz(12),fontWeight:700,fontFamily:F}}>{completed?'✓':i+1}</div>
                <div style={{flex:1,minWidth:0}}>
                  <div style={{color:active?T.text:T.sub,fontSize:fz(15),fontWeight:active?700:500,fontFamily:F}}>{stop.name}</div>
                  {stop.where&&<div style={{color:T.muted,fontSize:fz(13),fontFamily:F,marginTop:4}}>{stop.where}</div>}
                </div>
                {active&&<Chip label={de?'Jetzt':'Now'} kind="ink"/>}
                {!active&&<Ic k="chevR" size={16} color={T.muted}/>}
              </button>;
            })}
          </div>
        )}
        {tab==='highlights'&&currentStop&&q&&(
          <Card padding="0" style={{overflow:'hidden'}}>
            <Photo src={currentStop.img||q.img} alt="" h={160} radius={0}/>
            <div style={{padding:18}}>
              <Chip label={`${de?'Stop':'Stop'} ${cur+1}/${total}`} kind="gold"/>
              <h2 style={{color:T.text,fontSize:fz(20),fontWeight:800,fontFamily:FD,margin:'12px 0 8px',lineHeight:1.25}}>{visitStop?.name||L(currentStop)}</h2>
              {visitStop?.where&&<p style={{color:T.muted,fontSize:fz(13),fontFamily:F,margin:'0 0 12px',display:'flex',gap:6,alignItems:'center'}}><Ic k="location" size={14}/>{visitStop.where}</p>}
              {currentStop.look&&<p style={{color:T.sub,fontSize:fz(14),fontFamily:F,lineHeight:1.6,margin:'0 0 16px'}}>{L(currentStop.look)}</p>}
              <Btn label={de?'Objekt ansehen':'View object'} variant="secondary" onClick={()=>nav.push('object-detail',{questId:q.id,stopIndex:cur})}/>
            </div>
          </Card>
        )}
      </div>
    </div>
    {!done&&<div className="cu-step-footer">
      <Btn label={de?'Angekommen — weiter':'Arrived — next stop'} icon={<Ic k="check" size={18}/>} onClick={handleArrived}/>
    </div>}
    {done&&<div className="cu-step-footer">
      <Btn label={de?'Besuch abschließen':'Finish visit'} variant="gold" onClick={()=>{actions.endVisit(); nav.goTab('home');}}/>
    </div>}
    {confirmEnd&&<Sheet onClose={()=>setConfirmEnd(false)}>
      <h2 style={{color:T.text,fontSize:fz(20),fontWeight:800,fontFamily:FD,margin:'0 0 8px'}}>{t('sessionSettings')}</h2>
      <p style={{color:T.muted,fontSize:fz(14),fontFamily:F,lineHeight:1.55,margin:'0 0 20px'}}>{de?'Besuch pausieren oder beenden — dein Plan bleibt gespeichert, bis du ihn löschst.':'Pause or end your visit — your plan stays saved until you delete it.'}</p>
      <div style={{display:'flex',flexDirection:'column',gap:10}}>
        <Btn label={de?'Besuch pausieren':'Pause visit'} variant="secondary" onClick={()=>{setConfirmEnd(false); showToast(de?'Besuch pausiert':'Visit paused — pick up anytime'); nav.goTab('home');}}/>
        <Btn label={de?'Besuch beenden & löschen':'End & delete visit'} variant="secondary" style={{color:'#C0392B'}} onClick={()=>{actions.endVisit(); setConfirmEnd(false); showToast(de?'Besuch beendet':'Visit ended'); nav.goTab('home');}}/>
        <Btn label={t('cancel')} variant="tonal" onClick={()=>setConfirmEnd(false)}/>
      </div>
    </Sheet>}
  </div>;
}

Object.assign(window, {MuseumMapContent, MapOverlay, ScanSheet, ScanTabScreen, VisitPlannerScreen, VisitHubScreen});
