{"id":4795,"date":"2026-06-01T16:10:00","date_gmt":"2026-06-01T16:10:00","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=4795"},"modified":"2026-08-08T06:30:33","modified_gmt":"2026-08-08T06:30:33","slug":"free-offline-smart-file-organizer","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/free-offline-smart-file-organizer\/","title":{"rendered":"Free offline smart file organizer &amp; Zip Studio | 100% Offline"},"content":{"rendered":"<div class=\"pth-hero-section\">\n<div class=\"pth-hero-content\">\n<h2>Free Smart File Organizer &#038; Zip Studio | 100% Offline<\/h2>\n<p>Auto-sort, preview, and organize your files with our free offline smart file organizer and zip studio. Create virtual folders and download as a ZIP securely.<\/p>\n<div id=\"pth-toc-placeholder\"><\/div>\n<\/p>\n<\/div>\n<div class=\"pth-hero-image\">\n        <img decoding=\"async\" data-no-lazy=\"1\" width=\"450\" height=\"253\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/06\/offline-smart-file-organizer-800x447.jpeg\" alt=\"offline smart file organizer\">\n    <\/div>\n<\/div>\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#\ud83d\udfe7-memory-allocation-and-cpu-efficiency\">\ud83d\udfe7 Memory Allocation and CPU Efficiency<\/a><ul><li><a href=\"#\ud83d\udfe8-cryptographic-duplicate-detection-and-parsing\">\ud83d\udfe8 Cryptographic Duplicate Detection and Parsing<\/a><\/li><li><a href=\"#\ud83d\udfe9-expanding-your-technical-toolkit\">\ud83d\udfe9 Expanding Your Technical Toolkit<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n\n\n<style>\r\n\/* ========================================================\r\n   MASTER CODE SKELETON - SCOPED CSS\r\n======================================================== *\/\r\n#pth-smartfileorg-wrapper { font-family: 'Inter', system-ui, sans-serif; max-width: 1500px; margin: 0 auto; box-sizing: border-box; background: #f8fafc; padding: 20px; border-radius: 16px; color: #0f172a; }\r\n#pth-smartfileorg-wrapper * { box-sizing: border-box; min-width: 0; }\r\n#pth-smartfileorg-wrapper .pth-card { background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 25px; margin-bottom: 25px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }\r\n#pth-smartfileorg-wrapper .pth-tool-title { font-size: 32px; font-weight: 800; color: #3b82f6; margin-top: 0; }\r\n#pth-smartfileorg-wrapper .pth-flex-layout { display: grid; grid-template-columns: 1.8fr 1fr; gap: 30px; align-items: start; transition: 0.3s ease; }\r\n#pth-smartfileorg-wrapper .pth-flex-layout.pth-full-width { grid-template-columns: 1fr; }\r\n#pth-smartfileorg-wrapper .pth-btn { padding: 12px 24px; border-radius: 8px; font-weight: 700; cursor: pointer; border: none; font-family: 'Inter', sans-serif; transition: 0.2s; display: inline-flex; align-items: center; justify-content: center; gap: 8px;}\r\n#pth-smartfileorg-wrapper .pth-sample-btn { background: #ecfdf5; color: #10b981; border: 1px solid #6ee7b7; font-size: 0.75rem; padding: 4px 10px; border-radius: 6px; font-weight: 700; cursor: pointer; transition: 0.2s; display: inline-flex; align-items: center; gap: 4px; }\r\n#pth-smartfileorg-wrapper .pth-sample-btn:hover { background: #d1fae5; }\r\n\r\n\/* ========================================================\r\n   TOOL SPECIFIC VARIABLES & CSS (SCOPED)\r\n======================================================== *\/\r\n#pth-smartfileorg-wrapper {\r\n  --blue: #3b82f6; --blue-dark: #2563eb; --blue-light: #eff6ff; --blue-mid: #bfdbfe;\r\n  --green: #10b981; --green-dark: #059669; --green-light: #ecfdf5;\r\n  --red: #ef4444; --red-dark: #dc2626; --red-light: #fef2f2;\r\n  --amber: #f59e0b; --amber-light: #fffbeb;\r\n  --purple: #8b5cf6; --purple-light: #f5f3ff;\r\n  --slate-50: #f8fafc; --slate-100: #f1f5f9; --slate-200: #e2e8f0;\r\n  --slate-300: #cbd5e1; --slate-400: #94a3b8; --slate-500: #64748b;\r\n  --slate-600: #475569; --slate-700: #334155; --slate-800: #1e293b; --slate-900: #0f172a;\r\n  --white: #ffffff;\r\n  --radius-sm: 6px; --radius: 10px; --radius-lg: 14px; --radius-xl: 20px;\r\n  --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);\r\n  --shadow: 0 4px 6px -1px rgba(0,0,0,0.07), 0 2px 4px -1px rgba(0,0,0,0.04);\r\n  --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -2px rgba(0,0,0,0.04);\r\n  --shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.04);\r\n}\r\n\r\n#pth-smartfileorg-wrapper .topbar { display: flex; align-items: center; justify-content: space-between; background: var(--white); border: 1px solid var(--slate-200); border-radius: var(--radius-lg); padding: 12px 20px; margin-bottom: 16px; box-shadow: var(--shadow-sm); flex-wrap: wrap; gap: 10px; }\r\n#pth-smartfileorg-wrapper .brand { display: flex; align-items: center; gap: 12px; }\r\n#pth-smartfileorg-wrapper .brand-icon { width: 42px; height: 42px; background: linear-gradient(135deg, var(--blue) 0%, var(--green) 100%); border-radius: var(--radius); display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }\r\n#pth-smartfileorg-wrapper .brand-name { font-size: 18px; font-weight: 800; color: var(--slate-900); }\r\n#pth-smartfileorg-wrapper .brand-name span { color: var(--blue); }\r\n#pth-smartfileorg-wrapper .brand-sub { font-size: 11px; color: var(--slate-400); font-weight: 500; margin-top: 1px; }\r\n#pth-smartfileorg-wrapper .topbar-actions { display: flex; gap: 8px; align-items: center; }\r\n\r\n\/* Stats Bar *\/\r\n#pth-smartfileorg-wrapper .stats-bar { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; margin-bottom: 16px; }\r\n#pth-smartfileorg-wrapper .stat-card { background: var(--white); border: 1px solid var(--slate-200); border-radius: var(--radius-lg); padding: 14px 16px; display: flex; align-items: center; gap: 12px; box-shadow: var(--shadow-sm); }\r\n#pth-smartfileorg-wrapper .stat-icon { font-size: 22px; flex-shrink: 0; }\r\n#pth-smartfileorg-wrapper .stat-value { font-size: 20px; font-weight: 800; color: var(--slate-900); line-height: 1; }\r\n#pth-smartfileorg-wrapper .stat-label { font-size: 11px; color: var(--slate-400); font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; margin-top: 2px; }\r\n\r\n\/* Tabs *\/\r\n#pth-smartfileorg-wrapper .tab-nav { display: flex; gap: 4px; background: var(--slate-100); border: 1px solid var(--slate-200); border-radius: var(--radius-lg); padding: 4px; margin-bottom: 16px; flex-wrap: wrap; }\r\n#pth-smartfileorg-wrapper .tab-btn { padding: 8px 16px; border-radius: var(--radius); border: none; background: transparent; cursor: pointer; font-weight: 600; font-size: 13px; color: var(--slate-500); transition: all 0.18s; display: flex; align-items: center; gap: 6px; font-family: 'Inter', sans-serif; }\r\n#pth-smartfileorg-wrapper .tab-btn:hover { background: var(--white); color: var(--slate-700); }\r\n#pth-smartfileorg-wrapper .tab-btn.active { background: var(--white); color: var(--blue); box-shadow: var(--shadow-sm); }\r\n#pth-smartfileorg-wrapper .tab-panel { display: none; }\r\n#pth-smartfileorg-wrapper .tab-panel.active { display: block; }\r\n\r\n\/* Buttons *\/\r\n#pth-smartfileorg-wrapper .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 8px 16px; border-radius: var(--radius); border: none; font-weight: 600; font-size: 12px; cursor: pointer; transition: all 0.18s; font-family: 'Inter', sans-serif; white-space: nowrap; }\r\n#pth-smartfileorg-wrapper .btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none !important; }\r\n#pth-smartfileorg-wrapper .btn-primary { background: var(--blue); color: var(--white); box-shadow: 0 2px 8px rgba(59,130,246,0.3); }\r\n#pth-smartfileorg-wrapper .btn-primary:hover:not(:disabled) { background: var(--blue-dark); transform: translateY(-1px); }\r\n#pth-smartfileorg-wrapper .btn-success { background: var(--green); color: var(--white); box-shadow: 0 2px 8px rgba(16,185,129,0.3); }\r\n#pth-smartfileorg-wrapper .btn-success:hover:not(:disabled) { background: var(--green-dark); transform: translateY(-1px); }\r\n#pth-smartfileorg-wrapper .btn-danger { background: var(--red-light); color: var(--red-dark); border: 1px solid #fecaca; }\r\n#pth-smartfileorg-wrapper .btn-danger:hover:not(:disabled) { background: #fee2e2; }\r\n#pth-smartfileorg-wrapper .btn-secondary { background: var(--slate-100); color: var(--slate-600); border: 1px solid var(--slate-200); }\r\n#pth-smartfileorg-wrapper .btn-secondary:hover:not(:disabled) { background: var(--slate-200); color: var(--slate-800); }\r\n#pth-smartfileorg-wrapper .btn-outline { background: transparent; color: var(--slate-600); border: 1px solid var(--slate-300); }\r\n#pth-smartfileorg-wrapper .btn-outline:hover:not(:disabled) { background: var(--slate-100); border-color: var(--slate-500); }\r\n#pth-smartfileorg-wrapper .btn-sm { padding: 5px 10px; font-size: 11px; border-radius: var(--radius-sm); }\r\n\r\n\/* Dropzone *\/\r\n#pth-smartfileorg-wrapper #dropzone { border: 2.5px dashed var(--slate-300); border-radius: var(--radius-xl); padding: 60px 40px; text-align: center; background: var(--white); transition: all 0.25s; cursor: pointer; position: relative; }\r\n#pth-smartfileorg-wrapper #dropzone:hover, #pth-smartfileorg-wrapper #dropzone.dragover { border-color: var(--blue); background: var(--blue-light); }\r\n#pth-smartfileorg-wrapper .drop-emoji { font-size: 52px; display: block; margin-bottom: 16px; }\r\n#pth-smartfileorg-wrapper .drop-title { font-size: 22px; font-weight: 800; color: var(--slate-800); margin-bottom: 8px; }\r\n#pth-smartfileorg-wrapper .drop-sub { font-size: 13px; color: var(--slate-500); line-height: 1.7; margin-bottom: 28px; max-width: 500px; margin-left: auto; margin-right: auto; }\r\n#pth-smartfileorg-wrapper .drop-btns { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-bottom: 12px; }\r\n#pth-smartfileorg-wrapper .drop-note { font-size: 11px; color: var(--red-dark); font-weight: 600; }\r\n#pth-smartfileorg-wrapper .badges { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 24px; }\r\n#pth-smartfileorg-wrapper .badge { padding: 4px 12px; border-radius: 20px; font-size: 10px; font-weight: 700; letter-spacing: 0.4px; }\r\n#pth-smartfileorg-wrapper .badge-img { background: var(--green-light); color: #065f46; border: 1px solid #a7f3d0; }\r\n#pth-smartfileorg-wrapper .badge-vid { background: var(--purple-light); color: #5b21b6; border: 1px solid #ddd6fe; }\r\n#pth-smartfileorg-wrapper .badge-doc { background: var(--red-light); color: var(--red-dark); border: 1px solid #fecaca; }\r\n#pth-smartfileorg-wrapper .badge-zip { background: var(--amber-light); color: #92400e; border: 1px solid #fde68a; }\r\n\r\n\/* Organizer Layout *\/\r\n#pth-smartfileorg-wrapper .org-layout { display: grid; grid-template-columns: 240px 1fr; gap: 16px; align-items: start; }\r\n#pth-smartfileorg-wrapper .org-layout.expanded { grid-template-columns: 1fr; }\r\n#pth-smartfileorg-wrapper .sidebar { display: flex; flex-direction: column; gap: 12px; position: sticky; top: 16px; }\r\n#pth-smartfileorg-wrapper .panel { background: var(--white); border: 1px solid var(--slate-200); border-radius: var(--radius-lg); padding: 16px; box-shadow: var(--shadow-sm); }\r\n#pth-smartfileorg-wrapper .panel-title { font-size: 10px; font-weight: 800; letter-spacing: 1px; text-transform: uppercase; color: var(--slate-400); margin-bottom: 10px; display: flex; align-items: center; justify-content: space-between; }\r\n#pth-smartfileorg-wrapper .folder-list { list-style: none; max-height: 180px; overflow-y: auto; padding-right: 4px; margin: 0; padding-left: 0; }\r\n#pth-smartfileorg-wrapper .folder-item { display: flex; align-items: center; justify-content: space-between; padding: 7px 10px; border-radius: var(--radius-sm); cursor: pointer; font-weight: 600; font-size: 12px; color: var(--slate-600); transition: all 0.15s; margin-bottom: 2px; }\r\n#pth-smartfileorg-wrapper .folder-item:hover { background: var(--slate-100); color: var(--slate-800); }\r\n#pth-smartfileorg-wrapper .folder-item.active { background: var(--blue-light); color: var(--blue-dark); border: 1px solid var(--blue-mid); }\r\n#pth-smartfileorg-wrapper .folder-item .fi-left { display: flex; align-items: center; gap: 7px; overflow: hidden; }\r\n#pth-smartfileorg-wrapper .folder-item .fi-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\r\n#pth-smartfileorg-wrapper .folder-count { background: var(--slate-200); padding: 1px 7px; border-radius: 10px; font-size: 10px; color: var(--slate-500); flex-shrink: 0; }\r\n#pth-smartfileorg-wrapper .folder-item.active .folder-count { background: var(--blue); color: var(--white); }\r\n#pth-smartfileorg-wrapper .empty-hint { font-size: 11px; color: var(--slate-400); padding: 6px 10px; }\r\n\r\n#pth-smartfileorg-wrapper .storage-bar { border-top: 1px solid var(--slate-100); margin-top: 14px; padding-top: 14px; }\r\n#pth-smartfileorg-wrapper .storage-header { display: flex; justify-content: space-between; font-size: 12px; font-weight: 600; color: var(--slate-600); margin-bottom: 6px; }\r\n#pth-smartfileorg-wrapper .progress-track { height: 6px; background: var(--slate-200); border-radius: 3px; overflow: hidden; }\r\n#pth-smartfileorg-wrapper .progress-fill { height: 100%; background: linear-gradient(90deg, var(--blue), var(--green)); border-radius: 3px; transition: width 0.5s; }\r\n\r\n\/* Smart Panel *\/\r\n#pth-smartfileorg-wrapper .smart-panel { background: linear-gradient(135deg, rgba(59,130,246,0.04), rgba(16,185,129,0.04)); border: 1px solid var(--blue-mid); border-radius: var(--radius-lg); padding: 16px 20px; margin-bottom: 16px; }\r\n#pth-smartfileorg-wrapper .smart-panel-title { font-size: 12px; font-weight: 800; color: var(--blue-dark); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 12px; }\r\n#pth-smartfileorg-wrapper .smart-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }\r\n#pth-smartfileorg-wrapper .date-range-row { display: flex; align-items: center; gap: 10px; background: var(--white); border: 1px solid var(--slate-200); padding: 7px 14px; border-radius: var(--radius-sm); margin-top: 12px; width: fit-content; }\r\n#pth-smartfileorg-wrapper .date-input { border: none; outline: none; font-size: 12px; color: var(--slate-600); font-family: 'Inter', sans-serif; background: transparent; cursor: pointer; }\r\n\r\n\/* Gallery Toolbar *\/\r\n#pth-smartfileorg-wrapper .gallery-card { background: var(--white); border: 1px solid var(--slate-200); border-radius: var(--radius-lg); padding: 18px; box-shadow: var(--shadow-sm); }\r\n#pth-smartfileorg-wrapper .toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 12px 14px; background: var(--slate-50); border: 1px solid var(--slate-200); border-radius: var(--radius); margin-bottom: 12px; }\r\n#pth-smartfileorg-wrapper .toolbar-title { font-size: 17px; font-weight: 800; color: var(--slate-900); margin-right: 8px; }\r\n#pth-smartfileorg-wrapper .divider-v { width: 1px; height: 22px; background: var(--slate-200); margin: 0 4px; }\r\n#pth-smartfileorg-wrapper .filter-bar { display: flex; gap: 6px; margin-bottom: 12px; flex-wrap: wrap; align-items: center; }\r\n#pth-smartfileorg-wrapper .filter-tag { padding: 5px 13px; border-radius: 20px; font-size: 12px; font-weight: 600; cursor: pointer; border: 1px solid var(--slate-200); color: var(--slate-500); background: var(--white); transition: all 0.15s; }\r\n#pth-smartfileorg-wrapper .filter-tag:hover { border-color: var(--slate-400); color: var(--slate-700); }\r\n#pth-smartfileorg-wrapper .filter-tag.active { background: var(--blue); color: var(--white); border-color: var(--blue); }\r\n#pth-smartfileorg-wrapper .search-box { padding: 7px 11px; border: 1px solid var(--slate-200); border-radius: var(--radius-sm); font-size: 13px; outline: none; transition: 0.18s; font-family: 'Inter', sans-serif; background: var(--white); color: var(--slate-800); }\r\n#pth-smartfileorg-wrapper .search-box:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(59,130,246,0.1); }\r\n#pth-smartfileorg-wrapper .sort-select { padding: 6px 10px; border-radius: var(--radius-sm); border: 1px solid var(--slate-200); font-size: 12px; outline: none; background: var(--white); font-weight: 600; color: var(--slate-600); font-family: 'Inter', sans-serif; cursor: pointer; }\r\n#pth-smartfileorg-wrapper .view-toggle { display: flex; background: var(--slate-200); border-radius: var(--radius-sm); padding: 3px; }\r\n#pth-smartfileorg-wrapper .view-btn { padding: 4px 9px; border: none; background: transparent; cursor: pointer; border-radius: 5px; color: var(--slate-500); font-size: 14px; transition: 0.15s; }\r\n#pth-smartfileorg-wrapper .view-btn.active { background: var(--white); box-shadow: var(--shadow-sm); color: var(--slate-800); }\r\n#pth-smartfileorg-wrapper .toolbar-right { margin-left: auto; display: flex; gap: 6px; }\r\n\r\n\/* Gallery Grid *\/\r\n#pth-smartfileorg-wrapper .gallery { display: grid; gap: 12px; max-height: 62vh; overflow-y: auto; padding-right: 6px; padding-bottom: 16px; --grid-min: 210px; --thumb-h: 145px; }\r\n#pth-smartfileorg-wrapper .gallery::-webkit-scrollbar { width: 5px; }\r\n#pth-smartfileorg-wrapper .gallery::-webkit-scrollbar-track { background: var(--slate-100); border-radius: 4px; }\r\n#pth-smartfileorg-wrapper .gallery::-webkit-scrollbar-thumb { background: var(--slate-300); border-radius: 4px; }\r\n#pth-smartfileorg-wrapper .gallery.grid-view { grid-template-columns: repeat(auto-fill, minmax(var(--grid-min), 1fr)); }\r\n#pth-smartfileorg-wrapper .gallery.list-view { grid-template-columns: 1fr; }\r\n#pth-smartfileorg-wrapper .gallery-empty { grid-column: 1 \/ -1; text-align: center; padding: 60px 20px; border: 2px dashed var(--slate-200); border-radius: var(--radius-lg); color: var(--slate-400); }\r\n\r\n\/* File Cards *\/\r\n#pth-smartfileorg-wrapper .file-card { background: var(--white); border: 1px solid var(--slate-200); border-radius: var(--radius); overflow: hidden; position: relative; transition: all 0.2s; display: flex; flex-direction: column; cursor: pointer; }\r\n#pth-smartfileorg-wrapper .file-card:hover { border-color: var(--blue); box-shadow: var(--shadow-lg); transform: translateY(-2px); }\r\n#pth-smartfileorg-wrapper .file-card.selected { border: 2px solid var(--blue); box-shadow: 0 0 0 3px rgba(59,130,246,0.12); }\r\n#pth-smartfileorg-wrapper .file-card.list-card { flex-direction: row; align-items: center; }\r\n#pth-smartfileorg-wrapper .file-card.list-card .card-preview { height: 58px; width: 76px; min-width: 76px; border-right: 1px solid var(--slate-200); border-radius: 0; }\r\n#pth-smartfileorg-wrapper .file-card.list-card .card-info { flex-grow: 1; border-top: none; display: flex; justify-content: space-between; align-items: center; padding: 0 14px; }\r\n#pth-smartfileorg-wrapper .file-card.list-card .card-checkbox { position: static; margin-left: 12px; }\r\n#pth-smartfileorg-wrapper .file-card.list-card .card-badge-dup, #pth-smartfileorg-wrapper .file-card.list-card .card-badge-date { position: static; display: inline-block; margin-left: 8px; }\r\n\r\n#pth-smartfileorg-wrapper .card-checkbox { position: absolute; top: 9px; left: 9px; width: 18px; height: 18px; z-index: 10; cursor: pointer; accent-color: var(--blue); }\r\n#pth-smartfileorg-wrapper .card-badge-dup { position: absolute; top: 7px; right: 7px; background: var(--red); color: var(--white); font-size: 9px; padding: 2px 5px; border-radius: 4px; font-weight: 800; z-index: 5; }\r\n#pth-smartfileorg-wrapper .card-badge-date { position: absolute; top: 34px; left: 9px; background: rgba(15,23,42,0.65); color: var(--white); font-size: 9px; padding: 2px 6px; border-radius: 4px; font-weight: 600; z-index: 5; backdrop-filter: blur(2px); }\r\n#pth-smartfileorg-wrapper .card-preview { height: var(--thumb-h); background: var(--slate-100); display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; }\r\n#pth-smartfileorg-wrapper .card-preview img, #pth-smartfileorg-wrapper .card-preview video { width: 100%; height: 100%; object-fit: contain; }\r\n#pth-smartfileorg-wrapper .card-icon { font-size: 40px; color: var(--slate-300); }\r\n#pth-smartfileorg-wrapper .card-info { padding: 10px 12px; font-size: 12px; border-top: 1px solid var(--slate-100); }\r\n#pth-smartfileorg-wrapper .card-name { font-weight: 700; color: var(--slate-800); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 5px; }\r\n#pth-smartfileorg-wrapper .card-meta { display: flex; justify-content: space-between; align-items: center; }\r\n#pth-smartfileorg-wrapper .card-size { color: var(--slate-400); }\r\n#pth-smartfileorg-wrapper .card-ext { font-weight: 800; text-transform: uppercase; font-size: 10px; }\r\n#pth-smartfileorg-wrapper .card-ext.img { color: var(--green-dark); }\r\n#pth-smartfileorg-wrapper .card-ext.video { color: #7c3aed; }\r\n#pth-smartfileorg-wrapper .card-ext.doc { color: var(--red-dark); }\r\n#pth-smartfileorg-wrapper .file-card .select-overlay { position: absolute; inset: 0; background: rgba(59,130,246,0.0); transition: 0.15s; pointer-events: none; border-radius: inherit; }\r\n#pth-smartfileorg-wrapper .file-card:hover .select-overlay { background: rgba(59,130,246,0.03); }\r\n\r\n\/* Tools Tab *\/\r\n#pth-smartfileorg-wrapper .tools-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }\r\n#pth-smartfileorg-wrapper .tool-section { background: var(--white); border: 1px solid var(--slate-200); border-radius: var(--radius-lg); padding: 20px; box-shadow: var(--shadow-sm); }\r\n#pth-smartfileorg-wrapper .tool-section-title { font-size: 13px; font-weight: 800; color: var(--slate-700); margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }\r\n#pth-smartfileorg-wrapper .tool-option { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }\r\n#pth-smartfileorg-wrapper .tool-option label { font-size: 13px; color: var(--slate-600); font-weight: 500; flex: 1; }\r\n#pth-smartfileorg-wrapper .tool-input { padding: 7px 10px; border: 1px solid var(--slate-200); border-radius: var(--radius-sm); font-size: 12px; font-family: 'Inter', sans-serif; outline: none; background: var(--white); color: var(--slate-800); }\r\n#pth-smartfileorg-wrapper .tool-input:focus { border-color: var(--blue); }\r\n#pth-smartfileorg-wrapper .tool-select { padding: 7px 10px; border: 1px solid var(--slate-200); border-radius: var(--radius-sm); font-size: 12px; font-family: 'Inter', sans-serif; outline: none; background: var(--white); color: var(--slate-700); cursor: pointer; }\r\n#pth-smartfileorg-wrapper .tool-result { background: var(--slate-50); border: 1px solid var(--slate-200); border-radius: var(--radius); padding: 14px; margin-top: 14px; }\r\n#pth-smartfileorg-wrapper .tool-result-title { font-size: 11px; font-weight: 700; color: var(--slate-400); text-transform: uppercase; margin-bottom: 8px; }\r\n\r\n\/* Meta Table *\/\r\n#pth-smartfileorg-wrapper .meta-table { width: 100%; border-collapse: collapse; font-size: 12px; }\r\n#pth-smartfileorg-wrapper .meta-table td { padding: 5px 8px; border-bottom: 1px solid var(--slate-100); color: var(--slate-600); }\r\n#pth-smartfileorg-wrapper .meta-table td:first-child { font-weight: 600; color: var(--slate-700); width: 40%; }\r\n\r\n\/* Modals *\/\r\n#pth-smartfileorg-wrapper .overlay { position: fixed; inset: 0; background: rgba(15,23,42,0.6); z-index: 99999; display: none; align-items: center; justify-content: center; backdrop-filter: blur(3px); }\r\n#pth-smartfileorg-wrapper .modal { background: var(--white); padding: 28px; border-radius: var(--radius-xl); width: 92%; max-width: 440px; box-shadow: var(--shadow-xl); animation: modal-in 0.2s ease; }\r\n@keyframes modal-in { from { opacity: 0; transform: scale(0.95) translateY(-10px); } to { opacity: 1; transform: scale(1) translateY(0); } }\r\n#pth-smartfileorg-wrapper .modal-title { font-size: 18px; font-weight: 800; color: var(--slate-900); margin-bottom: 6px; }\r\n#pth-smartfileorg-wrapper .modal-sub { font-size: 13px; color: var(--slate-500); margin-bottom: 16px; }\r\n#pth-smartfileorg-wrapper .modal-input { width: 100%; padding: 10px 12px; border: 1px solid var(--slate-200); border-radius: var(--radius-sm); margin: 12px 0; outline: none; font-family: 'Inter', sans-serif; font-size: 13px; color: var(--slate-800); }\r\n#pth-smartfileorg-wrapper .modal-footer { display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px; }\r\n\r\n\/* Preview Modal *\/\r\n#pth-smartfileorg-wrapper .preview-modal { background: transparent; width: 96%; max-width: 1050px; height: 88vh; display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; box-shadow: none; padding: 0; }\r\n#pth-smartfileorg-wrapper .preview-close { position: absolute; top: -44px; right: 0; background: var(--red); color: var(--white); border: none; width: 34px; height: 34px; border-radius: 50%; cursor: pointer; font-size: 16px; font-weight: 800; display: flex; align-items: center; justify-content: center; z-index: 10; }\r\n#pth-smartfileorg-wrapper .preview-nav { position: absolute; top: 50%; transform: translateY(-50%); width: 42px; height: 42px; border-radius: 50%; background: rgba(255,255,255,0.18); color: var(--white); border: none; cursor: pointer; font-size: 22px; display: flex; align-items: center; justify-content: center; z-index: 10; transition: 0.15s; backdrop-filter: blur(2px); }\r\n#pth-smartfileorg-wrapper .preview-nav:hover { background: rgba(255,255,255,0.35); }\r\n#pth-smartfileorg-wrapper .preview-prev { left: -56px; }\r\n#pth-smartfileorg-wrapper .preview-next { right: -56px; }\r\n#pth-smartfileorg-wrapper .preview-media { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column; }\r\n#pth-smartfileorg-wrapper .preview-img { max-width: 100%; max-height: 78vh; object-fit: contain; border-radius: var(--radius-lg); box-shadow: 0 24px 40px rgba(0,0,0,0.4); }\r\n#pth-smartfileorg-wrapper .preview-info { margin-top: 14px; color: rgba(255,255,255,0.7); font-size: 13px; font-weight: 500; }\r\n\r\n\/* Progress Overlay *\/\r\n#pth-smartfileorg-wrapper .progress-box { background: var(--white); border-radius: var(--radius-xl); padding: 40px; text-align: center; min-width: 300px; box-shadow: var(--shadow-xl); }\r\n#pth-smartfileorg-wrapper .spinner { width: 38px; height: 38px; border: 3px solid var(--slate-200); border-top-color: var(--blue); border-radius: 50%; animation: spin 0.9s linear infinite; margin: 0 auto 18px; }\r\n#pth-smartfileorg-wrapper .prog-bar-track { height: 6px; background: var(--slate-200); border-radius: 3px; margin-top: 16px; overflow: hidden; }\r\n#pth-smartfileorg-wrapper .prog-bar-fill { height: 100%; background: linear-gradient(90deg, var(--blue), var(--green)); border-radius: 3px; transition: width 0.3s; }\r\n\r\n\/* Toast *\/\r\n#pth-smartfileorg-wrapper .toast { position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%) translateY(12px); background: var(--slate-900); color: var(--white); padding: 11px 22px; border-radius: var(--radius); font-size: 13px; z-index: 999999; opacity: 0; transition: all 0.25s; pointer-events: none; font-weight: 600; box-shadow: var(--shadow-lg); white-space: nowrap; }\r\n#pth-smartfileorg-wrapper .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }\r\n#pth-smartfileorg-wrapper .alert-icon { font-size: 48px; margin-bottom: 10px; text-align: center; }\r\n#pth-smartfileorg-wrapper .alert-modal-content { text-align: center; }\r\n\r\n\/* Info Panel *\/\r\n#pth-smartfileorg-wrapper .info-panel { background: var(--white); border: 1px solid var(--slate-200); border-radius: var(--radius-lg); overflow: hidden; }\r\n#pth-smartfileorg-wrapper .info-panel-header { padding: 14px 16px; border-bottom: 1px solid var(--slate-200); font-weight: 700; font-size: 13px; color: var(--slate-700); background: var(--slate-50); }\r\n#pth-smartfileorg-wrapper .info-panel-body { padding: 14px 16px; max-height: 340px; overflow-y: auto; }\r\n\r\n\/* Timeline Chart *\/\r\n#pth-smartfileorg-wrapper .timeline-chart { display: flex; flex-direction: column; gap: 6px; }\r\n#pth-smartfileorg-wrapper .timeline-row { display: flex; align-items: center; gap: 10px; }\r\n#pth-smartfileorg-wrapper .timeline-label { font-size: 11px; font-weight: 600; color: var(--slate-500); width: 80px; flex-shrink: 0; text-align: right; }\r\n#pth-smartfileorg-wrapper .timeline-bar-wrap { flex: 1; background: var(--slate-100); border-radius: 4px; height: 18px; overflow: hidden; }\r\n#pth-smartfileorg-wrapper .timeline-bar { height: 100%; background: linear-gradient(90deg, var(--blue), var(--green)); border-radius: 4px; transition: width 0.5s; display: flex; align-items: center; padding-left: 8px; }\r\n#pth-smartfileorg-wrapper .timeline-count { font-size: 10px; font-weight: 700; color: var(--white); }\r\n\r\n\/* VITAL FIX: Keep inputs accessible for clicking natively (Screen Reader Only Method) *\/\r\n#pth-smartfileorg-wrapper .hidden-input { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }\r\n<\/style>\r\n\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jszip\/3.10.1\/jszip.min.js\"><\/script>\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/exif-js\/2.3.0\/exif.js\"><\/script>\r\n\r\n<div id=\"pth-smartfileorg-wrapper\">\r\n    <div class=\"pth-flex-layout pth-full-width\" id=\"pth-smartfileorg-layout\">\r\n        <div class=\"pth-main-col\">\r\n            <div class=\"pth-card\" style=\"padding: 15px 25px;\">\r\n                <div style=\"display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; flex-wrap: wrap; gap: 10px;\">\r\n                    <h2 class=\"pth-tool-title\">Smart File Organizer Pro<\/h2>\r\n                    <div style=\"display: flex; gap: 10px;\">\r\n                        <button class=\"pth-sample-btn\" id=\"pth-load-sample-btn\">\ud83d\udca1 Load Sample<\/button>\r\n                        <button class=\"pth-btn pth-btn-secondary\" id=\"pth-fw-btn-smartfileorg\" style=\"display:none;\">\u26f6 Full Width<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"topbar\">\r\n                    <div class=\"brand\">\r\n                        <div class=\"brand-icon\">\ud83d\udd27<\/div>\r\n                        <div>\r\n                            <div class=\"brand-name\">Smart File<span>Organizer<\/span> <span style=\"font-size:11px; background:linear-gradient(90deg,#3b82f6,#10b981); -webkit-background-clip:text; -webkit-text-fill-color:transparent; font-weight:800;\">PRO<\/span><\/div>\r\n                            <div class=\"brand-sub\">Professional Offline Media Suite \\u2014 100% In-Browser, Zero Upload<\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n                    <div class=\"topbar-actions\">\r\n                        <button class=\"btn btn-secondary btn-sm\" id=\"btn-expand\">\u26f6 Full Width<\/button>\r\n                        <button class=\"btn btn-danger btn-sm\" id=\"btn-restart\">\ud83d\udd04 Restart<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"stats-bar\" id=\"stats-bar\" style=\"display:none;\">\r\n                    <div class=\"stat-card\"><div class=\"stat-icon\">\ud83d\udcc1<\/div><div><div class=\"stat-value\" id=\"s-total\">0<\/div><div class=\"stat-label\">Total Files<\/div><\/div><\/div>\r\n                    <div class=\"stat-card\"><div class=\"stat-icon\">\ud83d\uddbc\ufe0f<\/div><div><div class=\"stat-value\" id=\"s-photos\">0<\/div><div class=\"stat-label\">Photos<\/div><\/div><\/div>\r\n                    <div class=\"stat-card\"><div class=\"stat-icon\">\ud83c\udfac<\/div><div><div class=\"stat-value\" id=\"s-videos\">0<\/div><div class=\"stat-label\">Videos<\/div><\/div><\/div>\r\n                    <div class=\"stat-card\"><div class=\"stat-icon\">\ud83d\udcc4<\/div><div><div class=\"stat-value\" id=\"s-docs\">0<\/div><div class=\"stat-label\">Documents<\/div><\/div><\/div>\r\n                    <div class=\"stat-card\"><div class=\"stat-icon\">\ud83d\udcbe<\/div><div><div class=\"stat-value\" id=\"s-size\">0<\/div><div class=\"stat-label\">Total Size<\/div><\/div><\/div>\r\n                    <div class=\"stat-card\"><div class=\"stat-icon\">\ud83d\uddc2\ufe0f<\/div><div><div class=\"stat-value\" id=\"s-folders\">0<\/div><div class=\"stat-label\">Folders<\/div><\/div><\/div>\r\n                    <div class=\"stat-card\"><div class=\"stat-icon\">\u26a0\ufe0f<\/div><div><div class=\"stat-value\" id=\"s-dups\">0<\/div><div class=\"stat-label\">Duplicates<\/div><\/div><\/div>\r\n                <\/div>\r\n\r\n                <div id=\"dropzone\">\r\n                    <span class=\"drop-emoji\">\ud83d\udcf2<\/span>\r\n                    <div class=\"drop-title\">Drop Your Files, Folders or ZIP Archives<\/div>\r\n                    <div class=\"drop-sub\">Works 100% offline \\u2014 your files never leave your device.<br>Supports nested folders, multiple ZIPs, batch rename, and EXIF metadata extraction.<\/div>\r\n                    \r\n                    <div class=\"drop-btns\">\r\n                        <label for=\"inp-files\" class=\"btn btn-success\" style=\"cursor:pointer; display:inline-flex; align-items:center; gap:6px;\">\ud83d\udcc4 Open Files<\/label>\r\n                        <label for=\"inp-folder\" class=\"btn btn-primary\" style=\"cursor:pointer; display:inline-flex; align-items:center; gap:6px;\">\ud83d\udcc1 Open Folder<\/label>\r\n                        <label for=\"inp-zip\" class=\"btn btn-outline\" style=\"cursor:pointer; display:inline-flex; align-items:center; gap:6px;\">\ud83d\udddc\ufe0f Open ZIP<\/label>\r\n                    <\/div>\r\n                    \r\n                    <div class=\"drop-note\">* Folder prompts browser safety confirmation. All processing stays local!<\/div>\r\n                    <div class=\"badges\">\r\n                        <span class=\"badge badge-img\">JPG PNG WEBP HEIC GIF BMP TIFF SVG<\/span>\r\n                        <span class=\"badge badge-vid\">MP4 MOV AVI MKV WEBM 3GP M4V<\/span>\r\n                        <span class=\"badge badge-doc\">PDF DOC DOCX TXT XLS XLSX PPT<\/span>\r\n                        <span class=\"badge badge-zip\">ZIP (Auto-Extract) + Any Folder<\/span>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <input type=\"file\" id=\"inp-files\" class=\"hidden-input\" multiple accept=\"image\/*,video\/*,.pdf,.doc,.docx,.txt,.xls,.xlsx,.ppt,.zip\">\r\n                <input type=\"file\" id=\"inp-folder\" class=\"hidden-input\" multiple webkitdirectory directory>\r\n                <input type=\"file\" id=\"inp-zip\" class=\"hidden-input\" accept=\".zip\">\r\n                <input type=\"file\" id=\"inp-add-files\" class=\"hidden-input\" multiple accept=\"image\/*,video\/*,.pdf,.doc,.docx,.txt,.xls,.xlsx,.ppt,.zip\">\r\n                <input type=\"file\" id=\"inp-add-folder\" class=\"hidden-input\" multiple webkitdirectory directory>\r\n\r\n                <div id=\"organizer\" style=\"display: none;\">\r\n\r\n                    <div class=\"smart-panel\" id=\"smart-panel\">\r\n                        <div class=\"smart-panel-title\">\u26a1 Smart Auto-Organizer \u2014 <span id=\"sp-count\">0<\/span> files detected<\/div>\r\n                        <div class=\"smart-row\" style=\"display: flex; gap: 8px; flex-wrap: wrap; align-items: center;\">\r\n                            <button class=\"btn btn-secondary btn-sm\" id=\"ao-month\">\ud83d\udcc5 By Month<\/button>\r\n                            <button class=\"btn btn-secondary btn-sm\" id=\"ao-year\">\ud83d\udcc6 By Year<\/button>\r\n                            <button class=\"btn btn-secondary btn-sm\" id=\"ao-type\">\ud83d\uddc2\ufe0f By Type<\/button>\r\n                            <button class=\"btn btn-secondary btn-sm\" id=\"ao-type-date\">\ud83d\udcf1 Type + Month<\/button>\r\n                            <button class=\"btn btn-secondary btn-sm\" id=\"ao-size\">\ud83d\udcca By Size<\/button>\r\n                            <button class=\"btn btn-secondary btn-sm\" id=\"ao-ext\">\ud83d\udd24 By Extension<\/button>\r\n                            \r\n                            <div class=\"date-range-row\" style=\"margin-top: 0; display: flex; align-items: center; gap: 10px; background: var(--white); border: 1px solid var(--slate-200); padding: 5px 12px; border-radius: var(--radius-sm); width: auto;\">\r\n                                <span style=\"font-size:11px; color:var(--slate-400); font-weight:700;\">\ud83d\udcc5 Date Filter:<\/span>\r\n                                <input type=\"date\" id=\"filter-start\" class=\"date-input\" title=\"From Date\">\r\n                                <span style=\"font-size:12px; color:var(--slate-300);\">\u2192<\/span>\r\n                                <input type=\"date\" id=\"filter-end\" class=\"date-input\" title=\"To Date\">\r\n                                <button class=\"btn btn-outline btn-sm\" id=\"btn-clear-dates\" style=\"padding: 2px 6px;\">\u2715<\/button>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"tab-nav\">\r\n                        <button class=\"tab-btn active\" data-tab=\"organizer-tab\">\ud83d\uddc2\ufe0f Organizer<\/button>\r\n                        <button class=\"tab-btn\" data-tab=\"tools-tab\">\ud83d\udee0\ufe0f Batch Tools<\/button>\r\n                        <button class=\"tab-btn\" data-tab=\"analytics-tab\">\ud83d\udcca Analytics<\/button>\r\n                        <button class=\"tab-btn\" data-tab=\"metadata-tab\">\ud83d\udd0d Metadata<\/button>\r\n                    <\/div>\r\n\r\n                    <div id=\"organizer-tab\" class=\"tab-panel active\">\r\n                        <div class=\"org-layout\" id=\"org-layout\">\r\n\r\n                            <div class=\"sidebar\">\r\n                                <div class=\"panel\">\r\n                                    <div class=\"panel-title\">Media Types<\/div>\r\n                                    <ul class=\"folder-list\" id=\"fl-types\"><\/ul>\r\n                                <\/div>\r\n                                <div class=\"panel\">\r\n                                    <div class=\"panel-title\">\r\n                                        Virtual Folders\r\n                                        <button class=\"btn btn-secondary btn-sm\" id=\"btn-new-folder\">+ New<\/button>\r\n                                    <\/div>\r\n                                    <ul class=\"folder-list\" id=\"fl-custom\"><\/ul>\r\n                                <\/div>\r\n                                <div class=\"panel\">\r\n                                    <div class=\"panel-title\">Timeline<\/div>\r\n                                    <ul class=\"folder-list\" id=\"fl-dates\"><\/ul>\r\n                                    <div class=\"storage-bar\">\r\n                                        <div class=\"storage-header\"><span>Storage<\/span><span id=\"storage-label\">0 B<\/span><\/div>\r\n                                        <div class=\"progress-track\"><div class=\"progress-fill\" id=\"storage-fill\" style=\"width:0%\"><\/div><\/div>\r\n                                    <\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"gallery-card\">\r\n                           <div class=\"toolbar\">\r\n                                    <span class=\"toolbar-title\" id=\"folder-title\">All Files<\/span>\r\n                                    <div class=\"divider-v\"><\/div>\r\n                                    <button class=\"btn btn-secondary btn-sm\" id=\"btn-select-all\">\u2611\ufe0f Select All<\/button>\r\n                                    <button class=\"btn btn-secondary btn-sm\" id=\"btn-move\" disabled>\ud83d\udcc2 Move<\/button>\r\n                                    <button class=\"btn btn-secondary btn-sm\" id=\"btn-copy-folder\" disabled>\ud83d\udccb Copy<\/button>\r\n                                    <button class=\"btn btn-secondary btn-sm\" id=\"btn-rename\" disabled>\u270f\ufe0f Rename<\/button>\r\n                                    <button class=\"btn btn-danger btn-sm\" id=\"btn-delete\" disabled>\ud83d\uddd1\ufe0f Delete<\/button>\r\n                                    \r\n                                    <button class=\"btn btn-danger btn-sm\" id=\"btn-remove-dups\" style=\"margin-left:4px;\">\ud83e\uddf9 Remove Duplicates (<span id=\"dup-count\">0<\/span>)<\/button>\r\n                                    \r\n                                    <div class=\"toolbar-right\">\r\n                                        <label for=\"inp-add-files\" class=\"btn btn-outline btn-sm\" style=\"cursor:pointer;margin:0;\">\ud83d\udcc4 Add Files<\/label>\r\n                                        <label for=\"inp-add-folder\" class=\"btn btn-outline btn-sm\" style=\"cursor:pointer;margin:0;\">\ud83d\udcc1 Add Folder<\/label>\r\n                                        <button class=\"btn btn-success btn-sm\" id=\"btn-export-zip\">\ud83d\udce6 Export ZIP<\/button>\r\n                                    <\/div>\r\n                                <\/div>\r\n\r\n                                <div class=\"filter-bar\">\r\n                                    <button class=\"filter-tag active\" data-filter=\"all\">All<\/button>\r\n                                    <button class=\"filter-tag\" data-filter=\"image\">\ud83d\uddbc\ufe0f Photos<\/button>\r\n                                    <button class=\"filter-tag\" data-filter=\"video\">\ud83c\udfac Videos<\/button>\r\n                                    <button class=\"filter-tag\" data-filter=\"doc\">\ud83d\udcc4 Docs<\/button>\r\n                                    <input type=\"text\" class=\"search-box\" id=\"search-box\" placeholder=\"\ud83d\udd0d Search files...\">\r\n                                    <select class=\"sort-select\" id=\"thumb-size\">\r\n                                        <option value=\"sm\">Small<\/option>\r\n                                        <option value=\"md\" selected>Medium<\/option>\r\n                                        <option value=\"lg\">Large<\/option>\r\n                                    <\/select>\r\n                                    <select class=\"sort-select\" id=\"sort-select\">\r\n                                        <option value=\"date-desc\" selected>Newest First<\/option>\r\n                                        <option value=\"date-asc\">Oldest First<\/option>\r\n                                        <option value=\"name-asc\">Name A-Z<\/option>\r\n                                        <option value=\"name-desc\">Name Z-A<\/option>\r\n                                        <option value=\"size-desc\">Largest First<\/option>\r\n                                        <option value=\"size-asc\">Smallest First<\/option>\r\n                                        <option value=\"ext\">By Extension<\/option>\r\n                                    <\/select>\r\n                                    <div class=\"view-toggle\">\r\n                                        <button class=\"view-btn active\" data-view=\"grid\">\u229e<\/button>\r\n                                        <button class=\"view-btn\" data-view=\"list\">\u2630<\/button>\r\n                                    <\/div>\r\n                                <\/div>\r\n\r\n                                <div class=\"gallery grid-view\" id=\"gallery\"><\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div id=\"tools-tab\" class=\"tab-panel\">\r\n                        <div class=\"tools-grid\">\r\n\r\n                            <div class=\"tool-section\">\r\n                                <div class=\"tool-section-title\">\u270f\ufe0f Batch Rename<\/div>\r\n                                <div style=\"font-size:12px; color:var(--slate-500); margin-bottom:12px; line-height:1.6;\">\r\n                                    Pattern tokens: <code style=\"background:var(--slate-100); padding:1px 5px; border-radius:3px; font-size:11px;\">{n}<\/code> number  \r\n                                    <code style=\"background:var(--slate-100); padding:1px 5px; border-radius:3px; font-size:11px;\">{ext}<\/code> extension  \r\n                                    <code style=\"background:var(--slate-100); padding:1px 5px; border-radius:3px; font-size:11px;\">{date}<\/code> date  \r\n                                    <code style=\"background:var(--slate-100); padding:1px 5px; border-radius:3px; font-size:11px;\">{folder}<\/code> folder  \r\n                                    <code style=\"background:var(--slate-100); padding:1px 5px; border-radius:3px; font-size:11px;\">{name}<\/code> original name\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Pattern<\/label>\r\n                                    <input type=\"text\" class=\"tool-input\" id=\"rename-pattern\" placeholder=\"Photo_{date}_{n}.{ext}\" style=\"flex:2;\">\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Start #<\/label>\r\n                                    <input type=\"number\" class=\"tool-input\" id=\"rename-start\" value=\"1\" min=\"0\" style=\"width:70px;\">\r\n                                    <label style=\"margin-left:10px;\">Padding<\/label>\r\n                                    <select class=\"tool-select\" id=\"rename-pad\" style=\"width:70px;\">\r\n                                        <option value=\"1\">None<\/option>\r\n                                        <option value=\"2\">00<\/option>\r\n                                        <option value=\"3\" selected>000<\/option>\r\n                                        <option value=\"4\">0000<\/option>\r\n                                    <\/select>\r\n                                <\/div>\r\n                                <div style=\"display:flex; gap:8px; margin-top:14px; flex-wrap:wrap;\">\r\n                                    <button class=\"btn btn-primary btn-sm\" id=\"btn-batch-rename\">Rename Selected (<span id=\"rename-sel-count\">0<\/span>)<\/button>\r\n                                    <button class=\"btn btn-secondary btn-sm\" id=\"btn-preview-rename\">Preview First 5<\/button>\r\n                                <\/div>\r\n                                <div class=\"tool-result\" id=\"rename-preview\" style=\"display:none;\"><\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"tool-section\">\r\n                                <div class=\"tool-section-title\">\ud83d\udcca File Statistics<\/div>\r\n                                <div id=\"ext-breakdown\" style=\"display:flex; flex-direction:column; gap:6px;\"><\/div>\r\n                                <div style=\"margin-top:14px; border-top:1px solid var(--slate-100); padding-top:12px;\">\r\n                                    <div class=\"tool-section-title\" style=\"margin-top:0;\">\ud83c\udff7\ufe0f Tag & Label Files<\/div>\r\n                                    <div class=\"tool-option\">\r\n                                        <label>Tag name<\/label>\r\n                                        <input type=\"text\" class=\"tool-input\" id=\"tag-input\" placeholder=\"e.g. Favorites\" style=\"flex:2;\">\r\n                                    <\/div>\r\n                                    <div class=\"tool-option\">\r\n                                        <select class=\"tool-select\" id=\"tag-color\" style=\"flex:1;\">\r\n                                            <option value=\"#3b82f6\">\ud83d\udd35 Blue<\/option>\r\n                                            <option value=\"#10b981\">\ud83d\udfe2 Green<\/option>\r\n                                            <option value=\"#ef4444\">\ud83d\udd34 Red<\/option>\r\n                                            <option value=\"#f59e0b\">\ud83d\udfe1 Yellow<\/option>\r\n                                            <option value=\"#8b5cf6\">\ud83d\udfe3 Purple<\/option>\r\n                                        <\/select>\r\n                                        <button class=\"btn btn-primary btn-sm\" id=\"btn-add-tag\" style=\"margin-left:8px;\">Add Tag<\/button>\r\n                                    <\/div>\r\n                                    <div id=\"tags-list\" style=\"display:flex; flex-wrap:wrap; gap:6px; margin-top:8px;\"><\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"tool-section\">\r\n                                <div class=\"tool-section-title\">\ud83d\udca7 Watermark Images<\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Text<\/label>\r\n                                    <input type=\"text\" class=\"tool-input\" id=\"wm-text\" placeholder=\"\u00a9 YourBrand 2026\" style=\"flex:2;\">\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Position<\/label>\r\n                                    <select class=\"tool-select\" id=\"wm-pos\" style=\"flex:2;\">\r\n                                        <option value=\"br\">Bottom Right<\/option>\r\n                                        <option value=\"bl\">Bottom Left<\/option>\r\n                                        <option value=\"tr\">Top Right<\/option>\r\n                                        <option value=\"tl\">Top Left<\/option>\r\n                                        <option value=\"center\">Center<\/option>\r\n                                    <\/select>\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Opacity<\/label>\r\n                                    <input type=\"range\" min=\"10\" max=\"100\" value=\"60\" id=\"wm-opacity\" class=\"styled-range\" style=\"flex:2;\">\r\n                                    <span id=\"wm-opacity-val\" style=\"font-size:12px; color:var(--slate-500); min-width:32px; text-align:right;\">60%<\/span>\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Font Size<\/label>\r\n                                    <input type=\"range\" min=\"12\" max=\"72\" value=\"24\" id=\"wm-size\" class=\"styled-range\" style=\"flex:2;\">\r\n                                    <span id=\"wm-size-val\" style=\"font-size:12px; color:var(--slate-500); min-width:30px; text-align:right;\">24px<\/span>\r\n                                <\/div>\r\n                                <div style=\"margin-top:14px; display:flex; gap:8px; flex-wrap:wrap;\">\r\n                                    <button class=\"btn btn-primary btn-sm\" id=\"btn-wm-preview\">Preview on Selected<\/button>\r\n                                    <button class=\"btn btn-success btn-sm\" id=\"btn-wm-apply\">Apply & Export ZIP<\/button>\r\n                                <\/div>\r\n                                <div id=\"wm-canvas-area\" style=\"margin-top:12px; display:none;\">\r\n                                    <canvas id=\"wm-canvas\" style=\"max-width:100%; border-radius:var(--radius-sm); border:1px solid var(--slate-200);\"><\/canvas>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"tool-section\">\r\n                                <div class=\"tool-section-title\">\ud83d\udce6 Export Options<\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Export Scope<\/label>\r\n                                    <select class=\"tool-select\" id=\"export-scope\" style=\"flex:2;\">\r\n                                        <option value=\"all\">All Files<\/option>\r\n                                        <option value=\"selected\">Selected Files Only<\/option>\r\n                                        <option value=\"current\">Current Folder View<\/option>\r\n                                        <option value=\"filtered\">Filtered Results<\/option>\r\n                                    <\/select>\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Folder Structure<\/label>\r\n                                    <select class=\"tool-select\" id=\"export-structure\" style=\"flex:2;\">\r\n                                        <option value=\"organized\">Organized (by folder)<\/option>\r\n                                        <option value=\"flat\">Flat (all in root)<\/option>\r\n                                        <option value=\"type\">By Type<\/option>\r\n                                        <option value=\"date-month\">By Month<\/option>\r\n                                        <option value=\"date-year\">By Year<\/option>\r\n                                    <\/select>\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>ZIP Name<\/label>\r\n                                    <input type=\"text\" class=\"tool-input\" id=\"export-name\" value=\"MyFiles_Organized\" style=\"flex:2;\">\r\n                                <\/div>\r\n                                <div style=\"margin-top:14px; display:flex; gap:8px; flex-wrap:wrap;\">\r\n                                    <button class=\"btn btn-success\" id=\"btn-export-adv\">\ud83d\udce6 Export Now<\/button>\r\n                                    <button class=\"btn btn-secondary btn-sm\" id=\"btn-gen-manifest\">\ud83d\udccb Generate Manifest<\/button>\r\n                                <\/div>\r\n                                <div id=\"manifest-output\" style=\"display:none;\" class=\"tool-result\"><\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"tool-section\">\r\n                                <div class=\"tool-section-title\">\ud83d\udd01 Find & Replace in Names<\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Find<\/label>\r\n                                    <input type=\"text\" class=\"tool-input\" id=\"fr-find\" placeholder=\"IMG_\" style=\"flex:2;\">\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Replace with<\/label>\r\n                                    <input type=\"text\" class=\"tool-input\" id=\"fr-replace\" placeholder=\"Photo_\" style=\"flex:2;\">\r\n                                <\/div>\r\n                                <div class=\"tool-option\">\r\n                                    <label>Case sensitive<\/label>\r\n                                    <input type=\"checkbox\" id=\"fr-case\" style=\"margin-left:0;\">\r\n                                <\/div>\r\n                                <div style=\"margin-top:12px; display:flex; gap:8px;\">\r\n                                    <button class=\"btn btn-primary btn-sm\" id=\"btn-fr-apply\">Apply to Selected (<span id=\"fr-sel-count\">0<\/span>)<\/button>\r\n                                    <button class=\"btn btn-secondary btn-sm\" id=\"btn-fr-all\">Apply to All<\/button>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"tool-section\">\r\n                                <div class=\"tool-section-title\">\ud83d\udd0d Duplicate Finder<\/div>\r\n                                <div id=\"dup-detail\" style=\"font-size:13px; color:var(--slate-500);\">Run a scan to find duplicate files by name + size.<\/div>\r\n                                <div style=\"margin-top:12px; display:flex; gap:8px; flex-wrap:wrap;\">\r\n                                    <button class=\"btn btn-primary btn-sm\" id=\"btn-scan-dups\">\ud83d\udd0d Scan Duplicates<\/button>\r\n                                    <button class=\"btn btn-danger btn-sm\" id=\"btn-del-dups\">\ud83d\uddd1\ufe0f Delete All Dupes<\/button>\r\n                                    <button class=\"btn btn-secondary btn-sm\" id=\"btn-sel-dups\">\u2611\ufe0f Select Dupes<\/button>\r\n                                <\/div>\r\n                                <div id=\"dup-list\" style=\"margin-top:12px; display:flex; flex-direction:column; gap:4px; max-height:160px; overflow-y:auto;\"><\/div>\r\n                            <\/div>\r\n\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div id=\"analytics-tab\" class=\"tab-panel\">\r\n                        <div style=\"display:grid; grid-template-columns:repeat(auto-fit, minmax(320px, 1fr)); gap:16px;\">\r\n                            <div class=\"panel\">\r\n                                <div class=\"panel-title\" style=\"margin-bottom:14px;\">\ud83d\udcc5 Files by Month<\/div>\r\n                                <div class=\"timeline-chart\" id=\"chart-month\"><\/div>\r\n                            <\/div>\r\n                            <div class=\"panel\">\r\n                                <div class=\"panel-title\" style=\"margin-bottom:14px;\">\ud83d\uddc2\ufe0f Files by Type<\/div>\r\n                                <div id=\"chart-type\" style=\"display:flex; flex-direction:column; gap:8px;\"><\/div>\r\n                            <\/div>\r\n                            <div class=\"panel\">\r\n                                <div class=\"panel-title\" style=\"margin-bottom:14px;\">\ud83d\udcca Size Distribution<\/div>\r\n                                <div id=\"chart-size\" style=\"display:flex; flex-direction:column; gap:6px;\"><\/div>\r\n                            <\/div>\r\n                            <div class=\"panel\">\r\n                                <div class=\"panel-title\" style=\"margin-bottom:14px;\">\ud83d\udd24 Top Extensions<\/div>\r\n                                <div id=\"chart-ext\" style=\"display:flex; flex-direction:column; gap:6px;\"><\/div>\r\n                            <\/div>\r\n                            <div class=\"panel\">\r\n                                <div class=\"panel-title\" style=\"margin-bottom:14px;\">\ud83d\udcc1 Folder Breakdown<\/div>\r\n                                <div id=\"chart-folders\" style=\"display:flex; flex-direction:column; gap:6px;\"><\/div>\r\n                            <\/div>\r\n                            <div class=\"panel\">\r\n                                <div class=\"panel-title\" style=\"margin-bottom:14px;\">\u26a1 Quick Actions<\/div>\r\n                                <div style=\"display:flex; flex-direction:column; gap:10px;\">\r\n                                    <button class=\"btn btn-secondary\" id=\"qa-select-all-imgs\">Select All Photos<\/button>\r\n                                    <button class=\"btn btn-secondary\" id=\"qa-select-all-vids\">Select All Videos<\/button>\r\n                                    <button class=\"btn btn-secondary\" id=\"qa-select-dups\">Select All Duplicates<\/button>\r\n                                    <button class=\"btn btn-secondary\" id=\"qa-select-large\">Select Files > 10MB<\/button>\r\n                                    <button class=\"btn btn-secondary\" id=\"qa-select-undated\">Select Undated Files<\/button>\r\n                                    <button class=\"btn btn-success\" id=\"qa-export-selected\">Export Selected as ZIP<\/button>\r\n                                <\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div id=\"metadata-tab\" class=\"tab-panel\">\r\n                        <div style=\"display:grid; grid-template-columns:1fr 1fr; gap:16px; align-items:start;\">\r\n                            <div class=\"panel\">\r\n                                <div class=\"panel-title\" style=\"margin-bottom:12px;\">Select a file to inspect its metadata<\/div>\r\n                                <div class=\"folder-list\" id=\"meta-file-list\" style=\"max-height:400px;\"><\/div>\r\n                            <\/div>\r\n                            <div id=\"meta-detail-panel\">\r\n                                <div class=\"info-panel\">\r\n                                    <div class=\"info-panel-header\">\ud83d\udccb File Info<\/div>\r\n                                    <div class=\"info-panel-body\" id=\"meta-basic\"><\/div>\r\n                                <\/div>\r\n                                <div class=\"info-panel\" style=\"margin-top:12px;\">\r\n                                    <div class=\"info-panel-header\">\ud83d\udcf7 EXIF \/ Extended Data<\/div>\r\n                                    <div class=\"info-panel-body\" id=\"meta-exif\">\r\n                                        <span style=\"color:var(--slate-400); font-size:12px;\">Select an image to view EXIF data<\/span>\r\n                                    <\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                <\/div><\/div>\r\n        <\/div>\r\n        <div class=\"pth-sidebar-col\" id=\"pth-smartfileorg-sidebar\" style=\"display: none;\"><\/div>\r\n    <\/div>\r\n\r\n    <div class=\"overlay\" id=\"modal-new-folder\">\r\n        <div class=\"modal\">\r\n            <div class=\"modal-title\">\ud83d\uddc2\ufe0f Create Virtual Folder<\/div>\r\n            <div class=\"modal-sub\">Name your new folder to organize files into it.<\/div>\r\n            <input type=\"text\" id=\"new-folder-name\" class=\"modal-input\" placeholder=\"e.g. Vacation 2026\">\r\n            <div class=\"modal-footer\">\r\n                <button class=\"btn btn-secondary\" id=\"close-folder-modal\">Cancel<\/button>\r\n                <button class=\"btn btn-primary\" id=\"confirm-new-folder\">Create<\/button>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"overlay\" id=\"modal-move\">\r\n        <div class=\"modal\">\r\n            <div class=\"modal-title\">\ud83d\udcc2 Move Selected Files<\/div>\r\n            <div class=\"modal-sub\">Choose destination folder.<\/div>\r\n            <select id=\"move-select\" class=\"modal-input\"><\/select>\r\n            <div class=\"modal-footer\">\r\n                <button class=\"btn btn-secondary\" id=\"close-move-modal\">Cancel<\/button>\r\n                <button class=\"btn btn-primary\" id=\"confirm-move\">Move Files<\/button>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"overlay\" id=\"modal-copy\">\r\n        <div class=\"modal\">\r\n            <div class=\"modal-title\">\ud83d\udccb Copy Files to Folder<\/div>\r\n            <div class=\"modal-sub\">Select destination \\u2014 originals remain in current folder.<\/div>\r\n            <select id=\"copy-select\" class=\"modal-input\"><\/select>\r\n            <div class=\"modal-footer\">\r\n                <button class=\"btn btn-secondary\" id=\"close-copy-modal\">Cancel<\/button>\r\n                <button class=\"btn btn-primary\" id=\"confirm-copy\">Copy Files<\/button>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"overlay\" id=\"modal-alert\">\r\n        <div class=\"modal alert-modal-content\">\r\n            <div class=\"alert-icon\" id=\"alert-icon\">\u26a0\ufe0f<\/div>\r\n            <div class=\"modal-title\" id=\"alert-title\" style=\"text-align:center;\">Alert<\/div>\r\n            <div class=\"modal-sub\" id=\"alert-msg\" style=\"text-align:center;\"><\/div>\r\n            <button class=\"btn btn-primary\" id=\"alert-ok\" style=\"width:100%; padding:12px; margin-top:10px;\">OK, Got It<\/button>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"overlay\" id=\"modal-preview\">\r\n        <div class=\"modal preview-modal\">\r\n            <button class=\"preview-close\" id=\"preview-close\">\u2715<\/button>\r\n            <button class=\"preview-nav preview-prev\" id=\"preview-prev\">\u2039<\/button>\r\n            <button class=\"preview-nav preview-next\" id=\"preview-next\">\u203a<\/button>\r\n            <div class=\"preview-media\" id=\"preview-media\"><\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"overlay\" id=\"progress-overlay\">\r\n        <div class=\"progress-box\">\r\n            <div class=\"spinner\"><\/div>\r\n            <div style=\"font-size:16px; font-weight:700; margin-bottom:6px;\" id=\"prog-title\">Processing...<\/div>\r\n            <div style=\"font-size:12px; color:var(--slate-500);\" id=\"prog-sub\">Please wait.<\/div>\r\n            <div class=\"prog-bar-track\"><div class=\"prog-bar-fill\" id=\"prog-fill\" style=\"width:0%\"><\/div><\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"toast\" id=\"toast\"><\/div>\r\n<\/div>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function() {\r\n    'use strict';\r\n    \r\n    window.pthSmartFileOrgApp = {\r\n        initialized: false,\r\n        state: {\r\n            files: [], customFolders: [], tags: {}, currentFolder: 'All',\r\n            selectedIds: new Set(), fileIdCounter: 0, viewMode: 'grid',\r\n            filterType: 'all', sortMode: 'date-desc', searchQuery: '',\r\n            previewIds: [], previewIndex: -1, dupIds: new Set(), activeTag: null\r\n        },\r\n        \r\n        init: function() {\r\n            this.attachEvents();\r\n            this.setThumbSize('md');\r\n        },\r\n        \r\n        el: function(id) { \r\n            var w = document.getElementById('pth-smartfileorg-wrapper');\r\n            return w ? w.querySelector('#' + id) : document.getElementById(id); \r\n        },\r\n        qsa: function(sel) { \r\n            var w = document.getElementById('pth-smartfileorg-wrapper');\r\n            return w ? w.querySelectorAll(sel) : document.querySelectorAll(sel); \r\n        },\r\n\r\n        safeOn: function(id, evt, cb) {\r\n            var el = this.el(id);\r\n            if (el) el.addEventListener(evt, cb);\r\n        },\r\n        \r\n        toast: function(msg, dur) {\r\n            dur = dur || 3000;\r\n            var t = this.el('toast');\r\n            if(!t) return;\r\n            t.textContent = msg;\r\n            t.classList.add('show');\r\n            setTimeout(function() { t.classList.remove('show'); }, dur);\r\n        },\r\n        \r\n        showAlert: function(title, msg, icon) {\r\n            var i = this.el('alert-icon'), t = this.el('alert-title'), m = this.el('alert-msg');\r\n            if(i) i.textContent = icon || '\u26a0\ufe0f';\r\n            if(t) t.textContent = title;\r\n            if(m) m.textContent = msg;\r\n            this.showOverlay('modal-alert');\r\n        },\r\n        \r\n        showOverlay: function(id) { var e = this.el(id); if(e) e.style.display = 'flex'; },\r\n        hideOverlay: function(id) { var e = this.el(id); if(e) e.style.display = 'none'; },\r\n        \r\n        showProgress: function(title, sub, pct) {\r\n            this.showOverlay('progress-overlay');\r\n            var pt = this.el('prog-title'), ps = this.el('prog-sub'), pf = this.el('prog-fill');\r\n            if(pt) pt.textContent = title;\r\n            if(ps) ps.textContent = sub;\r\n            if(pf) pf.style.width = (pct || 0) + '%';\r\n        },\r\n        hideProgress: function() { this.hideOverlay('progress-overlay'); },\r\n        \r\n        formatBytes: function(b) {\r\n            if (!b) return '0 B';\r\n            var k = 1024, s = ['B','KB','MB','GB'];\r\n            var i = Math.floor(Math.log(b) \/ Math.log(k));\r\n            return parseFloat((b \/ Math.pow(k, i)).toFixed(1)) + ' ' + s[i];\r\n        },\r\n        \r\n        getExt: function(name) { return (name.split('.').pop() || '').toLowerCase(); },\r\n        getType: function(name) {\r\n            var e = this.getExt(name);\r\n            if (\/^(jpg|jpeg|png|gif|webp|heic|heif|bmp|tiff|tif|svg|avif)$\/.test(e)) return 'image';\r\n            if (\/^(mp4|mov|avi|mkv|webm|3gp|m4v|ts|wmv|flv)$\/.test(e)) return 'video';\r\n            return 'doc';\r\n        },\r\n        \r\n        extractDate: function(name) {\r\n            var patterns = [\/(\\d{4})[-_](\\d{2})[-_](\\d{2})\/, \/(\\d{4})(\\d{2})(\\d{2})\/];\r\n            for (var i = 0; i < patterns.length; i++) {\r\n                var m = name.match(patterns[i]);\r\n                if (m) {\r\n                    var y = parseInt(m[1]), mo = parseInt(m[2]), d = parseInt(m[3]);\r\n                    if (y > 1990 && y < 2035 && mo >= 1 && mo <= 12 && d >= 1 && d <= 31)\r\n                        return new Date(y, mo - 1, d);\r\n                }\r\n            }\r\n            return null;\r\n        },\r\n        \r\n        getMonthLabel: function(d) {\r\n            if (!d) return 'Unknown Date';\r\n            var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];\r\n            return months[d.getMonth()] + ' ' + d.getFullYear();\r\n        },\r\n        \r\n        sizeCategory: function(bytes) {\r\n            if (bytes < 100 * 1024) return '\\x3C 100 KB';\r\n            if (bytes < 1024 * 1024) return '100 KB \\u2013 1 MB';\r\n            if (bytes < 10 * 1024 * 1024) return '1 \\u2013 10 MB';\r\n            if (bytes < 100 * 1024 * 1024) return '10 \\u2013 100 MB';\r\n            return '\\x3E 100 MB';\r\n        },\r\n        \r\n        addFile: function(blob, name) {\r\n            var type = this.getType(name);\r\n            var url = null;\r\n            try { \r\n                if (type === 'image' || type === 'video') {\r\n                    url = URL.createObjectURL(blob);\r\n                }\r\n            } catch(e) { console.error(\"URL err:\", e); }\r\n            \r\n            var dDate = this.extractDate(name);\r\n            this.state.files.push({\r\n                id: 'f_' + (++this.state.fileIdCounter),\r\n                name: name, type: type, blob: blob, size: blob.size, url: url,\r\n                detectedDate: dDate,\r\n                monthLabel: this.getMonthLabel(dDate),\r\n                ext: this.getExt(name),\r\n                hashKey: name.toLowerCase() + '_' + blob.size,\r\n                folder: type === 'image' ? 'Photos' : type === 'video' ? 'Videos' : 'Documents',\r\n                tags: []\r\n            });\r\n        },\r\n        \r\n        extractZip: function(zipBlob) {\r\n            var self = this;\r\n            return new Promise(function(resolve, reject) {\r\n                if (typeof JSZip === 'undefined') {\r\n                    reject(new Error('JSZip not loaded'));\r\n                    return;\r\n                }\r\n                self.showProgress('Unpacking ZIP', zipBlob.name, 30);\r\n                JSZip.loadAsync(zipBlob).then(function(zip) {\r\n                    var filePromises = [];\r\n                    zip.forEach(function(path, entry) {\r\n                        if (!entry.dir) {\r\n                            filePromises.push(entry.async('blob').then(function(b) { self.addFile(b, path.split('\/').pop()); }));\r\n                        }\r\n                    });\r\n                    Promise.all(filePromises).then(resolve).catch(reject);\r\n                }).catch(reject);\r\n            });\r\n        },\r\n        \r\n        processFileList: function(fileList) {\r\n            try {\r\n                if (!fileList || fileList.length === 0) return;\r\n                var files = Array.prototype.slice.call(fileList);\r\n                var zips = [], others = [];\r\n                var hasRar = false;\r\n                \r\n                for (var j = 0; j < files.length; j++) {\r\n                    var f = files[j];\r\n                    var n = f.name ? f.name.toLowerCase() : '';\r\n                    if (n.endsWith('.rar')) hasRar = true;\r\n                    else if (n.endsWith('.zip')) zips.push(f);\r\n                    else others.push(f);\r\n                }\r\n                \r\n                if (hasRar) this.showAlert('Unsupported Format', 'RAR files cannot be processed natively in-browser. Please extract them first.', '\ud83d\uded1');\r\n                if (others.length === 0 && zips.length === 0) return;\r\n\r\n                this.showProgress('Processing Files...', (others.length + zips.length) + ' items', 10);\r\n                \r\n                for (var k = 0; k < others.length; k++) { this.addFile(others[k], others[k].name); }\r\n                \r\n                var self = this;\r\n                if (zips.length > 0) {\r\n                    var zipPromises = zips.map(function(z) { return self.extractZip(z); });\r\n                    Promise.all(zipPromises).then(function() {\r\n                        self.hideProgress();\r\n                        self.finalizeIngestion();\r\n                    }).catch(function(err) {\r\n                        self.hideProgress();\r\n                        self.showAlert('ZIP Error', err.message, '\u274c');\r\n                    });\r\n                } else {\r\n                    this.hideProgress();\r\n                    this.finalizeIngestion();\r\n                }\r\n            } catch (err) {\r\n                this.hideProgress();\r\n                this.showAlert('Error Loading Files', err.message || 'An unknown error occurred while loading files.', '\u274c');\r\n            }\r\n        },\r\n        \r\n        finalizeIngestion: function() {\r\n            if (this.state.files.length === 0) {\r\n                this.showAlert('No Valid Files', 'No readable files were selected.', '\u26a0\ufe0f');\r\n                return;\r\n            }\r\n            var dz = this.el('dropzone'), org = this.el('organizer'), sb = this.el('stats-bar');\r\n            if(dz) dz.style.display = 'none';\r\n            if(org) org.style.display = 'block';\r\n            if(sb) sb.style.display = 'grid';\r\n            \r\n            this.updateStats();\r\n            this.renderSidebar();\r\n            this.renderGallery();\r\n            this.updateAllCharts();\r\n            this.updateMetaFileList();\r\n            this.updateBatchToolCounts();\r\n        },\r\n        \r\n        updateStats: function() {\r\n            var seen = {};\r\n            this.state.dupIds.clear();\r\n            var totalSize = 0, photos = 0, videos = 0, docs = 0, self = this;\r\n            this.state.files.forEach(function(f) {\r\n                totalSize += f.size;\r\n                if (f.type === 'image') photos++;\r\n                else if (f.type === 'video') videos++;\r\n                else docs++;\r\n                if (seen[f.hashKey]) self.state.dupIds.add(f.id);\r\n                else seen[f.hashKey] = true;\r\n            });\r\n            var st = this.el('s-total'), sp = this.el('s-photos'), sv = this.el('s-videos'), sd = this.el('s-docs'), ss = this.el('s-size'), sf = this.el('s-folders'), sdu = this.el('s-dups'), spc = this.el('sp-count'), sdc = this.el('dup-count'), sl = this.el('storage-label'), sfill = this.el('storage-fill');\r\n            if(st) st.textContent = this.state.files.length;\r\n            if(sp) sp.textContent = photos;\r\n            if(sv) sv.textContent = videos;\r\n            if(sd) sd.textContent = docs;\r\n            if(ss) ss.textContent = this.formatBytes(totalSize);\r\n            var folders = new Set();\r\n            this.state.files.forEach(function(f){ folders.add(f.folder); });\r\n            if(sf) sf.textContent = folders.size;\r\n            if(sdu) sdu.textContent = this.state.dupIds.size;\r\n            if(spc) spc.textContent = this.state.files.length;\r\n            if(sdc) sdc.textContent = this.state.dupIds.size;\r\n            if(sl) sl.textContent = this.formatBytes(totalSize);\r\n            if(sfill) sfill.style.width = Math.min(100, (totalSize \/ (2 * 1024 * 1024 * 1024)) * 100) + '%';\r\n        },\r\n        \r\n        renderSidebar: function() {\r\n            var counts = { All: this.state.files.length, Photos: 0, Videos: 0, Documents: 0 };\r\n            var dMap = {};\r\n            var self = this;\r\n            this.state.customFolders.forEach(function(f) { if (!counts[f]) counts[f] = 0; });\r\n            this.state.files.forEach(function(f) {\r\n                if (f.type === 'image') counts.Photos++;\r\n                else if (f.type === 'video') counts.Videos++;\r\n                else counts.Documents++;\r\n                if (self.state.customFolders.includes(f.folder)) counts[f.folder] = (counts[f.folder] || 0) + 1;\r\n                dMap[f.monthLabel] = (dMap[f.monthLabel] || 0) + 1;\r\n            });\r\n\r\n            var makeLi = function(folder, icon, label, count) {\r\n                var active = self.state.currentFolder === folder ? 'active' : '';\r\n                return '\\x3Cli class=\"folder-item ' + active + '\" data-folder=\"' + folder + '\"\\x3E\\x3Cdiv class=\"fi-left\"\\x3E\\x3Cspan\\x3E' + icon + '\\x3C\/span\\x3E\\x3Cspan class=\"fi-name\"\\x3E' + label + '\\x3C\/span\\x3E\\x3C\/div\\x3E\\x3Cspan class=\"folder-count\"\\x3E' + count + '\\x3C\/span\\x3E\\x3C\/li\\x3E';\r\n            };\r\n\r\n            var t = this.el('fl-types');\r\n            if(t) t.innerHTML = makeLi('All','\ud83d\uddc2\ufe0f','All Files', counts.All) + makeLi('Photos','\ud83d\uddbc\ufe0f','Photos', counts.Photos) + makeLi('Videos','\ud83c\udfac','Videos', counts.Videos) + makeLi('Documents','\ud83d\udcc4','Documents', counts.Documents);\r\n\r\n            var c = this.el('fl-custom');\r\n            if(c) c.innerHTML = this.state.customFolders.length ? this.state.customFolders.map(function(f) { return makeLi(f, '\ud83d\udcc1', f, counts[f] || 0); }).join('') : '\\x3Cli class=\"empty-hint\"\\x3ENo custom folders\\x3C\/li\\x3E';\r\n\r\n            var sortedDates = Object.keys(dMap).sort(function(a, b) {\r\n                if (a === 'Unknown Date') return 1;\r\n                if (b === 'Unknown Date') return -1;\r\n                return b.localeCompare(a);\r\n            });\r\n            \r\n            var d = this.el('fl-dates');\r\n            if(d) d.innerHTML = sortedDates.length ? sortedDates.map(function(l) { return makeLi('date:' + l, '\ud83d\udcc5', l, dMap[l]); }).join('') : '\\x3Cli class=\"empty-hint\"\\x3ENo dates detected\\x3C\/li\\x3E';\r\n\r\n            this.qsa('.folder-item').forEach(function(item) {\r\n                item.addEventListener('click', function() {\r\n                    self.state.currentFolder = this.getAttribute('data-folder');\r\n                    self.state.selectedIds.clear();\r\n                    var ft = self.el('folder-title');\r\n                    if(ft) ft.textContent = self.state.currentFolder.replace('date:', '\ud83d\udcc5 ');\r\n                    self.renderSidebar();\r\n                    self.renderGallery();\r\n                });\r\n            });\r\n        },\r\n        \r\n        getDisplayFiles: function() {\r\n            var self = this;\r\n            var files = this.state.files.filter(function(f) {\r\n                if (self.state.currentFolder === 'All') return true;\r\n                if (self.state.currentFolder === 'Photos') return f.type === 'image';\r\n                if (self.state.currentFolder === 'Videos') return f.type === 'video';\r\n                if (self.state.currentFolder === 'Documents') return f.type === 'doc';\r\n                if (self.state.currentFolder.startsWith('date:')) return f.monthLabel === self.state.currentFolder.slice(5);\r\n                return f.folder === self.state.currentFolder;\r\n            });\r\n\r\n            if (this.state.filterType !== 'all') files = files.filter(function(f) { return f.type === self.state.filterType; });\r\n            if (this.state.searchQuery) files = files.filter(function(f) { return f.name.toLowerCase().includes(self.state.searchQuery); });\r\n            if (this.state.activeTag) files = files.filter(function(f) { return f.tags && f.tags.includes(self.state.activeTag); });\r\n\r\n            var fs = this.el('filter-start'), fe = this.el('filter-end');\r\n            var sDate = fs && fs.value ? new Date(fs.value) : null;\r\n            var eDate = fe && fe.value ? new Date(fe.value) : null;\r\n            if (sDate || eDate) {\r\n                var start = sDate || new Date(0);\r\n                var end = eDate ? new Date(new Date(eDate).setHours(23,59,59,999)) : new Date(8640000000000000);\r\n                files = files.filter(function(f) { return f.detectedDate && f.detectedDate >= start && f.detectedDate <= end; });\r\n            }\r\n\r\n            var fallback = new Date(0);\r\n            switch (this.state.sortMode) {\r\n                case 'name-asc': files.sort(function(a,b) { return a.name.localeCompare(b.name); }); break;\r\n                case 'name-desc': files.sort(function(a,b) { return b.name.localeCompare(a.name); }); break;\r\n                case 'size-desc': files.sort(function(a,b) { return b.size - a.size; }); break;\r\n                case 'size-asc': files.sort(function(a,b) { return a.size - b.size; }); break;\r\n                case 'date-asc': files.sort(function(a,b) { return (a.detectedDate||fallback) - (b.detectedDate||fallback); }); break;\r\n                case 'ext': files.sort(function(a,b) { return a.ext.localeCompare(b.ext); }); break;\r\n                default: files.sort(function(a,b) { return (b.detectedDate||fallback) - (a.detectedDate||fallback); });\r\n            }\r\n            return files;\r\n        },\r\n        \r\n        renderGallery: function() {\r\n            var grid = this.el('gallery');\r\n            if(!grid) return;\r\n            var self = this;\r\n            grid.className = 'gallery ' + (this.state.viewMode === 'grid' ? 'grid-view' : 'list-view');\r\n            var display = this.getDisplayFiles();\r\n            this.state.previewIds = display.map(function(f){ return f.id; });\r\n\r\n            if (!display.length) {\r\n                grid.innerHTML = '\\x3Cdiv class=\"gallery-empty\"\\x3E\\x3Cdiv style=\"font-size:40px;margin-bottom:10px;\"\\x3E\ud83d\udd0d\\x3C\/div\\x3E\\x3Cdiv style=\"font-weight:600;\"\\x3ENo files match current filters\\x3C\/div\\x3E\\x3C\/div\\x3E';\r\n                this.updateToolbarState(); return;\r\n            }\r\n\r\n            var isList = this.state.viewMode === 'list';\r\n            grid.innerHTML = display.map(function(f) {\r\n                var sel = self.state.selectedIds.has(f.id) ? 'selected' : '';\r\n                var dup = self.state.dupIds.has(f.id) ? '\\x3Cspan class=\"card-badge-dup\"\\x3EDUP\\x3C\/span\\x3E' : '';\r\n                var dateBadge = f.detectedDate ? '\\x3Cspan class=\"card-badge-date\"\\x3E' + f.detectedDate.toLocaleDateString() + '\\x3C\/span\\x3E' : '';\r\n                var extClass = f.type === 'image' ? 'img' : f.type === 'video' ? 'video' : 'doc';\r\n                var thumb = '\\x3Cdiv class=\"card-icon\"\\x3E' + (f.type==='doc'?'\ud83d\udcc4':f.type==='video'?'\ud83c\udfac':'\ud83d\uddbc\ufe0f') + '\\x3C\/div\\x3E';\r\n                if (f.url && f.type === 'image') thumb = '\\x3Cimg src=\"' + f.url + '\" loading=\"lazy\" alt=\"' + f.name + '\"\\x3E';\r\n                else if (f.url && f.type === 'video') thumb = '\\x3Cvideo src=\"' + f.url + '\" preload=\"none\"\\x3E\\x3C\/video\\x3E\\x3Cdiv style=\"position:absolute;background:rgba(0,0,0,0.45);color:#fff;padding:4px 10px;border-radius:12px;font-size:11px;font-weight:700;\"\\x3E\u25b6 Video\\x3C\/div\\x3E';\r\n\r\n                var tagDots = (f.tags && f.tags.length) ? f.tags.map(function(t) { return '\\x3Cspan style=\"width:8px;height:8px;border-radius:50%;background:' + (self.state.tags[t]||'#3b82f6') + ';display:inline-block;margin-right:3px;\" title=\"' + t + '\"\\x3E\\x3C\/span\\x3E'; }).join('') : '';\r\n\r\n                if (!isList) {\r\n                    return '\\x3Cdiv class=\"file-card ' + sel + '\" data-id=\"' + f.id + '\"\\x3E\\x3Cdiv class=\"select-overlay\"\\x3E\\x3C\/div\\x3E' + dup + '\\x3Cinput type=\"checkbox\" class=\"card-checkbox\" ' + (sel?'checked':'') + ' data-id=\"' + f.id + '\"\\x3E\\x3Cdiv class=\"card-preview preview-trigger\" data-id=\"' + f.id + '\"\\x3E' + thumb + dateBadge + '\\x3C\/div\\x3E\\x3Cdiv class=\"card-info\"\\x3E\\x3Cdiv class=\"card-name\" title=\"' + f.name + '\"\\x3E' + tagDots + f.name + '\\x3C\/div\\x3E\\x3Cdiv class=\"card-meta\"\\x3E\\x3Cspan class=\"card-size\"\\x3E' + self.formatBytes(f.size) + '\\x3C\/span\\x3E\\x3Cspan class=\"card-ext ' + extClass + '\"\\x3E' + f.ext + '\\x3C\/span\\x3E\\x3C\/div\\x3E\\x3C\/div\\x3E\\x3C\/div\\x3E';\r\n                } else {\r\n                    return '\\x3Cdiv class=\"file-card list-card ' + sel + '\" data-id=\"' + f.id + '\"\\x3E' + dup + '\\x3Cinput type=\"checkbox\" class=\"card-checkbox\" ' + (sel?'checked':'') + ' data-id=\"' + f.id + '\"\\x3E\\x3Cdiv class=\"card-preview preview-trigger\" data-id=\"' + f.id + '\" style=\"cursor:pointer;\"\\x3E' + thumb + '\\x3C\/div\\x3E\\x3Cdiv class=\"card-info\"\\x3E\\x3Cdiv\\x3E\\x3Cdiv class=\"card-name\" style=\"font-size:14px;\"\\x3E' + tagDots + f.name + '\\x3C\/div\\x3E\\x3Cdiv style=\"display:flex;gap:14px;align-items:center;font-size:12px;color:var(--slate-400);\"\\x3E\\x3Cspan\\x3E' + self.formatBytes(f.size) + '\\x3C\/span\\x3E\\x3Cspan class=\"card-ext ' + extClass + '\"\\x3E' + f.ext + '\\x3C\/span\\x3E' + (f.detectedDate?'\\x3Cspan\\x3E\ud83d\udcc5 ' + f.detectedDate.toLocaleDateString() + '\\x3C\/span\\x3E':'') + '\\x3Cspan\\x3E\ud83d\udcc1 ' + f.folder + '\\x3C\/span\\x3E\\x3C\/div\\x3E\\x3C\/div\\x3E\\x3Cdiv style=\"display:flex;gap:6px;align-items:center;\"\\x3E\\x3Cbutton class=\"btn btn-secondary btn-sm preview-trigger\" data-id=\"' + f.id + '\"\\x3E\ud83d\udc41\ufe0f Preview\\x3C\/button\\x3E\\x3C\/div\\x3E\\x3C\/div\\x3E\\x3C\/div\\x3E';\r\n                }\r\n            }).join('');\r\n\r\n            grid.querySelectorAll('.card-checkbox').forEach(function(chk) {\r\n                chk.addEventListener('click', function(e) { e.stopPropagation(); });\r\n                chk.addEventListener('change', function() {\r\n                    var id = this.getAttribute('data-id');\r\n                    if (this.checked) self.state.selectedIds.add(id); else self.state.selectedIds.delete(id);\r\n                    this.closest('.file-card').classList.toggle('selected', this.checked);\r\n                    self.updateToolbarState(); self.updateBatchToolCounts();\r\n                });\r\n            });\r\n\r\n            grid.querySelectorAll('.preview-trigger').forEach(function(p) {\r\n                p.addEventListener('click', function(e) {\r\n                    e.stopPropagation();\r\n                    self.openPreview(this.getAttribute('data-id'));\r\n                });\r\n            });\r\n\r\n            this.updateToolbarState();\r\n            this.updateBatchToolCounts();\r\n        },\r\n        \r\n        switchTab: function(tabId) {\r\n            this.qsa('.tab-btn').forEach(function(b) { b.classList.toggle('active', b.getAttribute('data-tab') === tabId); });\r\n            this.qsa('.tab-panel').forEach(function(p) { p.classList.toggle('active', p.id === tabId); });\r\n        },\r\n        \r\n        updateToolbarState: function() {\r\n            var c = this.state.selectedIds.size;\r\n            var disabled = c === 0;\r\n            var self = this;\r\n            ['btn-move','btn-copy-folder','btn-rename','btn-delete'].forEach(function(id) { \r\n                var e = self.el(id); if(e) e.disabled = disabled; \r\n            });\r\n            var bsa = this.el('btn-select-all');\r\n            if(bsa) bsa.textContent = c > 0 ? '\u2715 Deselect' : '\u2611\ufe0f Select All';\r\n        },\r\n        updateBatchToolCounts: function() {\r\n            var c = this.state.selectedIds.size;\r\n            var rc = this.el('rename-sel-count'), fc = this.el('fr-sel-count');\r\n            if (rc) rc.textContent = c;\r\n            if (fc) fc.textContent = c;\r\n        },\r\n        \r\n        setThumbSize: function(size) {\r\n            var g = this.el('gallery');\r\n            var sizes = { sm: ['150px','100px'], md: ['210px','145px'], lg: ['320px','240px'] };\r\n            var minH = sizes[size] || sizes.md;\r\n            if(g) { g.style.setProperty('--grid-min', minH[0]); g.style.setProperty('--thumb-h', minH[1]); }\r\n        },\r\n        \r\n        createFolder: function(name) {\r\n            if (!name) return this.showAlert('Missing Name', 'Folder name cannot be empty.', '\ud83d\uded1');\r\n            if (this.state.customFolders.includes(name)) return this.showAlert('Already Exists', 'A folder with this name already exists.', '\ud83d\uded1');\r\n            this.state.customFolders.push(name);\r\n            this.hideOverlay('modal-new-folder');\r\n            var nf = this.el('new-folder-name');\r\n            if(nf) nf.value = '';\r\n            this.updateStats(); this.renderSidebar(); this.renderGallery();\r\n            this.toast('\u2705 Folder created: ' + name);\r\n        },\r\n        \r\n        showMoveModal: function(action) {\r\n            var selectId = action === 'move' ? 'move-select' : 'copy-select';\r\n            var modalId = action === 'move' ? 'modal-move' : 'modal-copy';\r\n            var sel = this.el(selectId);\r\n            if(sel) {\r\n                var opts = ['Photos','Videos','Documents'].concat(this.state.customFolders);\r\n                sel.innerHTML = opts.map(function(f) { return '\\x3Coption value=\"' + f + '\"\\x3E' + f + '\\x3C\/option\\x3E'; }).join('');\r\n            }\r\n            this.showOverlay(modalId);\r\n        },\r\n        \r\n        moveFiles: function(action) {\r\n            var ms = this.el('move-select'), cs = this.el('copy-select');\r\n            var target = action === 'move' ? (ms?ms.value:'') : (cs?cs.value:'');\r\n            if(!target) return;\r\n            var self = this;\r\n            if (action === 'copy') {\r\n                var copies = [];\r\n                this.state.files.forEach(function(f) {\r\n                    if (self.state.selectedIds.has(f.id)) copies.push(Object.assign({}, f, { id: 'f_' + (++self.state.fileIdCounter), folder: target }));\r\n                });\r\n                this.state.files.push.apply(this.state.files, copies);\r\n                this.toast('\ud83d\udccb Copied ' + copies.length + ' files to ' + target);\r\n            } else {\r\n                this.state.files.forEach(function(f) { if (self.state.selectedIds.has(f.id)) f.folder = target; });\r\n                this.toast('\ud83d\udcc2 Moved ' + this.state.selectedIds.size + ' files to ' + target);\r\n            }\r\n            this.state.selectedIds.clear();\r\n            this.hideOverlay(action === 'move' ? 'modal-move' : 'modal-copy');\r\n            this.updateStats(); this.renderSidebar(); this.renderGallery();\r\n        },\r\n        \r\n        deleteSelected: function() {\r\n            var c = this.state.selectedIds.size;\r\n            if (!c) return;\r\n            var self = this;\r\n            this.state.files = this.state.files.filter(function(f) { return !self.state.selectedIds.has(f.id); });\r\n            this.state.selectedIds.clear();\r\n            this.updateStats(); this.renderSidebar(); this.renderGallery(); this.updateAllCharts(); this.updateMetaFileList();\r\n            this.toast('\ud83d\uddd1\ufe0f Deleted ' + c + ' files');\r\n            if (this.state.files.length === 0) this.restartApp();\r\n        },\r\n        \r\n        autoOrganize: function(mode) {\r\n            var count = 0;\r\n            var self = this;\r\n            this.state.files.forEach(function(f) {\r\n                var folder;\r\n                if (mode === 'date-month') folder = f.detectedDate ? self.getMonthLabel(f.detectedDate) : 'Unknown Date';\r\n                else if (mode === 'date-year') folder = f.detectedDate ? String(f.detectedDate.getFullYear()) : 'Unknown Year';\r\n                else if (mode === 'type') folder = f.type === 'image' ? 'Photos' : f.type === 'video' ? 'Videos' : 'Documents';\r\n                else if (mode === 'type-date') {\r\n                    var t = f.type === 'image' ? 'Photos' : f.type === 'video' ? 'Videos' : 'Docs';\r\n                    folder = t + ' \\u2014 ' + (f.detectedDate ? self.getMonthLabel(f.detectedDate) : 'Unknown');\r\n                }\r\n                else if (mode === 'size') folder = self.sizeCategory(f.size);\r\n                else if (mode === 'ext') folder = f.ext.toUpperCase() + ' Files';\r\n                \r\n                if (folder) {\r\n                    f.folder = folder;\r\n                    if (['Photos','Videos','Documents'].indexOf(folder) === -1 && !self.state.customFolders.includes(folder))\r\n                        self.state.customFolders.push(folder);\r\n                    count++;\r\n                }\r\n            });\r\n            this.updateStats(); this.renderSidebar(); this.renderGallery(); this.updateAllCharts();\r\n            this.toast('\u26a1 Organized ' + count + ' files');\r\n        },\r\n        \r\n        removeDuplicates: function() {\r\n            var c = this.state.dupIds.size;\r\n            if (c === 0) return this.showAlert('No Duplicates', 'No duplicate files found.', '\u2705');\r\n            var self = this;\r\n            this.state.files = this.state.files.filter(function(f) { return !self.state.dupIds.has(f.id); });\r\n            this.updateStats(); this.renderSidebar(); this.renderGallery(); this.updateAllCharts();\r\n            var dl = this.el('dup-list'); if(dl) dl.innerHTML = '';\r\n            this.toast('\ud83e\uddf9 Removed ' + c + ' duplicates');\r\n        },\r\n\r\n        openPreview: function(id) {\r\n            this.state.previewIndex = this.state.previewIds.indexOf(id);\r\n            if (this.state.previewIndex === -1) return;\r\n            this.showPreviewAt(this.state.previewIndex);\r\n            this.showOverlay('modal-preview');\r\n        },\r\n        showPreviewAt: function(idx) {\r\n            var id = this.state.previewIds[idx];\r\n            var f = this.state.files.find(function(x) { return x.id === id; });\r\n            if (!f) return;\r\n            var c = this.el('preview-media');\r\n            if(!c) return;\r\n            \r\n            c.innerHTML = ''; \r\n\r\n            if (f.type === 'image') {\r\n                var src = f.url ? f.url : '';\r\n                c.innerHTML = '\\x3Cimg src=\"' + src + '\" class=\"preview-img\" alt=\"' + f.name + '\"\\x3E\\x3Cdiv class=\"preview-info\"\\x3E' + f.name + ' \\u00B7 ' + this.formatBytes(f.size) + '\\x3C\/div\\x3E';\r\n            } else if (f.type === 'video') {\r\n                var src = f.url ? f.url : '';\r\n                c.innerHTML = '\\x3Cvideo src=\"' + src + '\" class=\"preview-img\" controls autoplay style=\"max-height:75vh;\"\\x3E\\x3C\/video\\x3E\\x3Cdiv class=\"preview-info\"\\x3E' + f.name + ' \\u00B7 ' + this.formatBytes(f.size) + '\\x3C\/div\\x3E';\r\n            } else {\r\n                c.innerHTML = '\\x3Cdiv style=\"background:var(--white);padding:50px;border-radius:var(--radius-lg);text-align:center;\"\\x3E\\x3Cdiv style=\"font-size:60px;margin-bottom:12px;\"\\x3E\ud83d\udcc4\\x3C\/div\\x3E\\x3Ch2 style=\"color:var(--slate-800);\"\\x3E' + f.name + '\\x3C\/h2\\x3E\\x3Cp style=\"color:var(--slate-500);\"\\x3EPreview not available \\u2014 ' + this.formatBytes(f.size) + '\\x3C\/p\\x3E\\x3C\/div\\x3E';\r\n            }\r\n        },\r\n        \r\n        updateAllCharts: function() {\r\n            this.renderChartMonth(); this.renderChartType(); this.renderChartSize();\r\n            this.renderChartExt(); this.renderChartFolders(); this.renderExtBreakdown();\r\n        },\r\n        renderBar: function(label, count, max, color) {\r\n            color = color || 'linear-gradient(90deg,var(--blue),var(--green))';\r\n            var pct = max > 0 ? Math.round((count \/ max) * 100) : 0;\r\n            return '\\x3Cdiv class=\"timeline-row\"\\x3E\\x3Cdiv class=\"timeline-label\"\\x3E' + label + '\\x3C\/div\\x3E\\x3Cdiv class=\"timeline-bar-wrap\"\\x3E\\x3Cdiv class=\"timeline-bar\" style=\"width:' + pct + '%;background:' + color + ';\"\\x3E\\x3Cspan class=\"timeline-count\"\\x3E' + count + '\\x3C\/span\\x3E\\x3C\/div\\x3E\\x3C\/div\\x3E\\x3C\/div\\x3E';\r\n        },\r\n        renderChartMonth: function() {\r\n            var map = {};\r\n            this.state.files.forEach(function(f) { map[f.monthLabel] = (map[f.monthLabel] || 0) + 1; });\r\n            var sorted = Object.keys(map).filter(function(k){return k!=='Unknown Date';}).map(function(k){return [k, map[k]];}).sort(function(a,b){return b[0].localeCompare(a[0]);}).slice(0, 12);\r\n            var max = sorted.length ? Math.max.apply(null, sorted.map(function(e){return e[1];})) : 1;\r\n            var self = this, el = this.el('chart-month');\r\n            if(el) el.innerHTML = sorted.length ? sorted.map(function(e){ return self.renderBar(e[0], e[1], max); }).join('') : '\\x3Cdiv style=\"color:var(--slate-400);font-size:12px;\"\\x3ENo dated files\\x3C\/div\\x3E';\r\n        },\r\n        renderChartType: function() {\r\n            var types = { Photos: 0, Videos: 0, Documents: 0 };\r\n            this.state.files.forEach(function(f) { if (f.type === 'image') types.Photos++; else if (f.type === 'video') types.Videos++; else types.Documents++; });\r\n            var max = Math.max(types.Photos, types.Videos, types.Documents, 1);\r\n            var colors = { Photos: 'linear-gradient(90deg,#10b981,#059669)', Videos: 'linear-gradient(90deg,#8b5cf6,#7c3aed)', Documents: 'linear-gradient(90deg,#ef4444,#dc2626)' };\r\n            var self = this, el = this.el('chart-type');\r\n            if(el) el.innerHTML = Object.keys(types).map(function(l){ return self.renderBar(l, types[l], max, colors[l]); }).join('');\r\n        },\r\n        renderChartSize: function() {\r\n            var cats = { '\\x3C 100 KB': 0, '100 KB \\u2013 1 MB': 0, '1 \\u2013 10 MB': 0, '10 \\u2013 100 MB': 0, '\\x3E 100 MB': 0 };\r\n            var self = this;\r\n            this.state.files.forEach(function(f) { cats[self.sizeCategory(f.size)]++; });\r\n            var max = Math.max.apply(null, Object.keys(cats).map(function(k){return cats[k];}).concat([1]));\r\n            var el = this.el('chart-size');\r\n            if(el) el.innerHTML = Object.keys(cats).map(function(l){ return self.renderBar(l, cats[l], max, 'linear-gradient(90deg,#f59e0b,#d97706)'); }).join('');\r\n        },\r\n        renderChartExt: function() {\r\n            var map = {};\r\n            this.state.files.forEach(function(f) { map[f.ext] = (map[f.ext] || 0) + 1; });\r\n            var sorted = Object.keys(map).map(function(k){return [k, map[k]];}).sort(function(a,b){return b[1]-a[1];}).slice(0, 10);\r\n            var max = sorted.length ? Math.max.apply(null, sorted.map(function(e){return e[1];})) : 1;\r\n            var self = this, el = this.el('chart-ext');\r\n            if(el) el.innerHTML = sorted.map(function(e){ return self.renderBar(e[0].toUpperCase(), e[1], max, 'linear-gradient(90deg,#06b6d4,#0891b2)'); }).join('');\r\n        },\r\n        renderChartFolders: function() {\r\n            var map = {};\r\n            this.state.files.forEach(function(f) { map[f.folder] = (map[f.folder] || 0) + 1; });\r\n            var sorted = Object.keys(map).map(function(k){return [k, map[k]];}).sort(function(a,b){return b[1]-a[1];}).slice(0, 10);\r\n            var max = sorted.length ? Math.max.apply(null, sorted.map(function(e){return e[1];})) : 1;\r\n            var self = this, el = this.el('chart-folders');\r\n            if(el) el.innerHTML = sorted.map(function(e){ return self.renderBar(e[0], e[1], max, 'linear-gradient(90deg,#ec4899,#db2777)'); }).join('');\r\n        },\r\n        renderExtBreakdown: function() {\r\n            var map = {};\r\n            this.state.files.forEach(function(f) { map[f.ext] = (map[f.ext] || 0) + 1; });\r\n            var sorted = Object.keys(map).map(function(k){return [k, map[k]];}).sort(function(a,b){return b[1]-a[1];}).slice(0, 8);\r\n            var el = this.el('ext-breakdown');\r\n            if(el) el.innerHTML = sorted.map(function(e){\r\n                return '\\x3Cdiv style=\"display:flex;align-items:center;justify-content:space-between;padding:5px 8px;background:var(--slate-50);border-radius:var(--radius-sm);\"\\x3E\\x3Cspan style=\"font-weight:700;font-size:12px;color:var(--slate-700);\"\\x3E.' + e[0].toUpperCase() + '\\x3C\/span\\x3E\\x3Cspan style=\"font-size:12px;color:var(--slate-500);\"\\x3E' + e[1] + ' files\\x3C\/span\\x3E\\x3C\/div\\x3E';\r\n            }).join('');\r\n        },\r\n        \r\n        updateMetaFileList: function() {\r\n            var self = this, list = this.el('meta-file-list');\r\n            if(!list) return;\r\n            list.innerHTML = this.state.files.slice(0, 200).map(function(f) {\r\n                return '\\x3Cli class=\"folder-item\" data-id=\"' + f.id + '\" style=\"cursor:pointer;\"\\x3E\\x3Cdiv class=\"fi-left\"\\x3E\\x3Cspan\\x3E' + (f.type==='image'?'\ud83d\uddbc\ufe0f':f.type==='video'?'\ud83c\udfac':'\ud83d\udcc4') + '\\x3C\/span\\x3E\\x3Cspan class=\"fi-name\"\\x3E' + f.name + '\\x3C\/span\\x3E\\x3C\/div\\x3E\\x3Cspan class=\"folder-count\"\\x3E' + self.formatBytes(f.size) + '\\x3C\/span\\x3E\\x3C\/li\\x3E';\r\n            }).join('');\r\n            list.querySelectorAll('.folder-item').forEach(function(item) {\r\n                item.addEventListener('click', function() { self.showMetadata(this.getAttribute('data-id')); });\r\n            });\r\n        },\r\n        showMetadata: function(id) {\r\n            var f = this.state.files.find(function(x) { return x.id === id; });\r\n            if (!f) return;\r\n            var mb = this.el('meta-basic'), me = this.el('meta-exif');\r\n            if(mb) mb.innerHTML = '\\x3Ctable class=\"meta-table\"\\x3E\\x3Ctr\\x3E\\x3Ctd\\x3EName\\x3C\/td\\x3E\\x3Ctd\\x3E' + f.name + '\\x3C\/td\\x3E\\x3C\/tr\\x3E\\x3Ctr\\x3E\\x3Ctd\\x3EType\\x3C\/td\\x3E\\x3Ctd\\x3E' + f.type + '\\x3C\/td\\x3E\\x3C\/tr\\x3E\\x3Ctr\\x3E\\x3Ctd\\x3EExtension\\x3C\/td\\x3E\\x3Ctd\\x3E.' + f.ext + '\\x3C\/td\\x3E\\x3C\/tr\\x3E\\x3Ctr\\x3E\\x3Ctd\\x3ESize\\x3C\/td\\x3E\\x3Ctd\\x3E' + this.formatBytes(f.size) + ' (' + f.size.toLocaleString() + ' bytes)\\x3C\/td\\x3E\\x3C\/tr\\x3E\\x3Ctr\\x3E\\x3Ctd\\x3EFolder\\x3C\/td\\x3E\\x3Ctd\\x3E' + f.folder + '\\x3C\/td\\x3E\\x3C\/tr\\x3E\\x3Ctr\\x3E\\x3Ctd\\x3EDetected Date\\x3C\/td\\x3E\\x3Ctd\\x3E' + (f.detectedDate ? f.detectedDate.toLocaleDateString() : 'Not found in filename') + '\\x3C\/td\\x3E\\x3C\/tr\\x3E\\x3C\/table\\x3E';\r\n            \r\n            if(!me) return;\r\n            me.innerHTML = '\\x3Cspan style=\"color:var(--slate-400);font-size:12px;\"\\x3ELoading EXIF...\\x3C\/span\\x3E';\r\n            if (f.type === 'image' && f.blob && typeof EXIF !== 'undefined') {\r\n                EXIF.getData(f.blob, function() {\r\n                    var tags = EXIF.getAllTags(this);\r\n                    var rows = Object.keys(tags).filter(function(k){return tags[k] !== undefined && String(tags[k]).trim();}).slice(0, 30);\r\n                    if (rows.length) {\r\n                        me.innerHTML = '\\x3Ctable class=\"meta-table\"\\x3E' + rows.map(function(k){ return '\\x3Ctr\\x3E\\x3Ctd\\x3E' + k + '\\x3C\/td\\x3E\\x3Ctd\\x3E' + String(tags[k]).slice(0,100) + '\\x3C\/td\\x3E\\x3C\/tr\\x3E'; }).join('') + '\\x3C\/table\\x3E';\r\n                    } else { me.innerHTML = '\\x3Cspan style=\"color:var(--slate-400);font-size:12px;\"\\x3ENo EXIF data found.\\x3C\/span\\x3E'; }\r\n                });\r\n            } else if (f.type !== 'image') {\r\n                me.innerHTML = '\\x3Cspan style=\"color:var(--slate-400);font-size:12px;\"\\x3EEXIF data is only available for images.\\x3C\/span\\x3E';\r\n            }\r\n        },\r\n        \r\n        batchRename: function() {\r\n            var patEl = this.el('rename-pattern'), padEl = this.el('rename-pad'), stEl = this.el('rename-start');\r\n            if(!patEl) return;\r\n            var pattern = patEl.value.trim();\r\n            if (!pattern) return this.showAlert('Missing Pattern', 'Please enter a rename pattern.', '\ud83d\uded1');\r\n            var pad = parseInt(padEl ? padEl.value : '3') || 3;\r\n            var start = parseInt(stEl ? stEl.value : '1') || 1;\r\n            var n = start, self = this;\r\n            var targets = this.state.files.filter(function(f){ return self.state.selectedIds.has(f.id); });\r\n            if (!targets.length) return this.showAlert('No Selection', 'Please select files to rename.', '\ud83d\uded1');\r\n            targets.forEach(function(f) {\r\n                var dStr = f.detectedDate ? f.detectedDate.toISOString().slice(0,10) : 'undated';\r\n                f.name = pattern\r\n                    .replace('{n}', String(n).padStart(pad, '0'))\r\n                    .replace('{ext}', f.ext)\r\n                    .replace('{date}', dStr)\r\n                    .replace('{folder}', f.folder.replace(\/[^a-z0-9]\/gi,'_'))\r\n                    .replace('{name}', f.name.replace('.' + f.ext, ''));\r\n                n++;\r\n            });\r\n            this.state.selectedIds.clear();\r\n            this.renderGallery(); this.updateMetaFileList();\r\n            this.toast('\u270f\ufe0f Renamed ' + (n - start) + ' files');\r\n        },\r\n        previewRename: function() {\r\n            var patEl = this.el('rename-pattern'), padEl = this.el('rename-pad'), stEl = this.el('rename-start'), preEl = this.el('rename-preview');\r\n            if(!patEl || !preEl) return;\r\n            var pattern = patEl.value.trim();\r\n            if (!pattern) return;\r\n            var pad = parseInt(padEl ? padEl.value : '3') || 3;\r\n            var start = parseInt(stEl ? stEl.value : '1') || 1;\r\n            var self = this;\r\n            var targets = this.state.files.filter(function(f){ return self.state.selectedIds.has(f.id); }).slice(0, 5);\r\n            if (!targets.length) { preEl.style.display='none'; return; }\r\n            var rows = targets.map(function(f, i) {\r\n                var dStr = f.detectedDate ? f.detectedDate.toISOString().slice(0,10) : 'undated';\r\n                var newName = pattern\r\n                    .replace('{n}', String(start + i).padStart(pad, '0'))\r\n                    .replace('{ext}', f.ext).replace('{date}', dStr)\r\n                    .replace('{folder}', f.folder.replace(\/[^a-z0-9]\/gi,'_'))\r\n                    .replace('{name}', f.name.replace('.'+f.ext,''));\r\n                return '\\x3Cdiv style=\"font-size:11px; padding:4px 0; border-bottom:1px solid var(--slate-100);\"\\x3E\\x3Cspan style=\"color:var(--slate-400);\"\\x3E' + f.name + '\\x3C\/span\\x3E \\u2192 \\x3Cstrong style=\"color:var(--blue);\"\\x3E' + newName + '\\x3C\/strong\\x3E\\x3C\/div\\x3E';\r\n            });\r\n            preEl.style.display = 'block';\r\n            preEl.innerHTML = '\\x3Cdiv style=\"font-size:11px;font-weight:700;color:var(--slate-400);margin-bottom:6px;\"\\x3EPREVIEW (first 5):\\x3C\/div\\x3E' + rows.join('');\r\n        },\r\n        \r\n        findReplace: function(scope) {\r\n            var fEl = this.el('fr-find'), rEl = this.el('fr-replace'), cEl = this.el('fr-case');\r\n            if(!fEl || !rEl) return;\r\n            var find = fEl.value, replace = rEl.value, caseSensitive = cEl ? cEl.checked : false;\r\n            if (!find) return this.showAlert('Missing Input', 'Enter the text to find.', '\ud83d\uded1');\r\n            var self = this;\r\n            var targets = scope === 'selected' ? this.state.files.filter(function(f){ return self.state.selectedIds.has(f.id); }) : this.state.files;\r\n            var count = 0;\r\n            targets.forEach(function(f) {\r\n                var original = f.name;\r\n                f.name = caseSensitive ? f.name.split(find).join(replace) : f.name.replace(new RegExp(find.replace(\/[.*+?^${}()|[\\]\\\\]\/g, '\\\\$&'), 'gi'), replace);\r\n                if (f.name !== original) count++;\r\n            });\r\n            this.renderGallery(); this.updateMetaFileList();\r\n            this.toast('\ud83d\udd01 Replaced in ' + count + ' filenames');\r\n        },\r\n        \r\n        scanDuplicates: function() {\r\n            this.updateStats();\r\n            var groups = {};\r\n            this.state.files.forEach(function(f) {\r\n                if (!groups[f.hashKey]) groups[f.hashKey] = [];\r\n                groups[f.hashKey].push(f);\r\n            });\r\n            var dupes = Object.keys(groups).map(function(k){return groups[k];}).filter(function(g) { return g.length > 1; });\r\n            var list = this.el('dup-list'), detailEl = this.el('dup-detail');\r\n            var self = this;\r\n            if (!dupes.length) {\r\n                if(detailEl) detailEl.textContent = '\u2705 No duplicates found!';\r\n                if(list) list.innerHTML = ''; return;\r\n            }\r\n            if(detailEl) detailEl.textContent = 'Found ' + this.state.dupIds.size + ' duplicate files across ' + dupes.length + ' groups.';\r\n            if(list) list.innerHTML = dupes.map(function(g) {\r\n                return '\\x3Cdiv style=\"background:var(--red-light);border-radius:var(--radius-sm);padding:8px 10px;margin-bottom:5px;\"\\x3E\\x3Cdiv style=\"font-size:11px;font-weight:700;color:var(--red-dark);margin-bottom:4px;\"\\x3EDuplicate group (' + g.length + 'x):\\x3C\/div\\x3E' +\r\n                g.map(function(f){ return '\\x3Cdiv style=\"font-size:11px;color:var(--slate-600);\"\\x3E\ud83d\udcc4 ' + f.name + ' \\u2014 ' + self.formatBytes(f.size) + ' \\u2014 \ud83d\udcc1 ' + f.folder + '\\x3C\/div\\x3E'; }).join('') + '\\x3C\/div\\x3E';\r\n            }).join('');\r\n            this.toast('\ud83d\udd0d Found ' + this.state.dupIds.size + ' duplicates');\r\n        },\r\n        selectDuplicates: function() {\r\n            var self = this;\r\n            this.state.dupIds.forEach(function(id){ self.state.selectedIds.add(id); });\r\n            this.renderGallery(); this.toast('\u2611\ufe0f Selected ' + this.state.dupIds.size + ' duplicates');\r\n        },\r\n        \r\n        addTag: function(name, color) {\r\n            if (!name) return;\r\n            this.state.tags[name] = color;\r\n            var self = this;\r\n            var tagged = this.state.files.filter(function(f){ return self.state.selectedIds.has(f.id); });\r\n            tagged.forEach(function(f) {\r\n                if (!f.tags) f.tags = [];\r\n                if (!f.tags.includes(name)) f.tags.push(name);\r\n            });\r\n            this.renderTagsList(); this.renderGallery();\r\n            this.toast('\ud83c\udff7\ufe0f Tag \"' + name + '\" applied to ' + tagged.length + ' files');\r\n        },\r\n        renderTagsList: function() {\r\n            var self = this, tl = this.el('tags-list');\r\n            if(!tl) return;\r\n            tl.innerHTML = Object.keys(this.state.tags).map(function(name) {\r\n                var color = self.state.tags[name];\r\n                return '\\x3Cspan style=\"display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:20px;font-size:11px;font-weight:700;background:' + color + '20;color:' + color + ';border:1px solid ' + color + '40;cursor:pointer;\" class=\"tag-filter\" data-tag=\"' + name + '\"\\x3E\\x3Cspan style=\"width:7px;height:7px;border-radius:50%;background:' + color + ';\"\\x3E\\x3C\/span\\x3E' + name + '\\x3Cspan class=\"tag-remove\" data-tag=\"' + name + '\" style=\"margin-left:4px;opacity:0.6;font-size:12px;\"\\x3E\u2715\\x3C\/span\\x3E\\x3C\/span\\x3E';\r\n            }).join('');\r\n            tl.querySelectorAll('.tag-filter').forEach(function(t) {\r\n                t.addEventListener('click', function(e) {\r\n                    if (e.target.classList.contains('tag-remove')) {\r\n                        var name = e.target.getAttribute('data-tag');\r\n                        delete self.state.tags[name];\r\n                        self.state.files.forEach(function(f){ if(f.tags) f.tags = f.tags.filter(function(x){return x!==name;}); });\r\n                        if (self.state.activeTag === name) self.state.activeTag = null;\r\n                        self.renderTagsList(); self.renderGallery();\r\n                    } else {\r\n                        self.state.activeTag = self.state.activeTag === t.getAttribute('data-tag') ? null : t.getAttribute('data-tag');\r\n                        self.renderGallery();\r\n                        self.toast(self.state.activeTag ? '\ud83c\udff7\ufe0f Filtering by: ' + self.state.activeTag : '\ud83c\udff7\ufe0f Tag filter cleared');\r\n                    }\r\n                });\r\n            });\r\n        },\r\n        \r\n        applyWatermark: function(download) {\r\n            var tw = this.el('wm-text'); if(!tw) return;\r\n            var text = tw.value.trim();\r\n            if (!text) return this.showAlert('Missing Text', 'Enter watermark text.', '\ud83d\uded1');\r\n            var self = this;\r\n            var imgFiles = this.state.files.filter(function(f){ return f.type === 'image' && self.state.selectedIds.has(f.id); });\r\n            if (!imgFiles.length) return this.showAlert('No Images Selected', 'Select image files first.', '\ud83d\uded1');\r\n            var f = imgFiles[0];\r\n            var img = new Image();\r\n            img.onload = function() {\r\n                var canvas = self.el('wm-canvas'), ca = self.el('wm-canvas-area');\r\n                if(!canvas) return;\r\n                canvas.width = img.naturalWidth; canvas.height = img.naturalHeight;\r\n                var ctx = canvas.getContext('2d');\r\n                ctx.drawImage(img, 0, 0);\r\n                var pEl = self.el('wm-pos'), oEl = self.el('wm-opacity'), sEl = self.el('wm-size');\r\n                var pos = pEl ? pEl.value : 'br';\r\n                var opacity = (parseInt(oEl ? oEl.value : '60') \/ 100);\r\n                var fontSize = parseInt(sEl ? sEl.value : '24');\r\n                ctx.save(); ctx.globalAlpha = opacity; ctx.font = 'bold ' + fontSize + 'px sans-serif'; ctx.fillStyle = '#ffffff'; ctx.shadowColor = 'rgba(0,0,0,0.5)'; ctx.shadowBlur = 4;\r\n                var twx = ctx.measureText(text).width;\r\n                var margin = 20, x, y;\r\n                if (pos === 'br') { x = canvas.width - twx - margin; y = canvas.height - margin; }\r\n                else if (pos === 'bl') { x = margin; y = canvas.height - margin; }\r\n                else if (pos === 'tr') { x = canvas.width - twx - margin; y = fontSize + margin; }\r\n                else if (pos === 'tl') { x = margin; y = fontSize + margin; }\r\n                else { x = (canvas.width - twx) \/ 2; y = canvas.height \/ 2; }\r\n                ctx.fillText(text, x, y); ctx.restore();\r\n                if(ca) ca.style.display = 'block';\r\n                \r\n                if (download) {\r\n                    if (typeof JSZip === 'undefined') return self.showAlert('Error', 'JSZip not loaded.', '\u26a0\ufe0f');\r\n                    self.showProgress('Watermarking...', imgFiles.length + ' images', 10);\r\n                    var zip = new JSZip(), done = 0;\r\n                    var processNext = function() {\r\n                        if (done >= imgFiles.length) {\r\n                            zip.generateAsync({type:'blob'}).then(function(content) {\r\n                                self.hideProgress();\r\n                                var a = document.createElement('a'); a.href = URL.createObjectURL(content); a.download = 'Watermarked.zip'; document.body.appendChild(a); a.click(); document.body.removeChild(a);\r\n                                self.toast('\ud83d\udca7 Watermarked ZIP exported');\r\n                            }); return;\r\n                        }\r\n                        var imgF = imgFiles[done];\r\n                        var i2 = new Image();\r\n                        i2.onload = function() {\r\n                            var c2 = document.createElement('canvas'); c2.width = i2.width; c2.height = i2.height;\r\n                            var ctx2 = c2.getContext('2d'); ctx2.drawImage(i2, 0, 0);\r\n                            ctx2.save(); ctx2.globalAlpha = opacity; ctx2.font = 'bold ' + fontSize + 'px sans-serif'; ctx2.fillStyle = '#ffffff'; ctx2.shadowColor='rgba(0,0,0,0.5)'; ctx2.shadowBlur=4;\r\n                            var tw2 = ctx2.measureText(text).width, x2, y2;\r\n                            if (pos === 'br') { x2 = c2.width-tw2-margin; y2 = c2.height-margin; } else if (pos === 'bl') { x2 = margin; y2 = c2.height-margin; } else if (pos === 'tr') { x2 = c2.width-tw2-margin; y2 = fontSize+margin; } else if (pos === 'tl') { x2 = margin; y2 = fontSize+margin; } else { x2 = (c2.width-tw2)\/2; y2 = c2.height\/2; }\r\n                            ctx2.fillText(text, x2, y2); ctx2.restore();\r\n                            c2.toBlob(function(blob) { zip.file(imgF.name, blob); done++; var pf = self.el('prog-fill'); if(pf) pf.style.width = (done\/imgFiles.length*100) + '%'; processNext(); }, 'image\/jpeg', 0.92);\r\n                        };\r\n                        i2.src = imgF.url;\r\n                    };\r\n                    processNext();\r\n                }\r\n            };\r\n            img.src = f.url;\r\n        },\r\n        \r\n        generateManifest: function() {\r\n            var lines = ['# File Manifest \\u2014 Generated by SmartFileOrganizer PRO', '# Date: ' + new Date().toLocaleDateString(), '# Total Files: ' + this.state.files.length, ''];\r\n            var byFolder = {}, self = this;\r\n            this.state.files.forEach(function(f) {\r\n                if (!byFolder[f.folder]) byFolder[f.folder] = [];\r\n                byFolder[f.folder].push(f);\r\n            });\r\n            Object.keys(byFolder).forEach(function(folder) {\r\n                var files = byFolder[folder];\r\n                lines.push('## ' + folder + ' (' + files.length + ' files)');\r\n                files.forEach(function(f) { lines.push('  - ' + f.name + ' [' + self.formatBytes(f.size) + ']' + (f.detectedDate ? ' ['+f.detectedDate.toLocaleDateString()+']' : '')); });\r\n                lines.push('');\r\n            });\r\n            var text = lines.join('\\n');\r\n            var mo = this.el('manifest-output');\r\n            if(!mo) return;\r\n            mo.style.display = 'block';\r\n            mo.innerHTML = '\\x3Cdiv class=\"tool-result-title\"\\x3EManifest Preview (' + this.state.files.length + ' files)\\x3C\/div\\x3E\\x3Cpre style=\"font-size:10px;white-space:pre-wrap;max-height:200px;overflow-y:auto;color:var(--slate-600);\"\\x3E' + text.slice(0,3000) + (text.length>3000?'\\n... (truncated)':'') + '\\x3C\/pre\\x3E\\x3Cbutton class=\"btn btn-secondary btn-sm\" id=\"btn-dl-manifest\" style=\"margin-top:8px;\"\\x3E\u2b07\ufe0f Download .txt\\x3C\/button\\x3E';\r\n            this.safeOn('btn-dl-manifest', 'click', function() {\r\n                var a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([text], {type:'text\/plain'})); a.download = 'FileManifest.txt'; document.body.appendChild(a); a.click(); document.body.removeChild(a);\r\n            });\r\n        },\r\n        \r\n        exportZipAdv: function(scope, structure, zipName) {\r\n            var files, self = this;\r\n            if (scope === 'selected') files = this.state.files.filter(function(f){ return self.state.selectedIds.has(f.id); });\r\n            else if (scope === 'current') files = this.getDisplayFiles();\r\n            else files = this.state.files;\r\n            \r\n            if (!files.length) return this.showAlert('Empty Export', 'No files match export scope.', '\ud83d\uded1');\r\n            if (typeof JSZip === 'undefined') return this.showAlert('Error', 'JSZip not loaded.', '\u26a0\ufe0f');\r\n            \r\n            this.showProgress('Creating ZIP...', files.length + ' files', 10);\r\n            var zip = new JSZip();\r\n            files.forEach(function(f) {\r\n                var path = '';\r\n                if (structure === 'organized') path = f.folder + '\/';\r\n                else if (structure === 'type') path = (f.type === 'image' ? 'Photos' : f.type === 'video' ? 'Videos' : 'Documents') + '\/';\r\n                else if (structure === 'date-month') path = f.monthLabel + '\/';\r\n                else if (structure === 'date-year') path = (f.detectedDate ? f.detectedDate.getFullYear() : 'Unknown') + '\/';\r\n                zip.file(path + f.name, f.blob);\r\n            });\r\n            \r\n            zip.generateAsync({type:'blob', compression:'STORE'}, function(meta) { \r\n                var pf = self.el('prog-fill'); if(pf) pf.style.width = (10 + meta.percent * 0.9) + '%'; \r\n            }).then(function(content) {\r\n                self.hideProgress();\r\n                var a = document.createElement('a'); a.href = URL.createObjectURL(content); a.download = zipName.replace(\/[^a-z0-9_\\-]\/gi,'_') + '.zip'; document.body.appendChild(a); a.click(); document.body.removeChild(a);\r\n                self.toast('\ud83d\udce6 ZIP exported: ' + files.length + ' files');\r\n            }).catch(function(err) {\r\n                self.hideProgress();\r\n                self.showAlert('Export Error', err.message, '\u274c');\r\n            });\r\n        },\r\n        \r\n        quickSelectType: function(type) {\r\n            var self = this;\r\n            this.state.files.forEach(function(f){ if (f.type === type) self.state.selectedIds.add(f.id); });\r\n            this.renderGallery(); this.toast('\u2611\ufe0f Selected all ' + type + 's');\r\n        },\r\n        \r\n        restartApp: function() {\r\n            if (!this.state.files.length || confirm('Restart? All organized folders will be lost.')) {\r\n                this.state.files = []; this.state.customFolders = []; this.state.tags = {}; this.state.currentFolder = 'All';\r\n                this.state.selectedIds.clear(); this.state.dupIds.clear(); this.state.fileIdCounter = 0;\r\n                var org = this.el('organizer'), sb = this.el('stats-bar'), dz = this.el('dropzone');\r\n                if(org) org.style.display = 'none'; \r\n                if(sb) sb.style.display = 'none'; \r\n                if(dz) dz.style.display = 'block';\r\n                var fs = this.el('filter-start'), fe = this.el('filter-end'), sc = this.el('search-box');\r\n                if(fs) fs.value = ''; if(fe) fe.value = ''; if(sc) sc.value = '';\r\n                var self = this; ['inp-files','inp-folder','inp-zip','inp-add-files','inp-add-folder'].forEach(function(id) { var e=self.el(id); if(e) e.value=''; });\r\n                this.toast('\ud83d\udd04 Workspace reset');\r\n            }\r\n        },\r\n\r\n        loadSampleData: function() {\r\n            var self = this;\r\n            this.showProgress('Loading Sample Data...', 'Creating mock files', 50);\r\n            \r\n            var txtBlob = new Blob(['Mock document data'], {type: 'text\/plain'});\r\n            var d = new Date(); d.setDate(d.getDate() - 10);\r\n            txtBlob.name = 'Project_Notes_' + d.toISOString().slice(0,10) + '.txt';\r\n\r\n            var jsBlob = new Blob(['console.log(\"hello\");'], {type: 'text\/javascript'});\r\n            jsBlob.name = 'AppConfig_Old.js';\r\n\r\n            var b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgG2Sn32OQAAAABJRU5ErkJggg==';\r\n            fetch('data:image\/png;base64,' + b64Data).then(function(res){return res.blob()}).then(function(imgBlob) {\r\n                imgBlob.name = 'Sample_Photo.png';\r\n                self.hideProgress();\r\n                self.processFileList([txtBlob, jsBlob, imgBlob]);\r\n                self.toast('\ud83d\udca1 Mock sample files loaded!');\r\n            }).catch(function() {\r\n                self.hideProgress();\r\n                self.processFileList([txtBlob, jsBlob]);\r\n                self.toast('\ud83d\udca1 Mock sample docs loaded!');\r\n            });\r\n        },\r\n\r\n        attachEvents: function() {\r\n            var self = this;\r\n            \r\n            var wrapper = document.getElementById('pth-smartfileorg-wrapper');\r\n            if (wrapper && !wrapper._hasGlobalListener) {\r\n                wrapper._hasGlobalListener = true;\r\n                wrapper.addEventListener('change', function(e) {\r\n                    if (!e.target || !e.target.id) return;\r\n                    if (e.target.id === 'inp-files' || e.target.id === 'inp-add-files') {\r\n                        if(e.target.files.length > 0) { self.processFileList(e.target.files); }\r\n                        e.target.value = ''; \r\n                    } \r\n                    else if (e.target.id === 'inp-folder' || e.target.id === 'inp-add-folder') {\r\n                        if(e.target.files.length > 0) { self.processFileList(e.target.files); }\r\n                        e.target.value = '';\r\n                    } \r\n                    else if (e.target.id === 'inp-zip') {\r\n                        if (e.target.files.length > 0) { self.processFileList([e.target.files[0]]); }\r\n                        e.target.value = '';\r\n                    }\r\n                });\r\n            }\r\n\r\n            var dz = this.el('dropzone');\r\n            if (dz) {\r\n                dz.addEventListener('dragover', function(e) { e.preventDefault(); dz.classList.add('dragover'); });\r\n                dz.addEventListener('dragleave', function(e) { e.preventDefault(); dz.classList.remove('dragover'); });\r\n                dz.addEventListener('drop', function(e) {\r\n                    e.preventDefault(); dz.classList.remove('dragover');\r\n                    if(e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {\r\n                        self.processFileList(e.dataTransfer.files);\r\n                    }\r\n                });\r\n            }\r\n\r\n            this.safeOn('pth-load-sample-btn', 'click', function() { self.loadSampleData(); });\r\n            this.safeOn('btn-restart', 'click', function() { self.restartApp(); });\r\n            this.safeOn('btn-expand', 'click', function() {\r\n                var layout = self.el('org-layout'); \r\n                if(layout) layout.classList.toggle('expanded');\r\n                this.textContent = (layout && layout.classList.contains('expanded')) ? '\u25e8 Split View' : '\u26f6 Full Width';\r\n            });\r\n\r\n            this.safeOn('ao-month', 'click', function() { self.autoOrganize('date-month'); });\r\n            this.safeOn('ao-year', 'click', function() { self.autoOrganize('date-year'); });\r\n            this.safeOn('ao-type', 'click', function() { self.autoOrganize('type'); });\r\n            this.safeOn('ao-type-date', 'click', function() { self.autoOrganize('type-date'); });\r\n            this.safeOn('ao-size', 'click', function() { self.autoOrganize('size'); });\r\n            this.safeOn('ao-ext', 'click', function() { self.autoOrganize('ext'); });\r\n            this.safeOn('btn-remove-dups', 'click', function() { self.removeDuplicates(); });\r\n            this.safeOn('filter-start', 'change', function() { self.renderGallery(); });\r\n            this.safeOn('filter-end', 'change', function() { self.renderGallery(); });\r\n            this.safeOn('btn-clear-dates', 'click', function() { var fs = self.el('filter-start'), fe = self.el('filter-end'); if(fs) fs.value=''; if(fe) fe.value=''; self.renderGallery(); });\r\n\r\n            this.qsa('.tab-btn').forEach(function(btn) {\r\n                btn.addEventListener('click', function() {\r\n                    self.qsa('.tab-btn').forEach(function(b) { b.classList.remove('active'); });\r\n                    self.qsa('.tab-panel').forEach(function(p) { p.classList.remove('active'); });\r\n                    btn.classList.add('active'); \r\n                    var target = self.el(btn.getAttribute('data-tab'));\r\n                    if(target) target.classList.add('active');\r\n                });\r\n            });\r\n\r\n            this.safeOn('btn-select-all', 'click', function() {\r\n                if (self.state.selectedIds.size > 0) { self.state.selectedIds.clear(); } \r\n                else { self.getDisplayFiles().forEach(function(f){ self.state.selectedIds.add(f.id); }); }\r\n                self.renderGallery();\r\n            });\r\n            this.safeOn('btn-move', 'click', function() { self.showMoveModal('move'); });\r\n            this.safeOn('btn-copy-folder', 'click', function() { self.showMoveModal('copy'); });\r\n            this.safeOn('btn-rename', 'click', function() { var rp = self.el('rename-pattern'); if(rp) rp.value = ''; var tabs = self.qsa('.tab-btn'); if(tabs[1]) tabs[1].click(); });\r\n            this.safeOn('btn-delete', 'click', function() { self.deleteSelected(); });\r\n            this.safeOn('btn-export-zip', 'click', function() { self.exportZipAdv('current', 'organized', 'CurrentView'); });\r\n\r\n            this.qsa('.filter-tag').forEach(function(btn) {\r\n                btn.addEventListener('click', function() {\r\n                    self.qsa('.filter-tag').forEach(function(b) { b.classList.remove('active'); });\r\n                    this.classList.add('active'); self.state.filterType = this.getAttribute('data-filter'); self.renderGallery();\r\n                });\r\n            });\r\n            this.safeOn('search-box', 'input', function(e) { self.state.searchQuery = e.target.value.toLowerCase(); self.renderGallery(); });\r\n            this.safeOn('sort-select', 'change', function(e) { self.state.sortMode = e.target.value; self.renderGallery(); });\r\n            this.safeOn('thumb-size', 'change', function(e) { self.setThumbSize(e.target.value); });\r\n            this.qsa('.view-btn').forEach(function(btn) {\r\n                btn.addEventListener('click', function() {\r\n                    self.qsa('.view-btn').forEach(function(b){ b.classList.remove('active'); });\r\n                    this.classList.add('active'); self.state.viewMode = this.getAttribute('data-view'); self.renderGallery();\r\n                });\r\n            });\r\n\r\n            this.safeOn('btn-new-folder', 'click', function() { self.showOverlay('modal-new-folder'); });\r\n            this.safeOn('close-folder-modal', 'click', function() { self.hideOverlay('modal-new-folder'); });\r\n            this.safeOn('confirm-new-folder', 'click', function() { var nf = self.el('new-folder-name'); if(nf) self.createFolder(nf.value.trim()); });\r\n            this.safeOn('new-folder-name', 'keydown', function(e) { if (e.key === 'Enter') { var nf = self.el('new-folder-name'); if(nf) self.createFolder(nf.value.trim()); } });\r\n\r\n            this.safeOn('close-move-modal', 'click', function() { self.hideOverlay('modal-move'); });\r\n            this.safeOn('confirm-move', 'click', function() { self.moveFiles('move'); });\r\n            this.safeOn('close-copy-modal', 'click', function() { self.hideOverlay('modal-copy'); });\r\n            this.safeOn('confirm-copy', 'click', function() { self.moveFiles('copy'); });\r\n\r\n            this.safeOn('alert-ok', 'click', function() { self.hideOverlay('modal-alert'); });\r\n            this.safeOn('preview-close', 'click', function() { self.hideOverlay('modal-preview'); var pm = self.el('preview-media'); if(pm) pm.innerHTML=''; });\r\n            this.safeOn('preview-prev', 'click', function() { self.state.previewIndex = (self.state.previewIndex - 1 + self.state.previewIds.length) % self.state.previewIds.length; self.showPreviewAt(self.state.previewIndex); });\r\n            this.safeOn('preview-next', 'click', function() { self.state.previewIndex = (self.state.previewIndex + 1) % self.state.previewIds.length; self.showPreviewAt(self.state.previewIndex); });\r\n            \r\n            document.addEventListener('keydown', function(e) {\r\n                var modal = self.el('modal-preview');\r\n                if (modal && modal.style.display === 'flex') {\r\n                    if (e.key === 'ArrowLeft') { self.state.previewIndex = (self.state.previewIndex - 1 + self.state.previewIds.length) % self.state.previewIds.length; self.showPreviewAt(self.state.previewIndex); }\r\n                    if (e.key === 'ArrowRight') { self.state.previewIndex = (self.state.previewIndex + 1) % self.state.previewIds.length; self.showPreviewAt(self.state.previewIndex); }\r\n                    if (e.key === 'Escape') { self.hideOverlay('modal-preview'); var pm = self.el('preview-media'); if(pm) pm.innerHTML=''; }\r\n                }\r\n            });\r\n\r\n            this.safeOn('btn-batch-rename', 'click', function() { self.batchRename(); });\r\n            this.safeOn('btn-preview-rename', 'click', function() { self.previewRename(); });\r\n            this.safeOn('btn-fr-apply', 'click', function() { self.findReplace('selected'); });\r\n            this.safeOn('btn-fr-all', 'click', function() { self.findReplace('all'); });\r\n            this.safeOn('btn-scan-dups', 'click', function() { self.scanDuplicates(); });\r\n            this.safeOn('btn-del-dups', 'click', function() { self.removeDuplicates(); });\r\n            this.safeOn('btn-sel-dups', 'click', function() { self.selectDuplicates(); });\r\n            this.safeOn('btn-add-tag', 'click', function() { var ti = self.el('tag-input'), tc = self.el('tag-color'); if(ti && tc) self.addTag(ti.value.trim(), tc.value); });\r\n            this.safeOn('btn-wm-preview', 'click', function() { self.applyWatermark(false); });\r\n            this.safeOn('btn-wm-apply', 'click', function() { self.applyWatermark(true); });\r\n            this.safeOn('wm-opacity', 'input', function(e) { var ov = self.el('wm-opacity-val'); if(ov) ov.textContent = e.target.value + '%'; });\r\n            this.safeOn('wm-size', 'input', function(e) { var sv = self.el('wm-size-val'); if(sv) sv.textContent = e.target.value + 'px'; });\r\n            this.safeOn('btn-export-adv', 'click', function() { \r\n                var sc = self.el('export-scope'), st = self.el('export-structure'), na = self.el('export-name');\r\n                if(sc && st && na) self.exportZipAdv(sc.value, st.value, na.value); \r\n            });\r\n            this.safeOn('btn-gen-manifest', 'click', function() { self.generateManifest(); });\r\n\r\n            this.safeOn('qa-select-all-imgs', 'click', function() { self.quickSelectType('image'); });\r\n            this.safeOn('qa-select-all-vids', 'click', function() { self.quickSelectType('video'); });\r\n            this.safeOn('qa-select-dups', 'click', function() { self.selectDuplicates(); });\r\n            this.safeOn('qa-select-large', 'click', function() { self.state.files.filter(function(f){return f.size>10*1024*1024;}).forEach(function(f){self.state.selectedIds.add(f.id);}); self.renderGallery(); self.toast('\u2611\ufe0f Selected files > 10MB'); });\r\n            this.safeOn('qa-select-undated', 'click', function() { self.state.files.filter(function(f){return !f.detectedDate;}).forEach(function(f){self.state.selectedIds.add(f.id);}); self.renderGallery(); self.toast('\u2611\ufe0f Selected undated files'); });\r\n            this.safeOn('qa-export-selected', 'click', function() { self.exportZipAdv('selected', 'organized', 'Selected_Export'); });\r\n        }\r\n    };\r\n    \r\n    \/\/ \ud83d\udea8 INDESTRUCTIBLE BOOTLOADER \ud83d\udea8\r\n    var bootAttempts = 0;\r\n    var bootLoader = setInterval(function() {\r\n        if (document.getElementById('pth-smartfileorg-wrapper') && !window.pthSmartFileOrgApp.initialized) {\r\n            window.pthSmartFileOrgApp.initialized = true;\r\n            window.pthSmartFileOrgApp.init();\r\n            clearInterval(bootLoader);\r\n        }\r\n        if(++bootAttempts > 50) clearInterval(bootLoader);\r\n    }, 100);\r\n})();\r\n<\/script>\n\n\n\n<style>\n.pth-feature-wrap { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-bottom: 30px; }\n.pth-feat-box { border: 1px solid #e2e8f0; background: #ffffff; padding: 24px; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.02); transition: all 0.3s ease; }\n.pth-feat-box:hover { border-color: #bfdbfe; transform: translateY(-3px); box-shadow: 0 10px 15px -3px rgba(0,0,0,0.05); }\n.pth-feat-title { font-size: 1.1rem; font-weight: 800; color: #0f172a; margin-bottom: 10px; display: flex; align-items: center; gap: 10px; }\n.pth-feat-text { font-size: 0.9rem; color: #475569; line-height: 1.6; margin: 0; }\n.pth-steps-wrap { border: 1px solid #e2e8f0; background: #ffffff; padding: 40px 30px; border-radius: 16px; text-align: center; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.02); margin-bottom: 40px; }\n.pth-steps-title { font-size: 1.2rem; font-weight: 800; color: #1e293b; text-transform: uppercase; margin-bottom: 35px; letter-spacing: 1px; }\n.pth-steps-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 30px; }\n.pth-step-item { display: flex; flex-direction: column; align-items: center; }\n.pth-step-num { width: 45px; height: 45px; background: #3b82f6; color: #ffffff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 1.2rem; margin-bottom: 15px; box-shadow: 0 4px 10px rgba(59,130,246,0.3); }\n.pth-step-name { font-weight: 800; color: #0f172a; margin-bottom: 8px; font-size: 1.05rem; }\n.pth-step-desc { font-size: 0.9rem; color: #64748b; line-height: 1.5; margin: 0; }\n<\/style>\n\n<div class=\"pth-feature-wrap\">\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udd12 Local Environment<\/div>\n        <p class=\"pth-feat-text\">Our <strong>offline smart file organizer<\/strong> executes 100% locally in your browser. No data is transmitted to external servers, protecting sensitive intellectual property.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83c\udff7\ufe0f Advanced Pattern Renamer<\/div>\n        <p class=\"pth-feat-text\">The <strong>smart file organizer<\/strong> maps specific extension and timestamp values mathematically to execute batch renaming via dynamic regex-like tokens.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udddc\ufe0f Native ZIP Processing<\/div>\n        <p class=\"pth-feat-text\">Extract and compress archives directly using client-side memory. This <strong>smart file organizer<\/strong> packages your modified directory structures sequentially.<\/p>\n    <\/div>\n<\/div>\n\n<div class=\"pth-steps-wrap\">\n    <div class=\"pth-steps-title\">How to Use the smart file organizer<\/div>\n    <div class=\"pth-steps-grid\">\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">1<\/div>\n            <div class=\"pth-step-name\">Load Data<\/div>\n            <p class=\"pth-step-desc\">Drag and drop folders directly into the <strong>smart file organizer<\/strong> to initialize the local processing session.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">2<\/div>\n            <div class=\"pth-step-name\">Analyze Structurally<\/div>\n            <p class=\"pth-step-desc\">Review visual graphs, isolated duplicates, and parsed metadata distributions gathered by the engine.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">3<\/div>\n            <div class=\"pth-step-name\">Execute Logic<\/div>\n            <p class=\"pth-step-desc\">Apply tags, remove exact binary matches, and rename batches securely inside your browser DOM.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">4<\/div>\n            <div class=\"pth-step-name\">Export Package<\/div>\n            <p class=\"pth-step-desc\">Generate an optimized, compressed ZIP archive containing all your modified and organized elements.<\/p>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n\n<div id=\"start-seo-article\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udfe5 <strong>The Computational Logic of Our offline smart file organizer<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Modern web browser capabilities have fundamentally shifted how engineers handle heavy data operations. Historically, managing metadata, archiving arrays, or detecting duplicate arrays required server-side processing using PHP or Node.js. This traditional client-server architecture introduced latency and significant privacy risks. Today, our <strong>offline smart file organizer<\/strong> bypasses backend communication entirely by processing within the browser&#8217;s native JavaScript execution engine. By accessing the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/File_API\" target=\"_blank\" rel=\"noreferrer noopener\">Mozilla Web File API<\/a>, theoffline smart file organizer reads raw binary data (Blobs) directly from your local hard drive into volatile RAM.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe7-memory-allocation-and-cpu-efficiency\" class=\"wp-block-heading\">\ud83d\udfe7 Memory Allocation and CPU Efficiency<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When you input an archive or a directory into the <strong>offline smart file organizer<\/strong>, it initiates asynchronous JavaScript promises to unpack and index file signatures without blocking the main visual rendering thread. This asynchronous design ensures the application can evaluate thousands of objects, parse hexadecimal headers, and isolate duplicate byte-signatures almost instantaneously using your machine&#8217;s local CPU. Managing memory leaks is a known challenge in single-page applications. We engineered a strict garbage collection protocol that automatically flushes old Blob URLs and clears JavaScript memory sets when you restart the session. This prevents memory saturation, even if you analyze gigabytes of media. Traditional software often suffers from bottlenecking during I\/O operations, but executing logic directly in the Document Object Model solves this mathematical limitation.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud83d\udfe2 Direct DOM parsing prevents server latency and bandwidth exhaustion.<\/li>\n\n\n\n<li>\ud83d\udd35 High-speed algorithmic hash matching isolates duplicate elements accurately.<\/li>\n\n\n\n<li>\ud83d\udfe3 JavaScript typed arrays process raw binary headers for exact matching.<\/li>\n\n\n\n<li>\ud83d\udfe4 Local runtime isolation guarantees network interception is mathematically impossible.<\/li>\n<\/ul>\n\n\n\n<h3 id=\"\ud83d\udfe8-cryptographic-duplicate-detection-and-parsing\" class=\"wp-block-heading\">\ud83d\udfe8 Cryptographic Duplicate Detection and Parsing<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Finding exact duplicates requires more than merely checking nominal text strings. The <strong>offline smart file organizer<\/strong> calculates precise byte sizes and executes cryptographic hashing mechanisms to verify if two distinct files contain the exact same binary sequence. Furthermore, parsing JPEGs and MP4s for metadata requires traversing specific byte offsets. The utility scans for Exchangeable Image File Format (EXIF) markers without ever altering the source encoding. By mapping structural data formats directly into browser memory, the tool identifies origin timestamps and coordinates instantly, injecting them into the dynamic regex batch-renaming module. This non-destructive scanning ensures your original digital assets remain mathematically untouched during processing.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe9-expanding-your-technical-toolkit\" class=\"wp-block-heading\">\ud83d\udfe9 Expanding Your Technical Toolkit<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Because the <strong>offline smart file organizer<\/strong> never uploads your content, it acts as a highly secure, completely isolated offline sandbox. Operating without API dependencies ensures absolute longevity and privacy for your data. If you value this type of localized, zero-server engineering, you can discover similar client-side utilities when you <a href=\"https:\/\/schoolict.net\/tools\/free-web-tools-directory-prime-tool-hub\/\">explore our comprehensive Prime Tool Hub directory<\/a>. Every utility, including this <strong>offline smart file organizer<\/strong>, is meticulously engineered to optimize your technical workflow through applied computer science principles.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Free Smart File Organizer &#038; Zip Studio | 100% Offline Auto-sort, preview, and organize your files with our free offline smart file organizer and zip studio. Create virtual folders and download as a ZIP securely. \ud83d\udd12 Local Environment Our offline smart file organizer executes 100% locally in your browser. No data is transmitted to external &#8230; <a title=\"Free offline smart file organizer &amp; Zip Studio | 100% Offline\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/free-offline-smart-file-organizer\/\" aria-label=\"Read more about Free offline smart file organizer &amp; Zip Studio | 100% Offline\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":4868,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-4795","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/4795","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=4795"}],"version-history":[{"count":1,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/4795\/revisions"}],"predecessor-version":[{"id":6928,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/4795\/revisions\/6928"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/4868"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=4795"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}