{"id":2884,"date":"2026-04-21T12:48:30","date_gmt":"2026-04-21T12:48:30","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=2884"},"modified":"2026-07-04T13:52:55","modified_gmt":"2026-07-04T13:52:55","slug":"ai-offline-transcription","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/ai-offline-transcription\/","title":{"rendered":"Secure AI Offline Transcription Studio | Client-Side Audio to Text"},"content":{"rendered":"<div class=\"pth-hero-section\">\n<div class=\"pth-hero-content\">\n<h2>Secure AI Offline Transcription Studio | Client-Side Audio to Text<\/h2>\n<p>Convert speech to text securely using our AI offline transcription studio. It runs Whisper neural network models entirely client-side for zero-upload privacy.<\/p>\n<div id=\"pth-toc-placeholder\"><\/div>\n<\/p>\n<\/div>\n\n  <div class=\"pth-hero-image\">\n    <img data-no-lazy=\"1\"\n         src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/04\/AI-offline-transcription-800x447.jpeg\"\n         width=\"800\"\n         height=\"447\"\n         alt=\"AI offline transcription\"\n         fetchpriority=\"high\"\n         loading=\"eager\"\n         decoding=\"async\"\n         style=\"width:100%; height:auto; display:block;\">\n  <\/div>\n<\/div>\n\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\udd34-why-one-tab-is-never-enough-for-real-transcription-work\">\ud83d\udd34 Why One Tab Is Never Enough for Real Transcription Work<\/a><ul><li><a href=\"#the-5-tab-workspace-every-step-in-one-place\">The 5-Tab Workspace \u2014 Every Step in One Place<\/a><\/li><li><a href=\"#smart-notes-from-speech-to-structured-document\">Smart Notes \u2014 From Speech to Structured Document<\/a><\/li><li><a href=\"#\ud83d\udfe1-deep-analytics-what-your-speech-data-actually-reveals\">\ud83d\udfe1 Deep Analytics \u2014 What Your Speech Data Actually Reveals<\/a><\/li><li><a href=\"#text-tools-clean-and-reformat-without-leaving-the-tool\">Text Tools \u2014 Clean and Reformat Without Leaving the Tool<\/a><\/li><li><a href=\"#\ud83d\udfe2-export-hub-six-formats-four-copy-modes\">\ud83d\udfe2 Export Hub \u2014 Six Formats, Four Copy Modes<\/a><\/li><li><a href=\"#playback-speed-control-and-audio-trimmer\">Playback Speed Control and Audio Trimmer<\/a><\/li><li><a href=\"#live-microphone-and-20-language-support\">Live Microphone and 20-Language Support<\/a><\/li><\/ul><\/li><li><a href=\"#\ud83d\udd34-who-uses-this-tool-real-use-cases\">\ud83d\udd34 Who Uses This Tool \u2014 Real Use Cases<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<!-- External Dependencies -->\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/html2pdf.js\/0.10.1\/html2pdf.bundle.min.js\" data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\"><\/script>\r\n<style>\r\n\/* ============================================================\r\n   PTH AI OFFLINE TRANSCRIPTION STUDIO \u2014 v3.0\r\n   AdseSense + PageSpeed + WCAG 2.1 AA Compliant\r\n   All features: Tabs, Smart Notes, Deep Analytics, Text Tools,\r\n   Export Hub, Filler Filter, Bookmark Panel, Speed Control\r\n   ============================================================ *\/\r\n\r\n#pth-transcribe-wrapper {\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  max-width: 1500px; margin: 0 auto; box-sizing: border-box;\r\n  padding: 24px; border-radius: 20px; color: #1e293b;\r\n  background: #f1f5f9; position: relative;\r\n}\r\n#pth-transcribe-wrapper * { box-sizing: border-box; min-width: 0; }\r\n\r\n\/* Dark Mode *\/\r\n#pth-transcribe-wrapper.pth-dark { background: #0f172a; color: #e2e8f0; }\r\n#pth-transcribe-wrapper.pth-dark .pth-card { background: #1e293b; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-top-bar { background: #1e293b; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-select,\r\n#pth-transcribe-wrapper.pth-dark .pth-search-input,\r\n#pth-transcribe-wrapper.pth-dark .pth-trim-input,\r\n#pth-transcribe-wrapper.pth-dark .pth-notes-area { background: #1e293b; color: #e2e8f0; border-color: #475569; }\r\n#pth-transcribe-wrapper.pth-dark .pth-tab-bar { background: #1e293b; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-tab-btn { color: #94a3b8; }\r\n#pth-transcribe-wrapper.pth-dark .pth-tab-btn.active { background: #0f172a; color: #e2e8f0; border-color: #334155; border-bottom-color: #0f172a; }\r\n#pth-transcribe-wrapper.pth-dark .pth-editor-area { background: #1e293b; }\r\n#pth-transcribe-wrapper.pth-dark .pth-segment:hover { background: #263548; }\r\n#pth-transcribe-wrapper.pth-dark .pth-segment.pth-seg-active { background: #1e3a5f; }\r\n#pth-transcribe-wrapper.pth-dark .pth-toolbar { background: #1e293b; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-stat-chip { background: #263548; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-word-cloud { background: #263548; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-option-chip { background: #263548; border-color: #334155; color: #94a3b8; }\r\n#pth-transcribe-wrapper.pth-dark .pth-option-chip.active { background: rgba(16,185,129,0.15); border-color: #10b981; color: #10b981; }\r\n#pth-transcribe-wrapper.pth-dark .pth-btn-secondary { background: #1e293b; color: #e2e8f0; border-color: #475569; }\r\n#pth-transcribe-wrapper.pth-dark .pth-btn-ghost { color: #94a3b8; }\r\n#pth-transcribe-wrapper.pth-dark .pth-btn-ghost:hover { background: #263548; color: #e2e8f0; }\r\n#pth-transcribe-wrapper.pth-dark .pth-upload-zone { background: #1e293b; border-color: #475569; }\r\n#pth-transcribe-wrapper.pth-dark .pth-file-info-wrapper { background: rgba(59,130,246,0.1); }\r\n#pth-transcribe-wrapper.pth-dark .pth-bookmark-panel { background: #1e293b; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-bm-item { background: #263548; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-export-card { background: #263548; border-color: #334155; }\r\n#pth-transcribe-wrapper.pth-dark .pth-text-tool-area { background: #1e293b; color: #e2e8f0; border-color: #475569; }\r\n#pth-transcribe-wrapper.pth-dark .pth-speed-btn { background: #263548; color: #94a3b8; border-color: #475569; }\r\n#pth-transcribe-wrapper.pth-dark .pth-speed-btn.active { background: rgba(139,92,246,0.2); border-color: #8b5cf6; color: #a78bfa; }\r\n#pth-transcribe-wrapper.pth-dark .pth-copy-mode-btn { background: #263548; border-color: #334155; color: #94a3b8; }\r\n#pth-transcribe-wrapper.pth-dark .pth-copy-mode-btn:hover { background: #1e293b; color: #e2e8f0; }\r\n#pth-transcribe-wrapper.pth-dark .pth-phrase-tag { background: #263548; border-color: #334155; color: #94a3b8; }\r\n#pth-transcribe-wrapper.pth-dark .pth-shortcuts-panel { background: #1e293b; border-left-color: #334155; color: #e2e8f0; }\r\n#pth-transcribe-wrapper.pth-dark .pth-preview-inner { background: #1e293b; color: #e2e8f0; }\r\n#pth-transcribe-wrapper.pth-dark .pth-preview-inner pre { background: #0f172a; border-color: #334155; color: #e2e8f0; }\r\n#pth-transcribe-wrapper.pth-dark .pth-lang-modal { background: #1e293b; color: #e2e8f0; }\r\n#pth-transcribe-wrapper.pth-dark .pth-lang-btn { color: #e2e8f0; }\r\n#pth-transcribe-wrapper.pth-dark .pth-lang-btn:hover { background: #263548; }\r\n#pth-transcribe-wrapper.pth-dark .pth-pace-row:hover { background: #263548; }\r\n#pth-transcribe-wrapper.pth-dark .pth-silence-item { background: #263548; border-color: #334155; }\r\n\r\n\/* Layout *\/\r\n#pth-transcribe-wrapper .pth-top-bar {\r\n  background: #ffffff; border: 1px solid #e2e8f0; padding: 18px 24px;\r\n  border-radius: 14px; display: flex; justify-content: space-between;\r\n  align-items: center; margin-bottom: 22px; box-shadow: 0 2px 8px rgba(0,0,0,0.06);\r\n  flex-wrap: wrap; gap: 12px;\r\n}\r\n#pth-transcribe-wrapper .pth-tool-title {\r\n  font-size: 1.5rem; font-weight: 900; color: #0f172a; margin: 0;\r\n  display: flex; align-items: center; gap: 10px; letter-spacing: -0.5px;\r\n}\r\n#pth-transcribe-wrapper .pth-subtitle { font-size: 0.82rem; color: #334155; font-weight: 600; margin-top: 3px; display: block; }\r\n#pth-transcribe-wrapper .pth-badge { font-size: 0.68rem; background: linear-gradient(135deg,#10b981,#059669); color: white; padding: 3px 10px; border-radius: 999px; font-weight: 800; }\r\n#pth-transcribe-wrapper .pth-offline-badge { font-size: 0.68rem; background: #1e3a5f; color: #93c5fd; border: 1px solid #3b82f6; padding: 2px 8px; border-radius: 4px; font-weight: 700; }\r\n#pth-transcribe-wrapper .pth-session-badge { font-size: 0.7rem; background: rgba(16,185,129,0.1); color: #047857; border: 1px solid rgba(16,185,129,0.3); border-radius: 5px; padding: 2px 7px; font-weight: 700; display: none; }\r\n#pth-transcribe-wrapper .pth-top-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }\r\n\r\n#pth-transcribe-wrapper .pth-flex-layout { display: grid; grid-template-columns: 380px 1fr; gap: 20px; align-items: start; }\r\n#pth-transcribe-wrapper .pth-flex-layout.pth-full-width { grid-template-columns: 1fr; }\r\n#pth-transcribe-wrapper .pth-flex-layout.pth-full-width .pth-sidebar-col { display: none; }\r\n@media(max-width:1100px){ #pth-transcribe-wrapper .pth-flex-layout { grid-template-columns: 1fr; } }\r\n\r\n#pth-transcribe-wrapper .pth-card {\r\n  background: #ffffff; border: 1px solid #e2e8f0; border-radius: 14px;\r\n  padding: 20px; margin-bottom: 18px; box-shadow: 0 2px 6px rgba(0,0,0,0.04);\r\n}\r\n#pth-transcribe-wrapper .pth-card-title {\r\n  font-size: 1rem; font-weight: 800; color: #0f172a; margin: 0 0 14px 0;\r\n  display: flex; align-items: center; gap: 8px; padding-bottom: 12px;\r\n  border-bottom: 2px solid #e2e8f0; justify-content: space-between;\r\n}\r\n\r\n\/* Upload *\/\r\n#pth-transcribe-wrapper .pth-upload-zone {\r\n  background: #f8fafc; border: 2px dashed #cbd5e1; border-radius: 12px;\r\n  padding: 28px 16px; text-align: center; cursor: pointer; transition: all 0.3s;\r\n  display: flex; flex-direction: column; align-items: center; gap: 8px;\r\n}\r\n#pth-transcribe-wrapper .pth-upload-zone:hover,\r\n#pth-transcribe-wrapper .pth-upload-zone.dragover { border-color: #8b5cf6; background: rgba(139,92,246,0.06); }\r\n#pth-transcribe-wrapper .pth-upload-icon { font-size: 2.4rem; }\r\n#pth-transcribe-wrapper .pth-upload-text { font-size: 0.95rem; font-weight: 800; color: #0f172a; margin: 0; }\r\n#pth-transcribe-wrapper .pth-upload-sub { font-size: 0.78rem; color: #334155; margin: 0; }\r\n#pth-transcribe-wrapper .pth-media-preview { width: 100%; margin-top: 12px; border-radius: 8px; outline: none; background: #0f172a; max-height: 160px; }\r\n#pth-transcribe-wrapper .pth-file-info-wrapper { background: rgba(59,130,246,0.06); border: 1px solid rgba(59,130,246,0.2); padding: 14px; border-radius: 10px; margin-top: 12px; }\r\n#pth-transcribe-wrapper .pth-file-name { font-size: 0.88rem; font-weight: 800; color: #1d4ed8; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\r\n#pth-transcribe-wrapper .pth-file-meta { font-size: 0.72rem; color: #334155; font-family: 'Courier New',monospace; margin-top: 3px; }\r\n#pth-transcribe-wrapper .pth-waveform-canvas { width: 100%; height: 52px; border-radius: 8px; background: #f8fafc; border: 1px solid #e2e8f0; margin-top: 10px; display: none; }\r\n#pth-transcribe-wrapper .pth-trimmer-box { display: flex; gap: 10px; margin-top: 10px; background: rgba(245,158,11,0.06); border: 1px solid rgba(245,158,11,0.25); padding: 10px; border-radius: 8px; align-items: center; flex-wrap: wrap; }\r\n#pth-transcribe-wrapper .pth-trim-input { width: 64px; padding: 5px 7px; border: 1px solid #cbd5e1; border-radius: 6px; font-family: 'Courier New',monospace; text-align: center; font-size: 0.8rem; background: #ffffff; color: #0f172a; }\r\n\r\n\/* Speed Control *\/\r\n#pth-transcribe-wrapper .pth-speed-row { display: flex; align-items: center; gap: 6px; margin-top: 10px; flex-wrap: wrap; }\r\n#pth-transcribe-wrapper .pth-speed-label { font-size: 0.72rem; font-weight: 800; color: #334155; text-transform: uppercase; letter-spacing: 0.5px; }\r\n#pth-transcribe-wrapper .pth-speed-btn { background: #f8fafc; border: 1px solid #e2e8f0; color: #334155; padding: 4px 10px; border-radius: 6px; font-size: 0.75rem; font-weight: 700; cursor: pointer; transition: 0.15s; }\r\n#pth-transcribe-wrapper .pth-speed-btn.active { background: rgba(139,92,246,0.1); border-color: #8b5cf6; color: #5b21b6; }\r\n\r\n\/* Buttons *\/\r\n#pth-transcribe-wrapper .pth-label { font-size: 0.75rem; font-weight: 800; color: #334155; margin-bottom: 6px; display: block; text-transform: uppercase; letter-spacing: 0.6px; }\r\n#pth-transcribe-wrapper .pth-select { width: 100%; padding: 10px 12px; border: 2px solid #cbd5e1; border-radius: 8px; font-size: 0.88rem; font-weight: 700; color: #0f172a; outline: none; transition: 0.2s; font-family: 'Inter',sans-serif; cursor: pointer; background: #ffffff; }\r\n#pth-transcribe-wrapper .pth-select:focus { border-color: #8b5cf6; box-shadow: 0 0 0 3px rgba(139,92,246,0.15); }\r\n#pth-transcribe-wrapper .pth-controls-grid { display: flex; flex-direction: column; gap: 14px; margin-top: 14px; }\r\n#pth-transcribe-wrapper .pth-option-chip { display: inline-flex; align-items: center; gap: 6px; background: #f8fafc; border: 1.5px solid #e2e8f0; border-radius: 7px; padding: 5px 10px; font-size: 0.8rem; font-weight: 700; color: #334155; cursor: pointer; transition: 0.2s; user-select: none; }\r\n#pth-transcribe-wrapper .pth-option-chip.active { background: rgba(16,185,129,0.1); border-color: #10b981; color: #047857; }\r\n#pth-transcribe-wrapper .pth-option-chip input { display: none; }\r\n#pth-transcribe-wrapper .pth-chips-row { display: flex; flex-wrap: wrap; gap: 8px; }\r\n\r\n#pth-transcribe-wrapper .pth-btn { padding: 10px 18px; border-radius: 8px; font-weight: 800; font-size: 0.88rem; cursor: pointer; transition: all 0.2s; display: inline-flex; align-items: center; justify-content: center; gap: 6px; border: none; font-family: 'Inter',sans-serif; white-space: nowrap; }\r\n#pth-transcribe-wrapper .pth-btn-primary { background: linear-gradient(135deg,#8b5cf6,#6d28d9); color: white; box-shadow: 0 3px 10px rgba(139,92,246,0.3); }\r\n#pth-transcribe-wrapper .pth-btn-primary:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 6px 15px rgba(139,92,246,0.4); }\r\n#pth-transcribe-wrapper .pth-btn-success { background: linear-gradient(135deg,#10b981,#047857); color: white; box-shadow: 0 3px 10px rgba(16,185,129,0.3); }\r\n#pth-transcribe-wrapper .pth-btn-danger { background: linear-gradient(135deg,#dc2626,#991b1b); color: white; }\r\n#pth-transcribe-wrapper .pth-btn-secondary { background: #ffffff; color: #1e293b; border: 1.5px solid #e2e8f0; }\r\n#pth-transcribe-wrapper .pth-btn-secondary:hover:not(:disabled) { background: #f8fafc; transform: translateY(-1px); }\r\n#pth-transcribe-wrapper .pth-btn-ghost { background: transparent; color: #334155; border: 1.5px solid transparent; padding: 7px 11px; font-size: 0.8rem; }\r\n#pth-transcribe-wrapper .pth-btn-ghost:hover { background: #f1f5f9; color: #0f172a; }\r\n#pth-transcribe-wrapper .pth-btn-sm { padding: 7px 13px; font-size: 0.8rem; border-radius: 7px; }\r\n#pth-transcribe-wrapper .pth-btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none !important; box-shadow: none !important; }\r\n#pth-transcribe-wrapper .pth-sample-btn { background: #ecfdf5; color: #047857; 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-transcribe-wrapper .pth-sample-btn:hover { background: #d1fae5; }\r\n#pth-transcribe-wrapper .pth-mic-btn { width: 100%; height: 48px; font-size: 0.95rem; }\r\n#pth-transcribe-wrapper .pth-mic-btn.recording { animation: pthPulse 1.5s infinite; background: linear-gradient(135deg,#dc2626,#991b1b); box-shadow: 0 4px 15px rgba(220,38,38,0.4); }\r\n@keyframes pthPulse { 0%,100%{opacity:1;}50%{opacity:0.7;} }\r\n\r\n\/* Progress *\/\r\n#pth-transcribe-wrapper .pth-progress-container { display: none; background: rgba(59,130,246,0.06); border: 1px solid rgba(59,130,246,0.2); border-radius: 10px; padding: 14px 16px; margin-bottom: 12px; }\r\n#pth-transcribe-wrapper .pth-progress-header { display: flex; justify-content: space-between; font-size: 0.82rem; font-weight: 800; color: #1e40af; margin-bottom: 8px; }\r\n#pth-transcribe-wrapper .pth-progress-bar-wrap { width: 100%; height: 5px; background: rgba(59,130,246,0.15); border-radius: 3px; overflow: hidden; }\r\n#pth-transcribe-wrapper .pth-progress-fill { height: 100%; background: linear-gradient(90deg,#3b82f6,#8b5cf6); border-radius: 3px; transition: width 0.3s ease; }\r\n#pth-transcribe-wrapper .pth-status-msg { font-size: 0.75rem; color: #334155; margin-top: 7px; font-weight: 600; font-family: 'Courier New',monospace; }\r\n\r\n\/* Tab System *\/\r\n#pth-transcribe-wrapper .pth-tab-bar { display: flex; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px 12px 0 0; overflow-x: auto; border-bottom: none; padding: 4px 4px 0; gap: 2px; }\r\n#pth-transcribe-wrapper .pth-tab-btn { padding: 10px 16px; font-size: 0.82rem; font-weight: 800; color: #334155; background: transparent; border: 1px solid transparent; border-bottom: none; border-radius: 8px 8px 0 0; cursor: pointer; white-space: nowrap; transition: 0.15s; font-family: 'Inter',sans-serif; }\r\n#pth-transcribe-wrapper .pth-tab-btn:hover { background: #f8fafc; color: #0f172a; }\r\n#pth-transcribe-wrapper .pth-tab-btn.active { background: #ffffff; color: #5b21b6; border-color: #e2e8f0; border-bottom-color: #ffffff; font-weight: 900; position: relative; bottom: -1px; }\r\n#pth-transcribe-wrapper .pth-tab-content-wrap { background: #ffffff; border: 1px solid #e2e8f0; border-radius: 0 0 12px 12px; padding: 16px; min-height: 500px; }\r\n#pth-transcribe-wrapper .pth-tab-panel { display: none; }\r\n#pth-transcribe-wrapper .pth-tab-panel.active { display: block; }\r\n\r\n\/* Toolbar & Editor *\/\r\n#pth-transcribe-wrapper .pth-toolbar { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 10px 12px; margin-bottom: 10px; display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }\r\n#pth-transcribe-wrapper .pth-toolbar-sep { width: 1px; height: 22px; background: #e2e8f0; margin: 0 2px; }\r\n#pth-transcribe-wrapper .pth-search-input { padding: 7px 11px; border: 1.5px solid #cbd5e1; border-radius: 7px; font-size: 0.82rem; outline: none; background: #ffffff; color: #0f172a; font-family: 'Inter',sans-serif; transition: 0.2s; width: 120px; }\r\n#pth-transcribe-wrapper .pth-search-input:focus { border-color: #3b82f6; width: 150px; }\r\n#pth-transcribe-wrapper .pth-zoom-wrap { display: flex; align-items: center; gap: 5px; font-size: 0.75rem; color: #334155; font-weight: 700; }\r\n#pth-transcribe-wrapper .pth-zoom-slider { -webkit-appearance: none; width: 75px; height: 4px; border-radius: 2px; background: #cbd5e1; outline: none; cursor: pointer; }\r\n#pth-transcribe-wrapper .pth-zoom-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 13px; height: 13px; border-radius: 50%; background: #8b5cf6; cursor: pointer; }\r\n#pth-transcribe-wrapper .pth-editor-area { width: 100%; min-height: 420px; max-height: 560px; background: #f8fafc; padding: 14px; overflow-y: auto; font-size: 1rem; line-height: 1.75; color: #1e293b; scrollbar-width: thin; scrollbar-color: #8b5cf6 transparent; border: 1px solid #e2e8f0; border-radius: 8px; }\r\n#pth-transcribe-wrapper .pth-segment { display: flex; gap: 8px; margin-bottom: 5px; padding: 9px; border-radius: 8px; transition: background 0.15s; border: 1px solid transparent; position: relative; }\r\n#pth-transcribe-wrapper .pth-segment:hover { background: #f1f5f9; border-color: #e2e8f0; }\r\n#pth-transcribe-wrapper .pth-segment.pth-seg-active { background: #eff6ff; border-color: rgba(59,130,246,0.35); }\r\n#pth-transcribe-wrapper .pth-segment.pth-seg-bookmarked { border-left: 3px solid #f59e0b; }\r\n#pth-transcribe-wrapper .pth-segment.pth-seg-speaker1 { border-left: 3px solid #3b82f6; }\r\n#pth-transcribe-wrapper .pth-segment.pth-seg-speaker2 { border-left: 3px solid #10b981; }\r\n#pth-transcribe-wrapper .pth-seg-gutter { display: flex; flex-direction: column; align-items: center; gap: 4px; flex-shrink: 0; padding-top: 2px; }\r\n#pth-transcribe-wrapper .pth-line-num { font-family: 'Courier New',monospace; font-size: 0.68rem; color: #64748b; min-width: 20px; text-align: right; }\r\n#pth-transcribe-wrapper .pth-confidence-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; margin-top: 6px; cursor: help; }\r\n#pth-transcribe-wrapper .pth-timestamp { font-family: 'Courier New',monospace; font-size: 0.75rem; font-weight: 700; color: #5b21b6; flex-shrink: 0; padding-top: 2px; cursor: pointer; transition: 0.2s; white-space: nowrap; }\r\n#pth-transcribe-wrapper .pth-timestamp:hover { color: #4c1d95; text-decoration: underline; }\r\n#pth-transcribe-wrapper .pth-text-content { flex: 1; outline: none; padding: 2px 5px; border-radius: 4px; transition: background 0.15s; color: #1e293b; }\r\n#pth-transcribe-wrapper .pth-text-content:focus { background: rgba(139,92,246,0.06); }\r\n#pth-transcribe-wrapper .pth-seg-actions { display: none; gap: 3px; align-items: center; flex-shrink: 0; }\r\n#pth-transcribe-wrapper .pth-segment:hover .pth-seg-actions { display: flex; }\r\n#pth-transcribe-wrapper .pth-seg-action-btn { background: transparent; border: none; cursor: pointer; padding: 3px 5px; border-radius: 4px; font-size: 0.78rem; color: #334155; font-family: 'Inter',sans-serif; transition: 0.15s; }\r\n#pth-transcribe-wrapper .pth-paragraph-view { white-space: pre-wrap; outline: none; padding: 8px; color: #1e293b; line-height: 1.9; }\r\n#pth-transcribe-wrapper .pth-chapter-divider { display: flex; align-items: center; gap: 8px; margin: 12px 0 8px; font-size: 0.75rem; font-weight: 800; color: #92400e; text-transform: uppercase; letter-spacing: 0.7px; }\r\n#pth-transcribe-wrapper .pth-chapter-divider::before,\r\n#pth-transcribe-wrapper .pth-chapter-divider::after { content: ''; flex: 1; height: 1px; background: rgba(245,158,11,0.3); }\r\n\r\n\/* Analytics *\/\r\n#pth-transcribe-wrapper .pth-stats-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 14px; }\r\n#pth-transcribe-wrapper .pth-stat-chip { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 9px 10px; text-align: center; }\r\n#pth-transcribe-wrapper .pth-stat-val { font-size: 1.25rem; font-weight: 900; display: block; letter-spacing: -0.5px; }\r\n#pth-transcribe-wrapper .pth-stat-lbl { font-size: 0.66rem; color: #334155; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; }\r\n#pth-transcribe-wrapper .pth-word-cloud { display: flex; flex-wrap: wrap; gap: 6px; padding: 12px; background: #f8fafc; border-radius: 8px; border: 1px solid #e2e8f0; justify-content: center; min-height: 70px; align-items: center; }\r\n#pth-transcribe-wrapper .pth-cloud-word { display: inline-block; font-weight: 800; line-height: 1; cursor: pointer; transition: transform 0.15s; }\r\n#pth-transcribe-wrapper .pth-cloud-word:hover { transform: scale(1.15); }\r\n#pth-transcribe-wrapper .pth-speaking-rate { display: flex; align-items: center; gap: 7px; font-size: 0.78rem; color: #334155; font-weight: 600; margin-top: 6px; }\r\n#pth-transcribe-wrapper .pth-rate-bar { flex: 1; height: 5px; background: #e2e8f0; border-radius: 3px; overflow: hidden; }\r\n#pth-transcribe-wrapper .pth-rate-fill { height: 100%; background: linear-gradient(90deg,#10b981,#3b82f6); border-radius: 3px; transition: width 0.5s ease; }\r\n#pth-transcribe-wrapper .pth-chapter-pills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }\r\n#pth-transcribe-wrapper .pth-chapter-pill { background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.3); color: #92400e; padding: 3px 10px; border-radius: 999px; font-size: 0.75rem; font-weight: 700; cursor: pointer; }\r\n\r\n\/* Deep Analytics - Pace Graph *\/\r\n#pth-transcribe-wrapper .pth-pace-row { display: flex; align-items: center; gap: 10px; padding: 5px 8px; border-radius: 6px; transition: 0.15s; }\r\n#pth-transcribe-wrapper .pth-pace-row:hover { background: #f1f5f9; }\r\n#pth-transcribe-wrapper .pth-pace-label { font-size: 0.72rem; color: #334155; font-family: 'Courier New',monospace; min-width: 50px; }\r\n#pth-transcribe-wrapper .pth-pace-bar-wrap { flex: 1; height: 14px; background: #f1f5f9; border-radius: 4px; overflow: hidden; }\r\n#pth-transcribe-wrapper .pth-pace-bar-fill { height: 100%; border-radius: 4px; transition: width 0.5s ease; }\r\n#pth-transcribe-wrapper .pth-pace-val { font-size: 0.72rem; font-weight: 700; color: #334155; min-width: 55px; text-align: right; }\r\n#pth-transcribe-wrapper .pth-phrase-tag { background: #f1f5f9; border: 1px solid #e2e8f0; color: #334155; padding: 4px 10px; border-radius: 6px; font-size: 0.8rem; font-weight: 700; display: inline-flex; align-items: center; gap: 5px; }\r\n#pth-transcribe-wrapper .pth-silence-item { background: #fef9c3; border: 1px solid #fde047; border-radius: 6px; padding: 7px 10px; font-size: 0.78rem; font-weight: 700; color: #92400e; }\r\n\r\n\/* Bookmark Panel *\/\r\n#pth-transcribe-wrapper .pth-bookmark-panel { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 14px; margin-top: 12px; }\r\n#pth-transcribe-wrapper .pth-bm-item { background: #ffffff; border: 1px solid #e2e8f0; border-left: 3px solid #f59e0b; border-radius: 6px; padding: 8px 12px; margin-bottom: 7px; cursor: pointer; transition: 0.15s; }\r\n#pth-transcribe-wrapper .pth-bm-item:hover { transform: translateX(3px); border-left-color: #d97706; }\r\n#pth-transcribe-wrapper .pth-bm-time { font-size: 0.72rem; color: #5b21b6; font-weight: 700; font-family: 'Courier New',monospace; }\r\n#pth-transcribe-wrapper .pth-bm-text { font-size: 0.82rem; color: #1e293b; font-weight: 500; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\r\n\r\n\/* Smart Notes *\/\r\n#pth-transcribe-wrapper .pth-notes-area { width: 100%; min-height: 380px; padding: 16px; border: 1.5px solid #cbd5e1; border-radius: 10px; font-size: 0.95rem; line-height: 1.8; font-family: 'Inter',sans-serif; color: #1e293b; background: #ffffff; resize: vertical; outline: none; }\r\n#pth-transcribe-wrapper .pth-notes-area:focus { border-color: #8b5cf6; }\r\n#pth-transcribe-wrapper .pth-notes-toolbar { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 10px; }\r\n\r\n\/* Text Tools *\/\r\n#pth-transcribe-wrapper .pth-text-tools-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }\r\n#pth-transcribe-wrapper .pth-text-tool-area { width: 100%; min-height: 200px; padding: 12px; border: 1.5px solid #cbd5e1; border-radius: 8px; font-size: 0.9rem; line-height: 1.7; font-family: 'Courier New',monospace; color: #1e293b; background: #ffffff; resize: vertical; outline: none; }\r\n#pth-transcribe-wrapper .pth-text-tool-area:focus { border-color: #8b5cf6; }\r\n#pth-transcribe-wrapper .pth-limit-row { display: flex; align-items: center; gap: 10px; margin-top: 10px; flex-wrap: wrap; }\r\n#pth-transcribe-wrapper .pth-limit-chip { font-size: 0.75rem; font-weight: 700; padding: 4px 10px; border-radius: 6px; cursor: pointer; border: 1.5px solid #e2e8f0; background: #f8fafc; color: #334155; transition: 0.15s; }\r\n#pth-transcribe-wrapper .pth-limit-chip:hover { border-color: #8b5cf6; color: #5b21b6; }\r\n\r\n\/* Export Hub *\/\r\n#pth-transcribe-wrapper .pth-export-hub-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 12px; margin-bottom: 16px; }\r\n@media(max-width:600px){ #pth-transcribe-wrapper .pth-export-hub-grid { grid-template-columns: repeat(2,1fr); } }\r\n#pth-transcribe-wrapper .pth-export-card { background: #f8fafc; border: 2px solid #e2e8f0; border-radius: 12px; padding: 16px; text-align: center; cursor: pointer; transition: all 0.2s; }\r\n#pth-transcribe-wrapper .pth-export-card:hover:not(.disabled) { transform: translateY(-3px); box-shadow: 0 6px 16px rgba(0,0,0,0.08); border-color: #8b5cf6; }\r\n#pth-transcribe-wrapper .pth-export-card.disabled { opacity: 0.4; cursor: not-allowed; }\r\n#pth-transcribe-wrapper .pth-export-icon { font-size: 2rem; display: block; margin-bottom: 6px; }\r\n#pth-transcribe-wrapper .pth-export-name { font-size: 0.82rem; font-weight: 800; color: #0f172a; display: block; }\r\n#pth-transcribe-wrapper .pth-export-desc { font-size: 0.7rem; color: #334155; margin-top: 2px; display: block; }\r\n\r\n\/* Copy Modes *\/\r\n#pth-transcribe-wrapper .pth-copy-modes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }\r\n#pth-transcribe-wrapper .pth-copy-mode-btn { background: #f8fafc; border: 1.5px solid #e2e8f0; color: #334155; padding: 7px 14px; border-radius: 8px; font-size: 0.8rem; font-weight: 700; cursor: pointer; transition: 0.15s; font-family: 'Inter',sans-serif; }\r\n#pth-transcribe-wrapper .pth-copy-mode-btn:hover { background: #f1f5f9; border-color: #8b5cf6; color: #5b21b6; }\r\n\r\n\/* Modals *\/\r\n#pth-ts-toast { position: fixed; bottom: 22px; right: 22px; background: #1e293b; color: white; padding: 13px 22px; border-radius: 10px; font-weight: 800; font-size: 0.9rem; box-shadow: 0 10px 30px rgba(0,0,0,0.35); z-index: 99999; display: none; align-items: center; gap: 10px; max-width: 320px; }\r\n#pth-ts-toast.show { display: flex; animation: pthSlideIn 0.3s ease; }\r\n@keyframes pthSlideIn { from{opacity:0;transform:translateY(28px);}to{opacity:1;transform:translateY(0);} }\r\n#pth-lang-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.55); z-index: 99998; display: none; justify-content: center; align-items: center; backdrop-filter: blur(4px); }\r\n#pth-lang-overlay.active { display: flex; }\r\n#pth-lang-overlay .pth-lang-modal { background: #ffffff; width: 100%; max-width: 720px; border-radius: 16px; padding: 26px; display: flex; flex-direction: column; gap: 14px; color: #0f172a; }\r\n#pth-lang-overlay .pth-lang-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 5px; overflow-y: auto; max-height: 420px; }\r\n#pth-lang-overlay .pth-lang-btn { display: flex; align-items: center; gap: 9px; background: transparent; border: 1px solid transparent; padding: 8px 11px; border-radius: 8px; cursor: pointer; transition: 0.15s; color: #0f172a; font-size: 0.85rem; font-family: 'Inter',sans-serif; }\r\n#pth-lang-overlay .pth-lang-btn:hover { background: #f8fafc; }\r\n#pth-preview-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.55); z-index: 99997; display: none; justify-content: center; align-items: center; }\r\n#pth-preview-modal.active { display: flex; }\r\n#pth-preview-modal .pth-preview-inner { background: #ffffff; border-radius: 14px; padding: 26px; width: 90%; max-width: 680px; color: #0f172a; }\r\n#pth-preview-modal pre { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 14px; font-family: 'Courier New',monospace; font-size: 0.78rem; white-space: pre-wrap; max-height: 45vh; overflow-y: auto; }\r\n#pth-shortcuts-panel { position: fixed; top: 0; right: -350px; width: 330px; height: 100%; background: #ffffff; border-left: 1px solid #e2e8f0; z-index: 99997; padding: 22px; overflow-y: auto; transition: right 0.3s ease; box-shadow: -6px 0 30px rgba(0,0,0,0.1); color: #0f172a; }\r\n#pth-shortcuts-panel.open { right: 0; }\r\n#pth-transcribe-wrapper .pth-kbd { display: inline-flex; align-items: center; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 4px; padding: 1px 5px; font-family: 'Courier New',monospace; font-size: 0.7rem; color: #334155; margin-left: 3px; }\r\n<\/style>\r\n\r\n<!-- Toast & Modals -->\r\n<div id=\"pth-ts-toast\">Done!<\/div>\r\n\r\n<div id=\"pth-lang-overlay\">\r\n  <div class=\"pth-lang-modal\">\r\n    <div style=\"display:flex;justify-content:space-between;align-items:center;\">\r\n      <h3 style=\"margin:0;color:#0f172a;\">\ud83c\udf10 Translate To Language<\/h3>\r\n      <div style=\"display:flex;gap:10px;align-items:center;\">\r\n        <input type=\"text\" id=\"pth-lang-search\" placeholder=\"Search language...\" style=\"padding:6px 10px;border-radius:6px;border:1px solid #cbd5e1;outline:none;font-size:0.85rem;\" aria-label=\"Search language\">\r\n        <button id=\"pth-modal-close-btn\" style=\"background:none;border:none;font-size:18px;cursor:pointer;color:#334155;\" aria-label=\"Close language modal\">\u2715<\/button>\r\n      <\/div>\r\n    <\/div>\r\n    <div class=\"pth-lang-grid\" id=\"pth-lang-grid\"><\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<div id=\"pth-preview-modal\">\r\n  <div class=\"pth-preview-inner\">\r\n    <div style=\"display:flex;justify-content:space-between;margin-bottom:14px;align-items:center;\">\r\n      <h3 id=\"pth-preview-title\" style=\"margin:0;\">Preview<\/h3>\r\n      <button id=\"pth-preview-close\" style=\"background:none;border:none;cursor:pointer;font-size:18px;color:#334155;\" aria-label=\"Close preview\">\u2715<\/button>\r\n    <\/div>\r\n    <pre id=\"pth-preview-content\" style=\"margin:0;\"><\/pre>\r\n    <button class=\"pth-btn pth-btn-primary\" id=\"pth-preview-download\" style=\"margin-top:12px;\">Download<\/button>\r\n  <\/div>\r\n<\/div>\r\n\r\n<div id=\"pth-shortcuts-panel\" role=\"dialog\" aria-label=\"Keyboard shortcuts\">\r\n  <div style=\"display:flex;justify-content:space-between;margin-bottom:16px;align-items:center;\">\r\n    <h3 style=\"margin:0;\">Keyboard Shortcuts<\/h3>\r\n    <button id=\"pth-shortcuts-close\" style=\"background:none;border:none;cursor:pointer;font-size:18px;color:#334155;\" aria-label=\"Close shortcuts\">\u2715<\/button>\r\n  <\/div>\r\n  <div style=\"display:flex;flex-direction:column;gap:10px;font-size:0.88rem;\">\r\n    <div style=\"display:flex;justify-content:space-between;\"><span>Start Transcription<\/span><span><kbd class=\"pth-kbd\">Ctrl<\/kbd><kbd class=\"pth-kbd\">Enter<\/kbd><\/span><\/div>\r\n    <div style=\"display:flex;justify-content:space-between;\"><span>Undo<\/span><span><kbd class=\"pth-kbd\">Ctrl<\/kbd><kbd class=\"pth-kbd\">Z<\/kbd><\/span><\/div>\r\n    <div style=\"display:flex;justify-content:space-between;\"><span>Redo<\/span><span><kbd class=\"pth-kbd\">Ctrl<\/kbd><kbd class=\"pth-kbd\">Y<\/kbd><\/span><\/div>\r\n    <div style=\"display:flex;justify-content:space-between;\"><span>Find & Replace<\/span><span><kbd class=\"pth-kbd\">Ctrl<\/kbd><kbd class=\"pth-kbd\">H<\/kbd><\/span><\/div>\r\n    <div style=\"display:flex;justify-content:space-between;\"><span>Toggle Full Width<\/span><span><kbd class=\"pth-kbd\">Ctrl<\/kbd><kbd class=\"pth-kbd\">F<\/kbd><\/span><\/div>\r\n    <div style=\"display:flex;justify-content:space-between;\"><span>Play \/ Pause Media<\/span><span><kbd class=\"pth-kbd\">Space<\/kbd><\/span><\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<!-- MAIN WRAPPER -->\r\n<div id=\"pth-transcribe-wrapper\">\r\n\r\n  <!-- Top Bar -->\r\n  <div class=\"pth-top-bar\">\r\n    <div>\r\n      <h2 class=\"pth-tool-title\">\r\n        \ud83c\udf99\ufe0f AI Transcription Studio\r\n        <span class=\"pth-badge\">v3.0 PRO<\/span>\r\n        <span class=\"pth-offline-badge\">\ud83d\udd12 100% Offline<\/span>\r\n        <span class=\"pth-session-badge\" id=\"pth-session-badge\">\ud83d\udcbe Saved<\/span>\r\n      <\/h2>\r\n      <span class=\"pth-subtitle\">Speech-to-Text \u00b7 Smart Notes \u00b7 Deep Analytics \u00b7 Text Tools \u00b7 Export Hub \u00b7 100% Offline<\/span>\r\n    <\/div>\r\n    <div class=\"pth-top-actions\">\r\n      <button class=\"pth-btn pth-btn-ghost pth-btn-sm\" id=\"pth-dark-mode-btn\" aria-label=\"Toggle dark mode\">\ud83c\udf19 Dark<\/button>\r\n      <button class=\"pth-btn pth-btn-ghost pth-btn-sm\" id=\"pth-shortcuts-btn\" aria-label=\"Show keyboard shortcuts\">\u2328\ufe0f Keys<\/button>\r\n      <button class=\"pth-btn pth-btn-ghost pth-btn-sm\" id=\"pth-restore-session-btn\" style=\"display:none;\" aria-label=\"Restore previous session\">\u267b\ufe0f Restore<\/button>\r\n      <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-fw-btn-transcription\" aria-label=\"Toggle full width\">\u26f6 Full Width<\/button>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div class=\"pth-flex-layout\" id=\"pth-transcribe-layout\">\r\n\r\n    <!-- LEFT SIDEBAR -->\r\n    <div class=\"pth-sidebar-col\" id=\"pth-transcribe-sidebar\">\r\n\r\n      <!-- Card: Media Input -->\r\n      <div class=\"pth-card\" style=\"border-top:4px solid #8b5cf6;\">\r\n        <div class=\"pth-card-title\">\r\n          <span>\ud83d\udcc1 Media Input<\/span>\r\n          <button class=\"pth-sample-btn\" id=\"pth-load-sample-btn\" aria-label=\"Load sample audio file\">\ud83d\udca1 Load Sample<\/button>\r\n        <\/div>\r\n        <div class=\"pth-upload-zone\" id=\"pth-upload-zone\" role=\"button\" tabindex=\"0\" aria-label=\"Upload audio or video file\">\r\n          <div class=\"pth-upload-icon\">\ud83d\udce5<\/div>\r\n          <p class=\"pth-upload-text\">Drag & Drop Audio or Video<\/p>\r\n          <p class=\"pth-upload-sub\">MP3 \u00b7 WAV \u00b7 MP4 \u00b7 WEBM \u00b7 OGG (Max 500 MB)<\/p>\r\n          <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" style=\"margin-top:10px;\" id=\"pth-browse-btn\" aria-label=\"Browse for media file\">Browse Files<\/button>\r\n          <input type=\"file\" id=\"pth-media-file\" accept=\"audio\/*,video\/*\" style=\"display:none;\" aria-label=\"File input\">\r\n        <\/div>\r\n        <div id=\"pth-file-info-box\" style=\"display:none;\">\r\n          <div class=\"pth-file-info-wrapper\">\r\n            <div style=\"display:flex;justify-content:space-between;align-items:flex-start;\">\r\n              <div style=\"min-width:0;flex:1;\">\r\n                <div class=\"pth-file-name\" id=\"pth-file-name\">filename.mp4<\/div>\r\n                <div class=\"pth-file-meta\" id=\"pth-file-meta-details\">Loading...<\/div>\r\n              <\/div>\r\n              <button class=\"pth-btn pth-btn-ghost pth-btn-sm\" id=\"pth-remove-file-btn\" style=\"color:#dc2626;\" aria-label=\"Remove file\">\u2716<\/button>\r\n            <\/div>\r\n            <div id=\"pth-media-container\"><\/div>\r\n            <canvas class=\"pth-waveform-canvas\" id=\"pth-waveform-canvas\" width=\"340\" height=\"52\" aria-label=\"Audio waveform visualization\"><\/canvas>\r\n            <!-- Speed Control -->\r\n            <div class=\"pth-speed-row\">\r\n              <span class=\"pth-speed-label\">\u26a1 Speed:<\/span>\r\n              <button class=\"pth-speed-btn\" data-speed=\"0.5\" aria-label=\"0.5x speed\">0.5x<\/button>\r\n              <button class=\"pth-speed-btn\" data-speed=\"0.75\" aria-label=\"0.75x speed\">0.75x<\/button>\r\n              <button class=\"pth-speed-btn active\" data-speed=\"1\" aria-label=\"1x speed (normal)\">1x<\/button>\r\n              <button class=\"pth-speed-btn\" data-speed=\"1.25\" aria-label=\"1.25x speed\">1.25x<\/button>\r\n              <button class=\"pth-speed-btn\" data-speed=\"1.5\" aria-label=\"1.5x speed\">1.5x<\/button>\r\n            <\/div>\r\n            <!-- Trim -->\r\n            <div class=\"pth-trimmer-box\">\r\n              <span>\u2702\ufe0f<\/span>\r\n              <div style=\"flex:1;\">\r\n                <span style=\"font-size:0.72rem;font-weight:800;color:#92400e;display:block;margin-bottom:5px;\">Trim Range (MM:SS)<\/span>\r\n                <div style=\"display:flex;align-items:center;gap:7px;\">\r\n                  <input type=\"text\" id=\"pth-trim-start\" class=\"pth-trim-input\" value=\"00:00\" aria-label=\"Trim start time\">\r\n                  <span style=\"color:#334155;\">\u2192<\/span>\r\n                  <input type=\"text\" id=\"pth-trim-end\" class=\"pth-trim-input\" placeholder=\"00:00\" aria-label=\"Trim end time\">\r\n                <\/div>\r\n              <\/div>\r\n            <\/div>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-export-wav-btn\" style=\"width:100%;margin-top:10px;\">\ud83d\udce5 Download Trimmed Audio (WAV)<\/button>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Card: Live Mic -->\r\n      <div class=\"pth-card\" style=\"border-top:4px solid #10b981;\">\r\n        <h3 class=\"pth-card-title\" style=\"margin-bottom:12px;\">\ud83c\udfa4 Live Microphone<\/h3>\r\n        <button id=\"pth-mic-btn\" class=\"pth-btn pth-btn-primary pth-mic-btn\" aria-label=\"Start or stop live microphone recording\">\ud83c\udf99\ufe0f Start Live Recording<\/button>\r\n        <div id=\"pth-mic-status\" style=\"margin-top:9px;font-size:0.8rem;color:#334155;text-align:center;display:none;font-weight:700;\" aria-live=\"polite\">\u25cf 00:00<\/div>\r\n      <\/div>\r\n\r\n      <!-- Card: Engine Settings -->\r\n      <div class=\"pth-card\" style=\"border-top:4px solid #f59e0b;\">\r\n        <h3 class=\"pth-card-title\" style=\"margin-bottom:12px;\">\u2699\ufe0f Engine Settings<\/h3>\r\n        <div class=\"pth-controls-grid\">\r\n          <div>\r\n            <label class=\"pth-label\" for=\"pth-model-select\">\ud83e\udde0 AI Model<\/label>\r\n            <select id=\"pth-model-select\" class=\"pth-select\" aria-label=\"Select AI transcription model\">\r\n              <option value=\"Xenova\/whisper-tiny\" selected>Whisper Tiny (~74 MB)<\/option>\r\n              <option value=\"Xenova\/whisper-base\">Whisper Base (~140 MB)<\/option>\r\n            <\/select>\r\n          <\/div>\r\n          <div>\r\n            <label class=\"pth-label\" for=\"pth-lang-select\">\ud83c\udf0d Language<\/label>\r\n            <select id=\"pth-lang-select\" class=\"pth-select\" aria-label=\"Select transcription language\">\r\n              <option value=\"auto\" selected>\u2728 Auto-Detect<\/option>\r\n              <option value=\"en\">English<\/option>\r\n              <option value=\"si\">Sinhala<\/option>\r\n              <option value=\"es\">Spanish<\/option>\r\n              <option value=\"fr\">French<\/option>\r\n              <option value=\"de\">German<\/option>\r\n              <option value=\"pt\">Portuguese<\/option>\r\n              <option value=\"hi\">Hindi<\/option>\r\n              <option value=\"ja\">Japanese<\/option>\r\n              <option value=\"zh\">Chinese<\/option>\r\n              <option value=\"ar\">Arabic<\/option>\r\n              <option value=\"ko\">Korean<\/option>\r\n              <option value=\"it\">Italian<\/option>\r\n              <option value=\"ru\">Russian<\/option>\r\n              <option value=\"ta\">Tamil<\/option>\r\n            <\/select>\r\n          <\/div>\r\n          <div>\r\n            <label class=\"pth-label\" for=\"pth-task-select\">\ud83c\udfaf Task<\/label>\r\n            <select id=\"pth-task-select\" class=\"pth-select\" aria-label=\"Select transcription or translation task\">\r\n              <option value=\"transcribe\" selected>\ud83d\udcdd Transcribe<\/option>\r\n              <option value=\"translate\">\ud83c\udf10 Translate to English<\/option>\r\n            <\/select>\r\n          <\/div>\r\n          <div class=\"pth-chips-row\">\r\n            <label class=\"pth-option-chip active\" id=\"pth-quick-chip\"><input type=\"checkbox\" id=\"pth-quick-mode\" checked aria-label=\"Quick mode\"> \u26a1 Quick<\/label>\r\n            <label class=\"pth-option-chip active\" id=\"pth-filter-chip\"><input type=\"checkbox\" id=\"pth-noise-filter\" checked aria-label=\"Noise filter\"> \ud83d\udd07 Filter<\/label>\r\n            <label class=\"pth-option-chip active\" id=\"pth-chapters-chip\"><input type=\"checkbox\" id=\"pth-auto-chapters\" checked aria-label=\"Auto chapters\"> \ud83d\udcd1 Chapters<\/label>\r\n            <label class=\"pth-option-chip active\" id=\"pth-waveform-chip\"><input type=\"checkbox\" id=\"pth-show-waveform\" checked aria-label=\"Show waveform\"> \ud83c\udf0a Wave<\/label>\r\n            <label class=\"pth-option-chip active\" id=\"pth-filler-chip\"><input type=\"checkbox\" id=\"pth-filler-filter\" checked aria-label=\"Filter filler words\"> \ud83d\udd24 Filler<\/label>\r\n          <\/div>\r\n        <\/div>\r\n        <button class=\"pth-btn pth-btn-primary\" id=\"pth-generate-btn\" style=\"width:100%;margin-top:16px;padding:14px;\" disabled aria-label=\"Start transcription\">\ud83d\ude80 Start Transcription<\/button>\r\n        <div class=\"pth-progress-container\" id=\"pth-progress-box\" style=\"margin-top:12px;\">\r\n          <div class=\"pth-progress-header\"><span id=\"pth-progress-title\">Initializing...<\/span><span id=\"pth-progress-pct\">0%<\/span><\/div>\r\n          <div class=\"pth-progress-bar-wrap\"><div class=\"pth-progress-fill\" id=\"pth-progress-bar\" style=\"width:0%\"><\/div><\/div>\r\n          <div class=\"pth-status-msg\" id=\"pth-status-msg\">Loading...<\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Card: Analytics Sidebar -->\r\n      <div class=\"pth-card\" style=\"border-top:4px solid #3b82f6;\">\r\n        <h3 class=\"pth-card-title\" style=\"margin-bottom:12px;\">\ud83d\udcca Quick Stats<\/h3>\r\n        <div id=\"pth-stats-panel\" style=\"display:none;\">\r\n          <div class=\"pth-stats-grid\">\r\n            <div class=\"pth-stat-chip\"><span class=\"pth-stat-val\" style=\"color:#1d4ed8;\" id=\"pth-word-count\">0<\/span><span class=\"pth-stat-lbl\">Words<\/span><\/div>\r\n            <div class=\"pth-stat-chip\"><span class=\"pth-stat-val\" style=\"color:#5b21b6;\" id=\"pth-char-count\">0<\/span><span class=\"pth-stat-lbl\">Chars<\/span><\/div>\r\n            <div class=\"pth-stat-chip\"><span class=\"pth-stat-val\" style=\"color:#047857;\" id=\"pth-read-time\">0m<\/span><span class=\"pth-stat-lbl\">Read Time<\/span><\/div>\r\n            <div class=\"pth-stat-chip\"><span class=\"pth-stat-val\" style=\"color:#92400e;\" id=\"pth-seg-count\">0<\/span><span class=\"pth-stat-lbl\">Segments<\/span><\/div>\r\n          <\/div>\r\n          <div class=\"pth-speaking-rate\">\r\n            <span style=\"color:#047857;font-weight:700;\">\ud83c\udfaf Rate<\/span>\r\n            <div class=\"pth-rate-bar\"><div class=\"pth-rate-fill\" id=\"pth-rate-fill\" style=\"width:0%\"><\/div><\/div>\r\n            <span id=\"pth-rate-val\" style=\"color:#334155;font-weight:700;\">0 wpm<\/span>\r\n          <\/div>\r\n          <div style=\"font-size:0.7rem;font-weight:800;color:#334155;margin:12px 0 7px;text-transform:uppercase;\">\u2601\ufe0f Keywords<\/div>\r\n          <div id=\"pth-word-cloud\" class=\"pth-word-cloud\"><\/div>\r\n          <div style=\"font-size:0.7rem;font-weight:800;color:#334155;margin:12px 0 7px;text-transform:uppercase;\">\ud83d\udcd1 Chapters<\/div>\r\n          <div id=\"pth-chapter-pills\" class=\"pth-chapter-pills\"><\/div>\r\n        <\/div>\r\n        <div id=\"pth-stats-empty\" style=\"text-align:center;color:#334155;font-size:0.82rem;font-weight:600;padding:20px 0;\">Stats appear after transcription.<\/div>\r\n      <\/div>\r\n\r\n    <\/div>\r\n    <!-- END SIDEBAR -->\r\n\r\n    <!-- RIGHT MAIN - TAB SYSTEM -->\r\n    <div class=\"pth-main-col\">\r\n\r\n      <!-- Tab Header Area -->\r\n      <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:0;flex-wrap:wrap;gap:8px;\">\r\n        <div class=\"pth-tab-bar\" id=\"pth-tab-bar\" role=\"tablist\">\r\n          <button class=\"pth-tab-btn active\" data-tab=\"transcribe\" role=\"tab\" aria-selected=\"true\" aria-controls=\"pth-panel-transcribe\">\ud83c\udfac Transcribe<\/button>\r\n          <button class=\"pth-tab-btn\" data-tab=\"notes\" role=\"tab\" aria-selected=\"false\" aria-controls=\"pth-panel-notes\">\ud83d\udcdd Smart Notes<\/button>\r\n          <button class=\"pth-tab-btn\" data-tab=\"analytics\" role=\"tab\" aria-selected=\"false\" aria-controls=\"pth-panel-analytics\">\ud83d\udcca Deep Analytics<\/button>\r\n          <button class=\"pth-tab-btn\" data-tab=\"texttools\" role=\"tab\" aria-selected=\"false\" aria-controls=\"pth-panel-texttools\">\ud83d\udd24 Text Tools<\/button>\r\n          <button class=\"pth-tab-btn\" data-tab=\"export\" role=\"tab\" aria-selected=\"false\" aria-controls=\"pth-panel-export\">\ud83c\udfaf Export Hub<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"pth-tab-content-wrap\">\r\n\r\n        <!-- TAB 1: TRANSCRIBE -->\r\n        <div class=\"pth-tab-panel active\" id=\"pth-panel-transcribe\" role=\"tabpanel\">\r\n          <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;flex-wrap:wrap;gap:8px;\">\r\n            <div style=\"display:flex;gap:7px;flex-wrap:wrap;align-items:center;\">\r\n              <button class=\"pth-btn pth-btn-ghost pth-btn-sm\" id=\"pth-undo-btn\" disabled aria-label=\"Undo\">\u21a9 Undo<\/button>\r\n              <button class=\"pth-btn pth-btn-ghost pth-btn-sm\" id=\"pth-redo-btn\" disabled aria-label=\"Redo\">\u21aa Redo<\/button>\r\n              <button class=\"pth-btn pth-btn-primary pth-btn-sm\" id=\"pth-open-translate-modal\" disabled aria-label=\"Open translation modal\">\ud83c\udf10 Translate<\/button>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- Toolbar Row 1 -->\r\n          <div class=\"pth-toolbar\">\r\n            <label for=\"pth-view-mode\" class=\"pth-label\" style=\"margin:0;white-space:nowrap;\">View:<\/label>\r\n            <select id=\"pth-view-mode\" class=\"pth-select\" style=\"padding:7px 11px;font-size:0.82rem;width:auto;\" disabled aria-label=\"Select view mode\">\r\n              <option value=\"subtitles\">\ud83d\udccb Subtitle View<\/option>\r\n              <option value=\"paragraph\">\ud83d\udcc4 Paragraph View<\/option>\r\n            <\/select>\r\n            <div class=\"pth-toolbar-sep\"><\/div>\r\n            <input type=\"text\" id=\"pth-search-input\" class=\"pth-search-input\" placeholder=\"\ud83d\udd0d Find...\" disabled aria-label=\"Search in transcription\">\r\n            <input type=\"text\" id=\"pth-replace-input\" class=\"pth-search-input\" placeholder=\"Replace...\" disabled aria-label=\"Replace text\">\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-replace-btn\" disabled aria-label=\"Replace found text\">\u2194 Replace<\/button>\r\n            <div class=\"pth-toolbar-sep\"><\/div>\r\n            <div class=\"pth-zoom-wrap\">\r\n              <span style=\"color:#334155;font-size:0.8rem;\">A<\/span>\r\n              <input type=\"range\" class=\"pth-zoom-slider\" id=\"pth-zoom-slider\" min=\"80\" max=\"140\" value=\"100\" aria-label=\"Font size zoom\">\r\n              <span style=\"color:#334155;font-size:0.95rem;\">A<\/span>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- Toolbar Row 2 -->\r\n          <div class=\"pth-toolbar\" style=\"margin-top:-4px;\">\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-spk1-btn\" disabled aria-label=\"Tag as Speaker 1\">\ud83d\udc64 Spk 1<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-spk2-btn\" disabled aria-label=\"Tag as Speaker 2\">\ud83d\udc65 Spk 2<\/button>\r\n            <div class=\"pth-toolbar-sep\"><\/div>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-merge-btn\" disabled aria-label=\"Merge short segments\">\ud83d\udd17 Merge<\/button>\r\n            <div class=\"pth-toolbar-sep\"><\/div>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-read-aloud-btn\" disabled aria-label=\"Read transcription aloud\">\ud83d\udd0a Read Aloud<\/button>\r\n            <button class=\"pth-btn pth-btn-danger pth-btn-sm\" id=\"pth-stop-read-btn\" style=\"display:none;\" aria-label=\"Stop reading aloud\">\ud83d\uded1 Stop<\/button>\r\n            <div class=\"pth-toolbar-sep\"><\/div>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-copy-btn\" disabled aria-label=\"Copy transcription text\">\ud83d\udccb Copy<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-print-btn\" disabled aria-label=\"Print transcription\">\ud83d\udda8\ufe0f Print<\/button>\r\n            <button class=\"pth-btn pth-btn-danger pth-btn-sm\" id=\"pth-clear-all-btn\" aria-label=\"Clear all transcription\">\ud83d\uddd1\ufe0f Clear<\/button>\r\n          <\/div>\r\n\r\n          <!-- Progress -->\r\n          <div class=\"pth-progress-container\" id=\"pth-right-progress-box\" style=\"display:none;\">\r\n            <div class=\"pth-progress-header\"><span id=\"pth-right-progress-title\">Processing...<\/span><span id=\"pth-right-progress-pct\">0%<\/span><\/div>\r\n            <div class=\"pth-progress-bar-wrap\"><div class=\"pth-progress-fill\" id=\"pth-right-progress-bar\" style=\"width:0%\"><\/div><\/div>\r\n          <\/div>\r\n\r\n          <!-- Editor Area -->\r\n          <div class=\"pth-editor-area\" id=\"pth-editor-area\">\r\n            <div id=\"pth-empty-state\" style=\"text-align:center;color:#334155;margin-top:110px;font-weight:600;\">\r\n              <span style=\"font-size:2.8rem;display:block;margin-bottom:12px;\">\ud83c\udfa7<\/span>\r\n              Upload media or use live mic, then click Start \u2728\r\n            <\/div>\r\n            <div id=\"pth-transcription-content\"><\/div>\r\n          <\/div>\r\n\r\n          <!-- Bookmark Panel -->\r\n          <div id=\"pth-bookmark-panel-wrap\" style=\"display:none;margin-top:14px;\">\r\n            <div style=\"font-size:0.75rem;font-weight:800;color:#334155;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px;\">\ud83d\udd16 Bookmarked Segments<\/div>\r\n            <div class=\"pth-bookmark-panel\" id=\"pth-bookmark-list\"><\/div>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- TAB 2: SMART NOTES -->\r\n        <div class=\"pth-tab-panel\" id=\"pth-panel-notes\" role=\"tabpanel\">\r\n          <div style=\"margin-bottom:10px;\">\r\n            <p style=\"font-size:0.85rem;font-weight:600;color:#334155;margin:0 0 12px;\">Auto-formatted meeting notes generated from your transcription. Edit freely \u2014 changes stay here only.<\/p>\r\n          <\/div>\r\n          <div class=\"pth-notes-toolbar\">\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-notes-gen-btn\" aria-label=\"Generate smart notes from transcription\">\u2728 Generate Notes<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-notes-bullets-btn\" aria-label=\"Convert to bullet points\">\u2022 Bullets<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-notes-numbered-btn\" aria-label=\"Convert to numbered list\">1. Numbered<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-notes-clear-btn\" aria-label=\"Clear notes\">\ud83d\uddd1\ufe0f Clear<\/button>\r\n            <button class=\"pth-btn pth-btn-success pth-btn-sm\" id=\"pth-notes-copy-btn\" aria-label=\"Copy notes to clipboard\">\ud83d\udccb Copy Notes<\/button>\r\n          <\/div>\r\n          <textarea class=\"pth-notes-area\" id=\"pth-notes-area\" placeholder=\"Click Generate Notes to auto-format your transcription into structured notes...\" aria-label=\"Smart notes editor\"><\/textarea>\r\n          <div style=\"margin-top:10px;display:flex;align-items:center;gap:10px;flex-wrap:wrap;\">\r\n            <span id=\"pth-notes-word-count\" style=\"font-size:0.78rem;color:#334155;font-weight:600;\">0 words<\/span>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-notes-summary-btn\" aria-label=\"Generate brief summary\">\ud83d\udcdd Quick Summary<\/button>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- TAB 3: DEEP ANALYTICS -->\r\n        <div class=\"pth-tab-panel\" id=\"pth-panel-analytics\" role=\"tabpanel\">\r\n          <div id=\"pth-analytics-empty\" style=\"text-align:center;color:#334155;font-weight:600;padding:60px 0;\">\r\n            <span style=\"font-size:2.5rem;display:block;margin-bottom:10px;\">\ud83d\udcca<\/span>\r\n            Run a transcription first to see deep analytics.\r\n          <\/div>\r\n          <div id=\"pth-analytics-content\" style=\"display:none;\">\r\n            <!-- Sentiment -->\r\n            <div style=\"font-size:0.78rem;font-weight:800;color:#334155;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px;\">\ud83c\udfad Sentiment Word Highlights<\/div>\r\n            <div id=\"pth-sentiment-cloud\" class=\"pth-word-cloud\" style=\"margin-bottom:18px;min-height:60px;\"><\/div>\r\n            <!-- Top Phrases -->\r\n            <div style=\"font-size:0.78rem;font-weight:800;color:#334155;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px;\">\ud83c\udfc6 Top Phrases<\/div>\r\n            <div id=\"pth-top-phrases\" style=\"display:flex;flex-wrap:wrap;gap:7px;margin-bottom:18px;\"><\/div>\r\n            <!-- Speaking Pace per Minute -->\r\n            <div style=\"font-size:0.78rem;font-weight:800;color:#334155;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px;\">\ud83d\udcc8 Speaking Pace per Minute<\/div>\r\n            <div id=\"pth-pace-graph\" style=\"margin-bottom:18px;\"><\/div>\r\n            <!-- Silence Detection -->\r\n            <div style=\"font-size:0.78rem;font-weight:800;color:#334155;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px;\">\ud83d\udd07 Silence \/ Gap Detection<\/div>\r\n            <div id=\"pth-silence-list\" style=\"display:flex;flex-direction:column;gap:7px;margin-bottom:18px;\"><\/div>\r\n            <!-- Unique Words -->\r\n            <div style=\"font-size:0.78rem;font-weight:800;color:#334155;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px;\">\ud83d\udcda Vocabulary Stats<\/div>\r\n            <div class=\"pth-stats-grid\" style=\"max-width:400px;\">\r\n              <div class=\"pth-stat-chip\"><span class=\"pth-stat-val\" style=\"color:#1d4ed8;\" id=\"pth-unique-words\">0<\/span><span class=\"pth-stat-lbl\">Unique Words<\/span><\/div>\r\n              <div class=\"pth-stat-chip\"><span class=\"pth-stat-val\" style=\"color:#047857;\" id=\"pth-vocab-richness\">0%<\/span><span class=\"pth-stat-lbl\">Vocab Richness<\/span><\/div>\r\n            <\/div>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- TAB 4: TEXT TOOLS -->\r\n        <div class=\"pth-tab-panel\" id=\"pth-panel-texttools\" role=\"tabpanel\">\r\n          <p style=\"font-size:0.85rem;color:#334155;font-weight:600;margin:0 0 14px;\">Load transcription into the text tool area, apply transformations, copy result.<\/p>\r\n          <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px;\">\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-load-btn\" aria-label=\"Load transcription into text tools\">\ud83d\udce5 Load Transcription<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-upper-btn\" aria-label=\"Convert to uppercase\">\u2b06 UPPERCASE<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-lower-btn\" aria-label=\"Convert to lowercase\">\u2b07 lowercase<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-title-btn\" aria-label=\"Convert to title case\">Title Case<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-sentence-btn\" aria-label=\"Convert to sentence case\">Sentence case<\/button>\r\n          <\/div>\r\n          <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px;\">\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-filler-btn\" aria-label=\"Remove filler words\">\ud83d\udd07 Remove Filler Words<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-dedup-btn\" aria-label=\"Remove duplicate words\">\u267b\ufe0f Remove Duplicates<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-clean-btn\" aria-label=\"Clean extra whitespace\">\ud83e\uddf9 Clean Spaces<\/button>\r\n            <button class=\"pth-btn pth-btn-secondary pth-btn-sm\" id=\"pth-tt-trim-social-btn\" aria-label=\"Trim to 280 characters for social media\">\u2702\ufe0f Trim 280 chars<\/button>\r\n          <\/div>\r\n          <div class=\"pth-text-tools-grid\">\r\n            <div>\r\n              <div style=\"font-size:0.75rem;font-weight:800;color:#334155;margin-bottom:5px;text-transform:uppercase;\">Input \/ Output<\/div>\r\n              <textarea class=\"pth-text-tool-area\" id=\"pth-tt-input\" placeholder=\"Load your transcription here or paste text...\" aria-label=\"Text tool input area\"><\/textarea>\r\n            <\/div>\r\n            <div>\r\n              <div style=\"font-size:0.75rem;font-weight:800;color:#334155;margin-bottom:5px;text-transform:uppercase;\">Result<\/div>\r\n              <textarea class=\"pth-text-tool-area\" id=\"pth-tt-output\" placeholder=\"Result appears here...\" readonly aria-label=\"Text tool result area\"><\/textarea>\r\n            <\/div>\r\n          <\/div>\r\n          <div class=\"pth-limit-row\">\r\n            <span style=\"font-size:0.78rem;font-weight:700;color:#334155;\">Char Limit:<\/span>\r\n            <button class=\"pth-limit-chip\" data-limit=\"280\" aria-label=\"Twitter limit 280 characters\">Twitter 280<\/button>\r\n            <button class=\"pth-limit-chip\" data-limit=\"500\" aria-label=\"YouTube description limit 500 characters\">YouTube 500<\/button>\r\n            <button class=\"pth-limit-chip\" data-limit=\"2200\" aria-label=\"Instagram limit 2200 characters\">Instagram 2200<\/button>\r\n            <button class=\"pth-btn pth-btn-success pth-btn-sm\" id=\"pth-tt-copy-result-btn\" aria-label=\"Copy result text\">\ud83d\udccb Copy Result<\/button>\r\n            <span id=\"pth-tt-char-count\" style=\"font-size:0.78rem;font-weight:700;color:#334155;\">0 chars<\/span>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- TAB 5: EXPORT HUB -->\r\n        <div class=\"pth-tab-panel\" id=\"pth-panel-export\" role=\"tabpanel\">\r\n          <p style=\"font-size:0.85rem;color:#334155;font-weight:600;margin:0 0 16px;\">All export formats in one place. Click any format to download.<\/p>\r\n          <div class=\"pth-export-hub-grid\" id=\"pth-export-hub-grid\">\r\n            <div class=\"pth-export-card disabled\" id=\"pth-exp-txt\" role=\"button\" tabindex=\"0\" aria-label=\"Export as plain text\">\r\n              <span class=\"pth-export-icon\">\ud83d\udcc4<\/span>\r\n              <span class=\"pth-export-name\">.TXT<\/span>\r\n              <span class=\"pth-export-desc\">Plain text transcript<\/span>\r\n            <\/div>\r\n            <div class=\"pth-export-card disabled\" id=\"pth-exp-srt\" role=\"button\" tabindex=\"0\" aria-label=\"Export as SRT subtitles\">\r\n              <span class=\"pth-export-icon\">\ud83d\udcdd<\/span>\r\n              <span class=\"pth-export-name\">.SRT<\/span>\r\n              <span class=\"pth-export-desc\">Subtitle file<\/span>\r\n            <\/div>\r\n            <div class=\"pth-export-card disabled\" id=\"pth-exp-vtt\" role=\"button\" tabindex=\"0\" aria-label=\"Export as WebVTT subtitles\">\r\n              <span class=\"pth-export-icon\">\ud83d\udcfa<\/span>\r\n              <span class=\"pth-export-name\">.VTT<\/span>\r\n              <span class=\"pth-export-desc\">Web Video Text Tracks<\/span>\r\n            <\/div>\r\n            <div class=\"pth-export-card disabled\" id=\"pth-exp-pdf\" role=\"button\" tabindex=\"0\" aria-label=\"Export as PDF document\">\r\n              <span class=\"pth-export-icon\">\ud83d\udccb<\/span>\r\n              <span class=\"pth-export-name\">.PDF<\/span>\r\n              <span class=\"pth-export-desc\">Formatted PDF document<\/span>\r\n            <\/div>\r\n            <div class=\"pth-export-card disabled\" id=\"pth-exp-json\" role=\"button\" tabindex=\"0\" aria-label=\"Export as JSON data\">\r\n              <span class=\"pth-export-icon\">\ud83d\uddc2\ufe0f<\/span>\r\n              <span class=\"pth-export-name\">.JSON<\/span>\r\n              <span class=\"pth-export-desc\">Structured data with timestamps<\/span>\r\n            <\/div>\r\n            <div class=\"pth-export-card disabled\" id=\"pth-exp-srt-preview\" role=\"button\" tabindex=\"0\" aria-label=\"Preview SRT content\">\r\n              <span class=\"pth-export-icon\">\ud83d\udc41\ufe0f<\/span>\r\n              <span class=\"pth-export-name\">Preview<\/span>\r\n              <span class=\"pth-export-desc\">Preview SRT before download<\/span>\r\n            <\/div>\r\n          <\/div>\r\n          <!-- Smart Copy Modes -->\r\n          <div style=\"font-size:0.78rem;font-weight:800;color:#334155;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:10px;\">\ud83d\udccb Smart Copy Modes<\/div>\r\n          <div class=\"pth-copy-modes\">\r\n            <button class=\"pth-copy-mode-btn\" id=\"pth-copy-plain\" aria-label=\"Copy as plain text\">\ud83d\udcc4 Plain Text<\/button>\r\n            <button class=\"pth-copy-mode-btn\" id=\"pth-copy-timestamps\" aria-label=\"Copy with timestamps\">\u23f1\ufe0f With Timestamps<\/button>\r\n            <button class=\"pth-copy-mode-btn\" id=\"pth-copy-srt-clip\" aria-label=\"Copy in SRT format\">\ud83d\udcdd SRT Format<\/button>\r\n            <button class=\"pth-copy-mode-btn\" id=\"pth-copy-meeting\" aria-label=\"Copy as meeting notes\">\ud83d\udccb Meeting Notes<\/button>\r\n          <\/div>\r\n        <\/div>\r\n\r\n      <\/div>\r\n      <!-- END TAB CONTENT WRAP -->\r\n\r\n    <\/div>\r\n    <!-- END MAIN COL -->\r\n\r\n  <\/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.pthTranscriptionApp = {\r\n    initialized: false,\r\n\r\n    LANG_MAP: {\r\n      'en':{name:'English',tts:'en-US',flag:'us'}, 'si':{name:'Sinhala',tts:'si-LK',flag:'lk'},\r\n      'es':{name:'Espa\u00f1ol',tts:'es-ES',flag:'es'}, 'fr':{name:'Fran\u00e7ais',tts:'fr-FR',flag:'fr'},\r\n      'de':{name:'Deutsch',tts:'de-DE',flag:'de'}, 'pt':{name:'Portugu\u00eas',tts:'pt-PT',flag:'pt'},\r\n      'hi':{name:'Hindi',tts:'hi-IN',flag:'in'}, 'ja':{name:'\u65e5\u672c\u8a9e',tts:'ja-JP',flag:'jp'},\r\n      'zh':{name:'Chinese',tts:'zh-CN',flag:'cn'}, 'ar':{name:'Arabic',tts:'ar-SA',flag:'sa'},\r\n      'ko':{name:'Korean',tts:'ko-KR',flag:'kr'}, 'it':{name:'Italiano',tts:'it-IT',flag:'it'},\r\n      'ru':{name:'Russian',tts:'ru-RU',flag:'ru'}, 'ta':{name:'Tamil',tts:'ta-IN',flag:'in'},\r\n      'nl':{name:'Dutch',tts:'nl-NL',flag:'nl'}, 'pl':{name:'Polish',tts:'pl-PL',flag:'pl'},\r\n      'tr':{name:'Turkish',tts:'tr-TR',flag:'tr'}, 'vi':{name:'Vietnamese',tts:'vi-VN',flag:'vn'},\r\n      'th':{name:'Thai',tts:'th-TH',flag:'th'}, 'uk':{name:'Ukrainian',tts:'uk-UA',flag:'ua'}\r\n    },\r\n\r\n    FILLER_WORDS: ['um','uh','like','you know','sort of','kind of','basically','literally','actually','i mean','right','okay','so','well'],\r\n\r\n    POSITIVE_WORDS: {good:1,great:1,excellent:1,amazing:1,perfect:1,love:1,best:1,fantastic:1,wonderful:1,happy:1,success:1,positive:1,yes:1,agree:1,definitely:1,absolutely:1,clear:1,easy:1,helpful:1,thank:1},\r\n    NEGATIVE_WORDS: {bad:1,wrong:1,problem:1,issue:1,fail:1,error:1,difficult:1,hard:1,never:1,no:1,not:1,disagree:1,confusing:1,unclear:1,sorry:1,unfortunately:1,concern:1,risk:1,miss:1,lost:1},\r\n\r\n    state: {\r\n      file: null, mediaObjectURL: null, mediaPlayer: null, isRecording: false,\r\n      mediaRecorder: null, audioChunks: [], timerInterval: null,\r\n      transcriptionResult: [], aiWorker: null, currentSearchTerm: '',\r\n      currentLang: 'en', activeSegIndex: null, undoStack: [], redoStack: [],\r\n      chaptersData: [], previewContent: '', previewFilename: '', previewMime: '',\r\n      sessionKey: 'pth_transcribe_v30', audioData: null,\r\n      transcriptionTimer: 0, transcriptionInterval: null, fontSize: 100,\r\n      currentTab: 'transcribe'\r\n    },\r\n    UI: {},\r\n\r\n   init: function() {\r\n      this.cacheDOM();\r\n      \r\n      \/\/ --- BUG FIX: Move all Modals to document.body to prevent WP Theme CSS conflicts ---\r\n      if (this.UI.langOverlay) document.body.appendChild(this.UI.langOverlay);\r\n      if (this.UI.previewModal) document.body.appendChild(this.UI.previewModal);\r\n      if (this.UI.toast) document.body.appendChild(this.UI.toast);\r\n      if (this.UI.shortcutsPanel) document.body.appendChild(this.UI.shortcutsPanel);\r\n      \/\/ ----------------------------------------------------------------------------------\r\n\r\n      this.buildLangGrid();\r\n      this.checkSession();\r\n      this.attachEvents();\r\n    },\r\n\r\n    cacheDOM: function() {\r\n      var _el = function(id) { return document.getElementById(id); };\r\n      this.UI = {\r\n        wrapper: _el('pth-transcribe-wrapper'), layout: _el('pth-transcribe-layout'),\r\n        fwBtn: _el('pth-fw-btn-transcription'), darkBtn: _el('pth-dark-mode-btn'),\r\n        shortcutsBtn: _el('pth-shortcuts-btn'), shortcutsPanel: _el('pth-shortcuts-panel'),\r\n        shortcutsClose: _el('pth-shortcuts-close'), restoreBtn: _el('pth-restore-session-btn'),\r\n        sessionBadge: _el('pth-session-badge'),\r\n        dropZone: _el('pth-upload-zone'), fileInput: _el('pth-media-file'),\r\n        browseBtn: _el('pth-browse-btn'), fileInfoBox: _el('pth-file-info-box'),\r\n        fileNameEl: _el('pth-file-name'), fileMetaEl: _el('pth-file-meta-details'),\r\n        removeBtn: _el('pth-remove-file-btn'), mediaContainer: _el('pth-media-container'),\r\n        waveformCanvas: _el('pth-waveform-canvas'),\r\n        trimStart: _el('pth-trim-start'), trimEnd: _el('pth-trim-end'),\r\n        micBtn: _el('pth-mic-btn'), micStatus: _el('pth-mic-status'),\r\n        statsPanel: _el('pth-stats-panel'), statsEmpty: _el('pth-stats-empty'),\r\n        wordCountEl: _el('pth-word-count'), charCountEl: _el('pth-char-count'),\r\n        readTimeEl: _el('pth-read-time'), segCountEl: _el('pth-seg-count'),\r\n        rateFillEl: _el('pth-rate-fill'), rateValEl: _el('pth-rate-val'),\r\n        wordCloud: _el('pth-word-cloud'), chapterPills: _el('pth-chapter-pills'),\r\n        modelSelect: _el('pth-model-select'), langSelect: _el('pth-lang-select'),\r\n        taskSelect: _el('pth-task-select'),\r\n        quickMode: _el('pth-quick-mode'), noiseFilter: _el('pth-noise-filter'),\r\n        autoChapters: _el('pth-auto-chapters'), showWaveform: _el('pth-show-waveform'),\r\n        fillerFilter: _el('pth-filler-filter'),\r\n        quickChip: _el('pth-quick-chip'), filterChip: _el('pth-filter-chip'),\r\n        chaptersChip: _el('pth-chapters-chip'), waveformChip: _el('pth-waveform-chip'),\r\n        fillerChip: _el('pth-filler-chip'),\r\n        generateBtn: _el('pth-generate-btn'), progressBox: _el('pth-progress-box'),\r\n        progressBar: _el('pth-progress-bar'), progressPct: _el('pth-progress-pct'),\r\n        progressTitle: _el('pth-progress-title'), statusMsg: _el('pth-status-msg'),\r\n        tabBar: _el('pth-tab-bar'),\r\n        viewModeSelect: _el('pth-view-mode'), searchInput: _el('pth-search-input'),\r\n        replaceInput: _el('pth-replace-input'), replaceBtn: _el('pth-replace-btn'),\r\n        zoomSlider: _el('pth-zoom-slider'),\r\n        spk1Btn: _el('pth-spk1-btn'), spk2Btn: _el('pth-spk2-btn'),\r\n        mergeBtn: _el('pth-merge-btn'), undoBtn: _el('pth-undo-btn'), redoBtn: _el('pth-redo-btn'),\r\n        translateBtn: _el('pth-open-translate-modal'), readAloudBtn: _el('pth-read-aloud-btn'),\r\n        stopReadBtn: _el('pth-stop-read-btn'), copyBtn: _el('pth-copy-btn'),\r\n        printBtn: _el('pth-print-btn'), clearAllBtn: _el('pth-clear-all-btn'),\r\n        rightProgressBox: _el('pth-right-progress-box'),\r\n        rightProgressBar: _el('pth-right-progress-bar'), rightProgressPct: _el('pth-right-progress-pct'),\r\n        rightProgressTitle: _el('pth-right-progress-title'),\r\n        editorArea: _el('pth-editor-area'), emptyState: _el('pth-empty-state'),\r\n        transcriptionContent: _el('pth-transcription-content'),\r\n        bookmarkPanelWrap: _el('pth-bookmark-panel-wrap'), bookmarkList: _el('pth-bookmark-list'),\r\n        langOverlay: _el('pth-lang-overlay'), modalCloseBtn: _el('pth-modal-close-btn'),\r\n        langSearch: _el('pth-lang-search'), langGrid: _el('pth-lang-grid'),\r\n        previewModal: _el('pth-preview-modal'), previewTitle: _el('pth-preview-title'),\r\n        previewContent: _el('pth-preview-content'), previewClose: _el('pth-preview-close'),\r\n        previewDownload: _el('pth-preview-download'), toast: _el('pth-ts-toast'),\r\n        sampleBtn: _el('pth-load-sample-btn'), exportWavBtn: _el('pth-export-wav-btn'),\r\n        notesGenBtn: _el('pth-notes-gen-btn'), notesBulletsBtn: _el('pth-notes-bullets-btn'),\r\n        notesNumberedBtn: _el('pth-notes-numbered-btn'), notesClearBtn: _el('pth-notes-clear-btn'),\r\n        notesCopyBtn: _el('pth-notes-copy-btn'), notesArea: _el('pth-notes-area'),\r\n        notesWordCount: _el('pth-notes-word-count'), notesSummaryBtn: _el('pth-notes-summary-btn'),\r\n        analyticsEmpty: _el('pth-analytics-empty'), analyticsContent: _el('pth-analytics-content'),\r\n        sentimentCloud: _el('pth-sentiment-cloud'), topPhrases: _el('pth-top-phrases'),\r\n        paceGraph: _el('pth-pace-graph'), silenceList: _el('pth-silence-list'),\r\n        uniqueWords: _el('pth-unique-words'), vocabRichness: _el('pth-vocab-richness'),\r\n        ttLoadBtn: _el('pth-tt-load-btn'), ttUpperBtn: _el('pth-tt-upper-btn'),\r\n        ttLowerBtn: _el('pth-tt-lower-btn'), ttTitleBtn: _el('pth-tt-title-btn'),\r\n        ttSentenceBtn: _el('pth-tt-sentence-btn'), ttFillerBtn: _el('pth-tt-filler-btn'),\r\n        ttDedupBtn: _el('pth-tt-dedup-btn'), ttCleanBtn: _el('pth-tt-clean-btn'),\r\n        ttTrimSocialBtn: _el('pth-tt-trim-social-btn'),\r\n        ttInput: _el('pth-tt-input'), ttOutput: _el('pth-tt-output'),\r\n        ttCopyResultBtn: _el('pth-tt-copy-result-btn'), ttCharCount: _el('pth-tt-char-count'),\r\n        expTxt: _el('pth-exp-txt'), expSrt: _el('pth-exp-srt'), expVtt: _el('pth-exp-vtt'),\r\n        expPdf: _el('pth-exp-pdf'), expJson: _el('pth-exp-json'), expSrtPreview: _el('pth-exp-srt-preview'),\r\n        copyPlain: _el('pth-copy-plain'), copyTimestamps: _el('pth-copy-timestamps'),\r\n        copySrtClip: _el('pth-copy-srt-clip'), copyMeeting: _el('pth-copy-meeting')\r\n      };\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 UTILS \u2500\u2500\u2500 *\/\r\n    bindEvent: function(el, ev, fn) { if (el) el.addEventListener(ev, fn); },\r\n\r\n    showToast: function(msg, type) {\r\n      if (!this.UI.toast) return;\r\n      var icons = {success:'\u2705', error:'\u274c', info:'\u2139\ufe0f'};\r\n      var colors = {success:'#1e293b', error:'#dc2626', info:'#1d4ed8'};\r\n      var t = type || 'success';\r\n      this.UI.toast.innerHTML = '<span>' + (icons[t] || '\u2705') + '<\/span> ' + msg;\r\n      this.UI.toast.style.background = colors[t] || '#1e293b';\r\n      this.UI.toast.classList.add('show');\r\n      clearTimeout(this.toastTimer);\r\n      var self = this;\r\n      this.toastTimer = setTimeout(function() { self.UI.toast.classList.remove('show'); }, 3500);\r\n    },\r\n\r\n    formatTime: function(sec, isVtt) {\r\n      var h = Math.floor(sec \/ 3600), m = Math.floor((sec % 3600) \/ 60), s = Math.floor(sec % 60), ms = Math.floor((sec % 1) * 1000);\r\n      var sep = isVtt ? '.' : ',';\r\n      return String(h).padStart(2,'0') + ':' + String(m).padStart(2,'0') + ':' + String(s).padStart(2,'0') + sep + String(ms).padStart(3,'0');\r\n    },\r\n    parseMMSS: function(str) {\r\n      if (!str) return 0; var p = str.split(':');\r\n      return p.length === 2 ? parseInt(p[0]) * 60 + parseFloat(p[1]) : parseFloat(str) || 0;\r\n    },\r\n    toMMSS: function(secs) {\r\n      if (isNaN(secs) || secs < 0) return '00:00';\r\n      return String(Math.floor(secs \/ 60)).padStart(2,'0') + ':' + String(Math.floor(secs % 60)).padStart(2,'0');\r\n    },\r\n    cleanHallucinations: function(text) {\r\n      if (!text) return '';\r\n      if (this.UI.noiseFilter && !this.UI.noiseFilter.checked) return text.trim();\r\n      \/\/ \u0dc0\u0da9\u0dcf\u0dad\u0dca \u0db4\u0dca\u200d\u0dbb\u0db6\u0dbd Regex \u0d91\u0d9a\u0d9a\u0dca \u0db8\u0d9c\u0dd2\u0db1\u0dca \u0dc0\u0dcf\u0d9a\u0dca\u200d\u0dba \u0d9b\u0dab\u0dca\u0da9 \u0db1\u0dd0\u0dc0\u0dad \u0db1\u0dd0\u0dc0\u0dad \u0db4\u0dd0\u0db8\u0dd2\u0dab\u0dd3\u0db8 \u0d89\u0dc0\u0dad\u0dca \u0d9a\u0dd2\u0dbb\u0dd3\u0db8\r\n      var c = text.replace(\/\\b(.+?)(?:\\s+\\1\\b){2,}\/gi, '$1').replace(\/\\[Music\\]|\\[Applause\\]|\\[Laughter\\]\/gi, '').trim();\r\n      return c.split(\/\\s+\/).length < 3 && text.length > 20 ? '' : c;\r\n    },\r\n    removeFiller: function(text) {\r\n      if (!text) return '';\r\n      var self = this;\r\n      var result = text;\r\n      self.FILLER_WORDS.forEach(function(fw) {\r\n        var re = new RegExp('\\\\b' + fw.replace(\/\\s+\/g,'\\\\s+') + '\\\\b,?', 'gi');\r\n        result = result.replace(re, '');\r\n      });\r\n      return result.replace(\/\\s{2,}\/g, ' ').trim();\r\n    },\r\n    deepClone: function(arr) {\r\n      return arr.map(function(c) {\r\n        return {timestamp: c.timestamp.slice(), text: c.text, bookmarked: c.bookmarked || false, speaker: c.speaker || null};\r\n      });\r\n    },\r\n    pushUndo: function() {\r\n      this.state.undoStack.push(this.deepClone(this.state.transcriptionResult));\r\n      if (this.state.undoStack.length > 50) this.state.undoStack.shift();\r\n      this.state.redoStack = [];\r\n      if (this.UI.undoBtn) this.UI.undoBtn.disabled = false;\r\n      if (this.UI.redoBtn) this.UI.redoBtn.disabled = true;\r\n    },\r\n    performUndo: function() {\r\n      if (!this.state.undoStack.length) return;\r\n      this.state.redoStack.push(this.deepClone(this.state.transcriptionResult));\r\n      this.state.transcriptionResult = this.state.undoStack.pop();\r\n      if (this.UI.redoBtn) this.UI.redoBtn.disabled = false;\r\n      if (this.UI.undoBtn) this.UI.undoBtn.disabled = this.state.undoStack.length === 0;\r\n      this.renderEditor(); this.showToast('Undo applied');\r\n    },\r\n    performRedo: function() {\r\n      if (!this.state.redoStack.length) return;\r\n      this.state.undoStack.push(this.deepClone(this.state.transcriptionResult));\r\n      this.state.transcriptionResult = this.state.redoStack.pop();\r\n      if (this.UI.undoBtn) this.UI.undoBtn.disabled = false;\r\n      if (this.UI.redoBtn) this.UI.redoBtn.disabled = this.state.redoStack.length === 0;\r\n      this.renderEditor(); this.showToast('Redo applied');\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 SESSION \u2500\u2500\u2500 *\/\r\n    saveSession: function() {\r\n      try {\r\n        localStorage.setItem(this.state.sessionKey, JSON.stringify({result: this.state.transcriptionResult, lang: this.state.currentLang, ts: Date.now()}));\r\n        if (this.UI.sessionBadge) {\r\n          this.UI.sessionBadge.style.display = 'inline-flex';\r\n          clearTimeout(this.sessionTimer);\r\n          var self = this;\r\n          this.sessionTimer = setTimeout(function() { self.UI.sessionBadge.style.display = 'none'; }, 2500);\r\n        }\r\n      } catch(e) {}\r\n    },\r\n    checkSession: function() {\r\n      try {\r\n        var raw = localStorage.getItem(this.state.sessionKey);\r\n        if (!raw) return;\r\n        var d = JSON.parse(raw);\r\n        if (d && d.result && d.result.length > 0 && (Date.now() - d.ts) < 86400000 && this.UI.restoreBtn)\r\n          this.UI.restoreBtn.style.display = 'inline-flex';\r\n      } catch(e) {}\r\n    },\r\n    restoreSession: function() {\r\n      try {\r\n        var d = JSON.parse(localStorage.getItem(this.state.sessionKey));\r\n        this.state.transcriptionResult = d.result || [];\r\n        this.state.currentLang = d.lang || 'en';\r\n        if (this.state.transcriptionResult.length) {\r\n          this.renderEditor(); this.enableResultControls();\r\n          this.showToast('Session restored \u2728');\r\n          if (this.UI.restoreBtn) this.UI.restoreBtn.style.display = 'none';\r\n          if (this.UI.emptyState) this.UI.emptyState.style.display = 'none';\r\n          this.renderDeepAnalytics();\r\n        }\r\n      } catch(e) { this.showToast('Could not restore', 'error'); }\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 WAVEFORM \u2500\u2500\u2500 *\/\r\n    drawWaveform: function(audioBuffer) {\r\n      if (this.UI.showWaveform && !this.UI.showWaveform.checked) return;\r\n      var c = this.UI.waveformCanvas; if (!c) return;\r\n      c.style.display = 'block';\r\n      var ctx = c.getContext('2d'); var data = audioBuffer.getChannelData(0);\r\n      var W = c.offsetWidth || 340, H = 52; c.width = W; c.height = H; ctx.clearRect(0, 0, W, H);\r\n      var step = Math.ceil(data.length \/ W);\r\n      var isDark = this.UI.wrapper && this.UI.wrapper.classList.contains('pth-dark');\r\n      ctx.fillStyle = isDark ? '#8b5cf6' : '#c4b5fd';\r\n      for (var i = 0; i < W; i++) {\r\n        var sl = data.subarray(i * step, (i + 1) * step), mx = 0;\r\n        for (var j = 0; j < sl.length; j++) { var v = Math.abs(sl[j]); if (v > mx) mx = v; }\r\n        var bH = mx * H; ctx.fillRect(i, (H - bH) \/ 2, 1, bH || 1);\r\n      }\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 CHAPTERS \u2500\u2500\u2500 *\/\r\n    generateChapters: function(chunks) {\r\n      if (!this.UI.autoChapters || !this.UI.autoChapters.checked || chunks.length < 4) return [];\r\n      var ch = [], ev = Math.max(10, Math.floor(chunks.length \/ 5));\r\n      for (var i = 0; i < chunks.length; i += ev)\r\n        ch.push({index: i, time: chunks[i].timestamp[0], label: this.toMMSS(chunks[i].timestamp[0]) + ' - ' + chunks[i].text.split(' ').slice(0, 5).join(' ') + '..'});\r\n      return ch;\r\n    },\r\n    renderChapterPills: function(chapters) {\r\n      if (!this.UI.chapterPills) return;\r\n      this.UI.chapterPills.innerHTML = '';\r\n      if (!chapters.length) { this.UI.chapterPills.innerHTML = '<span style=\"font-size:0.75rem;color:#334155;\">No chapters detected.<\/span>'; return; }\r\n      var self = this;\r\n      chapters.forEach(function(ch, idx) {\r\n        var p = document.createElement('button'); p.className = 'pth-chapter-pill'; p.textContent = '\ud83d\udcd1 Ch.' + (idx + 1); p.title = ch.label; p.setAttribute('aria-label', 'Jump to chapter ' + (idx + 1));\r\n        p.addEventListener('click', function() {\r\n          var segs = self.UI.transcriptionContent.querySelectorAll('.pth-segment');\r\n          if (segs[ch.index]) { segs[ch.index].scrollIntoView({behavior: 'smooth', block: 'center'}); segs[ch.index].classList.add('pth-seg-active'); setTimeout(function() { segs[ch.index].classList.remove('pth-seg-active'); }, 1500); }\r\n        });\r\n        self.UI.chapterPills.appendChild(p);\r\n      });\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 WORD CLOUD \u2500\u2500\u2500 *\/\r\n    generateWordCloud: function(text) {\r\n      if (!this.UI.wordCloud) return;\r\n      this.UI.wordCloud.innerHTML = '';\r\n      var sw = {the:1,a:1,an:1,and:1,or:1,but:1,in:1,on:1,to:1,is:1,are:1,it:1,this:1,that:1,of:1,with:1,i:1,we:1,you:1,he:1,she:1,they:1,was:1,be:1,at:1,for:1,as:1,by:1};\r\n      var words = text.toLowerCase().replace(\/[^a-z\\s]\/g, ' ').split(\/\\s+\/).filter(function(w) { return w.length > 2 && !sw[w]; });\r\n      var counts = {}; words.forEach(function(w) { counts[w] = (counts[w] || 0) + 1; });\r\n      var sorted = Object.keys(counts).map(function(k){return [k,counts[k]];}).sort(function(a,b){return b[1]-a[1];}).slice(0, 22);\r\n      if (!sorted.length) { this.UI.wordCloud.innerHTML = '<span style=\"color:#334155;font-size:0.78rem;\">Not enough data.<\/span>'; return; }\r\n      var maxC = sorted[0][1]; var self = this;\r\n      sorted.forEach(function(pair) {\r\n        var sp = document.createElement('span'); sp.className = 'pth-cloud-word';\r\n        sp.style.fontSize = (0.75 + (pair[1] \/ maxC) * 1.3) + 'rem';\r\n        sp.style.color = 'hsl(' + (200 + Math.random() * 60) + ',75%,' + (35 + Math.random() * 15) + '%)';\r\n        sp.textContent = pair[0];\r\n        sp.setAttribute('aria-label', pair[0] + ' appears ' + pair[1] + ' times');\r\n        sp.addEventListener('click', function() {\r\n          self.state.currentSearchTerm = pair[0];\r\n          if (self.UI.searchInput) self.UI.searchInput.value = pair[0];\r\n          self.renderEditor();\r\n        });\r\n        self.UI.wordCloud.appendChild(sp);\r\n      });\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 STATS \u2500\u2500\u2500 *\/\r\n    updateStats: function() {\r\n      var full = this.state.transcriptionResult.map(function(c) { return c.text; }).join(' ');\r\n      var w = full.trim() ? full.trim().split(\/\\s+\/).filter(Boolean).length : 0;\r\n      if (this.UI.wordCountEl) this.UI.wordCountEl.textContent = w.toLocaleString();\r\n      if (this.UI.charCountEl) this.UI.charCountEl.textContent = full.length.toLocaleString();\r\n      if (this.UI.readTimeEl) this.UI.readTimeEl.textContent = Math.ceil(w \/ 200) + 'm';\r\n      if (this.UI.segCountEl) this.UI.segCountEl.textContent = this.state.transcriptionResult.length;\r\n      var s = this.state.transcriptionResult.length;\r\n      if (s > 0) {\r\n        var last = this.state.transcriptionResult[s - 1].timestamp[1] || this.state.transcriptionResult[s - 1].timestamp[0];\r\n        var wpm = last > 6 ? Math.round(w \/ (last \/ 60)) : 0;\r\n        if (this.UI.rateValEl) this.UI.rateValEl.textContent = wpm + ' wpm';\r\n        if (this.UI.rateFillEl) this.UI.rateFillEl.style.width = Math.min(100, (wpm \/ 200) * 100) + '%';\r\n      }\r\n      this.generateWordCloud(full);\r\n      this.state.chaptersData = this.generateChapters(this.state.transcriptionResult);\r\n      this.renderChapterPills(this.state.chaptersData);\r\n      if (this.UI.statsPanel) this.UI.statsPanel.style.display = 'block';\r\n      if (this.UI.statsEmpty) this.UI.statsEmpty.style.display = 'none';\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 DEEP ANALYTICS \u2500\u2500\u2500 *\/\r\n    renderDeepAnalytics: function() {\r\n      if (!this.state.transcriptionResult.length) return;\r\n      var full = this.state.transcriptionResult.map(function(c) { return c.text; }).join(' ');\r\n      var words = full.toLowerCase().replace(\/[^a-z\\s]\/g, ' ').split(\/\\s+\/).filter(function(w) { return w.length > 2; });\r\n      if (this.UI.analyticsEmpty) this.UI.analyticsEmpty.style.display = 'none';\r\n      if (this.UI.analyticsContent) this.UI.analyticsContent.style.display = 'block';\r\n\r\n      \/* Sentiment Cloud *\/\r\n      if (this.UI.sentimentCloud) {\r\n        this.UI.sentimentCloud.innerHTML = '';\r\n        var self = this;\r\n        words.forEach(function(w) {\r\n          if (self.POSITIVE_WORDS[w] || self.NEGATIVE_WORDS[w]) {\r\n            var sp = document.createElement('span'); sp.className = 'pth-cloud-word';\r\n            sp.style.fontSize = '0.95rem';\r\n            sp.style.color = self.POSITIVE_WORDS[w] ? '#047857' : '#991b1b';\r\n            sp.style.background = self.POSITIVE_WORDS[w] ? 'rgba(16,185,129,0.1)' : 'rgba(220,38,38,0.1)';\r\n            sp.style.padding = '2px 8px'; sp.style.borderRadius = '4px';\r\n            sp.textContent = w;\r\n            self.UI.sentimentCloud.appendChild(sp);\r\n          }\r\n        });\r\n        if (!this.UI.sentimentCloud.children.length)\r\n          this.UI.sentimentCloud.innerHTML = '<span style=\"color:#334155;font-size:0.78rem;\">No strong sentiment words detected.<\/span>';\r\n      }\r\n\r\n      \/* Top Phrases (bigrams) *\/\r\n      if (this.UI.topPhrases) {\r\n        this.UI.topPhrases.innerHTML = '';\r\n        var bigrams = {}; var sw = {the:1,a:1,an:1,and:1,or:1,but:1,in:1,on:1,to:1,is:1,are:1,it:1,this:1,that:1,of:1};\r\n        for (var i = 0; i < words.length - 1; i++) {\r\n          if (!sw[words[i]] && !sw[words[i+1]] && words[i].length > 2 && words[i+1].length > 2) {\r\n            var bg = words[i] + ' ' + words[i+1]; bigrams[bg] = (bigrams[bg] || 0) + 1;\r\n          }\r\n        }\r\n        var topBg = Object.keys(bigrams).map(function(k){return [k,bigrams[k]];}).sort(function(a,b){return b[1]-a[1];}).slice(0,12);\r\n        topBg.forEach(function(p) {\r\n          var span = document.createElement('span'); span.className = 'pth-phrase-tag';\r\n          span.innerHTML = p[0] + ' <span style=\"background:#e2e8f0;padding:1px 5px;border-radius:4px;font-size:0.68rem;color:#334155;\">' + p[1] + '<\/span>';\r\n          if (document.getElementById('pth-panel-analytics')) document.getElementById('pth-top-phrases').appendChild(span);\r\n        });\r\n      }\r\n\r\n      \/* Pace Per Minute *\/\r\n      if (this.UI.paceGraph) {\r\n        this.UI.paceGraph.innerHTML = '';\r\n        var minuteData = {}; var self2 = this;\r\n        this.state.transcriptionResult.forEach(function(c) {\r\n          var min = Math.floor(c.timestamp[0] \/ 60);\r\n          var wc = c.text.trim().split(\/\\s+\/).filter(Boolean).length;\r\n          minuteData[min] = (minuteData[min] || 0) + wc;\r\n        });\r\n        var mins = Object.keys(minuteData).map(Number).sort(function(a,b){return a-b;});\r\n        var maxWpm = Math.max.apply(null, mins.map(function(m){return minuteData[m];})) || 1;\r\n        mins.forEach(function(min) {\r\n          var wpm = minuteData[min];\r\n          var pct = Math.round((wpm \/ maxWpm) * 100);\r\n          var color = wpm > 150 ? '#dc2626' : wpm > 100 ? '#f59e0b' : '#10b981';\r\n          var row = document.createElement('div'); row.className = 'pth-pace-row';\r\n          row.innerHTML = '<span class=\"pth-pace-label\">' + self2.toMMSS(min * 60) + '<\/span>' +\r\n            '<div class=\"pth-pace-bar-wrap\"><div class=\"pth-pace-bar-fill\" style=\"width:' + pct + '%;background:' + color + ';\"><\/div><\/div>' +\r\n            '<span class=\"pth-pace-val\">' + wpm + ' wpm<\/span>';\r\n          self2.UI.paceGraph.appendChild(row);\r\n        });\r\n        if (!mins.length) self2.UI.paceGraph.innerHTML = '<span style=\"color:#334155;font-size:0.82rem;\">Not enough data for pace graph.<\/span>';\r\n      }\r\n\r\n      \/* Silence Detection *\/\r\n      if (this.UI.silenceList) {\r\n        this.UI.silenceList.innerHTML = '';\r\n        var silences = []; var self3 = this;\r\n        for (var si = 0; si < this.state.transcriptionResult.length - 1; si++) {\r\n          var end = this.state.transcriptionResult[si].timestamp[1] || this.state.transcriptionResult[si].timestamp[0];\r\n          var start = this.state.transcriptionResult[si + 1].timestamp[0];\r\n          var gap = start - end;\r\n          if (gap > 2) silences.push({at: self3.toMMSS(end), duration: gap.toFixed(1)});\r\n        }\r\n        silences.slice(0, 8).forEach(function(s) {\r\n          var div = document.createElement('div'); div.className = 'pth-silence-item';\r\n          div.textContent = '\ud83d\udd07 ' + s.duration + 's silence at ' + s.at;\r\n          self3.UI.silenceList.appendChild(div);\r\n        });\r\n        if (!silences.length) this.UI.silenceList.innerHTML = '<span style=\"color:#334155;font-size:0.82rem;\">No significant silences detected (>2s).<\/span>';\r\n      }\r\n\r\n      \/* Vocab Stats *\/\r\n      var uniqueSet = {}; words.forEach(function(w) { uniqueSet[w] = 1; });\r\n      var uniqueCount = Object.keys(uniqueSet).length;\r\n      if (this.UI.uniqueWords) this.UI.uniqueWords.textContent = uniqueCount.toLocaleString();\r\n      if (this.UI.vocabRichness) this.UI.vocabRichness.textContent = words.length ? Math.round((uniqueCount \/ words.length) * 100) + '%' : '0%';\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 BOOKMARK PANEL \u2500\u2500\u2500 *\/\r\n    renderBookmarkPanel: function() {\r\n      var bms = this.state.transcriptionResult.filter(function(c) { return c.bookmarked; });\r\n      if (!this.UI.bookmarkPanelWrap || !this.UI.bookmarkList) return;\r\n      if (!bms.length) { this.UI.bookmarkPanelWrap.style.display = 'none'; return; }\r\n      this.UI.bookmarkPanelWrap.style.display = 'block';\r\n      this.UI.bookmarkList.innerHTML = '';\r\n      var self = this;\r\n      bms.forEach(function(c, i) {\r\n        var item = document.createElement('div'); item.className = 'pth-bm-item';\r\n        item.setAttribute('role', 'button'); item.setAttribute('tabindex', '0');\r\n        item.setAttribute('aria-label', 'Jump to bookmarked segment at ' + self.toMMSS(c.timestamp[0]));\r\n        item.innerHTML = '<div class=\"pth-bm-time\">\ud83d\udd16 ' + self.toMMSS(c.timestamp[0]) + '<\/div><div class=\"pth-bm-text\">' + c.text + '<\/div>';\r\n        item.addEventListener('click', function() {\r\n          var segs = self.UI.transcriptionContent.querySelectorAll('.pth-segment');\r\n          var idx = self.state.transcriptionResult.indexOf(c);\r\n          if (segs[idx]) { segs[idx].scrollIntoView({behavior: 'smooth', block: 'center'}); segs[idx].classList.add('pth-seg-active'); setTimeout(function(){segs[idx].classList.remove('pth-seg-active');},1500); }\r\n          if (self.state.mediaPlayer && c.timestamp[0]) { self.state.mediaPlayer.currentTime = c.timestamp[0]; self.state.mediaPlayer.play(); }\r\n        });\r\n        self.UI.bookmarkList.appendChild(item);\r\n      });\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 RENDER EDITOR \u2500\u2500\u2500 *\/\r\n    renderEditor: function() {\r\n      if (!this.UI.transcriptionContent) return;\r\n      this.UI.transcriptionContent.innerHTML = '';\r\n      this.updateStats();\r\n      var mode = this.UI.viewModeSelect ? this.UI.viewModeSelect.value : 'subtitles';\r\n      var fs = this.state.fontSize; var self = this;\r\n      var applyFiller = this.UI.fillerFilter && this.UI.fillerFilter.checked;\r\n\r\n      if (mode === 'subtitles') {\r\n        var frag = document.createDocumentFragment();\r\n        this.state.transcriptionResult.forEach(function(chunk, idx) {\r\n          if (self.state.chaptersData.length) {\r\n            self.state.chaptersData.forEach(function(ch) {\r\n              if (ch.index === idx && idx !== 0) {\r\n                var div = document.createElement('div'); div.className = 'pth-chapter-divider';\r\n                div.textContent = '\ud83d\udcd1 Chapter ' + (self.state.chaptersData.indexOf(ch) + 1);\r\n                frag.appendChild(div);\r\n              }\r\n            });\r\n          }\r\n          var tsStr = self.toMMSS(chunk.timestamp[0]);\r\n          var displayText = applyFiller ? self.removeFiller(chunk.text) : chunk.text;\r\n          var txtHTML = displayText;\r\n          if (self.state.currentSearchTerm) {\r\n            var re = new RegExp('(' + self.state.currentSearchTerm.replace(\/[.*+?^${}()|[\\]\\\\]\/g,'\\\\$&') + ')','gi');\r\n            txtHTML = txtHTML.replace(re, '<mark style=\"background:#fef08a;color:#713f12;\">$1<\/mark>');\r\n          }\r\n          var wc = chunk.text.split(' ').length;\r\n          var confColor = wc > 6 ? '#10b981' : wc > 3 ? '#f59e0b' : '#dc2626';\r\n          var cls = 'pth-segment';\r\n          if (chunk.speaker === 1) cls += ' pth-seg-speaker1';\r\n          if (chunk.speaker === 2) cls += ' pth-seg-speaker2';\r\n          if (chunk.bookmarked) cls += ' pth-seg-bookmarked';\r\n          var seg = document.createElement('div'); seg.className = cls; seg.dataset.idx = idx;\r\n          seg.innerHTML = '<div class=\"pth-seg-gutter\">' +\r\n            '<div class=\"pth-line-num\">' + (idx + 1) + '<\/div>' +\r\n            '<div class=\"pth-confidence-dot\" style=\"background:' + confColor + ';\" title=\"' + (wc > 6 ? 'High' : wc > 3 ? 'Medium' : 'Low') + ' confidence\"><\/div><\/div>' +\r\n            '<div class=\"pth-timestamp\" data-start=\"' + chunk.timestamp[0] + '\" aria-label=\"Jump to ' + tsStr + '\">' + tsStr + '<\/div>' +\r\n            '<div class=\"pth-text-content\" contenteditable=\"true\" data-idx=\"' + idx + '\" style=\"font-size:' + fs + '%;\" aria-label=\"Edit segment ' + (idx+1) + '\">' + txtHTML + '<\/div>' +\r\n            '<div class=\"pth-seg-actions\">' +\r\n            '<button class=\"pth-seg-action-btn\" data-action=\"bookmark\" data-idx=\"' + idx + '\" aria-label=\"' + (chunk.bookmarked ? 'Remove bookmark' : 'Bookmark segment') + '\">' + (chunk.bookmarked ? '\ud83d\udd16' : '\u2606') + '<\/button>' +\r\n            '<button class=\"pth-seg-action-btn\" data-action=\"delete\" data-idx=\"' + idx + '\" aria-label=\"Delete segment\">\ud83d\uddd1<\/button><\/div>';\r\n          frag.appendChild(seg);\r\n        });\r\n        this.UI.transcriptionContent.appendChild(frag);\r\n\r\n        this.UI.transcriptionContent.querySelectorAll('.pth-timestamp').forEach(function(ts) {\r\n          ts.addEventListener('click', function() {\r\n            if (self.state.mediaPlayer && self.state.mediaPlayer.src)\r\n              { self.state.mediaPlayer.currentTime = parseFloat(ts.getAttribute('data-start')); self.state.mediaPlayer.play(); }\r\n          });\r\n        });\r\n        this.UI.transcriptionContent.querySelectorAll('.pth-text-content').forEach(function(el) {\r\n          el.addEventListener('focus', function() { self.state.activeSegIndex = parseInt(el.getAttribute('data-idx')); });\r\n          el.addEventListener('blur', function() {\r\n            var i = parseInt(el.getAttribute('data-idx'));\r\n            if (self.state.transcriptionResult[i] && el.textContent !== self.state.transcriptionResult[i].text)\r\n              { self.pushUndo(); self.state.transcriptionResult[i].text = el.textContent; self.updateStats(); self.saveSession(); }\r\n          });\r\n        });\r\n        this.UI.transcriptionContent.querySelectorAll('.pth-seg-action-btn').forEach(function(btn) {\r\n          btn.addEventListener('click', function() {\r\n            var a = btn.getAttribute('data-action'), i = parseInt(btn.getAttribute('data-idx'));\r\n            self.pushUndo();\r\n            if (a === 'bookmark') { self.state.transcriptionResult[i].bookmarked = !self.state.transcriptionResult[i].bookmarked; self.renderEditor(); self.renderBookmarkPanel(); }\r\n            else { self.state.transcriptionResult.splice(i, 1); self.renderEditor(); self.renderBookmarkPanel(); self.updateStats(); self.saveSession(); self.showToast('Segment deleted'); }\r\n          });\r\n        });\r\n      } else {\r\n        var p = document.createElement('div'); p.className = 'pth-paragraph-view'; p.contentEditable = 'true'; p.style.fontSize = fs + '%';\r\n        var pTxt = this.state.transcriptionResult.map(function(c) { return applyFiller ? self.removeFiller(c.text) : c.text; }).join(' ');\r\n        if (this.state.currentSearchTerm) {\r\n          var re2 = new RegExp('(' + this.state.currentSearchTerm.replace(\/[.*+?^${}()|[\\]\\\\]\/g,'\\\\$&') + ')','gi');\r\n          p.innerHTML = pTxt.replace(re2, '<mark style=\"background:#fef08a;color:#713f12;\">$1<\/mark>');\r\n        } else { p.textContent = pTxt; }\r\n        p.addEventListener('blur', function() {\r\n          self.pushUndo(); self.state.transcriptionResult = [{timestamp:[0,0], text: p.textContent, bookmarked: false, speaker: null}];\r\n          self.updateStats(); self.saveSession();\r\n        });\r\n        this.UI.transcriptionContent.appendChild(p);\r\n      }\r\n      this.renderBookmarkPanel();\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 MERGE \/ SPEAKER \/ ENABLE \u2500\u2500\u2500 *\/\r\n    mergeShortSegments: function() {\r\n      if (!this.state.transcriptionResult.length) return;\r\n      this.pushUndo(); var m = [], b = null;\r\n      this.state.transcriptionResult.forEach(function(c) {\r\n        if (!b) { b = {timestamp: c.timestamp.slice(), text: c.text, bookmarked: c.bookmarked, speaker: c.speaker}; return; }\r\n        if (c.text.split(' ').length < 4) { b.text += ' ' + c.text; b.timestamp[1] = c.timestamp[1]; }\r\n        else { m.push(b); b = {timestamp: c.timestamp.slice(), text: c.text, bookmarked: c.bookmarked, speaker: c.speaker}; }\r\n      });\r\n      if (b) m.push(b);\r\n      this.state.transcriptionResult = m; this.renderEditor(); this.showToast('Segments merged!'); this.saveSession();\r\n    },\r\n    addSpeakerTag: function(n) {\r\n      if (this.state.activeSegIndex === null || !this.state.transcriptionResult[this.state.activeSegIndex])\r\n        { this.showToast('Click a segment first!', 'error'); return; }\r\n      this.pushUndo(); this.state.transcriptionResult[this.state.activeSegIndex].speaker = n; this.renderEditor(); this.saveSession();\r\n    },\r\n    enableResultControls: function() {\r\n      var els = [this.UI.viewModeSelect, this.UI.translateBtn, this.UI.copyBtn, this.UI.printBtn, this.UI.readAloudBtn,\r\n        this.UI.searchInput, this.UI.replaceInput, this.UI.replaceBtn, this.UI.spk1Btn, this.UI.spk2Btn, this.UI.mergeBtn];\r\n      els.forEach(function(e) { if (e) e.disabled = false; });\r\n      var expCards = ['pth-exp-txt','pth-exp-srt','pth-exp-vtt','pth-exp-pdf','pth-exp-json','pth-exp-srt-preview'];\r\n      expCards.forEach(function(id) { var el = document.getElementById(id); if (el) el.classList.remove('disabled'); });\r\n    },\r\n    resetUI: function(success) {\r\n      if (this.UI.progressBox) this.UI.progressBox.style.display = 'none';\r\n      if (this.UI.rightProgressBox) this.UI.rightProgressBox.style.display = 'none';\r\n      if (this.UI.generateBtn) { this.UI.generateBtn.disabled = false; this.UI.generateBtn.innerHTML = '\ud83d\ude80 Start Transcription'; }\r\n      if (!success) {\r\n        if (this.UI.transcriptionContent) this.UI.transcriptionContent.innerHTML = '';\r\n        if (this.UI.emptyState) this.UI.emptyState.style.display = 'block';\r\n      }\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 EXPORT \u2500\u2500\u2500 *\/\r\n    buildSRT: function() {\r\n      var r = ''; var self = this;\r\n      this.state.transcriptionResult.forEach(function(c, i) {\r\n        if (c.text.trim()) r += (i + 1) + '\\n' + self.formatTime(c.timestamp[0], false) + ' --> ' + self.formatTime(c.timestamp[1] || (c.timestamp[0] + 3), false) + '\\n' + c.text.trim() + '\\n\\n';\r\n      });\r\n      return r;\r\n    },\r\n    buildVTT: function() {\r\n      var r = 'WEBVTT\\n\\n'; var self = this;\r\n      this.state.transcriptionResult.forEach(function(c) {\r\n        if (c.text.trim()) r += self.formatTime(c.timestamp[0], true) + ' --> ' + self.formatTime(c.timestamp[1] || (c.timestamp[0] + 3), true) + '\\n' + c.text.trim() + '\\n\\n';\r\n      });\r\n      return r;\r\n    },\r\n    buildJSON: function() {\r\n      return JSON.stringify(this.state.transcriptionResult.map(function(c) {\r\n        return {start: c.timestamp[0], end: c.timestamp[1], text: c.text, speaker: c.speaker, bookmarked: c.bookmarked};\r\n      }), null, 2);\r\n    },\r\n    downloadFile: function(content, name, mime) {\r\n      var a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([content], {type: mime})); a.download = name; a.click(); this.showToast(name + ' saved!');\r\n    },\r\n    exportPDF: function() {\r\n      if (typeof html2pdf === 'undefined') { this.showToast('PDF library not loaded', 'error'); return; }\r\n      this.showToast('Generating PDF...', 'info');\r\n      var e = document.createElement('div'); e.style.padding = '40px'; e.style.fontFamily = 'sans-serif';\r\n      e.innerHTML = '<h2 style=\"color:#1d4ed8;\">Transcription Document<\/h2><hr style=\"margin:10px 0;\">';\r\n      var c = ''; var self = this;\r\n      this.state.transcriptionResult.forEach(function(seg) {\r\n        c += '<p style=\"margin:8px 0;\"><strong style=\"color:#5b21b6;\">[' + self.toMMSS(seg.timestamp[0]) + ']<\/strong> ' + seg.text + '<\/p>';\r\n      });\r\n      e.innerHTML += c;\r\n      var opt = {margin:1, filename:'Transcription_PTH.pdf', image:{type:'jpeg',quality:0.98}, html2canvas:{scale:2}, jsPDF:{unit:'in',format:'letter',orientation:'portrait'}};\r\n      html2pdf().set(opt).from(e).save().then(function() { self.showToast('PDF exported!'); });\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 SMART NOTES \u2500\u2500\u2500 *\/\r\n    generateNotes: function() {\r\n      if (!this.state.transcriptionResult.length) { this.showToast('No transcription yet!', 'error'); return; }\r\n      var full = this.state.transcriptionResult.map(function(c) { return c.text.trim(); }).filter(Boolean).join(' ');\r\n      var sentences = full.match(\/[^.!?]+[.!?]*\/g) || [full];\r\n      var notes = '\ud83d\udccb MEETING NOTES\\n' + '='.repeat(40) + '\\n\\n';\r\n      notes += '\ud83d\udcc5 Date: ' + new Date().toLocaleDateString() + '\\n';\r\n      notes += '\ud83d\udd50 Duration: ~' + (this.state.transcriptionResult.length > 0 ? this.toMMSS(this.state.transcriptionResult[this.state.transcriptionResult.length-1].timestamp[0]) : '00:00') + '\\n\\n';\r\n      notes += '\ud83d\udcdd KEY POINTS:\\n';\r\n      var keyPts = sentences.filter(function(s) { return s.trim().split(' ').length > 5; }).slice(0, 8);\r\n      keyPts.forEach(function(s) { notes += '\u2022 ' + s.trim() + '\\n'; });\r\n      notes += '\\n\ud83d\udca1 SUMMARY:\\n' + (sentences.slice(0, 3).map(function(s){return s.trim();}).join(' ')) + '\\n\\n';\r\n      notes += '\ud83d\udd11 ACTION ITEMS:\\n\u2022 [Add action items here]\\n\u2022 [Add action items here]\\n';\r\n      if (this.UI.notesArea) { this.UI.notesArea.value = notes; this.updateNotesWordCount(); }\r\n      this.showToast('Notes generated!');\r\n    },\r\n    updateNotesWordCount: function() {\r\n      if (!this.UI.notesArea || !this.UI.notesWordCount) return;\r\n      var wc = this.UI.notesArea.value.trim().split(\/\\s+\/).filter(Boolean).length;\r\n      this.UI.notesWordCount.textContent = wc + ' words';\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 TEXT TOOLS \u2500\u2500\u2500 *\/\r\n    applyTextTool: function(fn) {\r\n      var inp = this.UI.ttInput; if (!inp) return;\r\n      var txt = inp.value; if (!txt.trim()) { this.showToast('Load or paste text first!', 'error'); return; }\r\n      var result = fn(txt);\r\n      if (this.UI.ttOutput) this.UI.ttOutput.value = result;\r\n      if (this.UI.ttCharCount) this.UI.ttCharCount.textContent = result.length + ' chars';\r\n    },\r\n    toTitleCase: function(str) { return str.replace(\/\\w\\S*\/g, function(w) { return w.charAt(0).toUpperCase() + w.substr(1).toLowerCase(); }); },\r\n    toSentenceCase: function(str) { return str.toLowerCase().replace(\/(^|[.!?]\\s+)([a-z])\/g, function(m, p1, p2) { return p1 + p2.toUpperCase(); }); },\r\n    removeFillerWords: function(str) { return this.removeFiller(str); },\r\n    removeDuplicateWords: function(str) { return str.replace(\/\\b(\\w+)(?:\\s+\\1\\b)+\/gi, '$1'); },\r\n\r\n    \/* \u2500\u2500\u2500 SMART COPY \u2500\u2500\u2500 *\/\r\n    copyToClipboard: function(text, label) {\r\n      navigator.clipboard.writeText(text).then(function() {}).catch(function() {});\r\n      this.showToast(label + ' copied!');\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 FILE \/ AUDIO \u2500\u2500\u2500 *\/\r\n    handleFile: function(file) {\r\n      if (!file.type.startsWith('audio\/') && !file.type.startsWith('video\/')) { this.showToast('Valid audio\/video needed!', 'error'); return; }\r\n      if (file.size > 500 * 1024 * 1024) { this.showToast('Max 500 MB.', 'error'); return; }\r\n      this.state.file = file;\r\n      if (this.UI.fileNameEl) this.UI.fileNameEl.textContent = file.name || 'Media File';\r\n      if (this.state.mediaObjectURL) URL.revokeObjectURL(this.state.mediaObjectURL);\r\n      this.state.mediaObjectURL = URL.createObjectURL(file);\r\n      if (this.UI.mediaContainer) this.UI.mediaContainer.innerHTML = '';\r\n      var tag = file.type.startsWith('video\/') ? 'video' : 'audio'; var self = this;\r\n      this.state.mediaPlayer = document.createElement(tag);\r\n      this.state.mediaPlayer.className = 'pth-media-preview'; this.state.mediaPlayer.controls = true;\r\n      this.state.mediaPlayer.src = this.state.mediaObjectURL;\r\n      this.state.mediaPlayer.addEventListener('loadedmetadata', function() {\r\n        var dur = self.toMMSS(self.state.mediaPlayer.duration);\r\n        if (self.UI.fileMetaEl) self.UI.fileMetaEl.textContent = (file.size \/ (1024 * 1024)).toFixed(2) + ' MB \u00b7 ' + dur + ' \u00b7 ' + (file.type || 'audio');\r\n        if (self.UI.trimStart) self.UI.trimStart.value = '00:00';\r\n        if (self.UI.trimEnd) self.UI.trimEnd.value = dur;\r\n        file.arrayBuffer().then(function(buf) {\r\n          var ac = new (window.AudioContext || window.webkitAudioContext)({sampleRate: 16000});\r\n          ac.decodeAudioData(buf, function(ab) { self.drawWaveform(ab); });\r\n        }).catch(function() {});\r\n      });\r\n      if (this.UI.mediaContainer) this.UI.mediaContainer.appendChild(this.state.mediaPlayer);\r\n      if (this.UI.dropZone) this.UI.dropZone.style.display = 'none';\r\n      if (this.UI.fileInfoBox) this.UI.fileInfoBox.style.display = 'block';\r\n      if (this.UI.generateBtn) this.UI.generateBtn.disabled = false;\r\n      this.showToast('Media loaded!');\r\n    },\r\n    removeFile: function() {\r\n      this.state.file = null; if (this.UI.fileInput) this.UI.fileInput.value = '';\r\n      if (this.state.mediaObjectURL) { URL.revokeObjectURL(this.state.mediaObjectURL); this.state.mediaObjectURL = null; }\r\n      if (this.UI.mediaContainer) this.UI.mediaContainer.innerHTML = '';\r\n      this.state.mediaPlayer = null;\r\n      if (this.UI.fileInfoBox) this.UI.fileInfoBox.style.display = 'none';\r\n      if (this.UI.dropZone) this.UI.dropZone.style.display = 'flex';\r\n      if (this.UI.waveformCanvas) this.UI.waveformCanvas.style.display = 'none';\r\n      if (this.UI.generateBtn) this.UI.generateBtn.disabled = true;\r\n    },\r\n    extractAudio: function() {\r\n      var self = this; this.updateProgress(0, 'Extracting audio...');\r\n      return new Promise(function(resolve, reject) {\r\n        var ac = new (window.AudioContext || window.webkitAudioContext)({sampleRate: 16000});\r\n        self.state.file.arrayBuffer().then(function(buf) {\r\n          ac.decodeAudioData(buf, function(ab) {\r\n            var s0 = self.UI.trimStart ? self.parseMMSS(self.UI.trimStart.value) || 0 : 0;\r\n            var s1 = self.UI.trimEnd ? self.parseMMSS(self.UI.trimEnd.value) || ab.duration : ab.duration;\r\n            if (s0 < 0) s0 = 0; if (s1 > ab.duration) s1 = ab.duration; if (s0 >= s1) { s0 = 0; s1 = ab.duration; }\r\n            resolve(ab.getChannelData(0).slice(Math.floor(s0 * 16000), Math.floor(s1 * 16000)));\r\n          }, reject);\r\n        }).catch(reject);\r\n      });\r\n    },\r\n    downloadTrimmedWAV: function() {\r\n      var self = this;\r\n      if (this.UI.exportWavBtn) { this.UI.exportWavBtn.disabled = true; this.UI.exportWavBtn.textContent = 'Processing...'; }\r\n      this.extractAudio().then(function(samples) {\r\n        var sr = 16000, buf = new ArrayBuffer(44 + samples.length * 2), view = new DataView(buf);\r\n        var wS = function(v, o, s) { for (var i = 0; i < s.length; i++) v.setUint8(o + i, s.charCodeAt(i)); };\r\n        wS(view,0,'RIFF'); view.setUint32(4, 36 + samples.length * 2, true); wS(view,8,'WAVE'); wS(view,12,'fmt ');\r\n        view.setUint32(16,16,true); view.setUint16(20,1,true); view.setUint16(22,1,true); view.setUint32(24,sr,true);\r\n        view.setUint32(28,sr*2,true); view.setUint16(32,2,true); view.setUint16(34,16,true); wS(view,36,'data'); view.setUint32(40,samples.length*2,true);\r\n        var off = 44;\r\n        for (var i = 0; i < samples.length; i++, off += 2) { var sv = Math.max(-1, Math.min(1, samples[i])); view.setInt16(off, sv < 0 ? sv * 0x8000 : sv * 0x7FFF, true); }\r\n        var b = new Blob([view], {type: 'audio\/wav'}), u = URL.createObjectURL(b), a = document.createElement('a');\r\n        a.href = u; a.download = 'Trimmed_PTH.wav'; document.body.appendChild(a); a.click();\r\n        setTimeout(function(){document.body.removeChild(a); URL.revokeObjectURL(u);}, 1000);\r\n        if (self.UI.exportWavBtn) { self.UI.exportWavBtn.disabled = false; self.UI.exportWavBtn.textContent = '\ud83d\udce5 Download Trimmed Audio (WAV)'; }\r\n        self.showToast('WAV saved!');\r\n      }).catch(function() { self.showToast('WAV export failed', 'error'); if (self.UI.exportWavBtn) { self.UI.exportWavBtn.disabled = false; self.UI.exportWavBtn.textContent = '\ud83d\udce5 Download Trimmed Audio (WAV)'; } });\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 PROGRESS \u2500\u2500\u2500 *\/\r\n    updateProgress: function(pct, text, rightOnly) {\r\n      if (!rightOnly) {\r\n        if (this.UI.progressBox) this.UI.progressBox.style.display = 'block';\r\n        if (this.UI.progressBar) this.UI.progressBar.style.width = pct + '%';\r\n        if (this.UI.progressPct) this.UI.progressPct.textContent = pct + '%';\r\n        if (this.UI.progressTitle) this.UI.progressTitle.textContent = text;\r\n        if (this.UI.statusMsg) this.UI.statusMsg.textContent = text;\r\n      }\r\n      if (this.UI.rightProgressBox) this.UI.rightProgressBox.style.display = 'block';\r\n      if (this.UI.rightProgressBar) this.UI.rightProgressBar.style.width = pct + '%';\r\n      if (this.UI.rightProgressPct) this.UI.rightProgressPct.textContent = pct + '%';\r\n      if (this.UI.rightProgressTitle) this.UI.rightProgressTitle.textContent = text;\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 AI WORKER \u2500\u2500\u2500 *\/\r\n    setupWorker: function() {\r\n      if (this.state.aiWorker) return; var self = this;\r\n      var workerLines = [\r\n        \"import { pipeline, env } from 'https:\/\/cdn.jsdelivr.net\/npm\/@xenova\/transformers@2.16.0';\",\r\n        \"env.allowLocalModels = false;\",\r\n        \"var T = null;\",\r\n        \"self.onmessage = async function(e) {\",\r\n        \"  if (e.data.type === 'load') {\",\r\n        \"    try {\",\r\n        \"      T = await pipeline('automatic-speech-recognition', e.data.model, {progress_callback: function(d){ self.postMessage({type:'progress', data:JSON.parse(JSON.stringify(d))}); }});\",\r\n        \"      self.postMessage({type:'loaded'});\",\r\n        \"    } catch(err) { self.postMessage({type:'error', error:err.message}); }\",\r\n        \"  } else if (e.data.type === 'transcribe') {\",\r\n        \"    try {\",\r\n        \"      var out = await T(e.data.audio, {language: e.data.language === 'auto' ? null : e.data.language, task: e.data.task, chunk_length_s: e.data.quick ? 15 : 30, return_timestamps: true});\",\r\n        \"      self.postMessage({type:'complete', data:JSON.parse(JSON.stringify(out))});\",\r\n        \"    } catch(err) { self.postMessage({type:'error', error:err.message}); }\",\r\n        \"  }\",\r\n        \"};\"\r\n      ];\r\n      var blob = new Blob([workerLines.join('\\n')], {type: 'application\/javascript'});\r\n      this.state.aiWorker = new Worker(URL.createObjectURL(blob), {type: 'module'});\r\n      this.state.aiWorker.onmessage = function(e) {\r\n        var t = e.data.type, d = e.data.data, err = e.data.error;\r\n        if (t === 'progress') {\r\n          if (d && d.status === 'downloading') { var pct = d.total ? Math.round((d.loaded \/ d.total) * 100) : 50; self.updateProgress(pct, 'Downloading AI... ' + pct + '%'); }\r\n        } else if (t === 'loaded') {\r\n          var sl = self.UI.langSelect ? self.UI.langSelect.value : 'en';\r\n          self.state.currentLang = (sl === 'auto') ? 'en' : sl;\r\n          self.state.transcriptionTimer = 0;\r\n          \r\n          self.state.transcriptionInterval = setInterval(function() {\r\n            self.state.transcriptionTimer++;\r\n            var msg = 'Transcribing... ' + self.state.transcriptionTimer + 's';\r\n            if (self.UI.statusMsg) self.UI.statusMsg.textContent = msg;\r\n            if (self.UI.progressTitle) self.UI.progressTitle.textContent = msg;\r\n            if (self.UI.rightProgressTitle) self.UI.rightProgressTitle.textContent = msg;\r\n            \r\n            \/\/ 0% \u0dc0\u0dd9\u0db1\u0dd4\u0dc0\u0da7 processing \u0d85\u0dba\u0dd2\u0d9a\u0db1\u0dba\u0d9a\u0dca \u0db4\u0dd9\u0db1\u0dca\u0dc0\u0dd3\u0db8\r\n            if (self.UI.progressPct) self.UI.progressPct.textContent = '\u23f3';\r\n            if (self.UI.rightProgressPct) self.UI.rightProgressPct.textContent = '\u23f3';\r\n            if (self.UI.progressBar) self.UI.progressBar.style.width = '100%';\r\n            if (self.UI.rightProgressBar) self.UI.rightProgressBar.style.width = '100%';\r\n          }, 1000);\r\n          \r\n          self.state.aiWorker.postMessage({type: 'transcribe', audio: self.state.audioData, language: sl, task: self.UI.taskSelect ? self.UI.taskSelect.value : 'transcribe', quick: self.UI.quickMode ? self.UI.quickMode.checked : true});\r\n        } else if (t === 'complete') {\r\n          clearInterval(self.state.transcriptionInterval);\r\n          self.finishTranscription(d.chunks || d);\r\n        } else if (t === 'error') {\r\n          clearInterval(self.state.transcriptionInterval);\r\n          self.showToast('Error: ' + err, 'error'); self.resetUI(false);\r\n        }\r\n      };\r\n    },\r\n    finishTranscription: function(chunks) {\r\n      var off = this.UI.trimStart ? this.parseMMSS(this.UI.trimStart.value) || 0 : 0;\r\n      var cl = []; var last = ''; var self = this;\r\n      chunks.forEach(function(c) {\r\n        var t = self.cleanHallucinations(c.text);\r\n        if (t && t !== last) { cl.push({timestamp: [(c.timestamp[0] || 0) + off, c.timestamp[1] ? (c.timestamp[1] + off) : null], text: t, bookmarked: false, speaker: null}); last = t; }\r\n      });\r\n      if (!cl.length) {\r\n        if (this.UI.transcriptionContent) this.UI.transcriptionContent.innerHTML = '<div style=\"text-align:center;color:#dc2626;margin-top:110px;\">No speech detected.<\/div>';\r\n        this.resetUI(false); return;\r\n      }\r\n      this.state.transcriptionResult = cl;\r\n      this.pushUndo(); this.renderEditor(); this.enableResultControls(); this.saveSession(); this.renderDeepAnalytics();\r\n      this.showToast('Transcription complete! \u2728'); this.resetUI(true);\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 TRANSLATE \u2500\u2500\u2500 *\/\r\n    buildLangGrid: function() {\r\n      if (!this.UI.langGrid) return;\r\n      this.UI.langGrid.innerHTML = ''; var self = this;\r\n      Object.keys(this.LANG_MAP).forEach(function(k) {\r\n        var p = self.LANG_MAP[k]; var b = document.createElement('button'); b.className = 'pth-lang-btn';\r\n        b.innerHTML = '<img decoding=\"async\" src=\"https:\/\/flagcdn.com\/24x18\/' + p.flag + '.png\" width=\"22\" height=\"16\" style=\"border-radius:2px;object-fit:cover;\" alt=\"' + p.name + ' flag\"> <span>' + p.name + '<\/span>';\r\n        b.addEventListener('click', function() { self.startTranslation(k, p.name); });\r\n        self.UI.langGrid.appendChild(b);\r\n      });\r\n    },\r\n    startTranslation: async function(tL, lN) {\r\n      if (!this.state.transcriptionResult.length) return;\r\n      if (this.UI.langOverlay) this.UI.langOverlay.classList.remove('active');\r\n      if (this.UI.transcriptionContent) this.UI.transcriptionContent.style.display = 'none';\r\n      this.updateProgress(0, 'Translating...', true);\r\n      if (this.UI.translateBtn) this.UI.translateBtn.disabled = true;\r\n      try {\r\n        for (var i = 0; i < this.state.transcriptionResult.length; i++) {\r\n          var t = this.state.transcriptionResult[i].text; if (!t.trim()) continue;\r\n          var r = await fetch('https:\/\/translate.googleapis.com\/translate_a\/single?client=gtx&sl=auto&tl=' + tL + '&dt=t', {method:'POST', headers:{'Content-Type':'application\/x-www-form-urlencoded'}, body:'q=' + encodeURIComponent(t)});\r\n          var d = await r.json(); this.state.transcriptionResult[i].text = d[0].map(function(p){return p[0];}).join('');\r\n          this.updateProgress(Math.round(((i + 1) \/ this.state.transcriptionResult.length) * 100), 'Translating ' + (i + 1), true);\r\n        }\r\n        this.state.currentLang = tL; this.renderEditor(); this.saveSession(); this.showToast('Translated to ' + lN + '!');\r\n      } catch(e) { this.showToast('Translation failed', 'error'); }\r\n      finally {\r\n        if (this.UI.rightProgressBox) this.UI.rightProgressBox.style.display = 'none';\r\n        if (this.UI.transcriptionContent) this.UI.transcriptionContent.style.display = 'block';\r\n        if (this.UI.translateBtn) this.UI.translateBtn.disabled = false;\r\n      }\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 READ ALOUD \u2500\u2500\u2500 *\/\r\n    startReadAloud: function() {\r\n      if (!this.state.transcriptionResult.length) return; window.speechSynthesis.cancel(); var self = this;\r\n      var utt = new SpeechSynthesisUtterance(this.state.transcriptionResult.map(function(c) { return c.text; }).join(' '));\r\n      utt.lang = (this.LANG_MAP[this.state.currentLang] ? this.LANG_MAP[this.state.currentLang].tts : this.state.currentLang) || 'en-US';\r\n      utt.onstart = function() { if (self.UI.readAloudBtn) self.UI.readAloudBtn.style.display = 'none'; if (self.UI.stopReadBtn) self.UI.stopReadBtn.style.display = 'inline-flex'; };\r\n      utt.onend = utt.onerror = function() { if (self.UI.readAloudBtn) self.UI.readAloudBtn.style.display = 'inline-flex'; if (self.UI.stopReadBtn) self.UI.stopReadBtn.style.display = 'none'; };\r\n      window.speechSynthesis.speak(utt); this.showToast('Reading aloud...');\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 TABS \u2500\u2500\u2500 *\/\r\n    switchTab: function(tab) {\r\n      this.state.currentTab = tab;\r\n      if (!this.UI.tabBar) return;\r\n      this.UI.tabBar.querySelectorAll('.pth-tab-btn').forEach(function(btn) {\r\n        var isActive = btn.getAttribute('data-tab') === tab;\r\n        btn.classList.toggle('active', isActive);\r\n        btn.setAttribute('aria-selected', isActive ? 'true' : 'false');\r\n      });\r\n      var panels = ['transcribe','notes','analytics','texttools','export'];\r\n      panels.forEach(function(p) {\r\n        var el = document.getElementById('pth-panel-' + p);\r\n        if (el) el.classList.toggle('active', p === tab);\r\n      });\r\n      if (tab === 'analytics' && this.state.transcriptionResult.length) this.renderDeepAnalytics();\r\n    },\r\n\r\n    \/* \u2500\u2500\u2500 EVENTS \u2500\u2500\u2500 *\/\r\n    attachEvents: function() {\r\n      var self = this;\r\n\r\n      \/* Layout *\/\r\n      this.bindEvent(this.UI.fwBtn, 'click', function() {\r\n        if (self.UI.layout) {\r\n          self.UI.layout.classList.toggle('pth-full-width');\r\n          self.UI.fwBtn.innerHTML = self.UI.layout.classList.contains('pth-full-width') ? '\u25c0 Split View' : '\u26f6 Full Width';\r\n        }\r\n      });\r\n      this.bindEvent(this.UI.darkBtn, 'click', function() {\r\n        if (self.UI.wrapper) {\r\n          self.UI.wrapper.classList.toggle('pth-dark');\r\n          self.UI.darkBtn.innerHTML = self.UI.wrapper.classList.contains('pth-dark') ? '\u2600\ufe0f Light' : '\ud83c\udf19 Dark';\r\n        }\r\n      });\r\n      this.bindEvent(this.UI.shortcutsBtn, 'click', function() { var p = document.getElementById('pth-shortcuts-panel'); if (p) p.classList.add('open'); });\r\n      this.bindEvent(this.UI.shortcutsClose, 'click', function() { var p = document.getElementById('pth-shortcuts-panel'); if (p) p.classList.remove('open'); });\r\n      this.bindEvent(this.UI.restoreBtn, 'click', function() { self.restoreSession(); });\r\n      this.bindEvent(this.UI.clearAllBtn, 'click', function() {\r\n        self.state.transcriptionResult = []; self.state.undoStack = []; self.state.redoStack = [];\r\n        if (self.UI.transcriptionContent) self.UI.transcriptionContent.innerHTML = '';\r\n        if (self.UI.emptyState) self.UI.emptyState.style.display = 'block';\r\n        if (self.UI.bookmarkPanelWrap) self.UI.bookmarkPanelWrap.style.display = 'none';\r\n        if (self.UI.statsPanel) self.UI.statsPanel.style.display = 'none';\r\n        if (self.UI.statsEmpty) self.UI.statsEmpty.style.display = 'block';\r\n        if (self.UI.analyticsEmpty) self.UI.analyticsEmpty.style.display = 'block';\r\n        if (self.UI.analyticsContent) self.UI.analyticsContent.style.display = 'none';\r\n        self.showToast('Cleared!');\r\n      });\r\n\r\n      \/* Tab switching *\/\r\n      if (this.UI.tabBar) {\r\n        this.UI.tabBar.querySelectorAll('.pth-tab-btn').forEach(function(btn) {\r\n          btn.addEventListener('click', function() { self.switchTab(btn.getAttribute('data-tab')); });\r\n        });\r\n      }\r\n\r\n      \/* Sample *\/\r\n      this.bindEvent(this.UI.sampleBtn, 'click', function() {\r\n        self.showToast('Loading sample...', 'info');\r\n        fetch('https:\/\/upload.wikimedia.org\/wikipedia\/commons\/c\/c8\/Example.ogg')\r\n          .then(function(r) { return r.blob(); })\r\n          .then(function(b) { self.handleFile(new File([b], 'English_Sample.ogg', {type: 'audio\/ogg'})); self.showToast('Sample loaded!'); })\r\n          .catch(function() { self.showToast('Sample load failed', 'error'); });\r\n      });\r\n\r\n      \/* File handlers *\/\r\n      this.bindEvent(this.UI.browseBtn, 'click', function() { if (self.UI.fileInput) self.UI.fileInput.click(); });\r\n      this.bindEvent(this.UI.fileInput, 'change', function(e) { if (e.target.files[0]) self.handleFile(e.target.files[0]); });\r\n      this.bindEvent(this.UI.dropZone, 'dragover', function(e) { e.preventDefault(); if (self.UI.dropZone) self.UI.dropZone.classList.add('dragover'); });\r\n      this.bindEvent(this.UI.dropZone, 'dragleave', function(e) { e.preventDefault(); if (self.UI.dropZone) self.UI.dropZone.classList.remove('dragover'); });\r\n      this.bindEvent(this.UI.dropZone, 'drop', function(e) { e.preventDefault(); if (self.UI.dropZone) self.UI.dropZone.classList.remove('dragover'); if (e.dataTransfer.files[0]) self.handleFile(e.dataTransfer.files[0]); });\r\n      this.bindEvent(this.UI.removeBtn, 'click', function() { self.removeFile(); });\r\n\r\n      \/* Speed buttons *\/\r\n      var speedBtns = document.querySelectorAll('#pth-transcribe-wrapper .pth-speed-btn');\r\n      for (var sb = 0; sb < speedBtns.length; sb++) {\r\n        (function(btn) {\r\n          btn.addEventListener('click', function() {\r\n            var sp = parseFloat(btn.getAttribute('data-speed'));\r\n            if (self.state.mediaPlayer) self.state.mediaPlayer.playbackRate = sp;\r\n            speedBtns.forEach(function(b) { b.classList.remove('active'); });\r\n            btn.classList.add('active');\r\n          });\r\n        })(speedBtns[sb]);\r\n      }\r\n\r\n      \/* Mic *\/\r\n      this.bindEvent(this.UI.micBtn, 'click', function() {\r\n        if (!self.state.isRecording) {\r\n          navigator.mediaDevices.getUserMedia({audio: true}).then(function(str) {\r\n            self.state.mediaRecorder = new MediaRecorder(str); self.state.audioChunks = [];\r\n            self.state.mediaRecorder.ondataavailable = function(e) { self.state.audioChunks.push(e.data); };\r\n            self.state.mediaRecorder.onstop = function() {\r\n              var b = new Blob(self.state.audioChunks, {type: 'audio\/webm'});\r\n              self.handleFile(new File([b], 'Live_Rec.webm', {type: 'audio\/webm'}));\r\n              if (self.UI.micStatus) self.UI.micStatus.style.display = 'none';\r\n            };\r\n            self.state.mediaRecorder.start(); self.state.isRecording = true;\r\n            if (self.UI.micBtn) { self.UI.micBtn.classList.add('recording'); self.UI.micBtn.textContent = '\u23f9\ufe0f Stop Recording'; }\r\n            if (self.UI.micStatus) self.UI.micStatus.style.display = 'block';\r\n            var s = 0; self.state.timerInterval = setInterval(function() { s++; if (self.UI.micStatus) self.UI.micStatus.textContent = '\u25cf ' + self.toMMSS(s); }, 1000);\r\n          }).catch(function() { self.showToast('Microphone access denied', 'error'); });\r\n        } else {\r\n          self.state.mediaRecorder.stop(); self.state.mediaRecorder.stream.getTracks().forEach(function(t) { t.stop(); });\r\n          self.state.isRecording = false;\r\n          if (self.UI.micBtn) { self.UI.micBtn.classList.remove('recording'); self.UI.micBtn.textContent = '\ud83c\udf99\ufe0f Start Live Recording'; }\r\n          clearInterval(self.state.timerInterval);\r\n        }\r\n      });\r\n\r\n      \/* Option chips *\/\r\n      var toggles = [\r\n        {c: this.UI.quickChip, i: this.UI.quickMode},\r\n        {c: this.UI.filterChip, i: this.UI.noiseFilter},\r\n        {c: this.UI.chaptersChip, i: this.UI.autoChapters},\r\n        {c: this.UI.waveformChip, i: this.UI.showWaveform},\r\n        {c: this.UI.fillerChip, i: this.UI.fillerFilter}\r\n      ];\r\n      toggles.forEach(function(p) {\r\n        if (p.c && p.i) p.i.addEventListener('change', function() { p.c.classList.toggle('active', p.i.checked); if (self.state.transcriptionResult.length) self.renderEditor(); });\r\n      });\r\n\r\n      \/* Generate *\/\r\n      this.bindEvent(this.UI.generateBtn, 'click', function() {\r\n        if (!self.state.file) { self.showToast('Upload a file first!', 'error'); return; }\r\n        if (self.UI.generateBtn) { self.UI.generateBtn.disabled = true; self.UI.generateBtn.textContent = '\u23f3 Processing...'; }\r\n        if (self.UI.emptyState) self.UI.emptyState.style.display = 'none';\r\n        if (self.UI.transcriptionContent) self.UI.transcriptionContent.innerHTML = '';\r\n        self.extractAudio().then(function(audio) {\r\n          self.state.audioData = audio; self.setupWorker();\r\n          self.state.aiWorker.postMessage({type: 'load', model: self.UI.modelSelect ? self.UI.modelSelect.value : 'Xenova\/whisper-tiny'});\r\n        }).catch(function() { self.showToast('Audio extraction failed', 'error'); self.resetUI(false); });\r\n      });\r\n\r\n      \/* Editor controls *\/\r\n      this.bindEvent(this.UI.viewModeSelect, 'change', function() { self.renderEditor(); });\r\n      this.bindEvent(this.UI.zoomSlider, 'input', function() {\r\n        self.state.fontSize = parseInt(self.UI.zoomSlider.value);\r\n        if (self.UI.transcriptionContent) self.UI.transcriptionContent.querySelectorAll('.pth-text-content,.pth-paragraph-view').forEach(function(e) { e.style.fontSize = self.state.fontSize + '%'; });\r\n      });\r\n      this.bindEvent(this.UI.searchInput, 'input', function() { self.state.currentSearchTerm = self.UI.searchInput.value.trim(); self.renderEditor(); });\r\n      this.bindEvent(this.UI.replaceBtn, 'click', function() {\r\n        if (!self.state.currentSearchTerm) return; self.pushUndo();\r\n        var re = new RegExp(self.state.currentSearchTerm.replace(\/[.*+?^${}()|[\\]\\\\]\/g,'\\\\$&'), 'gi');\r\n        var rep = self.UI.replaceInput ? self.UI.replaceInput.value : '';\r\n        self.state.transcriptionResult.forEach(function(c) { c.text = c.text.replace(re, rep); });\r\n        self.state.currentSearchTerm = '';\r\n        if (self.UI.searchInput) self.UI.searchInput.value = '';\r\n        if (self.UI.replaceInput) self.UI.replaceInput.value = '';\r\n        self.renderEditor(); self.saveSession(); self.showToast('Replaced!');\r\n      });\r\n      this.bindEvent(this.UI.spk1Btn, 'click', function() { self.addSpeakerTag(1); });\r\n      this.bindEvent(this.UI.spk2Btn, 'click', function() { self.addSpeakerTag(2); });\r\n      this.bindEvent(this.UI.mergeBtn, 'click', function() { self.mergeShortSegments(); });\r\n      this.bindEvent(this.UI.undoBtn, 'click', function() { self.performUndo(); });\r\n      this.bindEvent(this.UI.redoBtn, 'click', function() { self.performRedo(); });\r\n      this.bindEvent(this.UI.readAloudBtn, 'click', function() { self.startReadAloud(); });\r\n      this.bindEvent(this.UI.stopReadBtn, 'click', function() {\r\n        window.speechSynthesis.cancel();\r\n        if (self.UI.readAloudBtn) self.UI.readAloudBtn.style.display = 'inline-flex';\r\n        if (self.UI.stopReadBtn) self.UI.stopReadBtn.style.display = 'none';\r\n        self.showToast('Stopped');\r\n      });\r\n      this.bindEvent(this.UI.copyBtn, 'click', function() {\r\n        navigator.clipboard.writeText(self.state.transcriptionResult.map(function(c) { return c.text.trim(); }).join('\\n'));\r\n        self.showToast('Copied!');\r\n      });\r\n      this.bindEvent(this.UI.printBtn, 'click', function() {\r\n        var w = window.open('', '_blank');\r\n        w.document.write('<pre style=\"font-family:sans-serif;padding:40px;white-space:pre-wrap;\">' + self.state.transcriptionResult.map(function(c) { return c.text; }).join('\\n') + '<\/pre>');\r\n        w.document.close(); w.print();\r\n      });\r\n\r\n      \/* Translate modal *\/\r\n      this.bindEvent(this.UI.translateBtn, 'click', function() { if (!self.state.transcriptionResult.length) return; if (self.UI.langOverlay) self.UI.langOverlay.classList.add('active'); });\r\n      this.bindEvent(this.UI.modalCloseBtn, 'click', function() { if (self.UI.langOverlay) self.UI.langOverlay.classList.remove('active'); });\r\n      this.bindEvent(this.UI.langSearch, 'input', function() {\r\n        var q = self.UI.langSearch.value.toLowerCase();\r\n        if (self.UI.langGrid) self.UI.langGrid.querySelectorAll('.pth-lang-btn').forEach(function(b) { b.style.display = b.querySelector('span').textContent.toLowerCase().includes(q) ? '' : 'none'; });\r\n      });\r\n\r\n      \/* WAV export *\/\r\n      this.bindEvent(this.UI.exportWavBtn, 'click', function() { self.downloadTrimmedWAV(); });\r\n\r\n      \/* Preview modal *\/\r\n      this.bindEvent(this.UI.previewClose, 'click', function() { if (self.UI.previewModal) self.UI.previewModal.classList.remove('active'); });\r\n      this.bindEvent(this.UI.previewDownload, 'click', function() { self.downloadFile(self.state.previewContent, self.state.previewFilename, self.state.previewMime); });\r\n\r\n      \/* Smart Notes *\/\r\n      this.bindEvent(this.UI.notesGenBtn, 'click', function() { self.generateNotes(); });\r\n      this.bindEvent(this.UI.notesBulletsBtn, 'click', function() {\r\n        if (!self.UI.notesArea || !self.UI.notesArea.value.trim()) { self.showToast('Generate notes first!', 'error'); return; }\r\n        var lines = self.UI.notesArea.value.split('\\n').map(function(l) { return l.trim() ? '\u2022 ' + l.replace(\/^[\u2022\\-\\d.]+\\s*\/, '') : ''; });\r\n        self.UI.notesArea.value = lines.join('\\n'); self.updateNotesWordCount();\r\n      });\r\n      this.bindEvent(this.UI.notesNumberedBtn, 'click', function() {\r\n        if (!self.UI.notesArea || !self.UI.notesArea.value.trim()) return;\r\n        var n = 0; var lines = self.UI.notesArea.value.split('\\n').map(function(l) { if (l.trim()) { n++; return n + '. ' + l.replace(\/^[\u2022\\-\\d.]+\\s*\/, ''); } return ''; });\r\n        self.UI.notesArea.value = lines.join('\\n'); self.updateNotesWordCount();\r\n      });\r\n      this.bindEvent(this.UI.notesClearBtn, 'click', function() { if (self.UI.notesArea) self.UI.notesArea.value = ''; self.updateNotesWordCount(); });\r\n      this.bindEvent(this.UI.notesCopyBtn, 'click', function() {\r\n        if (self.UI.notesArea) { navigator.clipboard.writeText(self.UI.notesArea.value); self.showToast('Notes copied!'); }\r\n      });\r\n      this.bindEvent(this.UI.notesArea, 'input', function() { self.updateNotesWordCount(); });\r\n      this.bindEvent(this.UI.notesSummaryBtn, 'click', function() {\r\n        if (!self.state.transcriptionResult.length) { self.showToast('No transcription yet!', 'error'); return; }\r\n        var full = self.state.transcriptionResult.map(function(c) { return c.text; }).join(' ');\r\n        var s = full.match(\/[^.!?]+[.!?]*\/g) || [full]; var r = [];\r\n        if (s.length > 0) r.push(s[0].trim()); if (s.length > 3) r.push(s[Math.floor(s.length \/ 2)].trim()); if (s.length > 1) r.push(s[s.length - 1].trim());\r\n        self.state.previewContent = r.join(' '); self.state.previewFilename = 'summary.txt'; self.state.previewMime = 'text\/plain';\r\n        if (self.UI.previewTitle) self.UI.previewTitle.textContent = '\ud83d\udcdd Quick Summary';\r\n        if (self.UI.previewContent) self.UI.previewContent.textContent = r.join(' ');\r\n        if (self.UI.previewModal) self.UI.previewModal.classList.add('active');\r\n      });\r\n\r\n      \/* Text Tools *\/\r\n      this.bindEvent(this.UI.ttLoadBtn, 'click', function() {\r\n        if (!self.state.transcriptionResult.length) { self.showToast('No transcription yet!', 'error'); return; }\r\n        var txt = self.state.transcriptionResult.map(function(c) { return c.text.trim(); }).join(' ');\r\n        if (self.UI.ttInput) { self.UI.ttInput.value = txt; if (self.UI.ttCharCount) self.UI.ttCharCount.textContent = txt.length + ' chars'; }\r\n      });\r\n      this.bindEvent(this.UI.ttUpperBtn, 'click', function() { self.applyTextTool(function(t) { return t.toUpperCase(); }); });\r\n      this.bindEvent(this.UI.ttLowerBtn, 'click', function() { self.applyTextTool(function(t) { return t.toLowerCase(); }); });\r\n      this.bindEvent(this.UI.ttTitleBtn, 'click', function() { self.applyTextTool(function(t) { return self.toTitleCase(t); }); });\r\n      this.bindEvent(this.UI.ttSentenceBtn, 'click', function() { self.applyTextTool(function(t) { return self.toSentenceCase(t); }); });\r\n      this.bindEvent(this.UI.ttFillerBtn, 'click', function() { self.applyTextTool(function(t) { return self.removeFillerWords(t); }); });\r\n      this.bindEvent(this.UI.ttDedupBtn, 'click', function() { self.applyTextTool(function(t) { return self.removeDuplicateWords(t); }); });\r\n      this.bindEvent(this.UI.ttCleanBtn, 'click', function() { self.applyTextTool(function(t) { return t.replace(\/\\s{2,}\/g, ' ').replace(\/\\n{3,}\/g, '\\n\\n').trim(); }); });\r\n      this.bindEvent(this.UI.ttTrimSocialBtn, 'click', function() { self.applyTextTool(function(t) { return t.substring(0, 280) + (t.length > 280 ? '...' : ''); }); });\r\n      this.bindEvent(this.UI.ttCopyResultBtn, 'click', function() {\r\n        if (self.UI.ttOutput && self.UI.ttOutput.value) { navigator.clipboard.writeText(self.UI.ttOutput.value); self.showToast('Result copied!'); }\r\n      });\r\n      this.bindEvent(this.UI.ttInput, 'input', function() { if (self.UI.ttCharCount) self.UI.ttCharCount.textContent = self.UI.ttInput.value.length + ' chars'; });\r\n\r\n      \/* Char limit chips *\/\r\n      var limitChips = document.querySelectorAll('#pth-transcribe-wrapper .pth-limit-chip');\r\n      for (var lc = 0; lc < limitChips.length; lc++) {\r\n        (function(chip) {\r\n          chip.addEventListener('click', function() {\r\n            var lim = parseInt(chip.getAttribute('data-limit'));\r\n            var txt = self.UI.ttInput ? self.UI.ttInput.value : '';\r\n            if (self.UI.ttOutput) self.UI.ttOutput.value = txt.substring(0, lim) + (txt.length > lim ? '...' : '');\r\n            if (self.UI.ttCharCount) self.UI.ttCharCount.textContent = Math.min(txt.length, lim) + ' chars';\r\n          });\r\n        })(limitChips[lc]);\r\n      }\r\n\r\n      \/* Export Hub *\/\r\n      this.bindEvent(this.UI.expTxt, 'click', function() {\r\n        if (self.UI.expTxt && self.UI.expTxt.classList.contains('disabled')) return;\r\n        self.downloadFile(self.state.transcriptionResult.map(function(c){return c.text.trim();}).join('\\n'), 'Transcription_PTH.txt', 'text\/plain');\r\n      });\r\n      this.bindEvent(this.UI.expSrt, 'click', function() {\r\n        if (self.UI.expSrt && self.UI.expSrt.classList.contains('disabled')) return;\r\n        self.downloadFile(self.buildSRT(), 'Subtitles_PTH.srt', 'text\/plain');\r\n      });\r\n      this.bindEvent(this.UI.expVtt, 'click', function() {\r\n        if (self.UI.expVtt && self.UI.expVtt.classList.contains('disabled')) return;\r\n        self.downloadFile(self.buildVTT(), 'Subtitles_PTH.vtt', 'text\/vtt');\r\n      });\r\n      this.bindEvent(this.UI.expPdf, 'click', function() {\r\n        if (self.UI.expPdf && self.UI.expPdf.classList.contains('disabled')) return;\r\n        self.exportPDF();\r\n      });\r\n      this.bindEvent(this.UI.expJson, 'click', function() {\r\n        if (self.UI.expJson && self.UI.expJson.classList.contains('disabled')) return;\r\n        self.downloadFile(self.buildJSON(), 'Transcription_PTH.json', 'application\/json');\r\n      });\r\n      this.bindEvent(this.UI.expSrtPreview, 'click', function() {\r\n        if (self.UI.expSrtPreview && self.UI.expSrtPreview.classList.contains('disabled')) return;\r\n        self.state.previewContent = self.buildSRT(); self.state.previewFilename = 'Subtitles.srt'; self.state.previewMime = 'text\/plain';\r\n        if (self.UI.previewTitle) self.UI.previewTitle.textContent = '\ud83d\udcdd SRT Preview';\r\n        if (self.UI.previewContent) self.UI.previewContent.textContent = self.buildSRT();\r\n        if (self.UI.previewModal) self.UI.previewModal.classList.add('active');\r\n      });\r\n\r\n      \/* Smart Copy Modes *\/\r\n      this.bindEvent(this.UI.copyPlain, 'click', function() {\r\n        self.copyToClipboard(self.state.transcriptionResult.map(function(c){return c.text.trim();}).join('\\n'), 'Plain text');\r\n      });\r\n      this.bindEvent(this.UI.copyTimestamps, 'click', function() {\r\n        var txt = self.state.transcriptionResult.map(function(c){return '[' + self.toMMSS(c.timestamp[0]) + '] ' + c.text.trim();}).join('\\n');\r\n        self.copyToClipboard(txt, 'Timestamped text');\r\n      });\r\n      this.bindEvent(this.UI.copySrtClip, 'click', function() { self.copyToClipboard(self.buildSRT(), 'SRT format'); });\r\n      this.bindEvent(this.UI.copyMeeting, 'click', function() {\r\n        self.generateNotes();\r\n        var notes = self.UI.notesArea ? self.UI.notesArea.value : '';\r\n        self.copyToClipboard(notes, 'Meeting notes');\r\n      });\r\n\r\n      \/* Keyboard shortcuts *\/\r\n      document.addEventListener('keydown', function(e) {\r\n        var el = document.activeElement;\r\n        var inE = el ? (el.contentEditable === 'true' || ['INPUT','TEXTAREA'].includes(el.tagName)) : false;\r\n        if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); if (self.UI.generateBtn && !self.UI.generateBtn.disabled) self.UI.generateBtn.click(); return; }\r\n        if (e.ctrlKey && e.key.toLowerCase() === 'z' && !inE) { e.preventDefault(); self.performUndo(); return; }\r\n        if (e.ctrlKey && e.key.toLowerCase() === 'y' && !inE) { e.preventDefault(); self.performRedo(); return; }\r\n        if (e.ctrlKey && e.key.toLowerCase() === 'f' && !inE) { e.preventDefault(); if (self.UI.fwBtn) self.UI.fwBtn.click(); return; }\r\n        if (e.ctrlKey && e.key.toLowerCase() === 'h') { e.preventDefault(); if (self.UI.searchInput) self.UI.searchInput.focus(); return; }\r\n        if (e.key === ' ' && !inE && self.state.mediaPlayer) { e.preventDefault(); self.state.mediaPlayer.paused ? self.state.mediaPlayer.play() : self.state.mediaPlayer.pause(); }\r\n      });\r\n    }\r\n  };\r\n\r\n  \/* 4-Layer Bootstrap *\/\r\n  function runInit() {\r\n    if (!window.pthTranscriptionApp.initialized && document.getElementById('pth-transcribe-wrapper')) {\r\n      window.pthTranscriptionApp.initialized = true;\r\n      window.pthTranscriptionApp.init();\r\n    }\r\n  }\r\n  runInit();\r\n  document.addEventListener('DOMContentLoaded', runInit);\r\n  window.addEventListener('load', function() { setTimeout(runInit, 50); });\r\n  var _mo = new MutationObserver(function() { runInit(); });\r\n  _mo.observe(document.body, {childList: true, subtree: true});\r\n  setTimeout(function() { _mo.disconnect(); }, 10000);\r\n\r\n})();\r\n<\/script>\n\n\n\n\n<style>\n.pth-feature-wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px;margin:32px 0}\n.pth-feat-box{background:#f8fafc;border:1px solid #e2e8f0;border-radius:14px;padding:22px 24px}\n.pth-feat-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 10px;display:flex;align-items:center;gap:8px}\n.pth-feat-text{font-size:0.92rem;color:#1e293b;font-weight:500;line-height:1.7;margin:0}\n.pth-steps-wrap{margin:36px 0}\n.pth-steps-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-top:16px}\n.pth-step-item{background:#ffffff;border:1px solid #e2e8f0;border-radius:12px;padding:18px 20px;display:flex;flex-direction:column;gap:8px}\n.pth-step-num{width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,#8b5cf6,#6d28d9);color:#fff;font-weight:900;font-size:0.95rem;display:flex;align-items:center;justify-content:center;flex-shrink:0}\n.pth-step-name{font-size:0.9rem;font-weight:800;color:#0f172a}\n.pth-step-desc{font-size:0.82rem;color:#334155;font-weight:500;line-height:1.6;margin:0}\n<\/style>\n \n<div class=\"pth-feature-wrap\">\n \n  <div class=\"pth-feat-box\">\n    <p class=\"pth-feat-title\">\ud83d\udfe2 5-Tab All-in-One Workspace<\/p>\n    <p class=\"pth-feat-text\">One upload powers five complete tools. The <strong>Transcribe<\/strong> tab gives you an inline segment editor with speaker tags, search\/replace, and undo\/redo history. Switch to <strong>Smart Notes<\/strong> for auto-generated meeting notes. Jump to <strong>Deep Analytics<\/strong> for sentiment clouds, pace-per-minute graphs, and silence detection \u2014 all from a single audio file without re-uploading.<\/p>\n  <\/div>\n \n  <div class=\"pth-feat-box\">\n    <p class=\"pth-feat-title\">\ud83d\udd35 Professional Export Hub<\/p>\n    <p class=\"pth-feat-text\">The dedicated <strong>Export Hub<\/strong> tab puts every format in one grid: <strong>.TXT<\/strong>, <strong>.SRT<\/strong>, <strong>.VTT<\/strong>, <strong>.PDF<\/strong>, and <strong>.JSON<\/strong> with full timestamp data. Four <strong>Smart Copy Modes<\/strong> let you copy as Plain Text, With Timestamps, SRT Format, or Meeting Notes \u2014 instantly ready for YouTube, Premiere Pro, Notion, or email without reformatting.<\/p>\n  <\/div>\n \n  <div class=\"pth-feat-box\">\n    <p class=\"pth-feat-title\">\ud83d\udfe3 Offline AI \u2014 Zero Data Sent<\/p>\n    <p class=\"pth-feat-text\">The Whisper AI model downloads once to your browser cache \u2014 after that, every transcription runs entirely client-side with <strong>zero server calls<\/strong>. Your audio never leaves your device. Supports <strong>20 languages<\/strong> including Sinhala, Tamil, Hindi, Japanese, Arabic, and Ukrainian. Works on a plane, in a meeting room, or anywhere with no Wi-Fi after the first model load.<\/p>\n  <\/div>\n \n<\/div>\n \n<div class=\"pth-steps-wrap\">\n  <h2 style=\"font-size:1.3rem;font-weight:800;color:#0f172a;margin:0 0 4px;\">How to Use the AI Transcription Studio<\/h2>\n  <p style=\"font-size:0.88rem;color:#334155;font-weight:500;margin:0 0 16px;\">Four steps from audio file to polished, exported transcript.<\/p>\n  <div class=\"pth-steps-grid\">\n \n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">1<\/div>\n      <div class=\"pth-step-name\">Upload or Record<\/div>\n      <p class=\"pth-step-desc\">Drag &#038; Drop an MP3, WAV, MP4, WEBM, or OGG file onto the <strong>Media Input<\/strong> zone \u2014 or click <strong>Start Live Recording<\/strong> to capture from your microphone. Set a Trim Range if you only need part of the file.<\/p>\n    <\/div>\n \n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">2<\/div>\n      <div class=\"pth-step-name\">Configure Engine Settings<\/div>\n      <p class=\"pth-step-desc\">Pick your <strong>AI Model<\/strong> (Whisper Tiny for speed, Base for accuracy), select your <strong>Language<\/strong> or leave it on Auto-Detect, toggle <strong>Filler<\/strong> to strip out &#8220;um&#8221; and &#8220;uh&#8221;, then hit <strong>\ud83d\ude80 Start Transcription<\/strong>.<\/p>\n    <\/div>\n \n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">3<\/div>\n      <div class=\"pth-step-name\">Edit in Transcribe Tab<\/div>\n      <p class=\"pth-step-desc\">Segments appear in the <strong>\ud83c\udfac Transcribe<\/strong> tab. Click timestamps to seek media. Tag speakers with <strong>\ud83d\udc64 Spk 1<\/strong> \/ <strong>\ud83d\udc65 Spk 2<\/strong>. Bookmark key moments, use <strong>Find &#038; Replace<\/strong>, and switch between Subtitle View and Paragraph View.<\/p>\n    <\/div>\n \n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">4<\/div>\n      <div class=\"pth-step-name\">Export from Export Hub<\/div>\n      <p class=\"pth-step-desc\">Click the <strong>\ud83c\udfaf Export Hub<\/strong> tab. Choose <strong>.SRT<\/strong> for subtitles, <strong>.JSON<\/strong> for developer data, <strong>.PDF<\/strong> for formal documents, or use a <strong>Smart Copy Mode<\/strong> to paste straight into Notion, Google Docs, or email.<\/p>\n    <\/div>\n \n  <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Last updated: June 2025<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-why-one-tab-is-never-enough-for-real-transcription-work\" class=\"wp-block-heading\">\ud83d\udd34 Why One Tab Is Never Enough for Real Transcription Work<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Every other free transcription tool on the web does one thing: it spits out a wall of text and leaves you to figure out the rest. You then open a second tab to reformat the output. A third to export subtitles. A fourth to analyze speaking pace for your podcast. The PTH AI Offline Transcription Studio v3.0 refuses this pattern. Upload once \u2014 everything else happens in a five-tab workspace that stays right where you are.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The tool is built around a single principle: a transcription is not a final product. It is raw material. Real workflows turn raw speech into meeting notes, subtitle files, content analytics, and social copy \u2014 all from the same source. Version 3.0 was rebuilt from scratch to serve that reality.<\/p>\n\n\n\n<h3 id=\"the-5-tab-workspace-every-step-in-one-place\" class=\"wp-block-heading\">The 5-Tab Workspace \u2014 Every Step in One Place<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The interface opens on the&nbsp;<strong>\ud83c\udfac Transcribe<\/strong>&nbsp;tab, where AI-generated segments appear as editable rows. Each row shows a clickable timestamp that seeks your audio or video player to that exact moment. Confidence is shown as a three-tier color dot \u2014 green for high-confidence segments (6+ words), amber for medium, red for short clips that may need a manual check. Click any dot to see the confidence level as a tooltip.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Speaker diarization is manual but fast: click any segment, then hit&nbsp;<strong>\ud83d\udc64 Spk 1<\/strong>&nbsp;or&nbsp;<strong>\ud83d\udc65 Spk 2<\/strong>&nbsp;in the toolbar. The segment instantly gets a left-border color \u2014 blue for Speaker 1, green for Speaker 2. This is enough for 95% of interview and podcast use cases without requiring a separate ML model. The&nbsp;<strong>\ud83d\udd17 Merge<\/strong>&nbsp;button fuses short segments together, cleaning up choppy output from fast speech.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bookmarks are persistent within your session. Star any segment with the \u2606 action button on hover \u2014 it flips to \ud83d\udd16 and the segment gets an amber left border. A&nbsp;<strong>Bookmarked Segments<\/strong>&nbsp;panel appears below the editor, listing every bookmarked line. Click any item in that panel to jump to the segment in the editor and seek the media player simultaneously. This is the workflow for pulling quotes from long interviews.<\/p>\n\n\n\n<h3 id=\"smart-notes-from-speech-to-structured-document\" class=\"wp-block-heading\">Smart Notes \u2014 From Speech to Structured Document<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<strong>\ud83d\udcdd Smart Notes<\/strong>&nbsp;tab solves a problem every meeting recorder knows: a raw transcript is not a meeting summary. Click&nbsp;<strong>\u2728 Generate Notes<\/strong>&nbsp;and the tool builds a structured document automatically \u2014 a date header, total duration, eight key bullet points pulled from the highest-information sentences, a three-sentence summary, and a placeholder for action items.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The notes are fully editable in a plain textarea. Two format buttons let you reformat:&nbsp;<strong>\u2022 Bullets<\/strong>&nbsp;converts every line to a bullet point, stripping existing list markers cleanly.&nbsp;<strong>1. Numbered<\/strong>&nbsp;applies sequential numbering. The word count updates live as you type. When ready,&nbsp;<strong>\ud83d\udccb Copy Notes<\/strong>&nbsp;copies the entire block \u2014 ready to paste into Notion, Confluence, or a Google Doc.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe1-deep-analytics-what-your-speech-data-actually-reveals\" class=\"wp-block-heading\">\ud83d\udfe1 Deep Analytics \u2014 What Your Speech Data Actually Reveals<\/h3>\n\n\n<figure class=\"pth-article-figure pth-img-left\" style=\"float:left; width:700px; max-width:100%; margin:4px 28px 16px 0; clear:left;\"><img decoding=\"async\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/06\/transcription-deep-analytics-chart-800x447.jpeg\" alt=\"Mid-body image for the Deep Analytics section. Data visualization aesthetic\" width=\"700\" height=\"394\" loading=\"lazy\" data-no-lazy=\"1\" class=\"pth-article-img\" style=\"width:100%;height:auto;display:block;border-radius:10px;border:1px solid #e2e8f0;\"><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<strong>\ud83d\udcca Deep Analytics<\/strong>&nbsp;tab does not just count words. It runs four separate analyses on the same transcription data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Sentiment Word Highlights<\/strong>&nbsp;scans every word against a positive and negative dictionary. Positive words render in green, negative in red, inside a cloud layout. This is a fast gut-check for customer calls, interviews, or lecture recordings \u2014 you can see the emotional tone of an hour of audio in about three seconds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Top Phrases<\/strong>&nbsp;extracts the most frequent bigrams (two-word sequences), filtering stopwords. If a phrase like &#8220;machine learning&#8221; or &#8220;budget approval&#8221; appears eight times in a one-hour recording, it surfaces at the top. Each phrase tag shows its frequency count in a small badge \u2014 this is the feature content researchers use to spot recurring themes without reading the full transcript.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Speaking Pace per Minute<\/strong>&nbsp;renders as a horizontal bar chart \u2014 one bar per minute of audio. Bars are color-coded: green for under 100 wpm (relaxed), amber for 100\u2013150 wpm (conversational), red for over 150 wpm (fast). Podcast editors use this to spot where a guest is rushing. Teachers use it to find where they lost control of their pace. Public speakers use it to identify sections that need deliberate slowdown.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Silence \/ Gap Detection<\/strong>&nbsp;flags every gap over two seconds between segments. Each silence shows its duration and position in MM:SS format. A recording with eight detected silences across forty minutes tells a completely different story than one with zero \u2014 the first is an interview with natural pauses, the second is a continuous lecture. This data matters for audio editors deciding where to cut.<\/p>\n\n\n\n<h3 id=\"text-tools-clean-and-reformat-without-leaving-the-tool\" class=\"wp-block-heading\">Text Tools \u2014 Clean and Reformat Without Leaving the Tool<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<strong>\ud83d\udd24 Text Tools<\/strong>&nbsp;tab gives eight transformations that every transcript needs at some point. Load your transcription with one click, or paste any text. The left panel is your editable input; the right shows the transformed result.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Remove Filler Words<\/strong>&nbsp;strips the twenty most common spoken fillers \u2014 &#8220;um&#8221;, &#8220;uh&#8221;, &#8220;like&#8221;, &#8220;you know&#8221;, &#8220;sort of&#8221;, &#8220;kind of&#8221;, &#8220;basically&#8221;, &#8220;literally&#8221;, &#8220;actually&#8221;, &#8220;i mean&#8221;, and more. The regex-based cleaner handles both standalone occurrences and those followed by commas. A transcript of casual speech that runs 1,200 words often drops to 1,050 after filler removal \u2014 cleaner for publishing, faster to read.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Remove Duplicates<\/strong>&nbsp;catches consecutive repeated words \u2014 a common Whisper output artifact where &#8220;the the&#8221; or &#8220;it was was&#8221; appears due to audio overlap.&nbsp;<strong>Clean Spaces<\/strong>&nbsp;collapses double whitespace and triple line breaks. Three social media limit chips let you trim output to exactly 280 characters (Twitter\/X), 500 characters (YouTube short description), or 2,200 characters (Instagram caption) \u2014 one click, no counting.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-export-hub-six-formats-four-copy-modes\" class=\"wp-block-heading\">\ud83d\udfe2 Export Hub \u2014 Six Formats, Four Copy Modes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<strong>\ud83c\udfaf Export Hub<\/strong>&nbsp;tab consolidates every download option that was previously scattered across multiple buttons. Six export cards sit in a responsive three-column grid.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>.TXT<\/strong>&nbsp;is plain text, one line per segment \u2014 fastest for notes or copy-paste.&nbsp;<strong>.SRT<\/strong>&nbsp;and&nbsp;<strong>.VTT<\/strong>&nbsp;are the two subtitle formats needed for YouTube, Vimeo, and most video players. SRT uses comma-separated milliseconds; VTT uses dot-separated and adds the WEBVTT header \u2014 the tool builds both formats correctly from the same timestamp data.&nbsp;<strong>.PDF<\/strong>&nbsp;generates a formatted document with a title, horizontal rule, and every segment listed as a paragraph with its timestamp in blue.&nbsp;<strong>.JSON<\/strong>&nbsp;is the developer format \u2014 an array of objects with&nbsp;<code>start<\/code>,&nbsp;<code>end<\/code>,&nbsp;<code>text<\/code>,&nbsp;<code>speaker<\/code>, and&nbsp;<code>bookmarked<\/code>&nbsp;fields, ready to feed into any downstream script or API.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Below the export grid, four&nbsp;<strong>Smart Copy Modes<\/strong>&nbsp;handle clipboard workflows without saving a file.&nbsp;<strong>\ud83d\udcc4 Plain Text<\/strong>&nbsp;copies clean prose.&nbsp;<strong>\u23f1\ufe0f With Timestamps<\/strong>&nbsp;adds [MM:SS] markers before each line \u2014 the format YouTubers use for chapter descriptions.&nbsp;<strong>\ud83d\udcdd SRT Format<\/strong>&nbsp;puts the full SRT block on the clipboard so you can paste directly into a video editor&#8217;s subtitle import field.&nbsp;<strong>\ud83d\udccb Meeting Notes<\/strong>&nbsp;triggers note generation and copies the structured output in one action.<\/p>\n\n\n\n<h3 id=\"playback-speed-control-and-audio-trimmer\" class=\"wp-block-heading\">Playback Speed Control and Audio Trimmer<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Five playback speed buttons live below the waveform display in the sidebar:&nbsp;<strong>0.5x<\/strong>,&nbsp;<strong>0.75x<\/strong>,&nbsp;<strong>1x<\/strong>,&nbsp;<strong>1.25x<\/strong>, and&nbsp;<strong>1.5x<\/strong>. The active speed is highlighted in purple. Slowing to 0.5x is the standard workflow for transcribing heavily accented speech or overlapping dialogue that the AI misses. Running at 1.5x is how you skim a one-hour recording in forty minutes during review.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<strong>Trim Range<\/strong>&nbsp;inputs use MM:SS format. Set a start and end, then click&nbsp;<strong>\ud83d\ude80 Start Transcription<\/strong>&nbsp;\u2014 only the trimmed range is sent to the AI. This is essential for long files: a 90-minute podcast where you only need minutes 12 to 45 should not waste processing time on the full file. The&nbsp;<strong>Download Trimmed Audio (WAV)<\/strong>&nbsp;button exports just that range as a 16 kHz WAV \u2014 useful for archiving interview clips or extracting quotes for social audio.<\/p>\n\n\n\n<h3 id=\"live-microphone-and-20-language-support\" class=\"wp-block-heading\">Live Microphone and 20-Language Support<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<strong>\ud83c\udfa4 Live Microphone<\/strong>&nbsp;card uses the&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/MediaRecorder\" rel=\"noreferrer noopener\" target=\"_blank\">MediaRecorder API<\/a>&nbsp;to capture audio directly in-browser. Hit&nbsp;<strong>Start Live Recording<\/strong>, speak, then hit&nbsp;<strong>\u23f9\ufe0f Stop Recording<\/strong>. The recorded blob is handed to the same file handler as an upload \u2014 it appears in the media player, the waveform draws, and you can trim and transcribe identically to a file upload. No extra steps.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Language support covers twenty languages including Sinhala (si), Tamil (ta), Hindi (hi), Arabic (ar), Japanese (ja), Korean (ko), Chinese (zh), Ukrainian (uk), Vietnamese (vi), and Thai (th). Set the language dropdown before transcription for best results, or leave it on&nbsp;<strong>\u2728 Auto-Detect<\/strong>&nbsp;for multilingual content. The&nbsp;<strong>\ud83c\udf10 Translate<\/strong>&nbsp;button in the editor opens a searchable language grid and uses the Google Translate API to convert every segment \u2014 preserving timestamps and segment structure while replacing the text.<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-who-uses-this-tool-real-use-cases\" class=\"wp-block-heading\">\ud83d\udd34 Who Uses This Tool \u2014 Real Use Cases<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Podcast editors<\/strong>&nbsp;upload their raw recordings, check the pace graph for rushing sections, export SRT for show notes timestamps, and copy the meeting notes format for episode descriptions \u2014 one tool, full workflow.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Students and researchers<\/strong>&nbsp;record lectures or interviews on their phones, upload the file, let Whisper transcribe while offline in the library, then use the Text Tools tab to clean and reformat before pasting into their thesis notes. The JSON export gives structured data for any digital humanities project.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Legal and medical professionals<\/strong>&nbsp;who need local processing use Whisper Tiny for speed or Whisper Base for accuracy, with the noise filter on to suppress hallucinated filler content. The 100% offline guarantee means sensitive recordings never touch an external server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Content creators<\/strong>&nbsp;use the social media character limit chips in Text Tools to trim quotes to Twitter\/X length, copy with the SRT copy mode for Premiere Pro caption import, and use the sentiment cloud to pick the most emotionally positive quote for their caption. See also our&nbsp;PTH Ultimate Text and SEO Studio&nbsp;for further content optimization after transcription.<\/p>\n\n\n\n\n<style>\n.pth-faq-section{margin-top:50px;margin-bottom:40px;font-family:inherit}\n.pth-faq-header{font-size:1.8rem;font-weight:800;color:#0f172a;margin-bottom:25px;border-bottom:2px solid #e2e8f0;padding-bottom:10px;display:flex;align-items:center;gap:10px}\n.pth-faq-grid{display:grid;grid-template-columns:100%;gap:20px}\n@media(min-width:768px){.pth-faq-grid{grid-template-columns:repeat(2,1fr)}}\n@media(min-width:1024px){.pth-faq-grid{grid-template-columns:repeat(3,1fr)}}\n.pth-faq-card{background:#f8fafc;padding:24px;border-radius:12px;border:1px solid #e2e8f0;transition:transform .2s ease;break-inside:avoid}\n.pth-faq-card:hover{transform:translateY(-3px);box-shadow:0 4px 12px rgba(0,0,0,.05)}\n.pth-faq-q{color:#0f172a;font-size:1rem;font-weight:700;margin:0 0 12px;line-height:1.4}\n.pth-faq-a{margin:0;font-size:.95rem;color:#1e293b;line-height:1.6;font-weight:500}\n<\/style>\n \n<div class=\"pth-faq-section\">\n  <h2 class=\"pth-faq-header\">\u2753 Frequently Asked Questions<\/h2>\n  <div class=\"pth-faq-grid\">\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Does the AI transcription work without internet?<\/p>\n      <p class=\"pth-faq-a\">After the Whisper model downloads to your browser cache on first use \u2014 around 74 MB for Tiny or 140 MB for Base \u2014 every transcription runs completely offline. No audio is ever sent to a server. Reload the page with Wi-Fi off and it still works.<\/p>\n    <\/div>\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What audio and video formats are supported?<\/p>\n      <p class=\"pth-faq-a\">The tool accepts MP3, WAV, MP4, WEBM, and OGG files up to 500 MB. Any format your browser&#8217;s AudioContext can decode will work \u2014 which covers almost every common audio and video format. The file is processed entirely in your browser memory.<\/p>\n    <\/div>\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What is the difference between Whisper Tiny and Whisper Base?<\/p>\n      <p class=\"pth-faq-a\">Whisper Tiny (~74 MB) is faster and ideal for clear speech in common languages like English or Spanish. Whisper Base (~140 MB) is more accurate for accented speech, technical vocabulary, and less common languages. For podcasts and meetings, Tiny is usually sufficient. For medical or legal content, use Base.<\/p>\n    <\/div>\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">How do I export subtitles for YouTube?<\/p>\n      <p class=\"pth-faq-a\">Go to the <strong>\ud83c\udfaf Export Hub<\/strong> tab and click the <strong>.SRT<\/strong> card. Download the file, then in YouTube Studio go to Subtitles \u2192 Add \u2192 Upload file and select your .SRT. YouTube reads the timestamps automatically and syncs captions to your video.<\/p>\n    <\/div>\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Can I transcribe only part of a long audio file?<\/p>\n      <p class=\"pth-faq-a\">Yes. After uploading, use the <strong>Trim Range (MM:SS)<\/strong> inputs in the sidebar. Enter your start and end times, then click Start Transcription. Only the trimmed segment is processed. You can also download just that trimmed clip as a WAV file using the Download Trimmed Audio button.<\/p>\n    <\/div>\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What languages does the transcription support?<\/p>\n      <p class=\"pth-faq-a\">The tool supports 20 languages including English, Sinhala, Tamil, Hindi, Spanish, French, German, Portuguese, Japanese, Chinese, Arabic, Korean, Italian, Russian, Dutch, Polish, Turkish, Vietnamese, Thai, and Ukrainian. Select your language before starting, or use Auto-Detect for multilingual recordings.<\/p>\n    <\/div>\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What does the Filler Word Filter chip do?<\/p>\n      <p class=\"pth-faq-a\">When the <strong>\ud83d\udd24 Filler<\/strong> chip is active, words like &#8220;um&#8221;, &#8220;uh&#8221;, &#8220;like&#8221;, &#8220;you know&#8221;, &#8220;basically&#8221;, and &#8220;literally&#8221; are stripped from the display in real time. This does not modify the underlying data \u2014 toggle the chip off to see the original. You can also apply filler removal permanently in the Text Tools tab.<\/p>\n    <\/div>\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">How does the JSON export work?<\/p>\n      <p class=\"pth-faq-a\">The <strong>.JSON<\/strong> export in the Export Hub creates an array of segment objects. Each object has <code>start<\/code> (seconds), <code>end<\/code> (seconds), <code>text<\/code> (string), <code>speaker<\/code> (1, 2, or null), and <code>bookmarked<\/code> (boolean). This format is ideal for developers building search indexes, subtitle renderers, or transcript databases.<\/p>\n    <\/div>\n \n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Does the session auto-save feature work offline?<\/p>\n      <p class=\"pth-faq-a\">Yes. Every transcription is automatically saved to your browser&#8217;s localStorage after each change. If you accidentally close the tab, click the <strong>\u267b\ufe0f Restore<\/strong> button in the top bar to recover your last session. Sessions expire after 24 hours.<\/p>\n    <\/div>\n \n  <\/div>\n<\/div>\n \n","protected":false},"excerpt":{"rendered":"<p>Secure AI Offline Transcription Studio | Client-Side Audio to Text Convert speech to text securely using our AI offline transcription studio. It runs Whisper neural network models entirely client-side for zero-upload privacy. \ud83d\udfe2 5-Tab All-in-One Workspace One upload powers five complete tools. The Transcribe tab gives you an inline segment editor with speaker tags, search\/replace, &#8230; <a title=\"Secure AI Offline Transcription Studio | Client-Side Audio to Text\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/ai-offline-transcription\/\" aria-label=\"Read more about Secure AI Offline Transcription Studio | Client-Side Audio to Text\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":2895,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2884","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2884","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=2884"}],"version-history":[{"count":0,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2884\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/2895"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=2884"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}