export const mobileSource = " // Note: Mobile-only filtering, sorting and card rendering lives here so torrent table code stays focused on desktop rows.\n function mobileSortDef(){ return MOBILE_SORT_STEPS.find(x=>x.key===sortState.key && x.dir===sortState.dir) || MOBILE_SORT_STEPS.find(x=>x.key===sortState.key) || MOBILE_SORT_STEPS[0]; }\n\n function mobileSortLabel(){ const def=mobileSortDef(); return `${def.label} ${sortState.dir>0?'↑':'↓'}`; }\n\n function mobileSortSelectOptions(){\n const defs = [['name','Name'], ...COLUMN_DEFS.map(([key,label]) => [key,label])];\n const seen = new Set();\n return defs.filter(([key]) => { if(seen.has(key)) return false; seen.add(key); return SORT_KEYS.has(key); });\n }\n\n function setMobileSortValue(value){\n const [key, dir] = String(value || 'name:1').split(':');\n if(!SORT_KEYS.has(key)) return;\n sortState = {key, dir: Number(dir) < 0 ? -1 : 1};\n saveTorrentSortPreference();\n if($('tableWrap')) $('tableWrap').scrollTop = 0;\n if($('mobileList')) $('mobileList').scrollTop = 0;\n scheduleRender(true);\n }\n\n function cycleMobileSort(){\n const current=MOBILE_SORT_STEPS.findIndex(x=>x.key===sortState.key && x.dir===sortState.dir);\n const next=MOBILE_SORT_STEPS[(current+1) % MOBILE_SORT_STEPS.length];\n sortState={key:next.key, dir:next.dir};\n saveTorrentSortPreference();\n if($('tableWrap'))$('tableWrap').scrollTop=0;\n if($('mobileList'))$('mobileList').scrollTop=0;\n scheduleRender(true);\n }\n\n function setMobileFilterValue(value){\n const key=String(value||'all');\n mobileActiveFilterKey=key;\n if(key.startsWith('tracker:')){\n activeTrackerFilter=key.slice(8);\n activeFilter='all';\n }else{\n activeTrackerFilter='';\n activeFilter=key || 'all';\n }\n syncFilterButtons();\n saveActiveFilterPreference();\n if($('tableWrap'))$('tableWrap').scrollTop=0;\n if($('mobileList'))$('mobileList').scrollTop=0;\n scheduleRender(true);\n }\n\n function mobileFilterDefs(){\n const arr=trackerScopedRows();\n const defs=Object.keys(FILTER_COUNT_IDS).filter(k=>k!=='moving').map(k=>[k,k==='all'?'All':k==='downloading'?'Downloading':k==='seeding'?'Seeding':k==='paused'?'Paused':k==='checking'?'Checking':k==='error'?'With error':'Stopped',filterSummaryBucket(k).count||0]);\n const movingCount=movingFilterCount();\n if(movingCount) defs.push(['moving','Moving',movingCount]);\n const counts=new Map();\n arr.forEach(t=>labelNames(t.label).forEach(l=>counts.set(l,(counts.get(l)||0)+1)));\n [...counts.keys()].sort((a,b)=>a.localeCompare(b)).forEach(l=>defs.push([`label:${l}`,l,counts.get(l),'label']));\n defs.push(['tracker:','All trackers',torrents.size,'tracker']);\n const trackerOptions=new Map((trackerSummary.trackers||[]).map(t=>[t.domain,t]));\n // Note: Preserve the selected tracker option even when the cache has not returned it yet, so the mobile select does not jump to All trackers.\n if(activeTrackerFilter && !trackerOptions.has(activeTrackerFilter)) trackerOptions.set(activeTrackerFilter, {domain:activeTrackerFilter, count:arr.length});\n [...trackerOptions.values()].forEach(t=>defs.push([`tracker:${t.domain}`,t.domain,t.count,'tracker']));\n if(mobileSmartFiltersEnabled) SMART_VIEW_DEFS.forEach(([key,label])=>defs.push([key,label,arr.filter(t=>smartViewVisible(t,key)).length,'smart']));\n return defs;\n }\n\n function renderMobileFilters(){\n const bar=$('mobileFilterBar');\n if(!bar) return;\n const allVisible=visibleRows.length>0 && visibleRows.every(t=>selected.has(t.hash));\n const someVisible=visibleRows.some(t=>selected.has(t.hash));\n const defs=mobileFilterDefs();\n const currentSelect=$('mobileFilterSelect');\n const focused=currentSelect && document.activeElement===currentSelect;\n const sig=[focused ? 'focus' : activeFilter, activeTrackerFilter, sortState.key, sortState.dir, selected.size, allVisible ? 1 : 0, someVisible ? 1 : 0, mobileSmartFiltersEnabled ? 1 : 0, defs.map(d=>`${d[0]}:${d[2]}`).join('|')].join('::');\n if(focused) return;\n if(sig===lastMobileFiltersSignature) return;\n lastMobileFiltersSignature=sig;\n const selectedMobileKey = activeTrackerFilter ? `tracker:${activeTrackerFilter}` : (mobileActiveFilterKey === 'tracker:' ? 'tracker:' : activeFilter);\n // Note: Select exactly one mobile option; \"All\" and \"All trackers\" share the same data filter but must not both render as selected.\n const opts=defs.map(([key,label,count,type])=>{ const selectedOpt = key === selectedMobileKey; return ``; }).join('');\n const bulk=selected.size?``:'';\n // Note: Mobile sorting stays as a single cycle button while the step list covers every sortable column.\n bar.innerHTML=`