{"id":70,"date":"2026-07-01T13:38:37","date_gmt":"2026-07-01T13:38:37","guid":{"rendered":"https:\/\/freewebtools.co.in\/?page_id=70"},"modified":"2026-07-16T16:56:22","modified_gmt":"2026-07-16T16:56:22","slug":"text-tools-2","status":"publish","type":"page","link":"https:\/\/freewebtools.co.in\/index.php\/text-tools-2\/","title":{"rendered":"Text Tools"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Word Counter, Case Converter, Remove Duplicates, Text Compare and more.<\/p>\n\n\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>All-in-One Professional Text Tools<\/title>\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/mammoth\/1.6.0\/mammoth.browser.min.js\"><\/script>\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\"><\/script>\n    <style>\n        \/* CSS RESET & DESIGN VARIABLES - Thoroughly namespaced to prevent conflict in any host environment *\/\n        :root {\n            --txto-bg: #f8fafc;\n            --txto-surface: #ffffff;\n            --txto-surface-glass: rgba(255, 255, 255, 0.85);\n            --txto-border: #e2e8f0;\n            --txto-border-focus: #3b82f6;\n            --txto-text-primary: #0f172a;\n            --txto-text-secondary: #475569;\n            --txto-primary: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);\n            --txto-primary-hover: linear-gradient(135deg, #1d4ed8 0%, #1e40af 100%);\n            --txto-accent: #8b5cf6;\n            --txto-success: #10b981;\n            --txto-error: #ef4444;\n            --txto-shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.05);\n            --txto-shadow-md: 0 4px 12px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);\n            --txto-shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n            --txto-radius: 12px;\n            --txto-radius-sm: 8px;\n            --txto-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n        }\n\n        .txto-wrapper {\n            box-sizing: border-box;\n            font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n            background-color: var(--txto-bg);\n            color: var(--txto-text-primary);\n            min-height: 100vh;\n            padding: 2rem 1rem;\n            display: flex;\n            justify-content: center;\n        }\n\n        .txto-wrapper * {\n            box-sizing: border-box;\n            margin: 0;\n            padding: 0;\n        }\n\n        .txto-container {\n            width: 100%;\n            max-width: 1400px;\n            display: flex;\n            flex-direction: column;\n            gap: 1.5rem;\n        }\n\n        \/* HEADER SECTION *\/\n        .txto-header {\n            text-align: center;\n            margin-bottom: 1rem;\n        }\n\n        .txto-header h1 {\n            font-size: 2.5rem;\n            font-weight: 800;\n            letter-spacing: -0.025em;\n            background: var(--txto-primary);\n            -webkit-background-clip: text;\n            -webkit-text-fill-color: transparent;\n            margin-bottom: 0.5rem;\n        }\n\n        .txto-header p {\n            color: var(--txto-text-secondary);\n            font-size: 1rem;\n        }\n\n        \/* SEARCH AND CATEGORIES FILTER *\/\n        .txto-controls-row {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 1rem;\n            align-items: center;\n            justify-content: space-between;\n            background: var(--txto-surface);\n            padding: 1rem;\n            border-radius: var(--txto-radius);\n            border: 1px solid var(--txto-border);\n            box-shadow: var(--txto-shadow-sm);\n        }\n\n        .txto-search-box {\n            position: relative;\n            flex: 1;\n            min-width: 280px;\n        }\n\n        .txto-search-input {\n            width: 100%;\n            padding: 0.75rem 1rem 0.75rem 2.5rem;\n            border: 1px solid var(--txto-border);\n            border-radius: var(--txto-radius-sm);\n            font-size: 0.9375rem;\n            outline: none;\n            transition: var(--txto-transition);\n        }\n\n        .txto-search-input:focus {\n            border-color: var(--txto-border-focus);\n            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n        }\n\n        .txto-search-icon {\n            position: absolute;\n            left: 0.75rem;\n            top: 50%;\n            transform: translateY(-50%);\n            color: var(--txto-text-secondary);\n            width: 18px;\n            height: 18px;\n            pointer-events: none;\n        }\n\n        .txto-categories {\n            display: flex;\n            gap: 0.5rem;\n            overflow-x: auto;\n            padding-bottom: 2px;\n            scrollbar-width: thin;\n        }\n\n        .txto-category-btn {\n            background: var(--txto-bg);\n            border: 1px solid var(--txto-border);\n            border-radius: var(--txto-radius-sm);\n            padding: 0.5rem 1rem;\n            font-size: 0.875rem;\n            font-weight: 600;\n            color: var(--txto-text-secondary);\n            cursor: pointer;\n            transition: var(--txto-transition);\n            white-space: nowrap;\n        }\n\n        .txto-category-btn:hover, .txto-category-btn.txto-active {\n            background: #2563eb;\n            color: #ffffff;\n            border-color: #2563eb;\n        }\n\n        \/* MAIN APP LAYOUT GRID *\/\n        .txto-layout {\n            display: grid;\n            grid-template-columns: 1fr;\n            gap: 1.5rem;\n        }\n\n        @media (min-width: 1024px) {\n            .txto-layout {\n                grid-template-columns: 350px 1fr;\n            }\n        }\n\n        \/* SIDEBAR - TOOLS LIST *\/\n        .txto-sidebar-card {\n            background: var(--txto-surface);\n            border: 1px solid var(--txto-border);\n            border-radius: var(--txto-radius);\n            box-shadow: var(--txto-shadow-md);\n            padding: 1.25rem;\n            display: flex;\n            flex-direction: column;\n            gap: 1rem;\n            max-height: 80vh;\n            position: sticky;\n            top: 1rem;\n            overflow-y: auto;\n        }\n\n        .txto-sidebar-card::-webkit-scrollbar {\n            width: 6px;\n        }\n\n        .txto-sidebar-card::-webkit-scrollbar-thumb {\n            background: var(--txto-border);\n            border-radius: 3px;\n        }\n\n        .txto-sidebar-title {\n            font-size: 1.125rem;\n            font-weight: 700;\n            color: var(--txto-text-primary);\n            border-bottom: 1px solid var(--txto-border);\n            padding-bottom: 0.5rem;\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n        }\n\n        .txto-tools-grid {\n            display: flex;\n            flex-direction: column;\n            gap: 0.5rem;\n        }\n\n        .txto-tool-item {\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            background: var(--txto-bg);\n            border: 1px solid var(--txto-border);\n            border-radius: var(--txto-radius-sm);\n            padding: 0.75rem 1rem;\n            cursor: pointer;\n            transition: var(--txto-transition);\n            text-align: left;\n            user-select: none;\n        }\n\n        .txto-tool-item:hover {\n            border-color: var(--txto-border-focus);\n            transform: translateX(4px);\n            background: rgba(59, 130, 246, 0.04);\n        }\n\n        .txto-tool-item.txto-active {\n            background: var(--txto-primary);\n            color: #ffffff;\n            border-color: transparent;\n        }\n\n        .txto-tool-meta {\n            display: flex;\n            flex-direction: column;\n            gap: 0.125rem;\n            flex: 1;\n        }\n\n        .txto-tool-name {\n            font-size: 0.875rem;\n            font-weight: 700;\n        }\n\n        .txto-tool-desc {\n            font-size: 0.75rem;\n            color: var(--txto-text-secondary);\n        }\n\n        .txto-tool-item.txto-active .txto-tool-desc {\n            color: rgba(255, 255, 255, 0.8);\n        }\n\n        .txto-fav-star {\n            cursor: pointer;\n            font-size: 1rem;\n            color: #cbd5e1;\n            transition: var(--txto-transition);\n            margin-left: 0.5rem;\n        }\n\n        .txto-fav-star.txto-starred {\n            color: #f59e0b;\n        }\n\n        \/* EDITOR \/ PREVIEW WORKSPACE *\/\n        .txto-workspace {\n            display: flex;\n            flex-direction: column;\n            gap: 1.5rem;\n        }\n\n        .txto-workspace-card {\n            background: var(--txto-surface);\n            border: 1px solid var(--txto-border);\n            border-radius: var(--txto-radius);\n            box-shadow: var(--txto-shadow-lg);\n            padding: 1.5rem;\n            display: flex;\n            flex-direction: column;\n            gap: 1rem;\n        }\n\n        \/* WORKSPACE TOOLBAR *\/\n        .txto-toolbar {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 0.5rem;\n            border-bottom: 1px solid var(--txto-border);\n            padding-bottom: 1rem;\n            align-items: center;\n        }\n\n        .txto-toolbar-btn {\n            background: var(--txto-bg);\n            border: 1px solid var(--txto-border);\n            color: var(--txto-text-secondary);\n            padding: 0.5rem 0.75rem;\n            font-size: 0.8125rem;\n            font-weight: 600;\n            border-radius: var(--txto-radius-sm);\n            cursor: pointer;\n            display: inline-flex;\n            align-items: center;\n            gap: 0.375rem;\n            transition: var(--txto-transition);\n        }\n\n        .txto-toolbar-btn:hover {\n            background: var(--txto-border);\n            color: var(--txto-text-primary);\n        }\n\n        .txto-toolbar-btn-danger {\n            background: rgba(239, 68, 68, 0.05);\n            border-color: rgba(239, 68, 68, 0.2);\n            color: var(--txto-error);\n        }\n\n        .txto-toolbar-btn-danger:hover {\n            background: var(--txto-error);\n            color: #ffffff;\n        }\n\n        \/* INTEGRATED EDITOR PANELS (SPLIT SCREEN) *\/\n        .txto-split-editor {\n            display: grid;\n            grid-template-columns: 1fr;\n            gap: 1.5rem;\n        }\n\n        @media (min-width: 768px) {\n            .txto-split-editor {\n                grid-template-columns: 1fr 1fr;\n            }\n        }\n\n        .txto-panel {\n            display: flex;\n            flex-direction: column;\n            gap: 0.5rem;\n        }\n\n        .txto-panel-header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            font-weight: 700;\n            font-size: 0.875rem;\n            color: var(--txto-text-secondary);\n        }\n\n        .txto-textarea-container {\n            position: relative;\n            border: 1px solid var(--txto-border);\n            border-radius: var(--txto-radius-sm);\n            background: #ffffff;\n            display: flex;\n            min-height: 350px;\n            overflow: hidden;\n        }\n\n        .txto-textarea-container:focus-within {\n            border-color: var(--txto-border-focus);\n            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n        }\n\n        \/* Dynamic Line Numbering Structure *\/\n        .txto-line-numbers {\n            width: 45px;\n            background: #f8fafc;\n            border-right: 1px solid var(--txto-border);\n            padding: 0.75rem 0;\n            font-family: monospace;\n            font-size: 0.875rem;\n            line-height: 1.5;\n            color: #94a3b8;\n            text-align: right;\n            padding-right: 8px;\n            user-select: none;\n            overflow: hidden;\n        }\n\n        .txto-textarea {\n            flex: 1;\n            padding: 0.75rem;\n            border: none;\n            outline: none;\n            resize: none;\n            font-family: monospace;\n            font-size: 0.875rem;\n            line-height: 1.5;\n            color: var(--txto-text-primary);\n            background: transparent;\n            overflow-y: auto;\n            white-space: pre;\n        }\n\n        .txto-textarea.txto-wrap {\n            white-space: pre-wrap;\n            word-wrap: break-word;\n        }\n\n        \/* TEXT FINDER AND REPLACER TOOLBAR SUB-PANEL *\/\n        .txto-search-panel {\n            background: var(--txto-bg);\n            border: 1px solid var(--txto-border);\n            border-radius: var(--txto-radius-sm);\n            padding: 1rem;\n            display: flex;\n            flex-direction: column;\n            gap: 0.75rem;\n        }\n\n        .txto-search-panel-row {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 0.5rem;\n            align-items: center;\n        }\n\n        .txto-search-input-field {\n            flex: 1;\n            min-width: 150px;\n            padding: 0.5rem 0.75rem;\n            border: 1px solid var(--txto-border);\n            border-radius: 4px;\n            font-size: 0.8125rem;\n            outline: none;\n        }\n\n        .txto-search-input-field:focus {\n            border-color: var(--txto-border-focus);\n        }\n\n        \/* DYNAMIC CONTEXTUAL OPTIONS PANEL FOR INDIVIDUAL SELECTED TOOLS *\/\n        .txto-options-panel {\n            background: rgba(59, 130, 246, 0.03);\n            border: 1px solid rgba(59, 130, 246, 0.1);\n            border-radius: var(--txto-radius-sm);\n            padding: 1rem;\n            display: flex;\n            flex-direction: column;\n            gap: 1rem;\n        }\n\n        .txto-options-title {\n            font-size: 0.875rem;\n            font-weight: 700;\n            color: var(--txto-border-focus);\n            display: flex;\n            align-items: center;\n            gap: 0.375rem;\n        }\n\n        .txto-options-grid {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n            gap: 1rem;\n        }\n\n        .txto-checkbox-label {\n            display: flex;\n            align-items: center;\n            gap: 0.5rem;\n            font-size: 0.875rem;\n            cursor: pointer;\n            font-weight: 500;\n        }\n\n        .txto-checkbox {\n            width: 16px;\n            height: 16px;\n            accent-color: #2563eb;\n            cursor: pointer;\n        }\n\n        \/* STATISTICS METRICS GRID BOARD *\/\n        .txto-stats-title {\n            font-size: 1rem;\n            font-weight: 700;\n            margin-top: 0.5rem;\n        }\n\n        .txto-stats-grid {\n            display: grid;\n            grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\n            gap: 0.75rem;\n        }\n\n        .txto-stat-tile {\n            background: var(--txto-bg);\n            border: 1px solid var(--txto-border);\n            border-radius: var(--txto-radius-sm);\n            padding: 0.75rem;\n            text-align: center;\n            display: flex;\n            flex-direction: column;\n            gap: 0.25rem;\n            transition: var(--txto-transition);\n        }\n\n        .txto-stat-tile:hover {\n            background: #ffffff;\n            box-shadow: var(--txto-shadow-sm);\n            border-color: var(--txto-border-focus);\n        }\n\n        .txto-stat-val {\n            font-size: 1.25rem;\n            font-weight: 800;\n            color: #2563eb;\n        }\n\n        .txto-stat-lbl {\n            font-size: 0.75rem;\n            font-weight: 700;\n            color: var(--txto-text-secondary);\n            text-transform: uppercase;\n            letter-spacing: 0.05em;\n        }\n\n        \/* NOTIFICATIONS & MESSAGES CONTAINER *\/\n        .txto-toast {\n            position: fixed;\n            bottom: 1.5rem;\n            right: 1.5rem;\n            background: #0f172a;\n            color: #ffffff;\n            padding: 0.75rem 1.25rem;\n            border-radius: var(--txto-radius-sm);\n            font-size: 0.875rem;\n            font-weight: 600;\n            display: flex;\n            align-items: center;\n            gap: 0.5rem;\n            box-shadow: var(--txto-shadow-lg);\n            z-index: 10000;\n            animation: txtoSlideIn 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n        }\n\n        .txto-toast-success {\n            border-left: 4px solid var(--txto-success);\n        }\n\n        .txto-toast-error {\n            border-left: 4px solid var(--txto-error);\n        }\n\n        @keyframes txtoSlideIn {\n            from { transform: translateY(1rem); opacity: 0; }\n            to { transform: translateY(0); opacity: 1; }\n        }\n\n        \/* TEXT DIFF VIEWER (HIGHLIGHTED DIFFERENCES OVERLAY) *\/\n        .txto-diff-output {\n            padding: 0.75rem;\n            border-radius: var(--txto-radius-sm);\n            font-family: monospace;\n            font-size: 0.875rem;\n            line-height: 1.5;\n            background: #fafafa;\n            border: 1px solid var(--txto-border);\n            max-height: 400px;\n            overflow-y: auto;\n            white-space: pre-wrap;\n        }\n\n        .txto-diff-del {\n            background-color: #fee2e2;\n            color: #b91c1c;\n            text-decoration: line-through;\n        }\n\n        .txto-diff-ins {\n            background-color: #d1fae5;\n            color: #047857;\n            font-weight: bold;\n        }\n\n        .txto-hidden {\n            display: none !important;\n        }\n    <\/style>\n<\/head>\n<body>\n\n<div class=\"txto-wrapper\">\n    <div class=\"txto-container\">\n        \n        <header class=\"txto-header\">\n            <h1>All-In-One Local Text Utility Engine<\/h1>\n            <p>Convert, analyze, extract, parse, format, and generate raw text datasets entirely in-browser.<\/p>\n        <\/header>\n\n        <div class=\"txto-controls-row\">\n            <div class=\"txto-search-box\">\n                <svg class=\"txto-search-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2.5\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"><\/path><\/svg>\n                <input type=\"text\" id=\"txto-tools-search\" class=\"txto-search-input\" placeholder=\"Search text utility tools...\">\n            <\/div>\n            <div class=\"txto-categories\" id=\"txto-category-tabs\">\n                <\/div>\n        <\/div>\n\n        <main class=\"txto-layout\">\n            \n            <aside class=\"txto-sidebar-card\">\n                <div class=\"txto-sidebar-title\">\n                    <span>Available Tools<\/span>\n                    <span id=\"txto-tools-count\" style=\"font-size: 0.75rem; background: var(--txto-border); padding: 2px 6px; border-radius: 10px;\">0<\/span>\n                <\/div>\n                <div class=\"txto-tools-grid\" id=\"txto-tools-list\">\n                    <\/div>\n            <\/aside>\n\n            <div class=\"txto-workspace\">\n                \n                <div class=\"txto-workspace-card\">\n                    \n                    <div class=\"txto-toolbar\">\n                        <button class=\"txto-toolbar-btn\" id=\"txto-import-trigger\">\ud83d\udcc1 Import Document\n                            <input type=\"file\" id=\"txto-import-file\" style=\"display:none;\" accept=\".txt,.doc,.docx,.pdf\">\n                        <\/button>\n                        <button class=\"txto-toolbar-btn\" id=\"txto-export-txt\">\ud83d\udce5 Save As TXT<\/button>\n                        <button class=\"txto-toolbar-btn\" id=\"txto-export-doc\">\ud83d\udce5 Save As Word<\/button>\n                        <button class=\"txto-toolbar-btn\" id=\"txto-export-pdf\">\ud83d\udce5 Export PDF<\/button>\n                        <div style=\"flex-grow: 1;\"><\/div>\n                        <button class=\"txto-toolbar-btn\" id=\"txto-action-undo\">\u21a9\ufe0f Undo<\/button>\n                        <button class=\"txto-toolbar-btn\" id=\"txto-action-redo\">\u21aa\ufe0f Redo<\/button>\n                        <button class=\"txto-toolbar-btn txto-toolbar-btn-danger\" id=\"txto-action-clear\">\ud83d\uddd1\ufe0f Clear Editor<\/button>\n                    <\/div>\n\n                    <div id=\"txto-dynamic-options\" class=\"txto-options-panel txto-hidden\">\n                        <\/div>\n\n                    <div class=\"txto-search-panel\">\n                        <div class=\"txto-search-panel-row\">\n                            <input type=\"text\" id=\"txto-find-str\" class=\"txto-search-input-field\" placeholder=\"String to locate...\">\n                            <input type=\"text\" id=\"txto-replace-str\" class=\"txto-search-input-field\" placeholder=\"Replace string...\">\n                            <label class=\"txto-checkbox-label\">\n                                <input type=\"checkbox\" id=\"txto-search-case\" class=\"txto-checkbox\"> Match Case\n                            <\/label>\n                            <label class=\"txto-checkbox-label\">\n                                <input type=\"checkbox\" id=\"txto-search-regex\" class=\"txto-checkbox\"> Regex\n                            <\/label>\n                        <\/div>\n                        <div class=\"txto-search-panel-row\">\n                            <button class=\"txto-toolbar-btn\" id=\"txto-btn-find-next\">\ud83d\udd0d Find Next<\/button>\n                            <button class=\"txto-toolbar-btn\" id=\"txto-btn-find-prev\">\ud83d\udd0d Find Prev<\/button>\n                            <button class=\"txto-toolbar-btn\" id=\"txto-btn-replace-one\">\ud83d\udd04 Replace Next<\/button>\n                            <button class=\"txto-toolbar-btn\" id=\"txto-btn-replace-all\">\ud83d\udd04 Replace All<\/button>\n                            <span id=\"txto-search-indicator\" style=\"font-size: 0.75rem; color: var(--txto-text-secondary); font-weight: bold; margin-left: auto;\"><\/span>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"txto-split-editor\">\n                        \n                        <div class=\"txto-panel\">\n                            <div class=\"txto-panel-header\">\n                                <span>SOURCE INPUT CHANNEL<\/span>\n                                <div style=\"display: flex; gap: 0.25rem;\">\n                                    <button class=\"txto-toolbar-btn\" style=\"padding: 2px 6px;\" id=\"txto-input-wrap\">Wrap<\/button>\n                                    <button class=\"txto-toolbar-btn\" style=\"padding: 2px 6px;\" id=\"txto-input-copy\">Copy<\/button>\n                                <\/div>\n                            <\/div>\n                            <div class=\"txto-textarea-container\">\n                                <div class=\"txto-line-numbers\" id=\"txto-input-lines\">1<\/div>\n                                <textarea id=\"txto-input-editor\" class=\"txto-textarea txto-wrap\" placeholder=\"Insert, paste, or import source data text structures here to begin processing actions...\"><\/textarea>\n                            <\/div>\n                        <\/div>\n\n                        <div class=\"txto-panel\">\n                            <div class=\"txto-panel-header\">\n                                <span>PROCESSED EXPORT TARGET<\/span>\n                                <div style=\"display: flex; gap: 0.25rem;\">\n                                    <button class=\"txto-toolbar-btn\" style=\"padding: 2px 6px;\" id=\"txto-output-wrap\">Wrap<\/button>\n                                    <button class=\"txto-toolbar-btn\" style=\"padding: 2px 6px;\" id=\"txto-output-copy\">Copy<\/button>\n                                <\/div>\n                            <\/div>\n                            <div class=\"txto-textarea-container\" id=\"txto-output-standard-wrap\">\n                                <div class=\"txto-line-numbers\" id=\"txto-output-lines\">1<\/div>\n                                <textarea id=\"txto-output-editor\" class=\"txto-textarea txto-wrap\" readonly placeholder=\"Output processing content displays here...\"><\/textarea>\n                            <\/div>\n                            <div class=\"txto-diff-output txto-hidden\" id=\"txto-output-diff-view\">\n                                <\/div>\n                        <\/div>\n\n                    <\/div>\n\n                    <div class=\"txto-stats-title\">\ud83e\uddee Comprehensive Text Parameters<\/div>\n                    <div class=\"txto-stats-grid\">\n                        <div class=\"txto-stat-tile\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-chars\">0<\/div>\n                            <div class=\"txto-stat-lbl\">Characters<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-chars-nospace\">0<\/div>\n                            <div class=\"txto-stat-lbl\">No-space Chars<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-words\">0<\/div>\n                            <div class=\"txto-stat-lbl\">Words Count<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-sentences\">0<\/div>\n                            <div class=\"txto-stat-lbl\">Sentences<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-paragraphs\">0<\/div>\n                            <div class=\"txto-stat-lbl\">Paragraphs<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-lines\">0<\/div>\n                            <div class=\"txto-stat-lbl\">Total Lines<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\" title=\"Est. based on average adult 200 wpm limit\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-read-time\">0s<\/div>\n                            <div class=\"txto-stat-lbl\">Reading Span<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\" title=\"Est. based on average adult 130 wpm limit\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-speak-time\">0s<\/div>\n                            <div class=\"txto-stat-lbl\">Speaking Span<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-avg-word-len\">0<\/div>\n                            <div class=\"txto-stat-lbl\">Avg Word Size<\/div>\n                        <\/div>\n                        <div class=\"txto-stat-tile\">\n                            <div class=\"txto-stat-val\" id=\"txto-stat-longest-word\">&#8211;<\/div>\n                            <div class=\"txto-stat-lbl\">Longest Word<\/div>\n                        <\/div>\n                    <\/div>\n\n                <\/div>\n\n            <\/div>\n\n        <\/main>\n\n    <\/div>\n<\/div>\n\n<script>\n(function() {\n    'use strict';\n\n    \/\/ Core namespaces application model configurations\n    const txtoState = {\n        activeToolId: 'word-counter',\n        currentCategory: 'all',\n        historyUndoStack: [],\n        historyRedoStack: [],\n        maxHistoryLevels: 50,\n        starredTools: new Set(),\n        activeSearches: {\n            matches: [],\n            currentIndex: -1\n        }\n    };\n\n    \/\/ Dictionary listing of all functional transformations\n    const txtoToolsMeta = [\n        \/\/ BASIC UTILITIES\n        { id: 'word-counter', category: 'analyze', name: 'Word Counter', desc: 'Analyzes composition parameters.' },\n        { id: 'remove-spaces', category: 'clean', name: 'Remove Extra Spaces', desc: 'Slashes multiple space structures into single spacing.' },\n        { id: 'remove-blank-lines', category: 'clean', name: 'Remove Blank Lines', desc: 'Trims out continuous blank space layers.' },\n        { id: 'remove-duplicate-lines', category: 'clean', name: 'Remove Duplicate Lines', desc: 'Weeds out duplicate string sequence records.' },\n        { id: 'sort-lines-az', category: 'format', name: 'Sort Lines A-Z', desc: 'Sorts line breaks alphabetically.' },\n        { id: 'sort-lines-za', category: 'format', name: 'Sort Lines Z-A', desc: 'Reverses alphabetical line breaks order.' },\n        { id: 'reverse-text', category: 'format', name: 'Reverse Characters', desc: 'Reverses the complete sequence of character bytes.' },\n        { id: 'reverse-words', category: 'format', name: 'Reverse Words', desc: 'Reverses word tokens sequence order.' },\n        { id: 'reverse-lines', category: 'format', name: 'Reverse Lines', desc: 'Reverses line ordering sequencing.' },\n        \n        \/\/ CAPITALIZATION CASING\n        { id: 'uppercase', category: 'case', name: 'Uppercase', desc: 'Converts letters to UPPERCASE equivalents.' },\n        { id: 'lowercase', category: 'case', name: 'Lowercase', desc: 'Converts letters to lowercase equivalents.' },\n        { id: 'title-case', category: 'case', name: 'Title Case', desc: 'Capitalizes key conversational tokens.' },\n        { id: 'sentence-case', category: 'case', name: 'Sentence Case', desc: 'Formats starting letters of standard sentences.' },\n        { id: 'capitalize-words', category: 'case', name: 'Capitalize Words', desc: 'Capitalizes the first character of each word.' },\n        { id: 'alternate-case', category: 'case', name: 'Alternate Case', desc: 'Alternates between casing layers: AlTeRnAtInG.' },\n        { id: 'random-case', category: 'case', name: 'Random Case', desc: 'Shuffles string casing randomly.' },\n\n        \/\/ WRAPPING & SYMBOLS Cleaners\n        { id: 'remove-breaks', category: 'clean', name: 'Remove Line Breaks', desc: 'Strips out hard wrap newline markers.' },\n        { id: 'add-line-numbers', category: 'format', name: 'Add Line Numbers', desc: 'Prefixes standard numeric numbering sequences.' },\n        { id: 'remove-line-numbers', category: 'format', name: 'Remove Line Numbers', desc: 'Strips starting numbers on line breaks.' },\n        { id: 'trim-text', category: 'clean', name: 'Trim Margins', desc: 'Wipes left\/right space offsets.' },\n        { id: 'remove-special', category: 'clean', name: 'Remove Special Symbols', desc: 'Strips out specialized characters.' },\n        { id: 'remove-numbers', category: 'clean', name: 'Remove Numbers', desc: 'Trims standard base-10 numerical indexes.' },\n        { id: 'remove-alphabets', category: 'clean', name: 'Remove Alphabets', desc: 'Wipes all standard multi-language alphabet runes.' },\n        { id: 'remove-emojis', category: 'clean', name: 'Remove Emojis', desc: 'Strips system emoticons or graphical glyphs.' },\n\n        \/\/ PARSERS & EXTRACTORS\n        { id: 'extract-urls', category: 'extract', name: 'Extract URLs', desc: 'Pulls absolute domains and web paths.' },\n        { id: 'extract-emails', category: 'extract', name: 'Extract Email Address', desc: 'Isolates and grabs e-mail structures.' },\n        { id: 'extract-numbers', category: 'extract', name: 'Extract Numbers', desc: 'Builds collection lists of integer values.' },\n        { id: 'extract-hashtags', category: 'extract', name: 'Extract Hashtags', desc: 'Grabs #tagged string references.' },\n        { id: 'extract-mentions', category: 'extract', name: 'Extract Mentions', desc: 'Grabs @mentions user tokens.' },\n\n        \/\/ GENERATORS\n        { id: 'lorem-ipsum', category: 'generate', name: 'Lorem Ipsum Generator', desc: 'Generates procedural placeholder copies.' },\n        { id: 'random-generator', category: 'generate', name: 'Random Text Generator', desc: 'Generates safe random alphanumeric sets.' },\n        { id: 'text-repeater', category: 'generate', name: 'Text Repeater', desc: 'Repeats a template text multiple times.' },\n        { id: 'text-shuffle', category: 'generate', name: 'Shuffle Lines \/ Words', desc: 'Shuffles ordering positions randomly.' },\n\n        \/\/ ENCODER & DECODERS\n        { id: 'unicode-converter', category: 'encode', name: 'Unicode Converter', desc: 'Swaps characters with unicode escape values.' },\n        { id: 'html-encode', category: 'encode', name: 'HTML Entities Encode', desc: 'Translates special characters to HTML tags.' },\n        { id: 'html-decode', category: 'encode', name: 'HTML Entities Decode', desc: 'Translates entities back to raw text standard.' },\n        { id: 'url-encode', category: 'encode', name: 'URL Percent Encoder', desc: 'Encodes URLs for safe transit.' },\n        { id: 'url-decode', category: 'encode', name: 'URL Percent Decoder', desc: 'Decodes parsed transit URL components.' },\n        { id: 'base64-encode', category: 'encode', name: 'Base64 Encoder', desc: 'Encodes ASCII streams to Base64.' },\n        { id: 'base64-decode', category: 'encode', name: 'Base64 Decoder', desc: 'Decodes Base64 payloads.' },\n\n        \/\/ DIFF CHECKER\n        { id: 'diff-checker', category: 'analyze', name: 'Text Diff Checker', desc: 'Highlights side-by-side deviations.' }\n    ];\n\n    const txtoNodes = {\n        toolsSearch: document.getElementById('txto-tools-search'),\n        categoryTabs: document.getElementById('txto-category-tabs'),\n        toolsList: document.getElementById('txto-tools-list'),\n        toolsCount: document.getElementById('txto-tools-count'),\n        importTrigger: document.getElementById('txto-import-trigger'),\n        importFile: document.getElementById('txto-import-file'),\n        exportTxt: document.getElementById('txto-export-txt'),\n        exportDoc: document.getElementById('txto-export-doc'),\n        exportPdf: document.getElementById('txto-export-pdf'),\n        undoBtn: document.getElementById('txto-action-undo'),\n        redoBtn: document.getElementById('txto-action-redo'),\n        clearBtn: document.getElementById('txto-action-clear'),\n        inputWrap: document.getElementById('txto-input-wrap'),\n        inputCopy: document.getElementById('txto-input-copy'),\n        inputLines: document.getElementById('txto-input-lines'),\n        inputEditor: document.getElementById('txto-input-editor'),\n        outputWrap: document.getElementById('txto-output-wrap'),\n        outputCopy: document.getElementById('txto-output-copy'),\n        outputLines: document.getElementById('txto-output-lines'),\n        outputEditor: document.getElementById('txto-output-editor'),\n        outputStandardWrap: document.getElementById('txto-output-standard-wrap'),\n        outputDiffView: document.getElementById('txto-output-diff-view'),\n        dynamicOptions: document.getElementById('txto-dynamic-options'),\n        \n        \/\/ Find & Replace nodes\n        findStr: document.getElementById('txto-find-str'),\n        replaceStr: document.getElementById('txto-replace-str'),\n        searchCase: document.getElementById('txto-search-case'),\n        searchRegex: document.getElementById('txto-search-regex'),\n        btnFindNext: document.getElementById('txto-btn-find-next'),\n        btnFindPrev: document.getElementById('txto-btn-find-prev'),\n        btnReplaceOne: document.getElementById('txto-btn-replace-one'),\n        btnReplaceAll: document.getElementById('txto-btn-replace-all'),\n        searchIndicator: document.getElementById('txto-search-indicator'),\n\n        \/\/ Live statistics\n        statChars: document.getElementById('txto-stat-chars'),\n        statNoSpaceChars: document.getElementById('txto-stat-chars-nospace'),\n        statWords: document.getElementById('txto-stat-words'),\n        statSentences: document.getElementById('txto-stat-sentences'),\n        statParagraphs: document.getElementById('txto-stat-paragraphs'),\n        statLines: document.getElementById('txto-stat-lines'),\n        statReadTime: document.getElementById('txto-stat-read-time'),\n        statSpeakTime: document.getElementById('txto-stat-speak-time'),\n        statAvgWordLen: document.getElementById('txto-stat-avg-word-len'),\n        statLongestWord: document.getElementById('txto-stat-longest-word')\n    };\n\n    \/\/ Initialize application settings & listeners\n    function txtoInit() {\n        txtoRestoreFavorites();\n        txtoRenderCategories();\n        txtoRenderTools();\n        txtoSetupListeners();\n        txtoApplyActiveTool('word-counter');\n        txtoUpdateLineNumbers(txtoNodes.inputEditor, txtoNodes.inputLines);\n        txtoUpdateLineNumbers(txtoNodes.outputEditor, txtoNodes.outputLines);\n\n        \/\/ Auto save restore triggers\n        const savedInput = localStorage.getItem('txto_autosave_input');\n        if (savedInput) {\n            txtoNodes.inputEditor.value = savedInput;\n            txtoTriggerProcessing();\n        }\n    }\n\n    \/\/ Dynamic rendering of category buttons\n    function txtoRenderCategories() {\n        const categories = [\n            { id: 'all', name: '\u2728 All Tools' },\n            { id: 'starred', name: '\u2b50 Favorites' },\n            { id: 'analyze', name: '\ud83d\udcca Analyze' },\n            { id: 'clean', name: '\ud83e\uddf9 Clean' },\n            { id: 'format', name: '\u270f\ufe0f Format' },\n            { id: 'case', name: '\ud83d\udd24 Case' },\n            { id: 'extract', name: '\ud83d\udd0d Extract' },\n            { id: 'generate', name: '\u2699\ufe0f Generate' },\n            { id: 'encode', name: '\ud83d\udd12 Encode' }\n        ];\n\n        txtoNodes.categoryTabs.innerHTML = '';\n        categories.forEach(cat => {\n            const btn = document.createElement('button');\n            btn.className = `txto-category-btn ${txtoState.currentCategory === cat.id ? 'txto-active' : ''}`;\n            btn.innerText = cat.name;\n            btn.addEventListener('click', () => {\n                txtoState.currentCategory = cat.id;\n                document.querySelectorAll('.txto-category-btn').forEach(b => b.classList.remove('txto-active'));\n                btn.classList.add('txto-active');\n                txtoRenderTools();\n            });\n            txtoNodes.categoryTabs.appendChild(btn);\n        });\n    }\n\n    \/\/ Dynamic rendering of the main sidebar items lists\n    function txtoRenderTools() {\n        txtoNodes.toolsList.innerHTML = '';\n        const searchVal = txtoNodes.toolsSearch.value.toLowerCase();\n\n        const filtered = txtoToolsMeta.filter(tool => {\n            const matchesSearch = tool.name.toLowerCase().includes(searchVal) || tool.desc.toLowerCase().includes(searchVal);\n            if (txtoState.currentCategory === 'all') return matchesSearch;\n            if (txtoState.currentCategory === 'starred') return txtoState.starredTools.has(tool.id) && matchesSearch;\n            return tool.category === txtoState.currentCategory && matchesSearch;\n        });\n\n        txtoNodes.toolsCount.innerText = filtered.length;\n\n        if (filtered.length === 0) {\n            txtoNodes.toolsList.innerHTML = `<div style=\"padding:1.5rem; text-align:center; color:var(--txto-text-secondary); font-size:0.875rem;\">No matching utility found.<\/div>`;\n            return;\n        }\n\n        filtered.forEach(tool => {\n            const item = document.createElement('div');\n            item.className = `txto-tool-item ${txtoState.activeToolId === tool.id ? 'txto-active' : ''}`;\n            \n            const meta = document.createElement('div');\n            meta.className = 'txto-tool-meta';\n            \n            const name = document.createElement('span');\n            name.className = 'txto-tool-name';\n            name.innerText = tool.name;\n\n            const desc = document.createElement('span');\n            desc.className = 'txto-tool-desc';\n            desc.innerText = tool.desc;\n\n            meta.appendChild(name);\n            meta.appendChild(desc);\n\n            const star = document.createElement('span');\n            star.className = `txto-fav-star ${txtoState.starredTools.has(tool.id) ? 'txto-starred' : ''}`;\n            star.innerText = '\u2605';\n            star.addEventListener('click', (e) => {\n                e.stopPropagation();\n                txtoToggleStar(tool.id);\n                star.classList.toggle('txto-starred');\n            });\n\n            item.appendChild(meta);\n            item.appendChild(star);\n\n            item.addEventListener('click', () => {\n                txtoApplyActiveTool(tool.id);\n            });\n\n            txtoNodes.toolsList.appendChild(item);\n        });\n    }\n\n    \/\/ Setup action triggers\n    function txtoSetupListeners() {\n        \/\/ Debounce input to optimize CPU load\n        let debounceTimer;\n        txtoNodes.inputEditor.addEventListener('input', () => {\n            clearTimeout(debounceTimer);\n            debounceTimer = setTimeout(() => {\n                txtoSaveUndoState();\n                txtoTriggerProcessing();\n                txtoUpdateLineNumbers(txtoNodes.inputEditor, txtoNodes.inputLines);\n                \/\/ Save state to local storage\n                localStorage.setItem('txto_autosave_input', txtoNodes.inputEditor.value);\n            }, 150);\n        });\n\n        \/\/ Track scrolling to sync line numbers\n        txtoNodes.inputEditor.addEventListener('scroll', () => {\n            txtoNodes.inputLines.scrollTop = txtoNodes.inputEditor.scrollTop;\n        });\n        txtoNodes.outputEditor.addEventListener('scroll', () => {\n            txtoNodes.outputLines.scrollTop = txtoNodes.outputEditor.scrollTop;\n        });\n\n        txtoNodes.toolsSearch.addEventListener('input', () => {\n            txtoRenderTools();\n        });\n\n        \/\/ Copy actions\n        txtoNodes.inputCopy.addEventListener('click', () => txtoCopyToClipboard(txtoNodes.inputEditor.value));\n        txtoNodes.outputCopy.addEventListener('click', () => txtoCopyToClipboard(txtoNodes.outputEditor.value));\n\n        \/\/ Format wraps\n        txtoNodes.inputWrap.addEventListener('click', () => txtoToggleWrap(txtoNodes.inputEditor));\n        txtoNodes.outputWrap.addEventListener('click', () => txtoToggleWrap(txtoNodes.outputEditor));\n\n        \/\/ Toolbar operations\n        txtoNodes.clearBtn.addEventListener('click', () => {\n            txtoSaveUndoState();\n            txtoNodes.inputEditor.value = '';\n            txtoNodes.outputEditor.value = '';\n            txtoTriggerProcessing();\n            txtoUpdateLineNumbers(txtoNodes.inputEditor, txtoNodes.inputLines);\n            txtoUpdateLineNumbers(txtoNodes.outputEditor, txtoNodes.outputLines);\n            localStorage.removeItem('txto_autosave_input');\n        });\n\n        txtoNodes.undoBtn.addEventListener('click', txtoUndo);\n        txtoNodes.redoBtn.addEventListener('click', txtoRedo);\n\n        \/\/ File system Import\n        txtoNodes.importTrigger.addEventListener('click', () => txtoNodes.importFile.click());\n        txtoNodes.importFile.addEventListener('change', txtoHandleFileImport);\n\n        \/\/ File system exports\n        txtoNodes.exportTxt.addEventListener('click', () => txtoDownloadFile('txt'));\n        txtoNodes.exportDoc.addEventListener('click', () => txtoDownloadFile('doc'));\n        txtoNodes.exportPdf.addEventListener('click', () => txtoDownloadFile('pdf'));\n\n        \/\/ Find\/Replace Actions\n        txtoNodes.btnFindNext.addEventListener('click', () => txtoSearchText(true));\n        txtoNodes.btnFindPrev.addEventListener('click', () => txtoSearchText(false));\n        txtoNodes.btnReplaceAll.addEventListener('click', txtoReplaceAll);\n        txtoNodes.btnReplaceOne.addEventListener('click', txtoReplaceNext);\n    }\n\n    \/\/ Render configuration panels on tool activation\n    function txtoApplyActiveTool(toolId) {\n        txtoState.activeToolId = toolId;\n        document.querySelectorAll('.txto-tool-item').forEach(itm => {\n            itm.classList.remove('txto-active');\n        });\n        \n        \/\/ Highlight active items\n        txtoRenderTools();\n\n        \/\/ Reveal standard output elements (Some tools like diff viewer hide this)\n        txtoNodes.outputStandardWrap.classList.remove('txto-hidden');\n        txtoNodes.outputDiffView.classList.add('txto-hidden');\n\n        \/\/ Reset configuration viewports\n        txtoNodes.dynamicOptions.classList.add('txto-hidden');\n        txtoNodes.dynamicOptions.innerHTML = '';\n\n        \/\/ Inject active settings if available\n        if (toolId === 'lorem-ipsum') {\n            txtoNodes.dynamicOptions.classList.remove('txto-hidden');\n            txtoNodes.dynamicOptions.innerHTML = `\n                <div class=\"txto-options-title\">\ud83d\udccb Lorem Ipsum Generator Parameters<\/div>\n                <div class=\"txto-options-grid\">\n                    <label class=\"txto-checkbox-label\">Paragraphs count: \n                        <input type=\"number\" id=\"txto-opt-paragraphs\" class=\"txto-search-input-field\" value=\"3\" min=\"1\" max=\"50\">\n                    <\/label>\n                <\/div>\n            `;\n            \/\/ Re-bind listeners on dynamic settings\n            document.getElementById('txto-opt-paragraphs').addEventListener('input', txtoTriggerProcessing);\n        } else if (toolId === 'random-generator') {\n            txtoNodes.dynamicOptions.classList.remove('txto-hidden');\n            txtoNodes.dynamicOptions.innerHTML = `\n                <div class=\"txto-options-title\">\ud83d\udccb Random Text Generation Parameters<\/div>\n                <div class=\"txto-options-grid\">\n                    <label class=\"txto-checkbox-label\">Generated Length: \n                        <input type=\"number\" id=\"txto-opt-length\" class=\"txto-search-input-field\" value=\"100\" min=\"10\" max=\"10000\">\n                    <\/label>\n                    <label class=\"txto-checkbox-label\">\n                        <input type=\"checkbox\" id=\"txto-opt-alphabets\" class=\"txto-checkbox\" checked> Alphanumeric\n                    <\/label>\n                <\/div>\n            `;\n            document.getElementById('txto-opt-length').addEventListener('input', txtoTriggerProcessing);\n            document.getElementById('txto-opt-alphabets').addEventListener('change', txtoTriggerProcessing);\n        } else if (toolId === 'text-repeater') {\n            txtoNodes.dynamicOptions.classList.remove('txto-hidden');\n            txtoNodes.dynamicOptions.innerHTML = `\n                <div class=\"txto-options-title\">\ud83d\udccb Text Repeater Parameters<\/div>\n                <div class=\"txto-options-grid\">\n                    <label class=\"txto-checkbox-label\">Repeat Amount: \n                        <input type=\"number\" id=\"txto-opt-repeats\" class=\"txto-search-input-field\" value=\"5\" min=\"1\" max=\"1000\">\n                    <\/label>\n                    <label class=\"txto-checkbox-label\">Delimiter: \n                        <input type=\"text\" id=\"txto-opt-delimiter\" class=\"txto-search-input-field\" value=\"\\\\n\">\n                    <\/label>\n                <\/div>\n            `;\n            document.getElementById('txto-opt-repeats').addEventListener('input', txtoTriggerProcessing);\n            document.getElementById('txto-opt-delimiter').addEventListener('input', txtoTriggerProcessing);\n        }\n\n        txtoTriggerProcessing();\n    }\n\n    \/\/ Run core text transformations\n    function txtoTriggerProcessing() {\n        const input = txtoNodes.inputEditor.value;\n        let output = '';\n\n        try {\n            switch (txtoState.activeToolId) {\n                case 'word-counter':\n                    output = input; \/\/ Displays stats primarily\n                    break;\n                case 'remove-spaces':\n                    output = input.replace(\/[ \\t]+\/g, ' ');\n                    break;\n                case 'remove-blank-lines':\n                    output = input.split('\\n').filter(line => line.trim() !== '').join('\\n');\n                    break;\n                case 'remove-duplicate-lines':\n                    output = [...new Set(input.split('\\n'))].join('\\n');\n                    break;\n                case 'sort-lines-az':\n                    output = input.split('\\n').sort((a, b) => a.localeCompare(b)).join('\\n');\n                    break;\n                case 'sort-lines-za':\n                    output = input.split('\\n').sort((a, b) => b.localeCompare(a)).join('\\n');\n                    break;\n                case 'reverse-text':\n                    output = input.split('').reverse().join('');\n                    break;\n                case 'reverse-words':\n                    output = input.split(\/\\s+\/).reverse().join(' ');\n                    break;\n                case 'reverse-lines':\n                    output = input.split('\\n').reverse().join('\\n');\n                    break;\n                case 'uppercase':\n                    output = input.toUpperCase();\n                    break;\n                case 'lowercase':\n                    output = input.toLowerCase();\n                    break;\n                case 'title-case':\n                    output = input.toLowerCase().replace(\/\\b(\\w)\/g, s => s.toUpperCase());\n                    break;\n                case 'sentence-case':\n                    output = input.toLowerCase().replace(\/(^\\s*|[.!?]\\s+)([a-z])\/g, s => s.toUpperCase());\n                    break;\n                case 'capitalize-words':\n                    output = input.replace(\/\\b[a-z]\/g, char => char.toUpperCase());\n                    break;\n                case 'alternate-case':\n                    output = input.split('').map((char, index) => index % 2 === 0 ? char.toLowerCase() : char.toUpperCase()).join('');\n                    break;\n                case 'random-case':\n                    output = input.split('').map(char => Math.random() > 0.5 ? char.toLowerCase() : char.toUpperCase()).join('');\n                    break;\n                case 'remove-breaks':\n                    output = input.replace(\/[\\r\\n]+\/g, ' ');\n                    break;\n                case 'add-line-numbers':\n                    output = input.split('\\n').map((line, idx) => `${idx + 1}. ${line}`).join('\\n');\n                    break;\n                case 'remove-line-numbers':\n                    output = input.split('\\n').map(line => line.replace(\/^\\s*\\d+[\\s.)-]\/, '')).join('\\n');\n                    break;\n                case 'trim-text':\n                    output = input.split('\\n').map(line => line.trim()).join('\\n');\n                    break;\n                case 'remove-special':\n                    output = input.replace(\/[^a-zA-Z0-9\\s\\n\\r]\/g, '');\n                    break;\n                case 'remove-numbers':\n                    output = input.replace(\/[0-9]\/g, '');\n                    break;\n                case 'remove-alphabets':\n                    output = input.replace(\/[a-zA-Z]\/g, '');\n                    break;\n                case 'remove-emojis':\n                    output = input.replace(\/[\\u2700-\\u27BF]|[\\uE000-\\uF8FF]|\\uD83C[\\uDC00-\\uDFFF]|\\uD83D[\\uDC00-\\uDFFF]|[\\u2011-\\u26FF]|\\uD83E[\\uDD10-\\uDDFF]\/g, '');\n                    break;\n                case 'extract-urls':\n                    const urls = input.match(\/https?:\\\/\\\/[^\\s\/$.?#].[^\\s]*\/gi) || [];\n                    output = urls.join('\\n');\n                    break;\n                case 'extract-emails':\n                    const emails = input.match(\/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\/g) || [];\n                    output = emails.join('\\n');\n                    break;\n                case 'extract-numbers':\n                    const numbers = input.match(\/\\d+\/g) || [];\n                    output = numbers.join('\\n');\n                    break;\n                case 'extract-hashtags':\n                    const hashtags = input.match(\/#[a-zA-Z0-9_]+\/g) || [];\n                    output = hashtags.join('\\n');\n                    break;\n                case 'extract-mentions':\n                    const mentions = input.match(\/@[a-zA-Z0-9_]+\/g) || [];\n                    output = mentions.join('\\n');\n                    break;\n                case 'lorem-ipsum':\n                    const paras = parseInt(document.getElementById('txto-opt-paragraphs')?.value) || 3;\n                    output = txtoGenerateLorem(paras);\n                    break;\n                case 'random-generator':\n                    const len = parseInt(document.getElementById('txto-opt-length')?.value) || 100;\n                    const alphanumeric = document.getElementById('txto-opt-alphabets')?.checked ?? true;\n                    output = txtoGenerateRandomString(len, alphanumeric);\n                    break;\n                case 'text-repeater':\n                    const repeats = parseInt(document.getElementById('txto-opt-repeats')?.value) || 5;\n                    let delimiter = document.getElementById('txto-opt-delimiter')?.value || '\\n';\n                    delimiter = delimiter.replace(\/\\\\n\/g, '\\n').replace(\/\\\\t\/g, '\\t');\n                    output = Array(repeats).fill(input).join(delimiter);\n                    break;\n                case 'text-shuffle':\n                    output = input.split('\\n').sort(() => Math.random() - 0.5).join('\\n');\n                    break;\n                case 'unicode-converter':\n                    output = input.split('').map(char => {\n                        const code = char.charCodeAt(0).toString(16).toUpperCase();\n                        return char.match(\/[A-Za-z0-9]\/) ? char : `\\\\u${'0000'.substring(0, 4 - code.length)}${code}`;\n                    }).join('');\n                    break;\n                case 'html-encode':\n                    const tempEnc = document.createElement('div');\n                    tempEnc.innerText = input;\n                    output = tempEnc.innerHTML;\n                    break;\n                case 'html-decode':\n                    const tempDec = document.createElement('div');\n                    tempDec.innerHTML = input;\n                    output = tempDec.innerText;\n                    break;\n                case 'url-encode':\n                    output = encodeURIComponent(input);\n                    break;\n                case 'url-decode':\n                    output = decodeURIComponent(input);\n                    break;\n                case 'base64-encode':\n                    output = btoa(unescape(encodeURIComponent(input)));\n                    break;\n                case 'base64-decode':\n                    output = decodeURIComponent(escape(atob(input)));\n                    break;\n                case 'diff-checker':\n                    txtoNodes.outputStandardWrap.classList.add('txto-hidden');\n                    txtoNodes.outputDiffView.classList.remove('txto-hidden');\n                    txtoRunDiffCheck(input);\n                    break;\n                default:\n                    output = input;\n            }\n\n            if (txtoState.activeToolId !== 'diff-checker') {\n                txtoNodes.outputEditor.value = output;\n                txtoUpdateLineNumbers(txtoNodes.outputEditor, txtoNodes.outputLines);\n            }\n\n            txtoCalculateStatistics(input);\n        } catch (e) {\n            txtoNodes.outputEditor.value = `[Processing Error] ${e.message}`;\n        }\n    }\n\n    \/\/ Calculate metrics and update panel UI\n    function txtoCalculateStatistics(text) {\n        if (!text) {\n            txtoNodes.statChars.innerText = '0';\n            txtoNodes.statNoSpaceChars.innerText = '0';\n            txtoNodes.statWords.innerText = '0';\n            txtoNodes.statSentences.innerText = '0';\n            txtoNodes.statParagraphs.innerText = '0';\n            txtoNodes.statLines.innerText = '0';\n            txtoNodes.statReadTime.innerText = '0s';\n            txtoNodes.statSpeakTime.innerText = '0s';\n            txtoNodes.statAvgWordLen.innerText = '0';\n            txtoNodes.statLongestWord.innerText = '-';\n            return;\n        }\n\n        const chars = text.length;\n        const noSpaces = text.replace(\/\\s\/g, '').length;\n        const lines = text.split('\\n').length;\n        \n        const words = text.trim().split(\/\\s+\/).filter(w => w.length > 0);\n        const wordCount = words.length;\n\n        const sentences = text.split(\/[.!?]+\/).filter(s => s.trim().length > 0).length;\n        const paragraphs = text.split(\/\\n\\s*\\n\/).filter(p => p.trim().length > 0).length;\n\n        \/\/ Reading speed based on 200WPM \/ 130WPM standards\n        const readSeconds = Math.ceil((wordCount \/ 200) * 60);\n        const speakSeconds = Math.ceil((wordCount \/ 130) * 60);\n\n        const avgWordLen = wordCount > 0 ? (words.reduce((sum, w) => sum + w.length, 0) \/ wordCount).toFixed(1) : 0;\n        \n        let longest = '-';\n        if (wordCount > 0) {\n            longest = [...words].sort((a, b) => b.length - a.length)[0];\n            if (longest.length > 12) longest = longest.substring(0, 10) + '...';\n        }\n\n        txtoNodes.statChars.innerText = chars;\n        txtoNodes.statNoSpaceChars.innerText = noSpaces;\n        txtoNodes.statWords.innerText = wordCount;\n        txtoNodes.statSentences.innerText = sentences;\n        txtoNodes.statParagraphs.innerText = paragraphs;\n        txtoNodes.statLines.innerText = lines;\n        txtoNodes.statReadTime.innerText = readSeconds < 60 ? `${readSeconds}s` : `${Math.ceil(readSeconds \/ 60)}m`;\n        txtoNodes.statSpeakTime.innerText = speakSeconds < 60 ? `${speakSeconds}s` : `${Math.ceil(speakSeconds \/ 60)}m`;\n        txtoNodes.statAvgWordLen.innerText = avgWordLen;\n        txtoNodes.statLongestWord.innerText = longest;\n    }\n\n    \/\/ Dynamic Line-counting rendering wrapper\n    function txtoUpdateLineNumbers(textarea, lineContainer) {\n        const linesCount = textarea.value.split('\\n').length;\n        let lineHtml = '';\n        for (let i = 1; i <= linesCount; i++) {\n            lineHtml += `${i}<br>`;\n        }\n        lineContainer.innerHTML = lineHtml;\n    }\n\n    \/\/ Toggle styling configurations\n    function txtoToggleWrap(textarea) {\n        textarea.classList.toggle('txto-wrap');\n        txtoUpdateLineNumbers(txtoNodes.inputEditor, txtoNodes.inputLines);\n        txtoUpdateLineNumbers(txtoNodes.outputEditor, txtoNodes.outputLines);\n    }\n\n    \/\/ Local file loader imports\n    async function txtoHandleFileImport(e) {\n        const file = e.target.files[0];\n        if (!file) return;\n\n        txtoSaveUndoState();\n        const extension = file.name.split('.').pop().toLowerCase();\n\n        try {\n            if (extension === 'txt') {\n                const reader = new FileReader();\n                reader.onload = function(evt) {\n                    txtoNodes.inputEditor.value = evt.target.result;\n                    txtoTriggerProcessing();\n                };\n                reader.readAsText(file);\n            } else if (extension === 'docx') {\n                const arrayBuffer = await file.arrayBuffer();\n                const result = await mammoth.extractRawText({ arrayBuffer: arrayBuffer });\n                txtoNodes.inputEditor.value = result.value;\n                txtoTriggerProcessing();\n            } else {\n                txtoShowToast(\"Import format not yet supported.\", \"error\");\n            }\n        } catch (err) {\n            txtoShowToast(`Error reading file: ${err.message}`, \"error\");\n        }\n    }\n\n    \/\/ Local file down exports\n    function txtoDownloadFile(type) {\n        const content = txtoNodes.outputEditor.value;\n        if (!content) {\n            txtoShowToast(\"There is no output text to save.\", \"error\");\n            return;\n        }\n\n        const baseFilename = `text_utility_output_${Date.now()}`;\n\n        if (type === 'txt') {\n            const blob = new Blob([content], { type: 'text\/plain;charset=utf-8' });\n            const url = URL.createObjectURL(blob);\n            const a = document.createElement('a');\n            a.href = url;\n            a.download = `${baseFilename}.txt`;\n            a.click();\n            URL.revokeObjectURL(url);\n        } else if (type === 'doc') {\n            \/\/ Basic layout file wrapper download\n            const blob = new Blob(['\\ufeff' + content], { type: 'application\/msword' });\n            const url = URL.createObjectURL(blob);\n            const a = document.createElement('a');\n            a.href = url;\n            a.download = `${baseFilename}.doc`;\n            a.click();\n            URL.revokeObjectURL(url);\n        } else if (type === 'pdf') {\n            const { jsPDF } = window.jspdf;\n            const doc = new jsPDF();\n            const margin = 15;\n            const pageHeight = doc.internal.pageSize.height;\n            const lines = doc.splitTextToSize(content, 180);\n            let y = margin;\n            \n            lines.forEach(line => {\n                if (y + 10 > pageHeight) {\n                    doc.addPage();\n                    y = margin;\n                }\n                doc.text(line, margin, y);\n                y += 7;\n            });\n            doc.save(`${baseFilename}.pdf`);\n        }\n    }\n\n    \/\/ Search Operations engine\n    function txtoSearchText(forward = true) {\n        const text = txtoNodes.inputEditor.value;\n        const findStr = txtoNodes.findStr.value;\n        if (!findStr) return;\n\n        const isRegex = txtoNodes.searchRegex.checked;\n        const isCase = txtoNodes.searchCase.checked;\n\n        let matches = [];\n        if (isRegex) {\n            try {\n                const regex = new RegExp(findStr, isCase ? 'g' : 'gi');\n                let match;\n                while ((match = regex.exec(text)) !== null) {\n                    matches.push({ index: match.index, length: match[0].length });\n                }\n            } catch (err) {\n                txtoShowToast(\"Invalid Regex structure specified.\", \"error\");\n                return;\n            }\n        } else {\n            let index = 0;\n            const searchStr = isCase ? findStr : findStr.toLowerCase();\n            const sourceText = isCase ? text : text.toLowerCase();\n\n            while ((index = sourceText.indexOf(searchStr, index)) !== -1) {\n                matches.push({ index: index, length: findStr.length });\n                index += findStr.length;\n            }\n        }\n\n        txtoState.activeSearches.matches = matches;\n        if (matches.length === 0) {\n            txtoNodes.searchIndicator.innerText = '0\/0';\n            return;\n        }\n\n        \/\/ Cycle through indices\n        if (forward) {\n            txtoState.activeSearches.currentIndex = (txtoState.activeSearches.currentIndex + 1) % matches.length;\n        } else {\n            txtoState.activeSearches.currentIndex = (txtoState.activeSearches.currentIndex - 1 + matches.length) % matches.length;\n        }\n\n        const activeMatch = matches[txtoState.activeSearches.currentIndex];\n        txtoNodes.inputEditor.focus();\n        txtoNodes.inputEditor.setSelectionRange(activeMatch.index, activeMatch.index + activeMatch.length);\n        txtoNodes.searchIndicator.innerText = `${txtoState.activeSearches.currentIndex + 1}\/${matches.length}`;\n    }\n\n    \/\/ Direct String replacements\n    function txtoReplaceNext() {\n        const findStr = txtoNodes.findStr.value;\n        const replaceStr = txtoNodes.replaceStr.value;\n        if (!findStr) return;\n\n        txtoSaveUndoState();\n        const start = txtoNodes.inputEditor.selectionStart;\n        const end = txtoNodes.inputEditor.selectionEnd;\n        const text = txtoNodes.inputEditor.value;\n\n        if (start !== end) {\n            const result = text.substring(0, start) + replaceStr + text.substring(end);\n            txtoNodes.inputEditor.value = result;\n            txtoTriggerProcessing();\n            txtoNodes.inputEditor.setSelectionRange(start, start + replaceStr.length);\n        } else {\n            txtoSearchText(true);\n        }\n    }\n\n    function txtoReplaceAll() {\n        const findStr = txtoNodes.findStr.value;\n        const replaceStr = txtoNodes.replaceStr.value;\n        if (!findStr) return;\n\n        txtoSaveUndoState();\n        const text = txtoNodes.inputEditor.value;\n        const isRegex = txtoNodes.searchRegex.checked;\n        const isCase = txtoNodes.searchCase.checked;\n\n        let resultText = '';\n        if (isRegex) {\n            const regex = new RegExp(findStr, isCase ? 'g' : 'gi');\n            resultText = text.replace(regex, replaceStr);\n        } else {\n            const regex = new RegExp(findStr.replace(\/[-\\\/\\\\^$*+?.()|[\\]{}]\/g, '\\\\$&'), isCase ? 'g' : 'gi');\n            resultText = text.replace(regex, replaceStr);\n        }\n\n        txtoNodes.inputEditor.value = resultText;\n        txtoTriggerProcessing();\n        txtoShowToast(\"Replaced occurrences globally in file.\", \"success\");\n    }\n\n    \/\/ Text Diff generator\n    function txtoRunDiffCheck(afterText) {\n        \/\/ Mock Side-By-Side Line difference engine\n        const beforeLines = localStorage.getItem('txto_autosave_input') || '';\n        const afterLines = afterText;\n\n        const diffContainer = txtoNodes.outputDiffView;\n        diffContainer.innerHTML = '';\n\n        const heading = document.createElement('div');\n        heading.style.fontWeight = 'bold';\n        heading.style.marginBottom = '0.5rem';\n        heading.innerText = 'Highlighting differences (Last autosaved state vs current live changes):';\n        diffContainer.appendChild(heading);\n\n        const diffOutput = document.createElement('div');\n        \n        \/\/ Basic line matching algorithm\n        const beforeSet = beforeLines.split('\\n');\n        const afterSet = afterLines.split('\\n');\n        const maxLen = Math.max(beforeSet.length, afterSet.length);\n\n        for (let i = 0; i < maxLen; i++) {\n            const lineWrap = document.createElement('div');\n            lineWrap.style.display = 'flex';\n            lineWrap.style.gap = '10px';\n\n            const lineNum = document.createElement('span');\n            lineNum.style.color = '#94a3b8';\n            lineNum.style.width = '30px';\n            lineNum.innerText = i + 1;\n\n            const textSpan = document.createElement('span');\n            \n            const bLine = beforeSet[i] || '';\n            const aLine = afterSet[i] || '';\n\n            if (bLine === aLine) {\n                textSpan.innerText = aLine;\n            } else {\n                if (bLine) {\n                    const del = document.createElement('span');\n                    del.className = 'txto-diff-del';\n                    del.innerText = ` - ${bLine} `;\n                    textSpan.appendChild(del);\n                }\n                if (aLine) {\n                    const ins = document.createElement('span');\n                    ins.className = 'txto-diff-ins';\n                    ins.innerText = ` + ${aLine} `;\n                    textSpan.appendChild(ins);\n                }\n            }\n\n            lineWrap.appendChild(lineNum);\n            lineWrap.appendChild(textSpan);\n            diffOutput.appendChild(lineWrap);\n        }\n        diffContainer.appendChild(diffOutput);\n    }\n\n    \/\/ Dynamic generation utilities\n    function txtoGenerateLorem(paragraphs) {\n        const sentences = [\n            \"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\n            \"Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\",\n            \"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\",\n            \"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\",\n            \"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\",\n            \"Curabitur pretium tincidunt lacus. Nulla gravida orci a odio.\",\n            \"Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris.\"\n        ];\n\n        let result = [];\n        for (let i = 0; i < paragraphs; i++) {\n            let paragraph = [];\n            let count = Math.floor(Math.random() * 4) + 3; \/\/ 3 to 6 sentences\n            for (let j = 0; j < count; j++) {\n                paragraph.push(sentences[Math.floor(Math.random() * sentences.length)]);\n            }\n            result.push(paragraph.join(' '));\n        }\n        return result.join('\\n\\n');\n    }\n\n    function txtoGenerateRandomString(length, alphaOnly) {\n        const pool = alphaOnly ? \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" : \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&#038;*()_+=-[]{}|;:,.\/<>?\";\n        let res = '';\n        for (let i = 0; i < length; i++) {\n            res += pool.charAt(Math.floor(Math.random() * pool.length));\n        }\n        return res;\n    }\n\n    \/\/ Clipboard mechanisms\n    function txtoCopyToClipboard(text) {\n        if (!text) return;\n        navigator.clipboard.writeText(text).then(() => {\n            txtoShowToast(\"Copied to clipboard successfully!\", \"success\");\n        }).catch(() => {\n            txtoShowToast(\"Clipboard access denied.\", \"error\");\n        });\n    }\n\n    \/\/ Feedback Toast alerts\n    function txtoShowToast(message, type = 'success') {\n        const toast = document.createElement('div');\n        toast.className = `txto-toast txto-toast-${type}`;\n        toast.innerHTML = `<span>${message}<\/span>`;\n        document.body.appendChild(toast);\n        setTimeout(() => {\n            toast.remove();\n        }, 3000);\n    }\n\n    \/\/ Favorite\/Star Operations management\n    function txtoToggleStar(toolId) {\n        if (txtoState.starredTools.has(toolId)) {\n            txtoState.starredTools.delete(toolId);\n        } else {\n            txtoState.starredTools.add(toolId);\n        }\n        localStorage.setItem('txto_starred', JSON.stringify([...txtoState.starredTools]));\n    }\n\n    function txtoRestoreFavorites() {\n        const raw = localStorage.getItem('txto_starred');\n        if (raw) {\n            const list = JSON.parse(raw);\n            list.forEach(id => txtoState.starredTools.add(id));\n        }\n    }\n\n    \/\/ Undo \/ Redo mechanics\n    function txtoSaveUndoState() {\n        const val = txtoNodes.inputEditor.value;\n        if (txtoState.historyUndoStack.length > 0 && txtoState.historyUndoStack[txtoState.historyUndoStack.length - 1] === val) return;\n        txtoState.historyUndoStack.push(val);\n        if (txtoState.historyUndoStack.length > txtoState.maxHistoryLevels) {\n            txtoState.historyUndoStack.shift();\n        }\n        txtoState.historyRedoStack = []; \/\/ Clear redo stack on structural modifications\n    }\n\n    function txtoUndo() {\n        if (txtoState.historyUndoStack.length === 0) return;\n        const currentVal = txtoNodes.inputEditor.value;\n        txtoState.historyRedoStack.push(currentVal);\n        const prev = txtoState.historyUndoStack.pop();\n        txtoNodes.inputEditor.value = prev;\n        txtoTriggerProcessing();\n        txtoUpdateLineNumbers(txtoNodes.inputEditor, txtoNodes.inputLines);\n    }\n\n    function txtoRedo() {\n        if (txtoState.historyRedoStack.length === 0) return;\n        const currentVal = txtoNodes.inputEditor.value;\n        txtoState.historyUndoStack.push(currentVal);\n        const next = txtoState.historyRedoStack.pop();\n        txtoNodes.inputEditor.value = next;\n        txtoTriggerProcessing();\n        txtoUpdateLineNumbers(txtoNodes.inputEditor, txtoNodes.inputLines);\n    }\n\n    \/\/ Kickoff run sequences\n    txtoInit();\n\n})();\n<\/script>\n\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Word Counter, Case Converter, Remove Duplicates, Text Compare and more. All-in-One Professional Text Tools All-In-One Local Text Utility Engine Convert, analyze, extract, parse, format, and generate raw text datasets entirely in-browser. Available Tools 0 \ud83d\udcc1 Import Document \ud83d\udce5 Save As TXT \ud83d\udce5 Save As Word \ud83d\udce5 Export PDF \u21a9\ufe0f Undo \u21aa\ufe0f Redo \ud83d\uddd1\ufe0f Clear Editor [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-70","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/70","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/comments?post=70"}],"version-history":[{"count":5,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/70\/revisions"}],"predecessor-version":[{"id":511,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/70\/revisions\/511"}],"wp:attachment":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/media?parent=70"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}