ADD 30 features to this script and make thee entire thing

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Ultimate AI Assistant - Extended 100+ Features</title>

  <!-- Core CSS/JS Libraries -->

  <!-- 1. Bootstrap 5 -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
  <script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

  <!-- 2. Animate.css -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.1/animate.min.css" />

  <!-- 3. SweetAlert2 -->
  <script defer src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>

  <!-- 4. Chart.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/chart.js@4.3.0/dist/chart.umd.min.js"></script>

  <!-- 5. Emoji Button -->
  <script defer src="https://cdn.jsdelivr.net/npm/@joeattardi/emoji-button@4.6.2/dist/index.min.js"></script>

  <!-- 6. Markdown-it -->
  <script defer src="https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"></script>

  <!-- 7. Highlight.js -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11.8.0/styles/default.min.css" />
  <script defer src="https://cdn.jsdelivr.net/npm/highlight.js@11.8.0/lib/core.min.js"></script>

  <!-- 8. jQuery -->
  <script defer src="https://cdn.jsdelivr.net/npm/jquery@3.7.0/dist/jquery.min.js"></script>

  <!-- 9. Typed.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/typed.js@2.0.12/lib/typed.min.js"></script>

  <!-- 10. Clipboard.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js"></script>

  <!-- 11. Tippy.js -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tippy.js@6.3.7/dist/tippy.css" />
  <script defer src="https://cdn.jsdelivr.net/npm/popper.js@2.11.6/dist/umd/popper.min.js"></script>
  <script defer src="https://cdn.jsdelivr.net/npm/tippy.js@6.3.7/dist/tippy-bundle.umd.min.js"></script>

  <!-- 12. Fuse.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2"></script>

  <!-- 13. Leaflet.js -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css" />
  <script defer src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script>

  <!-- 14. QRCode.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js"></script>

  <!-- 15. SortableJS -->
  <script defer src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>

  <!-- 16. jsPDF -->
  <script defer src="https://cdn.jsdelivr.net/npm/jspdf@2.5.1/dist/jspdf.umd.min.js"></script>

  <!-- 17. JSZip -->
  <script defer src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>

  <!-- 18. PapaParse -->
  <script defer src="https://cdn.jsdelivr.net/npm/papaparse@5.4.1/papaparse.min.js"></script>

  <!-- 19. Handlebars.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/handlebars@4.7.7/dist/handlebars.min.js"></script>

  <!-- 20. Axios -->
  <script defer src="https://cdn.jsdelivr.net/npm/axios@1.3.5/dist/axios.min.js"></script>

  <!-- 21. Web Speech API Polyfill -->
  <script defer src="https://cdn.jsdelivr.net/npm/web-speech-cognitive-services@0.2.7/dist/web-speech-cognitive-services.min.js"></script>

  <!-- 22. DOMPurify -->
  <script defer src="https://cdn.jsdelivr.net/npm/dompurify@2.4.3/dist/purify.min.js"></script>

  <!-- 23. Mousetrap.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/mousetrap@1.6.5/mousetrap.min.js"></script>

  <!-- 24. Day.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/dayjs@1.11.9/dayjs.min.js"></script>

  <!-- 25. Luxon (date/time) -->
  <script defer src="https://cdn.jsdelivr.net/npm/luxon@3.3.0/build/global/luxon.min.js"></script>

  <!-- 26. Chartjs-plugin-datalabels -->
  <script defer src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0/dist/chartjs-plugin-datalabels.min.js"></script>

  <!-- 27. Perfect Scrollbar -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/perfect-scrollbar@1.5.5/css/perfect-scrollbar.css" />
  <script defer src="https://cdn.jsdelivr.net/npm/perfect-scrollbar@1.5.5/dist/perfect-scrollbar.min.js"></script>

  <!-- 28. Lodash -->
  <script defer src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>

  <!-- 29. Granim.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/granim@2.0.0/dist/granim.min.js"></script>

  <!-- 30. Typed-Audio -->
  <script defer src="https://cdn.jsdelivr.net/npm/typed-audio@0.3.4/typed-audio.min.js"></script>

  <!-- 31. TensorFlow.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.8.0/dist/tf.min.js"></script>

  <!-- 32. ml5.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/ml5@0.12.2/dist/ml5.min.js"></script>

  <!-- 33. Three.js -->
  <script defer src="https://cdn.jsdelivr.net/npm/three@0.154.0/build/three.min.js"></script>

  <style>
    /* Reset and base styles */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body,
    html {
      height: 100%;
      background: #121212;
      color: #eee;
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      user-select: none;
    }

    a {
      color: #67f;
      text-decoration: underline;
    }

    a:hover {
      color: #449;
    }

    #app {
      display: flex;
      height: 100vh;
      max-width: 100vw;
      overflow: hidden;
      user-select: text;
    }

    /* SIDEBAR */
    #sidebar {
      width: 380px;
      background: #1e1f29;
      border-right: 1px solid #384155;
      display: flex;
      flex-direction: column;
      user-select: none;
    }

    #sidebar header {
      font-size: 1.6rem;
      text-align: center;
      padding: 15px 10px;
      border-bottom: 2px solid #4a90e2;
      color: #52aaff;
      user-select: none;
      font-weight: 700;
      background: linear-gradient(90deg, #4158d0, #c850c0);
      background-clip: text;
      -webkit-background-clip: text;
      color: transparent;
      text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.4);
    }

    #tabs {
      display: flex;
      flex-wrap: wrap;
      justify-content: space-around;
      border-bottom: 1px solid #384155;
      background: #293044;
      user-select: none;
      gap: 0.2rem;
      padding: 4px 6px;
      max-height: 48vh;
      overflow-y: auto;
    }

    .tabbtn {
      flex: 1 1 48%;
      padding: 10px 8px;
      border: none;
      cursor: pointer;
      font-weight: 700;
      color: #aaa;
      background: #293044;
      outline-offset: 0;
      transition: background-color 0.25s, color 0.25s;
      user-select: none;
      border-radius: 8px;
      font-size: 0.85rem;
      text-align: center;
    }

    .tabbtn:hover,
    .tabbtn:focus-visible {
      background: #4169e1;
      color: #fff;
      outline: none;
    }

    .tabbtn.active {
      background: #4a73ff;
      color: white;
      pointer-events: none;
      box-shadow: 0 0 8px #4a73ffaa;
    }

    .tabcontent {
      flex: 1 1 auto;
      overflow-y: auto;
      padding: 15px 18px;
      font-size: 14px;
      background: #1b1f2e;
      user-select: text;
      display: flex;
      flex-direction: column;
    }

    /* CHAT AREA */
    #chat-area {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      background: #141727;
      position: relative;
      user-select: text;
    }

    #msgs {
      flex-grow: 1;
      overflow-y: auto;
      padding: 20px 28px;
      font-size: 16px;
      line-height: 1.45em;
      scroll-behavior: smooth;
      background: linear-gradient(135deg, #161926 0%, #222b42 100%);
      font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
    }

    .msg {
      max-width: 70%;
      margin-bottom: 14px;
      padding: 12px 20px;
      border-radius: 16px;
      white-space: pre-wrap;
      word-wrap: break-word;
      border: 1px solid transparent;
      font-weight: 500;
      user-select: text;
    }

    .msg.user {
      background: #0f9b43dd;
      color: #d6efd6;
      margin-left: auto;
      border-bottom-right-radius: 0;
      border-color: #1acc65;
    }

    .msg.ai {
      background: #2f6eccbb;
      color: #dde9ff;
      border-bottom-left-radius: 0;
      border-color: #1f4697;
      font-style: normal;
    }

    /* Animations */
    .msg.ai.animate__animated {
      animation-name: fadeInUp;
      animation-duration: 0.7s;
      animation-fill-mode: both;
      animation-timing-function: cubic-bezier(.4, 0, .2, 1);
    }

    /* INPUT FORM */
    #input-form {
      border-top: 1px solid #293044;
      display: flex;
      background: #1e253b;
      padding: 12px 20px;
      align-items: center;
      gap: 0.6rem;
    }

    #user-input {
      flex-grow: 1;
      font-size: 17px;
      padding: 12px 16px;
      border-radius: 30px;
      background: #293046;
      border: none;
      color: #dde9ff;
      outline: none;
      resize: none;
      min-height: 36px;
      max-height: 80px;
    }

    #user-input:disabled {
      background: #1f273b;
      color: #607abfaa;
      cursor: not-allowed;
    }

    #send-btn {
      border: none;
      background: #4169e1;
      color: white;
      font-weight: 700;
      font-size: 17px;
      padding: 0 22px;
      border-radius: 30px;
      cursor: pointer;
      transition: background-color 0.3s;
      user-select: none;
      height: 40px;
    }

    #send-btn:hover:not(:disabled) {
      background: #548dff;
    }

    #send-btn:disabled {
      background: #667dbf66;
      cursor: default;
    }

    /* TYPING INDICATOR */
    #typing-indicator {
      margin: 6px 22px;
      font-style: italic;
      color: #7a90bf;
      display: flex;
      align-items: center;
      height: 24px;
      user-select: none;
    }

    .typing-dot {
      width: 8px;
      height: 8px;
      margin: 0 3px;
      background: #7a90bf;
      border-radius: 50%;
      display: inline-block;
      animation: bounce 1.4s infinite ease-in-out both;
    }

    .typing-dot:nth-child(1) {
      animation-delay: -0.32s;
    }

    .typing-dot:nth-child(2) {
      animation-delay: -0.16s;
    }

    .typing-dot:nth-child(3) {
      animation-delay: 0s;
    }

    @keyframes bounce {
      0%,
      80%,
      100% {
        transform: scale(0);
      }
      40% {
        transform: scale(1);
      }
    }

    /* PROXY SEARCH */
    #proxy-search-input {
      width: 70%;
      padding: 8px 14px;
      border-radius: 6px;
      border: none;
      outline: none;
      font-size: 14px;
      margin-bottom: 8px;
      flex-grow: 1;
    }

    #proxy-search-btn {
      padding: 8px 16px;
      font-weight: 700;
      font-size: 14px;
      border-radius: 6px;
      border: none;
      background-color: #4a73ff;
      color: white;
      cursor: pointer;
      transition: background-color 0.3s;
      margin-left: 6px;
      white-space: nowrap;
    }

    #proxy-search-btn:hover:not(:disabled) {
      background-color: #2669ff;
    }

    #proxy-search-results {
      max-height: 220px;
      overflow-y: auto;
      font-size: 14px;
      color: #ddefff;
      margin-top: 8px;
      user-select: text;
      line-height: 1.4em;
    }

    #proxy-search-results p {
      margin-bottom: 8px;
      cursor: pointer;
    }

    #proxy-iframe-wrapper {
      position: relative;
      flex-grow: 1;
      background: #000;
      border-top: 1px solid #4169e1;
      border-radius: 4px;
      overflow: hidden;
      box-shadow: inset 0 0 14px rgba(255, 255, 255, 0.1);
      margin-top: 8px;
      min-height: 50vh;
    }

    #proxy-iframe-wrapper iframe {
      width: 100%;
      height: 100%;
      border: none;
      background: #fff;
      display: block;
      border-radius: 4px;
    }

    #proxy-loading {
      position: absolute;
      top: 40%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: #4a73ff;
      font-weight: 700;
      font-size: 20px;
      user-select: none;
      display: none;
      pointer-events: none;
    }

    /* QUIZ AREA */
    #quiz-area {
      white-space: pre-wrap;
      font-size: 14px;
      margin-top: 10px;
      background: #24324a;
      border-radius: 8px;
      padding: 12px;
      color: #e0e7ff;
      max-height: 220px;
      overflow-y: auto;
      user-select: text;
      font-family: monospace;
    }

    /* SETTINGS PANELS */
    .form-check-label,
    label {
      cursor: pointer;
      user-select: none;
    }

    .form-range {
      width: 100%;
    }

    /* Media Upload & Preview Tab Styles */
    #media-tab {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      gap: 8px;
    }

    #image-upload-label {
      background-color: #4169e1;
      padding: 10px;
      color: white;
      font-weight: 600;
      border-radius: 8px;
      text-align: center;
      cursor: pointer;
      user-select: none;
    }

    #image-upload-label:hover {
      background-color: #548dff;
    }

    #image-upload-input {
      display: none;
    }

    #image-preview-container {
      border: 1px solid #4169e1;
      border-radius: 8px;
      padding: 12px;
      background-color: #222b44;
      overflow-y: auto;
      max-height: 200px;
      user-select: text;
    }

    #image-preview-container img {
      max-width: 100%;
      border-radius: 8px;
      margin-bottom: 8px;
      box-shadow: 0 0 10px #4169e1aa;
    }

    /* HTML Editor Tab Styles */
    #html-editor-tab {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      gap: 6px;
    }

    #html-editor-textarea {
      width: 100%;
      height: 200px;
      border-radius: 8px;
      font-family: monospace;
      background-color: #222b44;
      color: #ddeeff;
      border: 1px solid #4a73ff;
      padding: 10px;
      resize: vertical;
    }

    #html-preview {
      flex-grow: 1;
      border-radius: 8px;
      background-color: #12141b;
      border: 1px solid #4a73ff;
      overflow-y: auto;
      padding: 12px;
      color: #ddeeff;
      min-height: 150px;
      user-select: text;
    }

    #html-toggle-preview {
      background-color: #4a73ff;
      color: white;
      border: none;
      padding: 6px 14px;
      border-radius: 6px;
      align-self: flex-start;
      cursor: pointer;
    }

    #html-toggle-preview:hover {
      background-color: #669dff;
    }

    /* Text editor tab (like note with markdown) */
    #note-editor {
      flex-grow: 1;
      width: 100%;
      resize: vertical;
      border-radius: 8px;
      line-height: 1.5em;
      padding: 14px 16px;
      font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
      font-size: 14px;
      background-color: #222b44;
      color: #ddeeff;
      border: 1px solid #4a73ff;
      min-height: 140px;
    }

    /* Dark Mode Overrides */
    body.light-mode {
      background: #f5f7fa;
      color: #222;
    }

    body.light-mode #sidebar {
      background: #e4ecff;
      color: #222;
      border-right-color: #c1c9d6;
    }

    body.light-mode #chat-area {
      background: #eef2ff;
      color: #222;
    }

    body.light-mode #msgs {
      background: linear-gradient(135deg, #fff 0%, #dbeafe 100%);
      color: #222;
    }

    body.light-mode .msg.user {
      background: #aff3afcc;
      color: #064e00;
    }

    body.light-mode .msg.ai {
      background: #8cc8ffcc;
      color: #02266f;
    }

    body.light-mode #input-form {
      background: #d6dbfb;
    }

    body.light-mode #user-input {
      background: #f5f7fa;
      color: #222;
    }

    body.light-mode #proxy-search-input {
      background: #fff;
      color: #222;
      border: 1px solid #ccc;
    }

    body.light-mode #proxy-search-results {
      color: #222;
    }

    body.light-mode a {
      color: #3366cc;
    }

    /* Scrollbars */
    ::-webkit-scrollbar {
      width: 8px;
      height: 8px;
    }

    ::-webkit-scrollbar-track {
      background: transparent;
    }

    ::-webkit-scrollbar-thumb {
      background: #4a73ff88;
      border-radius: 20px;
    }

    /* Responsive for smaller viewports */
    @media (max-width: 720px) {
      #app {
        flex-direction: column;
      }

      #sidebar {
        width: 100%;
        height: 50vh;
      }

      #chat-area {
        height: 50vh;
      }

      #tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
      }

      .tabbtn {
        flex: 1 0 auto;
        font-size: 13px;
        padding: 8px 6px;
      }
    }
  </style>
</head>
<body>
  <div id="app" role="main" aria-label="Ultimate AI Assistant Extended">

    <!-- Sidebar: Control Panel with Extended Tabs -->
    <section id="sidebar" role="complementary" aria-label="Control panel">
      <header>Ultimate AI Assistant</header>
      <nav id="tabs" role="tablist" aria-label="Settings tabs">
        <button class="tabbtn active" role="tab" aria-selected="true" aria-controls="tab-ai" id="tab-btn-ai">AI Chat</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-data" id="tab-btn-data">Data APIs</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-quiz" id="tab-btn-quiz">Quiz Tools</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-search" id="tab-btn-search">Search Proxy</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-voice" id="tab-btn-voice">Voice Chat</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-export" id="tab-btn-export">Export Chat</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-media" id="tab-btn-media">Media Upload</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-html" id="tab-btn-html">HTML Editor</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-text" id="tab-btn-text">Text Notes</button>
        <!-- Additional tabs for extended features -->
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-analytics" id="tab-btn-analytics">Analytics & Graphs</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-map" id="tab-btn-map">Geo & Mapping</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-code" id="tab-btn-code">Code Helper</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-tools" id="tab-btn-tools">Utility Tools</button>
        <button class="tabbtn" role="tab" aria-selected="false" aria-controls="tab-settings" id="tab-btn-settings">Advanced Settings</button>
      </nav>

      <!-- Tab contents -->
      <div id="tab-ai" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-ai">
        <h5>Personality</h5>
        <select id="personality-select" class="form-select form-select-sm" aria-label="Select personality tone">
          <option value="friendly" selected>Friendly & Simple</option>
          <option value="formal">Formal & Precise</option>
          <option value="funny">Funny & Casual</option>
          <option value="robotic">Robotic & Technical</option>
          <option value="friendly-funny">Friendly-Funny Mix</option>
          <option value="philosophical">Philosophical & Reflective</option>
          <option value="motivational">Motivational & Uplifting</option>
        </select>
        <div class="form-check my-2">
          <input class="form-check-input" type="checkbox" id="use-context" checked />
          <label class="form-check-label" for="use-context">Enable Context Awareness</label>
        </div>
        <div class="form-check my-2">
          <input class="form-check-input" type="checkbox" id="use-external" checked />
          <label class="form-check-label" for="use-external">Use Online Knowledge APIs</label>
        </div>
        <div class="form-check my-2">
          <input class="form-check-input" type="checkbox" id="spellcheck" checked />
          <label class="form-check-label" for="spellcheck">Enable Spell Correction</label>
        </div>
        <div class="form-check my-2">
          <input class="form-check-input" type="checkbox" id="auto-translate" />
          <label class="form-check-label" for="auto-translate">Auto Translate Responses (detect language)</label>
        </div>
        <div class="form-check my-2">
          <input class="form-check-input" type="checkbox" id="typing-indicator-checkbox" checked />
          <label class="form-check-label" for="typing-indicator-checkbox">Show Typing Indicator</label>
        </div>
        <h5 class="mt-4">Performance</h5>
        <label for="typing-speed" class="form-label">Typing Speed (ms per char): <span id="typing-speed-val">30</span></label>
        <input type="range" id="typing-speed" class="form-range" min="10" max="80" value="30" />
        <label for="context-length" class="form-label mt-3">Max Memory Steps: <span id="context-length-val">5</span></label>
        <input type="range" id="context-length" class="form-range" min="1" max="20" value="5" />
        <label for="max-response-words" class="form-label mt-3">Max Words in Response: <span id="max-response-words-val">200</span></label>
        <input type="range" id="max-response-words" class="form-range" min="20" max="500" value="200" />
        <h5 class="mt-4">User Experience</h5>
        <div class="form-check mb-3">
          <input class="form-check-input" type="checkbox" id="dark-mode" checked />
          <label class="form-check-label" for="dark-mode">Enable Dark Mode</label>
        </div>
        <label for="font-size" class="form-label">Font Size: <span id="font-size-val">16</span> px</label>
        <input type="range" id="font-size" class="form-range" min="12" max="24" value="16" />
        <div class="form-check mb-3">
          <input class="form-check-input" type="checkbox" id="enable-emoji" />
          <label class="form-check-label" for="enable-emoji">Translate Emotions to Emojis</label>
        </div>
        <button class="btn btn-danger w-100 mt-4" id="clear-chat">Clear Chat History</button>
      </div>

      <div id="tab-data" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-data" hidden>
        <h5>Free & Demo APIs Integrated:</h5>
        <ul class="list-group list-group-flush" style="font-size: 14px;">
          <li class="list-group-item bg-transparent">• DuckDuckGo Instant Answer API (Knowledge & Search)</li>
          <li class="list-group-item bg-transparent">• Wikipedia REST API (Article summaries)</li>
          <li class="list-group-item bg-transparent">• Numbers API (Trivia & facts about numbers)</li>
          <li class="list-group-item bg-transparent">• Open Trivia DB (Quiz questions)</li>
          <li class="list-group-item bg-transparent">• Free Dictionary API (Word definitions & synonyms)</li>
          <li class="list-group-item bg-transparent">• NewsAPI demo (Tech news headlines)</li>
          <li class="list-group-item bg-transparent">• Weather APIs (Open-Meteo) for current weather</li>
          <li class="list-group-item bg-transparent">• Currency conversion (exchangerate.host)</li>
          <li class="list-group-item bg-transparent">• Unsplash + Flickr image search integration</li>
          <li class="list-group-item bg-transparent">• YouTube API preview (via embeds)</li>
          <li class="list-group-item bg-transparent">• Google Translate API demo (for translation)</li>
          <li class="list-group-item bg-transparent">• Merriam-Webster Thesaurus & Dictionary (demo)</li>
          <li class="list-group-item bg-transparent">• Oxford Dictionaries API (demo)</li>
          <li class="list-group-item bg-transparent">• Wikipedia GeoSearch (Places info)</li>
          <li class="list-group-item bg-transparent">• TimezoneDB API (Timezone info)</li>
          <li class="list-group-item bg-transparent">• IP Geolocation API (Your IP info)</li>
          <li class="list-group-item bg-transparent">• QR Code generator & scanner</li>
          <li class="list-group-item bg-transparent">• OpenAI GPT Q&A (requires API key)</li>
          <li class="list-group-item bg-transparent">• Free Text-to-Speech & Speech-to-Text APIs</li>
          <li class="list-group-item bg-transparent">• Handlebars.js templates for dynamic UI</li>
          <li class="list-group-item bg-transparent">• ML-powered sentiment analysis (ml5.js)</li>
          <li class="list-group-item bg-transparent">• Image recognition (ml5.js MobileNet demo)</li>
          <li class="list-group-item bg-transparent">• 3D rendering via Three.js for AI data visualization</li>
          <li class="list-group-item bg-transparent">• Local NLP utilities (tfjs)</li>
          <!-- Extendable for more APIs -->
        </ul>
        <p class="mt-3" style="font-style: italic;">Easily add more by editing code - all modular & modern!</p>
      </div>

      <div id="tab-quiz" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-quiz" hidden>
        <h5>Quiz & Learning Tools</h5>
        <button type="button" id="start-quiz-btn" class="btn btn-primary btn-sm mb-3" aria-label="Start random quiz">Start Random Quiz</button>
        <div id="quiz-area" aria-live="polite" aria-atomic="true" tabindex="0"></div>
        <small class="text-muted mt-2 d-block">Correct answers increase your score!</small>
        <button type="button" id="start-math-quiz-btn" class="btn btn-success btn-sm mt-3">Start Math Quiz</button>
        <div id="math-quiz-area" style="white-space: pre-wrap; font-family: monospace; margin-top: 8px; max-height: 180px; overflow-y: auto; background:#2a344e; border-radius:8px; padding: 10px; color:#cfffbf;" tabindex="0"></div>
      </div>

      <div id="tab-search" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-search" hidden>
        <h5>Search Proxy Browser</h5>
        <div class="d-flex flex-wrap mb-2">
          <input 
            id="proxy-search-input" 
            type="search" 
            class="form-control me-2" 
            placeholder="Search DuckDuckGo or enter URL..." 
            aria-label="Proxy search or direct URL input" 
            style="flex-grow:1; min-width:200px" 
            spellcheck="false" 
            autocomplete="off"
          />
          <button id="proxy-search-btn" class="btn btn-primary mb-2" title="Search or Load URL" aria-label="Search or load URL">Search / Load</button>
        </div>
        <div id="proxy-search-results" aria-live="polite" aria-atomic="false" tabindex="0"></div>
        <div id="proxy-iframe-wrapper" aria-live="off">
          <iframe 
            id="proxy-iframe" 
            srcdoc="<p style='font-family:sans-serif;color:#666;text-align:center;padding:2rem;'>Search results or embedded website will show here.</p>" 
            title="Proxy Browser Frame" 
            sandbox="allow-same-origin allow-scripts allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox" 
            loading="lazy" 
            frameborder="0" 
            tabindex="0"
            aria-label="Embedded browsing area"
          ></iframe>
          <div id="proxy-loading" aria-hidden="true">Loading...</div>
        </div>
      </div>

      <div id="tab-voice" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-voice" hidden>
        <h5>Voice Chat</h5>
        <p>Use mic button to speak to AI, and AI will talk back.</p>
        <button id="voice-start-btn" class="btn btn-success mb-3" aria-label="Start voice chat" >🎤 Start Voice Chat</button>
        <button id="voice-stop-btn" class="btn btn-danger mb-3" disabled aria-label="Stop voice chat">⏹ Stop Voice Chat</button>
        <div id="voice-text" style="background:#182135; padding:12px; border-radius:6px; min-height:36px; color:#8ab4f8; font-family: monospace;" aria-live="polite" aria-atomic="true" tabindex="0"></div>
      </div>

      <div id="tab-export" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-export" hidden>
        <h5>Export & Import Chat History</h5>
        <button id="export-json-btn" class="btn btn-outline-primary mb-2" aria-label="Export chat history JSON">Export as JSON</button>
        <button id="export-txt-btn" class="btn btn-outline-secondary mb-2" aria-label="Export chat history text">Export as Text</button>
        <button id="export-html-btn" class="btn btn-outline-success mb-2" aria-label="Export chat as HTML page">Export as HTML (.ai file)</button>
        <hr />
        <label for="import-json-input" class="form-label">Import chat from JSON file</label>
        <input type="file" id="import-json-input" accept="application/json" class="form-control mb-2" aria-label="Import chat JSON file" />
        <small class="form-text text-muted">Imported chat messages will replace current history.</small>
        <button id="import-html-btn" class="btn btn-outline-warning mt-3" aria-label="Import chat from HTML (.ai) file">Import .ai File</button>
        <input type="file" id="import-html-input" accept=".ai,.html" style="display:none" />
      </div>

      <div id="tab-media" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-media" hidden>
        <h5>Media Upload & AI Analysis</h5>
        <label id="image-upload-label" for="image-upload-input" tabindex="0" aria-controls="image-preview-container">Click or press Enter to upload images</label>
        <input type="file" id="image-upload-input" accept="image/*" multiple aria-describedby="upload-help" />
        <small id="upload-help" class="text-muted mb-2">Supports PNG, JPG, GIF. AI caption coming soon!</small>
        <div id="image-preview-container" aria-live="polite" aria-atomic="true" style="min-height:100px;">
          <p>No images uploaded yet.</p>
        </div>
        <hr />
        <button id="analyze-images-btn" class="btn btn-info" aria-label="Analyze uploaded images">Analyze Images (ML-powered)</button>
        <div id="image-analysis-results" style="margin-top:10px; font-size: 14px; min-height: 48px;" aria-live="polite" aria-atomic="true"></div>
      </div>

      <div id="tab-html" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-html" hidden>
        <h5>HTML Editor with Live Preview</h5>
        <textarea id="html-editor-textarea" placeholder="Write raw HTML here..." aria-label="HTML editor textarea"></textarea>
        <button id="html-toggle-preview" aria-pressed="false" aria-label="Toggle live HTML preview">Toggle Preview</button>
        <div id="html-preview" hidden aria-live="polite" aria-atomic="true" tabindex="0">Live preview will show here.</div>
      </div>

      <div id="tab-text" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-text" hidden>
        <h5>Notes & Markdown Editor</h5>
        <textarea id="note-editor" placeholder="Write notes or markdown here..." spellcheck="true" aria-label="Markdown notes editor"></textarea>
        <button id="render-markdown-btn" class="btn btn-secondary mt-2" aria-label="Render markdown preview">Render Markdown Preview</button>
        <div id="markdown-preview" style="margin-top: 10px; background:#212837; padding:12px; border-radius:8px; color:#ddd; max-height: 300px; overflow-y:auto;" aria-live="polite" aria-atomic="true" tabindex="0"></div>
      </div>

      <div id="tab-analytics" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-analytics" hidden>
        <h5>Analytics & Graphs</h5>
        <canvas id="analytics-chart" aria-label="Analytics data chart" role="img" style="max-height: 300px; background:#222d44; border-radius:8px;"></canvas>
        <button id="refresh-analytics-btn" class="btn btn-primary mt-3" aria-label="Refresh analytics data">Refresh Analytics</button>
        <small class="text-muted mt-2 d-block">Tracks user queries and AI response sentiment.</small>
      </div>

      <div id="tab-map" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-map" hidden>
        <h5>Geo & Mapping</h5>
        <input id="map-location-input" type="text" class="form-control mb-2" placeholder="Enter location to search" aria-label="Map location input" autocomplete="off"/>
        <button id="map-search-btn" class="btn btn-primary mb-3" aria-label="Search location on map">Search Location</button>
        <div id="map-container" style="height: 350px; border-radius:8px;" tabindex="0" aria-label="Map display"></div>
      </div>

      <div id="tab-code" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-code" hidden>
        <h5>Code Helper</h5>
        <textarea id="code-input" placeholder="Write or paste code here..." spellcheck="false" aria-label="Code input editor" style="width:100%; height: 160px; font-family: monospace; background:#222b44; color:#ddeeff; border-radius:8px; padding:10px;"></textarea>
        <button id="run-code-btn" class="btn btn-success mt-2" aria-label="Run JavaScript code">Run JS Code</button>
        <button id="format-code-btn" class="btn btn-secondary mt-2 ms-2" aria-label="Format JavaScript code">Format Code</button>
        <pre id="code-output" aria-live="polite" aria-atomic="true" style="background:#12141b; padding:10px; margin-top:8px; min-height: 100px; border-radius:8px; color:#aff;"></pre>
      </div>

      <div id="tab-tools" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-tools" hidden>
        <h5>Utility Tools</h5>
        <button id="generate-qr-btn" class="btn btn-info mb-2" aria-label="Generate QR Code from text input">Generate QR Code</button>
        <input id="qr-text-input" class="form-control mb-2" placeholder="Text/URL for QR Code" aria-label="QR code text input" />
        <canvas id="qr-canvas" style="border: 1px solid #4a73ff; border-radius: 8px; max-width: 100%; height: auto;"></canvas>
        <hr />
        <button id="generate-random-password-btn" class="btn btn-warning mb-2" aria-label="Generate random secure password">Generate Password</button>
        <input type="text" id="password-output" class="form-control mb-2" readonly aria-label="Generated password output"/>
        <button id="copy-password-btn" class="btn btn-outline-primary mb-2" aria-label="Copy password to clipboard">Copy Password</button>
        <hr />
        <button id="fetch-ip-btn" class="btn btn-primary" aria-label="Fetch client IP info">Get My IP Info</button>
        <pre id="ip-info-output" style="background:#12141b; margin-top: 8px; padding: 10px; min-height: 80px; border-radius:8px; color:#aff;" aria-live="polite" tabindex="0"></pre>
      </div>

      <div id="tab-settings" class="tabcontent" role="tabpanel" aria-labelledby="tab-btn-settings" hidden>
        <h5>Advanced Settings & Debug</h5>
        <div class="form-check">
          <input class="form-check-input" type="checkbox" id="enable-logging" />
          <label class="form-check-label" for="enable-logging">Enable Debug Logging</label>
        </div>
        <div class="form-check mt-2">
          <input class="form-check-input" type="checkbox" id="auto-clear-on-export" />
          <label class="form-check-label" for="auto-clear-on-export">Clear Chat on Export</label>
        </div>
        <label for="openai-key" class="form-label mt-3">OpenAI API Key (optional):</label>
        <input type="password" class="form-control" id="openai-key" autocomplete="off" placeholder="Paste API key here" aria-label="OpenAI API key input"/>
        <button id="save-openai-key-btn" class="btn btn-primary mt-2" aria-label="Save OpenAI API key">Save Key</button>
        <hr />
        <button id="clear-localstorage-btn" class="btn btn-danger mt-2" aria-label="Clear all saved data">Clear All Local Storage Data</button>
        <small class="text-muted mt-2 d-block">Advanced: reset all preferences and chat history.</small>
      </div>
    </section>

    <!-- Chat Area -->
    <section id="chat-area" role="main" aria-label="Chat conversation with AI">
      <div id="msgs" tabindex="0" aria-live="polite" aria-atomic="false" role="log"></div>
      <div id="typing-indicator" aria-live="assertive" aria-atomic="true" style="display:none;">
        AI is typing &nbsp;
        <span class="typing-dot"></span>
        <span class="typing-dot"></span>
        <span class="typing-dot"></span>
      </div>

      <form id="input-form" autocomplete="off" role="search" aria-label="Chat input form" style="padding:10px 20px; background:#1f263b; display:flex; align-items: center;">
        <textarea 
          id="user-input" 
          name="message" 
          placeholder="Ask me anything..." 
          aria-label="Message input" 
          autocomplete="off" 
          rows="1" 
          style="flex-grow:1; font-size:16px; padding: 12px 16px; border-radius: 30px; border:none; color:#ddeeff; background:#293046; resize:none;"
          spellcheck="true"
        ></textarea>
        <button id="send-btn" type="submit" aria-label="Send message"
          style="margin-left:12px; padding:0 20px; background:#3a70ff; border:none; color:white; font-weight:700; font-size:16px; border-radius:30px; cursor:pointer;">Send</button>
      </form>
    </section>

  </div>

  <script>
    window.addEventListener("load", () => {
      /////////////////////////////
      // --- DOM Elements ---
      /////////////////////////////
      // Tabs and pages
      const tabs = [...document.querySelectorAll(".tabbtn")];
      const tabContents = [...document.querySelectorAll(".tabcontent")];

      // Chat elements
      const msgs = document.getElementById("msgs");
      const inputForm = document.getElementById("input-form");
      const userInput = document.getElementById("user-input");
      const typingInd = document.getElementById("typing-indicator");
      const sendBtn = document.getElementById("send-btn");

      // Settings
      const personalitySelect = document.getElementById("personality-select");
      const useContextCheckbox = document.getElementById("use-context");
      const useExternalCheckbox = document.getElementById("use-external");
      const spellCheckCheckbox = document.getElementById("spellcheck");
      const typingIndicatorCheckbox = document.getElementById("typing-indicator-checkbox");
      const darkModeCheckbox = document.getElementById("dark-mode");
      const fontSizeSlider = document.getElementById("font-size");
      const fontSizeVal = document.getElementById("font-size-val");
      const typingSpeedSlider = document.getElementById("typing-speed");
      const typingSpeedVal = document.getElementById("typing-speed-val");
      const contextLengthSlider = document.getElementById("context-length");
      const contextLengthVal = document.getElementById("context-length-val");
      const clearChatBtn = document.getElementById("clear-chat");
      const maxResponseWordsSlider = document.getElementById("max-response-words");
      const maxResponseWordsVal = document.getElementById("max-response-words-val");
      const autoTranslateCheckbox = document.getElementById("auto-translate");
      const enableEmojiCheckbox = document.getElementById("enable-emoji");

      // Quiz tab elements
      const startQuizBtn = document.getElementById("start-quiz-btn");
      const quizArea = document.getElementById("quiz-area");
      const startMathQuizBtn = document.getElementById("start-math-quiz-btn");
      const mathQuizArea = document.getElementById("math-quiz-area");

      // Proxy tab elements
      const proxyInput = document.getElementById("proxy-search-input");
      const proxyBtn = document.getElementById("proxy-search-btn");
      const proxyResults = document.getElementById("proxy-search-results");
      const proxyIframeWrapper = document.getElementById("proxy-iframe-wrapper");
      const proxyIframe = document.getElementById("proxy-iframe");
      const proxyLoading = document.getElementById("proxy-loading");

      // Voice
      const voiceStartBtn = document.getElementById("voice-start-btn");
      const voiceStopBtn = document.getElementById("voice-stop-btn");
      const voiceText = document.getElementById("voice-text");

      // Export & Import
      const exportJsonBtn = document.getElementById("export-json-btn");
      const exportTxtBtn = document.getElementById("export-txt-btn");
      const exportHtmlBtn = document.getElementById("export-html-btn");
      const importJsonInput = document.getElementById("import-json-input");
      const importHtmlBtn = document.getElementById("import-html-btn");
      const importHtmlInput = document.getElementById("import-html-input");

      // Media
      const imageUploadInput = document.getElementById("image-upload-input");
      const imagePreviewContainer = document.getElementById("image-preview-container");
      const analyzeImagesBtn = document.getElementById("analyze-images-btn");
      const imageAnalysisResults = document.getElementById("image-analysis-results");

      // HTML editor
      const htmlEditorTextarea = document.getElementById("html-editor-textarea");
      const htmlPreview = document.getElementById("html-preview");
      const htmlTogglePreviewBtn = document.getElementById("html-toggle-preview");

      // Notes / Markdown
      const noteEditor = document.getElementById("note-editor");
      const renderMarkdownBtn = document.getElementById("render-markdown-btn");
      const markdownPreview = document.getElementById("markdown-preview");

      // Analytics
      const analyticsChartCtx = document.getElementById("analytics-chart")?.getContext("2d");
      const refreshAnalyticsBtn = document.getElementById("refresh-analytics-btn");

      // Map
      const mapLocationInput = document.getElementById("map-location-input");
      const mapSearchBtn = document.getElementById("map-search-btn");
      const mapContainer = document.getElementById("map-container");

      // Code helper
      const codeInput = document.getElementById("code-input");
      const runCodeBtn = document.getElementById("run-code-btn");
      const formatCodeBtn = document.getElementById("format-code-btn");
      const codeOutput = document.getElementById("code-output");

      // Tools tab
      const generateQrBtn = document.getElementById("generate-qr-btn");
      const qrTextInput = document.getElementById("qr-text-input");
      const qrCanvas = document.getElementById("qr-canvas");
      const generatePasswordBtn = document.getElementById("generate-random-password-btn");
      const passwordOutput = document.getElementById("password-output");
      const copyPasswordBtn = document.getElementById("copy-password-btn");
      const fetchIpBtn = document.getElementById("fetch-ip-btn");
      const ipInfoOutput = document.getElementById("ip-info-output");

      // Advanced settings
      const enableLoggingCheckbox = document.getElementById("enable-logging");
      const autoClearOnExportCheckbox = document.getElementById("auto-clear-on-export");
      const openaiKeyInput = document.getElementById("openai-key");
      const saveOpenaiKeyBtn = document.getElementById("save-openai-key-btn");
      const clearLocalStorageBtn = document.getElementById("clear-localstorage-btn");

      ////////////////////////////////
      // --- Global State / Variables
      ////////////////////////////////
      let settings = {
        personality: "friendly",
        useContext: true,
        useExternalData: true,
        enableSpellCheck: true,
        useTypingDelay: true,
        darkMode: true,
        fontSize: 16,
        typingSpeedMs: 30,
        maxMemorySteps: 5,
        maxResponseWords: 200,
        autoTranslate: false,
        enableEmoji: false,
        enableLogging: false,
        openaiKey: "",
        autoClearOnExport: false,
      };

      let chatMemory = [];
      let quizState = null;
      let mathQuizState = null;
      let userPreferences = {};

      let analyticsData = {
        totalQueries: 0,
        sentimentScores: [], // Store simple sentiment scores [-1,1]
        queriesByCategory: {}, // Tracking trivia, math, weather, etc
      };

      /////////////////////////////
      // --- Helper Functions ---
      /////////////////////////////
      function logDebug(...args) {
        if (settings.enableLogging) {
          console.debug("[DEBUG]", ...args);
        }
      }

      function sanitize(html) {
        return DOMPurify.sanitize(html);
      }

      function linkify(text) {
        const urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi;
        return text.replace(urlRegex, (url) => {
          return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
        });
      }

      function truncateWords(text, maxWords) {
        const words = text.split(/\s+/);
        if (words.length <= maxWords) return text;
        return words.slice(0, maxWords).join(" ") + " ...";
      }

      function parseSentiment(text) {
        // Very basic sentiment estimation (positive: +1, neutral: 0, negative: -1)
        // Extensible with ML models if needed.
        const positives = ["good", "nice", "great", "love", "happy", "awesome", "nice", "correct", "well done", "thank"];
        const negatives = ["bad", "hate", "wrong", "sad", "fail", "awful", "no", "not"];
        let score = 0;
        const txt = text.toLowerCase();
        for (const p of positives) {
          if (txt.includes(p)) score += 1;
        }
        for (const n of negatives) {
          if (txt.includes(n)) score -= 1;
        }
        if (score > 0) return 1;
        if (score < 0) return -1;
        return 0;
      }

      // Improved spell correction dictionary (could expand or better use API)
      function spellCorrect(text) {
        const corrections = {
          adn: "and",
          teh: "the",
          beleive: "believe",
          realy: "really",
          recieve: "receive",
          exmaple: "example",
          langauge: "language",
          becuase: "because",
          definately: "definitely",
          seperate: "separate",
          occured: "occurred",
          unwant: "unwanted",
        };
        return text.replace(/\b\w+\b/g, (word) => corrections[word.toLowerCase()] || word);
      }

      // Shuffle array helper
      function shuffle(array) {
        for (let i = array.length - 1; i > 0; i--) {
          let j = Math.floor(Math.random() * (i + 1));
          [array[i], array[j]] = [array[j], array[i]];
        }
      }

      function saveChatMemory() {
        try {
          localStorage.setItem(
            "ultimateAIChatMem",
            JSON.stringify(chatMemory.slice(-settings.maxMemorySteps * 2))
          );
        } catch (e) {
          logDebug("Failed to save chat memory", e);
        }
      }

      function loadChatMemory() {
        try {
          const mem = localStorage.getItem("ultimateAIChatMem");
          if (mem) {
            chatMemory = JSON.parse(mem);
            for (const m of chatMemory) {
              appendMsg(m.text, m.role === "user" ? "user" : "ai", false);
            }
          }
        } catch (e) {
          logDebug("Failed to load chat memory", e);
        }
      }

      function savePreferences() {
        try {
          localStorage.setItem("ultimateAIUserPrefs", JSON.stringify(userPreferences));
        } catch {}
      }

      function loadPreferences() {
        try {
          const prefs = localStorage.getItem("ultimateAIUserPrefs");
          if (prefs) userPreferences = JSON.parse(prefs);
        } catch {}
      }

      function saveSettings() {
        try {
          localStorage.setItem("ultimateAISettings", JSON.stringify(settings));
        } catch {}
      }

      function loadSettings() {
        try {
          const stored = localStorage.getItem("ultimateAISettings");
          if (stored) Object.assign(settings, JSON.parse(stored));
        } catch {}
        applySettingsUI();
      }

      function applySettingsUI() {
        personalitySelect.value = settings.personality;
        useContextCheckbox.checked = settings.useContext;
        useExternalCheckbox.checked = settings.useExternalData;
        spellCheckCheckbox.checked = settings.enableSpellCheck;
        typingIndicatorCheckbox.checked = settings.useTypingDelay;
        darkModeCheckbox.checked = settings.darkMode;
        fontSizeSlider.value = settings.fontSize;
        fontSizeVal.textContent = settings.fontSize;
        typingSpeedSlider.value = settings.typingSpeedMs;
        typingSpeedVal.textContent = settings.typingSpeedMs;
        contextLengthSlider.value = settings.maxMemorySteps;
        contextLengthVal.textContent = settings.maxMemorySteps;
        maxResponseWordsSlider.value = settings.maxResponseWords;
        maxResponseWordsVal.textContent = settings.maxResponseWords;
        autoTranslateCheckbox.checked = settings.autoTranslate;
        enableEmojiCheckbox.checked = settings.enableEmoji;
        enableLoggingCheckbox.checked = settings.enableLogging;
        autoClearOnExportCheckbox.checked = settings.autoClearOnExport;
        openaiKeyInput.value = settings.openaiKey || "";
        applyAppearance();
      }

      function applyAppearance() {
        if (settings.darkMode) {
          document.body.classList.remove("light-mode");
        } else {
          document.body.classList.add("light-mode");
        }
        msgs.style.fontSize = settings.fontSize + "px";
        userInput.style.fontSize = settings.fontSize + "px";
      }

      function attachSettingsListeners() {
        personalitySelect.addEventListener("change", (e) => {
          settings.personality = e.target.value;
          saveSettings();
          savePreferences();
        });
        useContextCheckbox.addEventListener("change", (e) => {
          settings.useContext = e.target.checked;
          saveSettings();
        });
        useExternalCheckbox.addEventListener("change", (e) => {
          settings.useExternalData = e.target.checked;
          saveSettings();
        });
        spellCheckCheckbox.addEventListener("change", (e) => {
          settings.enableSpellCheck = e.target.checked;
          saveSettings();
        });
        typingIndicatorCheckbox.addEventListener("change", (e) => {
          settings.useTypingDelay = e.target.checked;
          saveSettings();
        });
        darkModeCheckbox.addEventListener("change", (e) => {
          settings.darkMode = e.target.checked;
          applyAppearance();
          saveSettings();
        });
        fontSizeSlider.addEventListener("input", (e) => {
          settings.fontSize = Number(e.target.value);
          fontSizeVal.textContent = settings.fontSize;
          applyAppearance();
          saveSettings();
        });
        typingSpeedSlider.addEventListener("input", (e) => {
          settings.typingSpeedMs = Number(e.target.value);
          typingSpeedVal.textContent = settings.typingSpeedMs;
          saveSettings();
        });
        contextLengthSlider.addEventListener("input", (e) => {
          settings.maxMemorySteps = Number(e.target.value);
          contextLengthVal.textContent = settings.maxMemorySteps;
          saveSettings();
        });
        maxResponseWordsSlider.addEventListener("input", (e) => {
          settings.maxResponseWords = Number(e.target.value);
          maxResponseWordsVal.textContent = settings.maxResponseWords;
          saveSettings();
        });
        autoTranslateCheckbox.addEventListener("change", (e) => {
          settings.autoTranslate = e.target.checked;
          saveSettings();
        });
        enableEmojiCheckbox.addEventListener("change", (e) => {
          settings.enableEmoji = e.target.checked;
          saveSettings();
        });
        enableLoggingCheckbox.addEventListener("change", (e) => {
          settings.enableLogging = e.target.checked;
          saveSettings();
        });
        autoClearOnExportCheckbox.addEventListener("change", (e) => {
          settings.autoClearOnExport = e.target.checked;
          saveSettings();
        });
        clearChatBtn.addEventListener("click", () => {
          if (confirm("Clear chat history permanently?")) {
            chatMemory = [];
            msgs.innerHTML = "";
            saveChatMemory();
            quizState = null;
            mathQuizState = null;
            quizArea.textContent = "";
            mathQuizArea.textContent = "";
          }
        });
        saveOpenaiKeyBtn.addEventListener("click", () => {
          settings.openaiKey = openaiKeyInput.value.trim();
          if (settings.openaiKey.length > 0) {
            Swal.fire("Success", "OpenAI API key saved locally.", "success");
          } else {
            Swal.fire("Info", "OpenAI key is cleared.", "info");
          }
          saveSettings();
        });
        clearLocalStorageBtn.addEventListener("click", () => {
          if (
            confirm(
              "This will clear all local storage data (chat, settings, preferences). Are you sure?"
            )
          ) {
            localStorage.clear();
            location.reload();
          }
        });
      }

      ////////////////////
      // Tabs navigation
      ////////////////////
      function initTabs() {
        tabs.forEach((btn) => {
          btn.addEventListener("click", () => {
            tabs.forEach((b) => {
              b.classList.remove("active");
              const tid = b.getAttribute("aria-controls");
              const tabc = document.getElementById(tid);
              if (tabc) {
                tabc.hidden = true;
                tabc.setAttribute("aria-hidden", "true");
              }
              b.setAttribute("aria-selected", "false");
            });
            btn.classList.add("active");
            const showid = btn.getAttribute("aria-controls");
            const showTab = document.getElementById(showid);
            if (showTab) {
              showTab.hidden = false;
              showTab.setAttribute("aria-hidden", "false");
            }
            btn.setAttribute("aria-selected", "true");
          });
        });
      }

      ////////////////////
      // Message display
      ////////////////////
      function appendMsg(text, role = "ai", saveAfter = true) {
        if (!text) return;
        if (settings.enableEmoji && role === "ai") {
          text = text.replace(/happy|great|love/gi, "😊").replace(/sad|bad|hate/gi, "😞");
        }
        // Truncate long reply for user experience, not saved
        if (role === "ai" && settings.maxResponseWords > 0) {
          text = truncateWords(text, settings.maxResponseWords);
        }
        const div = document.createElement("div");
        div.className =
          "msg " + (role === "user" ? "user" : "ai") + " animate__animated animate__fadeInUp";
        div.innerHTML = sanitize(linkify(text));
        msgs.appendChild(div);
        msgs.scrollTo({ top: msgs.scrollHeight, behavior: "smooth" });
        if (saveAfter) {
          addToMemory(role, text);
        }
      }

      function addToMemory(role, text) {
        chatMemory.push({ role, text });
        let maxLen = settings.maxMemorySteps * 2;
        if (chatMemory.length > maxLen) {
          chatMemory.splice(0, chatMemory.length - maxLen);
        }
        saveChatMemory();
      }

      function contextText() {
        if (!settings.useContext) return "";
        let relevant = chatMemory.slice(-settings.maxMemorySteps * 2);
        return relevant.map((m) => (m.role === "user" ? "User: " : "AI: ") + m.text).join("\n");
      }

      /////////////////////////////
      // AI Response Generators and APIs
      /////////////////////////////
      const OPENAI_API_KEY = ""; // will override from saved settings if provided

      // Helpers for OpenAI
      async function openaiChatCompletion(messages) {
        let apiKey = settings.openaiKey || OPENAI_API_KEY;
        if (!apiKey) return null;
        try {
          const res = await fetch("https://api.openai.com/v1/chat/completions", {
            method: "POST",
            headers: { 
              "Content-Type": "application/json",
              "Authorization": `Bearer ${apiKey}`
            },
            body: JSON.stringify({
              model: "gpt-3.5-turbo",
              messages: messages,
              max_tokens: 300,
              temperature: 0.7,
            }),
          });
          if (!res.ok) return null;
          const data = await res.json();
          if (data.choices && data.choices.length) {
            return data.choices[0].message.content.trim();
          }
          return null;
        } catch (e) {
          logDebug("OpenAI API error", e);
          return null;
        }
      }

      // Simple helper - translate text (reusing LibreTranslate)
      async function translateText(text, target = "en") {
        try {
          if (target === "en") return text; // no translation needed
          const res = await fetch("https://libretranslate.com/translate", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ q: text, source: "en", target }),
          });
          if (!res.ok) return text;
          const data = await res.json();
          return data.translatedText || text;
        } catch {
          return text;
        }
      }

      // Detect language from text with a lightweight heuristic
      // (only checking if contains some accented letters or non-latin letters; for demo)
      function detectLanguage(text) {
        if (!text) return "en";
        // Very naive checks for demonstration
        if (/[áéíóúñü]/i.test(text)) return "es"; // Spanish demo
        if (/[а-яё]/i.test(text)) return "ru";
        if (/[äöüß]/i.test(text)) return "de";
        return "en";
      }

      // DuckDuckGo Instant Answer API
      async function duckDuckGoQuery(query) {
        try {
          const url = `https://api.duckduckgo.com/?q=${encodeURIComponent(
            query
          )}&format=json&skip_disambig=1&no_redirect=1&kl=us-en`;
          const res = await fetch(url);
          if (!res.ok) return null;
          return await res.json();
        } catch {
          return null;
        }
      }

      // Wikipedia summary API
      async function wikiSummary(query) {
        try {
          const url = `https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(
            query
          )}`;
          const res = await fetch(url);
          if (!res.ok) return null;
          const data = await res.json();
          if (data.extract) {
            let link =
              data.content_urls?.desktop?.page ||
              `https://en.wikipedia.org/wiki/${encodeURIComponent(query)}`;
            return `${data.extract}\n\n<a href="${link}" target="_blank" rel="noopener noreferrer">More on Wikipedia</a>`;
          }
          return null;
        } catch {
          return null;
        }
      }

      // Numbers API trivia fetch
      async function numbersFact(num) {
        try {
          const res = await fetch(`https://numbersapi.com/${num}/trivia?json`);
          if (!res.ok) return null;
          const data = await res.json();
          return data.text || null;
        } catch {
          return null;
        }
      }

      // Open Trivia DB random question
      async function openTrivia() {
        try {
          const res = await fetch(
            "https://opentdb.com/api.php?amount=1&type=multiple&difficulty=easy"
          );
          if (!res.ok) return null;
          const data = await res.json();
          if (!data.results || !data.results.length) return null;
          return data.results[0];
        } catch {
          return null;
        }
      }

      // Open-Meteo weather API demo
      async function fetchWeather(city = "London") {
        try {
          const geo = await fetch(
            `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(
              city
            )}&count=1`
          );
          const geoData = await geo.json();
          if (!geoData.results || !geoData.results.length) return null;
          const lat = geoData.results[0].latitude;
          const lon = geoData.results[0].longitude;
          const weatherRes = await fetch(
            `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}&current_weather=true`
          );
          if (!weatherRes.ok) return null;
          const weatherData = await weatherRes.json();
          if (!weatherData.current_weather) return null;
          return `Current temperature in ${city}: ${weatherData.current_weather.temperature}°C, wind speed: ${weatherData.current_weather.windspeed} km/h`;
        } catch {
          return null;
        }
      }

      // Currency exchange (EXR host)
      async function currencyConvert(from = "USD", to = "EUR") {
        try {
          const url = `https://api.exchangerate.host/convert?from=${from.toUpperCase()}&to=${to.toUpperCase()}`;
          const res = await fetch(url);
          if (!res.ok) return null;
          const data = await res.json();
          if (!data.result) return null;
          return `1 ${from.toUpperCase()} = ${data.result.toFixed(4)} ${to.toUpperCase()}`;
        } catch {
          return null;
        }
      }

      // Grammar check demo (LanguageTool)
      async function grammarCheck(text) {
        try {
          const res = await fetch("https://api.languagetool.org/v2/check", {
            method: "POST",
            headers: { "Content-Type": "application/x-www-form-urlencoded" },
            body: `text=${encodeURIComponent(text)}&language=en-US`,
          });
          if (!res.ok) return null;
          const data = await res.json();
          if (data.matches && data.matches.length) {
            return data.matches
              .map(
                (m) =>
                  `Issue: ${m.message} at ${m.offset}-${m.offset + m.length}`
              )
              .join("\n");
          }
          return "No grammar errors found.";
        } catch {
          return null;
        }
      }

      // OpenAI powered chat fallback or advanced conversational AI handling
      async function askOpenAI(prompt) {
        if (!settings.openaiKey) return null;

        const messages = [
          {
            role: "system",
            content: `You are an AI assistant with a "${settings.personality}" personality. Keep responses concise and useful.`,
          },
          ...chatMemory.map(m => ({
            role: m.role === 'user' ? 'user' : 'assistant',
            content: m.text
          })),
          { role: "user", content: prompt },
        ];

        // Limit messages length < 20 to avoid API issues
        if (messages.length > 20) messages.splice(0, messages.length - 20);

        return await openaiChatCompletion(messages);
      }

      /////////////////////////////
      // Generate AI reply logic
      /////////////////////////////
      async function generateReply(input) {
        let text = input.trim();
        if (settings.enableSpellCheck) text = spellCorrect(text);

        // Quiz answering first
        if (quizState) {
          const choice = Number(text);
          if (!isNaN(choice) && choice >= 1 && choice <= quizState.options.length) {
            const answer = quizState.options[choice - 1];
            if (answer === quizState.correct_answer) {
              quizState = null;
              quizArea.textContent = "";
              return "Correct! Nice job. Ask me for another quiz anytime.";
            } else {
              return "Oops, wrong answer. Try again or type 'skip' to skip the quiz.";
            }
          }
          if (text.toLowerCase() === "skip") {
            quizState = null;
            quizArea.textContent = "";
            return "Quiz skipped. Ask me anything else or start a new quiz.";
          }
          return "Please respond with the option number or type 'skip'.";
        }

        // Math quiz mode
        if (mathQuizState) {
          if (text.toLowerCase() === "skip") {
            mathQuizState = null;
            mathQuizArea.textContent = "";
            return "Math quiz skipped. Let's try something else!";
          }
          try {
            const userAns = Number(text);
            if (isNaN(userAns)) return "Please provide a valid number answer or type 'skip'.";

            if (Math.abs(userAns - mathQuizState.answer) < 0.01) {
              mathQuizState = null;
              mathQuizArea.textContent = "";
              return "Correct! Well done.";
            } else {
              return "That's not correct. Try again or type 'skip'.";
            }
          } catch {
            return "Error processing your answer. Try again or type 'skip'.";
          }
        }

        // Greetings
        if (/^(hello|hi|hey|yo|hola|greetings)/i.test(text)) {
          switch (settings.personality) {
            case "friendly": return "Hello! Ask me anything—from trivia to math or coding.";
            case "formal": return "Good day. Please ask your inquiry.";
            case "funny": return "Yo! Ready to rock some knowledge?";
            case "robotic": return "Greetings, human. Awaiting commands.";
            case "friendly-funny": return "Hey buddy! Brain juice incoming!";
            case "philosophical": return "Greetings. What wisdom do you seek today?";
            case "motivational": return "Hey! Let's achieve greatness together!";
          }
        }

        // Math evaluation
        const mathResult = parseMath(text);
        if (mathResult !== null) return `The answer is ${mathResult}.`;

        const spellMatch = text.match(/\bspell\s+(\w+)/i);
        if (spellMatch) {
          const w = spellMatch[1].toUpperCase();
          return `${w.split("").join("-")} spells ${spellMatch[1]}.`;
        }

        const numbMatch = text.match(/number fact for (\d+)/i);
        if (numbMatch) {
          const fact = await numbersFact(numbMatch[1]);
          if (fact) return `Did you know? ${fact}`;
        }

        if (/\b(quiz|trivia|question)\b/i.test(text)) {
          const trivia = await openTrivia();
          if (trivia) {
            let options = [...trivia.incorrect_answers, trivia.correct_answer];
            options = options.map(s => s.replace(/&quot;/g, '"')
              .replace(/&#039;/g, "'")
              .replace(/&amp;/g, "&"));
            shuffle(options);
            quizState = {
              question: trivia.question,
              correct_answer: trivia.correct_answer,
              options,
            };
            let msg = `Trivia question:\n${quizState.question}\nOptions:\n`;
            options.forEach((opt, i) => {
              msg += `${i + 1}: ${opt}\n`;
            });
            msg += '\nType your answer option number or "skip".';
            quizArea.textContent = msg;
            return msg;
          }
        }

        // Math Quiz start command
        if (/^start math quiz$/i.test(text)) {
          mathQuizState = generateMathQuestion();
          mathQuizArea.textContent = `Math Quiz:\n${mathQuizState.question}\nAnswer as a number or type 'skip' to cancel.`;
          return "Math quiz started! Check the Math Quiz panel.";
        }

        // Spell word query (extended)
        if (/^define\s+(\w+)/i.test(text)) {
          let word = text.match(/^define\s+(\w+)/i)[1];
          try {
            const def = await fetchFreeDictionary(word);
            if (def) return def;
          } catch {}
          return `Sorry, I couldn't find the definition of "${word}".`;
        }

        // API external queries
        if (settings.useExternalData) {
          // DuckDuckGo instant answer
          const ddgData = await duckDuckGoQuery(text);
          if (ddgData && ddgData.AbstractText && ddgData.AbstractText.trim().length > 3) {
            let ans = ddgData.AbstractText;
            if (ddgData.AbstractURL) {
              ans += `\n\n<a href="${ddgData.AbstractURL}" target="_blank" rel="noopener">Read more on DuckDuckGo</a>`;
            }
            return ans;
          }

          // Wikipedia fallback
          const wiki = await wikiSummary(text);
          if (wiki) return wiki;

          // Weather query
          const weatherMatch = text.match(/weather in (.+)/i);
          if (weatherMatch) {
            const weatherInfo = await fetchWeather(weatherMatch[1]);
            if (weatherInfo) return weatherInfo;
          }

          // Currency convert "convert 100 usd to eur"
          const currencyMatch = text.match(
            /convert\s+(\d+(?:\.\d+)?)\s+(\w{3})\s+to\s+(\w{3})/i
          );
          if (currencyMatch) {
            const v = Number(currencyMatch[1]);
            const from = currencyMatch[2];
            const to = currencyMatch[3];
            const rate = await currencyConvert(from, to);
            if (rate) {
              const rateValue = Number(rate.split('=')[1].trim().split(' ')[0]);
              if (!isNaN(rateValue)) {
                return `${v} ${from.toUpperCase()} is approx ${(rateValue * v).toFixed(4)} ${to.toUpperCase()} \n(Rate: ${rate})`;
              }
              return rate;
            }
          }

          // Grammar check if command starts with "check grammar:"
          const grammarMatch = text.match(/^check grammar:\s*(.+)$/i);
          if (grammarMatch) {
            const checkRes = await grammarCheck(grammarMatch[1]);
            if (checkRes) return checkRes;
          }
        }

        // Fallback dictionary definition
        const fallbackQA = {
          "how many continents are there": "There are 7 continents on Earth.",
          "what color do you get when you mix red and blue":
            "You get purple.",
          "who was abraham lincoln":
            "He was the 16th President of the United States.",
          "what is the largest planet": "Jupiter is the largest planet.",
          "how many legs does a spider have": "A spider has 8 legs.",
          "chemical formula of water": "H₂O is the chemical formula of water.",
          "what is photosynthesis":
            "Photosynthesis is the process plants use to turn sunlight into energy.",
          "who is the president of the united states": "Joe Biden",
        };
        const key = text.toLowerCase().replace(/[?.!]/g, "").trim();
        if (fallbackQA[key]) return fallbackQA[key];

        // Try OpenAI integration if API key provided
        if (settings.openaiKey) {
          const response = await askOpenAI(text);
          if (response) return response;
        }

        // Personality fallback
        const fallbackMsgs = {
          friendly:
            "Hmm... I don't know that one. Try asking me a math question or trivia!",
          formal:
            "Apologies, the information is unavailable. Please ask something else.",
          funny:
            "I can't help you with that... maybe take a snack break and try again!",
          robotic:
            "Processing incomplete. Cannot compute response.",
          "friendly-funny":
            "Whoa, that's beyond me. Let's keep it simple, friend!",
          philosophical:
            "Sometimes not knowing is the greatest wisdom. What else can I assist with?",
          motivational:
            "Don't be discouraged! Ask me anything else and we'll find an answer.",
        };
        return fallbackMsgs[settings.personality] || fallbackMsgs.friendly;
      }

      /////////////////////////////
      // Math parse from input
      /////////////////////////////
      function parseMath(text) {
        let expr = text.toLowerCase().replace(/[^0-9+\-*/()., ]/g, "").replace(/,/g, "");
        try {
          let val = eval(expr);
          if (typeof val === "number" && isFinite(val)) return val;
        } catch {}
        return null;
      }

      /////////////////////////////
      // Free Dictionary API fetch
      /////////////////////////////
      async function fetchFreeDictionary(word) {
        try {
          const res = await fetch(`https://api.dictionaryapi.dev/api/v2/entries/en/${word}`);
          if (!res.ok) return null;
          const data = await res.json();
          if (Array.isArray(data) && data.length > 0) {
            const defs = data[0]?.meanings
              ?.map((m) => `${m.partOfSpeech}: ${m.definitions[0].definition}`)
              .join("; ");
            return `Definition of "${word}": ${defs}`;
          }
          return null;
        } catch {
          return null;
        }
      }

      /////////////////////////////
      // Generate math quiz question
      /////////////////////////////
      function generateMathQuestion() {
        const ops = ["+", "-", "*", "/"];
        const op = ops[Math.floor(Math.random() * ops.length)];
        let a = Math.floor(Math.random() * 50) + 1;
        let b = Math.floor(Math.random() * 50) + 1;

        if (op === "/") {
          a = a * b; // ensures divisible
        }
        const question = `Calculate: ${a} ${op} ${b}`;
        let answer;
        switch (op) {
          case "+": answer = a + b; break;
          case "-": answer = a - b; break;
          case "*": answer = a * b; break;
          case "/": answer = a / b; break;
        }
        return { question, answer };
      }

      ///////////////////////
      // Typing indicator + bot reply display
      ///////////////////////
      async function botReplyWithTyping(text) {
        if (!settings.useTypingDelay) {
          appendMsg(text, "ai");
          return;
        }
        typingInd.style.display = "flex";
        sendBtn.disabled = true;
        userInput.disabled = true;

        const delay = Math.max(700, text.length * settings.typingSpeedMs);
        await new Promise((r) => setTimeout(r, delay));

        typingInd.style.display = "none";
        appendMsg(text, "ai");
        sendBtn.disabled = false;
        userInput.disabled = false;
        userInput.focus();
      }

      ////////////////////////
      // Chat form submit handler
      ////////////////////////
      inputForm.addEventListener("submit", async (e) => {
        e.preventDefault();
        let val = userInput.value.trim();
        if (!val) return;

        appendMsg(val, "user");
        addToMemory("user", val);
        userInput.value = "";
        userInput.disabled = true;

        try {
          // Special command: image caption or analyze request
          if (/^(analyze|caption) image$/i.test(val)) {
            if (uploadedImages.length) {
              await botReplyWithTyping(
                "Analyzing your uploaded images with ML models..."
              );
              // ML image analysis demo
              analyzeUploadedImages();
            } else {
              await botReplyWithTyping(
                "No images uploaded yet. Please upload images in the Media tab."
              );
            }
            userInput.disabled = false;
            userInput.focus();
            return;
          }

          // Start math quiz command
          if (/^start math quiz$/i.test(val)) {
            if (mathQuizState) {
              Swal.fire("Info", "Math quiz already in progress. Please answer or type 'skip'.", "info");
              userInput.disabled = false;
              userInput.focus();
              return;
            }
            mathQuizState = generateMathQuestion();
            mathQuizArea.textContent = `Math Quiz:\n${mathQuizState.question}\nAnswer as a number or type 'skip' to cancel.`;
            await botReplyWithTyping("Math quiz started. Check the Math Quiz panel.");
            userInput.disabled = false;
            userInput.focus();
            return;
          }

          // Start random quiz command
          if (/^(start )?quiz$/i.test(val)) {
            const trivia = await openTrivia();
            if (trivia) {
              let options = [...trivia.incorrect_answers, trivia.correct_answer];
              options = options.map(s => s.replace(/&quot;/g, '"')
                .replace(/&#039;/g, "'")
                .replace(/&amp;/g, "&"));
              shuffle(options);
              quizState = {
                question: trivia.question,
                correct_answer: trivia.correct_answer,
                options,
              };
              let msg = `Trivia question:\n${quizState.question}\nOptions:\n`;
              options.forEach((opt, i) => {
                msg += `${i + 1}: ${opt}\n`;
              });
              msg += '\nType your answer option number or "skip".';
              quizArea.textContent = msg;
              userInput.disabled = false;
              userInput.focus();
              return;
            }
          }

          let reply = await generateReply(val);

          // Auto translation if enabled and user language detected different from en
          if (settings.autoTranslate) {
            const userLang = detectLanguage(val);
            if (userLang !== "en") {
              const translated = await translateText(reply, userLang);
              reply = translated;
            }
          }

          await botReplyWithTyping(reply);

          // Sentiment tracking for analytics
          const s = parseSentiment(reply);
          analyticsData.sentimentScores.push(s);
          analyticsData.totalQueries++;
          // Simple categorization (very light)
          if (/quiz|trivia|question/.test(val.toLowerCase())) {
            analyticsData.queriesByCategory["quiz"] = (analyticsData.queriesByCategory["quiz"] || 0) + 1;
          } else if (/\d/.test(val) && /calculate|solve|math|plus|minus|times|divide|\+|\-|\*|\//i.test(val)) {
            analyticsData.queriesByCategory["math"] = (analyticsData.queriesByCategory["math"] || 0) + 1;
          } else {
            analyticsData.queriesByCategory["other"] = (analyticsData.queriesByCategory["other"] || 0) + 1;
          }

          addToMemory("ai", reply);

          // Track queries in preferences for "learning"
          userPreferences.lastPersonality = settings.personality;
          userPreferences.lastQuery = val;
          savePreferences();

        } catch (ex) {
          console.error(ex);
          await botReplyWithTyping(
            "Sorry, something went wrong. Please try again."
          );
        }

        userInput.disabled = false;
        userInput.focus();
      });

      ////////////////////////////////
      // --- Proxy Search Handling ---
      ////////////////////////////////
      proxyBtn.addEventListener("click", async () => {
        const q = proxyInput.value.trim();
        if (!q) return;

        // Detect if it's URL-like: starts with http(s) or has a dot and no spaces
        const isUrl = /^(https?:\/\/)/i.test(q) || (/^[^\s]+\.[^\s]+$/.test(q) && !/\s/.test(q));

        if (isUrl) {
          let urlToLoad = q;
          if (!/^https?:\/\//i.test(q)) {
            // Add https if no protocol
            urlToLoad = "https://" + q;
          }
          loadInIframe(urlToLoad);
          proxyResults.innerHTML = "";
          return;
        }

        proxyResults.innerHTML =
          'Searching <span class="spinner-border spinner-border-sm"></span>';
        proxyIframe.srcdoc =
          "<p style='font-family:sans-serif;color:#666;text-align:center;padding:2rem;'>Search results or embedded website will show here.</p>";
        proxyIframe.style.display = "none";
        proxyLoading.style.display = "block";

        try {
          const ddgData = await duckDuckGoQuery(q);
          if (ddgData && ddgData.RelatedTopics && ddgData.RelatedTopics.length) {
            proxyResults.innerHTML = "";
            for (const item of ddgData.RelatedTopics.slice(0, 10)) {
              if (item.Text && item.FirstURL) {
                const p = document.createElement("p");
                p.innerHTML = `<a href="${item.FirstURL}" target="_blank" rel="noopener noreferrer">${item.Text}</a>`;
                p.style.cursor = "pointer";
                p.setAttribute('tabindex', '0');
                p.addEventListener("click", (e) => {
                  e.preventDefault();
                  loadInIframe(item.FirstURL);
                });
                p.addEventListener("keydown", (e) => {
                  if (e.key === "Enter" || e.key === " ") {
                    e.preventDefault();
                    loadInIframe(item.FirstURL);
                  }
                });
                proxyResults.appendChild(p);
              } else if (item.Topics) {
                item.Topics.slice(0, 3).forEach((topic) => {
                  const p = document.createElement("p");
                  p.innerHTML = `<a href="${topic.FirstURL}" target="_blank" rel="noopener noreferrer">${topic.Text}</a>`;
                  p.style.cursor = "pointer";
                  p.setAttribute('tabindex', '0');
                  p.addEventListener("click", (e) => {
                    e.preventDefault();
                    loadInIframe(topic.FirstURL);
                  });
                  p.addEventListener("keydown", (e) => {
                    if (e.key === "Enter" || e.key === " ") {
                      e.preventDefault();
                      loadInIframe(topic.FirstURL);
                    }
                  });
                  proxyResults.appendChild(p);
                });
              }
            }
            proxyLoading.style.display = "none";
            proxyIframe.style.display = "none";
          } else {
            proxyResults.textContent = "No results found.";
            proxyLoading.style.display = "none";
            proxyIframe.style.display = "none";
          }
        } catch (error) {
          proxyResults.textContent = "Error during search.";
          proxyLoading.style.display = "none";
          proxyIframe.style.display = "none";
        }
      });

      function loadInIframe(url) {
        showProxyLoading(true);
        proxyIframe.src = url;
        proxyResults.innerHTML = "";
        proxyIframe.style.display = "block";

        proxyIframe.onload = () => {
          showProxyLoading(false);
        };
        proxyIframe.onerror = () => {
          proxyLoading.style.display = "none";
          proxyIframe.style.display = "none";
          proxyResults.textContent = "Failed to load page in proxy iframe.";
        };
      }

      function showProxyLoading(show = true) {
        proxyLoading.style.display = show ? "block" : "none";
        proxyIframe.style.display = show ? "none" : "block";
      }

      /////////////////////////////
      // --- Quiz Tools ---
      /////////////////////////////
      startQuizBtn.addEventListener("click", async () => {
        quizArea.textContent = "Loading quiz...";
        const trivia = await openTrivia();
        if (!trivia) {
          quizArea.textContent = "Failed to load question. Try again later.";
          return;
        }
        let options = [...trivia.incorrect_answers, trivia.correct_answer].map(
          s => s.replace(/&quot;/g, '"')
            .replace(/&#039;/g, "'")
            .replace(/&amp;/g, "&")
        );
        shuffle(options);
        quizState = {
          question: trivia.question,
          correct_answer: trivia.correct_answer,
          options,
        };
        let msg = `Trivia question:\n${quizState.question}\nOptions:\n`;
        quizState.options.forEach((o, i) => (msg += `${i + 1}: ${o}\n`));
        msg += `\nType your answer option number in chat or 'skip'.`;
        quizArea.textContent = msg;
      });

      startMathQuizBtn.addEventListener("click", () => {
        if (mathQuizState) {
          Swal.fire("Info", "Math quiz already in progress. Please answer or type 'skip'.", "info");
          return;
        }
        mathQuizState = generateMathQuestion();
        mathQuizArea.textContent = `Math Quiz:\n${mathQuizState.question}\nAnswer as a number or type 'skip' to cancel.`;
      });

      /////////////////////////////
      // --- Voice chat ---
      /////////////////////////////

      let recognition = null;
      let speechSynthesisObj = window.speechSynthesis;
      voiceStopBtn.disabled = true;

      if ("webkitSpeechRecognition" in window || "SpeechRecognition" in window) {
        const SpeechRecognition =
          window.SpeechRecognition || window.webkitSpeechRecognition;
        recognition = new SpeechRecognition();
        recognition.lang = "en-US";
        recognition.interimResults = false;
        recognition.maxAlternatives = 1;

        recognition.onresult = (evt) => {
          const spoken = evt.results[0][0].transcript;
          voiceText.textContent = "You: " + spoken;
          appendMsg(spoken, "user");
          addToMemory("user", spoken);
          replyViaAI(spoken);
        };
        recognition.onerror = (evt) => {
          voiceText.textContent = "Speech recognition error: " + evt.error;
          voiceStopBtn.disabled = true;
          voiceStartBtn.disabled = false;
        };
        recognition.onend = () => {
          voiceText.textContent += " (Stopped)";
          voiceStopBtn.disabled = true;
          voiceStartBtn.disabled = false;
        };
      } else {
        voiceText.textContent = "Speech recognition not supported in this browser.";
        voiceStartBtn.disabled = true;
      }

      async function replyViaAI(text) {
        try {
          const reply = await generateReply(text);
          await botReplyWithTyping(reply);
          addToMemory("ai", reply);
          if (speechSynthesisObj) {
            const utterance = new SpeechSynthesisUtterance(reply);
            utterance.lang = "en-US";
            speechSynthesisObj.speak(utterance);
          }
        } catch {
          await botReplyWithTyping("Sorry, I couldn't process your voice input.");
        }
      }

      voiceStartBtn.addEventListener("click", () => {
        if (recognition) {
          recognition.start();
          voiceText.textContent = "Listening... Speak now";
          voiceStartBtn.disabled = true;
          voiceStopBtn.disabled = false;
        }
      });
      voiceStopBtn.addEventListener("click", () => {
        if (recognition) {
          recognition.stop();
          voiceStartBtn.disabled = false;
          voiceStopBtn.disabled = true;
        }
      });

      /////////////////////////////////
      // --- Export/Import Chat ---
      /////////////////////////////////
      exportJsonBtn.addEventListener("click", () => {
        if (chatMemory.length === 0) {
          Swal.fire("Info", "No chat history to export.", "info");
          return;
        }
        const dataStr = JSON.stringify(chatMemory, null, 2);
        const blob = new Blob([dataStr], { type: "application/json" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = `chat-history-${Date.now()}.json`;
        a.click();
        URL.revokeObjectURL(url);
        if (settings.autoClearOnExport) {
          clearChatBtn.click();
        }
      });

      exportTxtBtn.addEventListener("click", () => {
        if (chatMemory.length === 0) {
          Swal.fire("Info", "No chat history to export.", "info");
          return;
        }
        const txt = chatMemory
          .map((m) => `${m.role.toUpperCase()}:\n${m.text}\n`)
          .join("\n");
        const blob = new Blob([txt], { type: "text/plain" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = `chat-history-${Date.now()}.txt`;
        a.click();
        URL.revokeObjectURL(url);
        if (settings.autoClearOnExport) {
          clearChatBtn.click();
        }
      });

      // Export as a single HTML .ai file that contains chat memory and app state (embeds entire conversation)
      exportHtmlBtn.addEventListener("click", () => {
        if (chatMemory.length === 0) {
          Swal.fire("Info", "No chat history to export.", "info");
          return;
        }
        const aiData = {
          chatMemory,
          settings,
          userPreferences,
        };
        const blobContent = `<!-- Ultimate AI Assistant Data Embed -->\n` +
          `<script type="application/json" id="ultimate-ai-data">\n${JSON.stringify(aiData)}\n</script>\n` +
          `<h1>Exported Ultimate AI Chat History</h1>\n` +
          chatMemory.map(m => `<p><strong>${m.role.toUpperCase()}:</strong> ${m.text.replace(/\n/g, '<br>')}</p>`).join('');

        const htmlBlob = new Blob([
          `<!DOCTYPE html><html lang="en"><head><title>Ultimate AI Assistant Export</title>
          <meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
          <style>body{background:#121212;color:#eee;font-family:sans-serif;padding:1rem;}h1{color:#4a73ff;}</style>
          </head><body>\n${blobContent}\n</body></html>`
        ], { type: "text/html" });

        const url = URL.createObjectURL(htmlBlob);
        const a = document.createElement("a");
        a.href = url;
        a.download = `ultimate-ai-chat-export-${Date.now()}.ai`;
        a.click();
        URL.revokeObjectURL(url);
        if (settings.autoClearOnExport) {
          clearChatBtn.click();
        }
      });

      importJsonInput.addEventListener("change", (e) => {
        const file = e.target.files[0];
        if (!file) return;
        const reader = new FileReader();
        reader.onload = (evt) => {
          try {
            const mem = JSON.parse(evt.target.result);
            if (!Array.isArray(mem)) throw new Error("Invalid format");
            chatMemory = mem;
            quizState = null;
            mathQuizState = null;
            msgs.innerHTML = "";
            chatMemory.forEach((m) => appendMsg(m.text, m.role === "user" ? "user" : "ai", false));
            saveChatMemory();
            quizArea.textContent = "";
            mathQuizArea.textContent = "";
            Swal.fire("Success", "Chat history imported successfully.", "success");
            importJsonInput.value = "";
          } catch {
            Swal.fire("Error", "Invalid JSON file.", "error");
          }
        };
        reader.readAsText(file);
      });

      importHtmlBtn.addEventListener("click", () => {
        importHtmlInput.click();
      });

      importHtmlInput.addEventListener("change", (e) => {
        const file = e.target.files[0];
        if (!file) return;
        const reader = new FileReader();
        reader.onload = (evt) => {
          try {
            // Extract JSON data embedded in special <script id="ultimate-ai-data"> inside HTML
            const htmlContent = evt.target.result;
            const match = htmlContent.match(/<script[^>]*id=["']ultimate-ai-data["'][^>]*>([\s\S]*?)<\/script>/);
            if (!match || !match[1]) throw new Error("No AI data found in file");

            const aiData = JSON.parse(match[1]);
            if (!aiData.chatMemory || !Array.isArray(aiData.chatMemory)) throw new Error("Invalid chat data");

            chatMemory = aiData.chatMemory;
            quizState = null;
            mathQuizState = null;
            settings = Object.assign(settings, aiData.settings || {});
            userPreferences = aiData.userPreferences || {};
            msgs.innerHTML = "";
            chatMemory.forEach((m) => appendMsg(m.text, m.role === "user" ? "user" : "ai", false));
            saveChatMemory();
            applySettingsUI();
            quizArea.textContent = "";
            mathQuizArea.textContent = "";
            Swal.fire("Success", "Chat history imported from .ai file.", "success");
            importHtmlInput.value = "";
          } catch (err) {
            Swal.fire("Error", "Invalid or corrupted .ai file.", "error");
          }
        };
        reader.readAsText(file);
      });

      /////////////////////////////
      // --- Media Upload & ML Image Analysis ---
      /////////////////////////////
      let uploadedImages = [];

      imageUploadInput.addEventListener("change", (e) => {
        const files = Array.from(e.target.files);
        if (!files.length) return;
        for (const file of files) {
          if (!file.type.startsWith("image/")) continue;
          const reader = new FileReader();
          reader.onload = (event) => {
            const imgUrl = event.target.result;
            uploadedImages.push({ file, url: imgUrl });
            renderImagePreviews();
          };
          reader.readAsDataURL(file);
        }
        e.target.value = "";
      });

      function renderImagePreviews() {
        if (!uploadedImages.length) {
          imagePreviewContainer.innerHTML = "<p>No images uploaded yet.</p>";
          return;
        }
        const content = uploadedImages
          .map(
            (img, i) =>
              `<div tabindex="0" aria-label="Uploaded image ${i + 1}" style="margin-bottom:12px;">
                <img src="${img.url}" alt="Uploaded image ${i + 1}" />
                <button 
                  aria-label="Remove image ${i + 1}" 
                  data-index="${i}" 
                  class="btn btn-sm btn-outline-danger mt-1 remove-img-btn" 
                  type="button"
                >Remove</button>
              </div>`
          )
          .join("");
        imagePreviewContainer.innerHTML = content;
        [...imagePreviewContainer.querySelectorAll(".remove-img-btn")].forEach((btn) => {
          btn.addEventListener("click", (ev) => {
            const idx = Number(ev.target.dataset.index);
            uploadedImages.splice(idx, 1);
            renderImagePreviews();
          });
        });
      }

      analyzeImagesBtn.addEventListener("click", () => {
        if (uploadedImages.length === 0) {
          imageAnalysisResults.textContent = "No images to analyze. Please upload first.";
          return;
        }
        imageAnalysisResults.textContent = "Analyzing images...";
        analyzeUploadedImages();
      });

      async function analyzeUploadedImages() {
        if (typeof ml5 === "undefined" || !ml5.imageClassifier) {
          imageAnalysisResults.textContent = "Image analysis unavailable (ml5.js not loaded).";
          return;
        }
        try {
          const classifier = await ml5.imageClassifier("MobileNet");
          let resultsSummary = "";
          for (const imgObj of uploadedImages) {
            // Create image element
            const img = new Image();
            img.src = imgObj.url;
            await new Promise(res => {
              if (img.complete) res();
              else img.onload = res;
              img.onerror = res;
            });
            const results = await classifier.classify(img);
            if (results.length > 0) {
              resultsSummary += `Image: ${imgObj.file.name} - Top Prediction: ${results[0].label} (${(results[0].confidence * 100).toFixed(1)}%)\n`;
            } else {
              resultsSummary += `Image: ${imgObj.file.name} - No prediction available.\n`;
            }
          }
          imageAnalysisResults.textContent = resultsSummary.trim();
          addToMemory("ai", "Image analysis results:\n" + resultsSummary.trim());
          appendMsg("Image analysis results:\n" + resultsSummary.trim(), "ai");
        } catch (error) {
          imageAnalysisResults.textContent = "Error analyzing images.";
          logDebug("Image analysis error:", error);
        }
      }

      /////////////////////////////
      // HTML Editor and Preview
      /////////////////////////////
      htmlTogglePreviewBtn.addEventListener("click", () => {
        const showing = htmlPreview.hasAttribute("hidden") === false;
        if (showing) {
          htmlPreview.setAttribute("hidden", "");
          htmlTogglePreviewBtn.setAttribute("aria-pressed", "false");
          htmlTogglePreviewBtn.textContent = "Toggle Preview";
        } else {
          htmlPreview.removeAttribute("hidden");
          htmlTogglePreviewBtn.setAttribute("aria-pressed", "true");
          htmlTogglePreviewBtn.textContent = "Hide Preview";
          updateHtmlPreview();
        }
      });

      htmlEditorTextarea.addEventListener("input", () => {
        if (!htmlPreview.hasAttribute("hidden")) updateHtmlPreview();
      });

      function updateHtmlPreview() {
        htmlPreview.innerHTML = sanitize(htmlEditorTextarea.value) || "<i>Nothing to preview</i>";
      }

      /////////////////////////////
      // Markdown Notes Editor and Preview
      /////////////////////////////
      renderMarkdownBtn.addEventListener("click", () => {
        const mdText = noteEditor.value;
        const md = window.markdownit ? window.markdownit() : null;
        if (!md) {
          markdownPreview.innerHTML = "<i>Markdown-it library not loaded.</i>";
          return;
        }
        const rendered = md.render(mdText);
        markdownPreview.innerHTML = sanitize(rendered);
      });

      noteEditor.addEventListener("input", () => {
        try {
          localStorage.setItem("ultimateAINotes", noteEditor.value);
        } catch {}
      });

      function loadNotes() {
        try {
          const val = localStorage.getItem("ultimateAINotes");
          if (val) noteEditor.value = val;
        } catch {}
      }

      /////////////////////////////
      // Analytics & Graphs (Chart.js)
      /////////////////////////////
      let analyticsChart = null;

      function renderAnalytics() {
        if (!analyticsChartCtx) return;
        const categories = Object.keys(analyticsData.queriesByCategory);
        const counts = categories.map(c => analyticsData.queriesByCategory[c]);
        const sentimentAvg = analyticsData.sentimentScores.length
          ? (analyticsData.sentimentScores.reduce((a,b) => a+b,0) / analyticsData.sentimentScores.length).toFixed(2)
          : "0";

        const data = {
          labels: categories,
          datasets: [
            {
              label: "Queries Count",
              data: counts,
              backgroundColor: "rgba(74, 115, 255, 0.7)",
            },
          ],
        };

        const config = {
          type: "bar",
          data: data,
          options: {
            scales: {
              y: { beginAtZero: true },
            },
            plugins: {
              legend: { display: false },
              title: {
                display: true,
                text: `Total queries: ${analyticsData.totalQueries}, Avg Sentiment: ${sentimentAvg}`,
                color: "#ddd",
                font: { size: 16 },
              },
            },
          },
        };

        if (analyticsChart) {
          analyticsChart.destroy();
        }
        analyticsChart = new Chart(analyticsChartCtx, config);
      }

      refreshAnalyticsBtn?.addEventListener("click", () => {
        renderAnalytics();
      });

      /////////////////////////////
      // Leaflet.js Map integration
      /////////////////////////////
      let map = null;
      let mapMarker = null;

      function initMap() {
        if (!mapContainer) return;
        map = L.map("map-container").setView([51.505, -0.09], 13);
        L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
          maxZoom: 19,
          attribution: '© OpenStreetMap',
        }).addTo(map);
      }

      async function searchLocationAndSetMarker(location) {
        if (!location) return;

        const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(location)}`;
        try {
          const res = await fetch(url);
          const results = await res.json();
          if (results.length > 0) {
            const loc = results[0];
            const lat = parseFloat(loc.lat);
            const lon = parseFloat(loc.lon);
            map.setView([lat, lon], 13);
            if (mapMarker) map.removeLayer(mapMarker);
            mapMarker = L.marker([lat, lon]).addTo(map).bindPopup(loc.display_name).openPopup();
          } else {
            Swal.fire("No results", "Location not found.", "info");
          }
        } catch (e) {
          Swal.fire("Error", "Failed to search location.", "error");
        }
      }

      mapSearchBtn?.addEventListener("click", () => {
        const loc = mapLocationInput.value.trim();
        if (loc) searchLocationAndSetMarker(loc);
      });

      /////////////////////////////
      // Code helper: Run and formatting
      /////////////////////////////
      runCodeBtn?.addEventListener("click", () => {
        try {
          let output = undefined;
          try {
            output = eval(codeInput.value);
          } catch (innerErr) {
            output = "Error: " + innerErr.message;
          }
          if (typeof output === "object" && output !== null) output = JSON.stringify(output, null, 2);
          codeOutput.textContent = String(output);
        } catch (e) {
          codeOutput.textContent = "Error: " + e.message;
        }
      });

      formatCodeBtn?.addEventListener("click", () => {
        try {
          if (typeof prettier === "undefined") {
            codeOutput.textContent = "Prettier library not loaded.";
            return;
          }
          const formatted = prettier.format(codeInput.value, { parser: "babel" });
          codeInput.value = formatted;
        } catch (e) {
          codeOutput.textContent = "Formatting error: " + e.message;
        }
      });

      /////////////////////////////
      // Utility Tools
      /////////////////////////////
      generateQrBtn?.addEventListener("click", () => {
        const text = qrTextInput.value.trim();
        if (!text) {
          Swal.fire("Info", "Please enter text or URL to generate QR code.", "info");
          return;
        }
        qrCanvas.width = 180;
        qrCanvas.height = 180;
        QRCode.toCanvas(qrCanvas, text, { width: 180 }, (error) => {
          if (error) {
            qrCanvas.getContext("2d").clearRect(0, 0, qrCanvas.width, qrCanvas.height);
            Swal.fire("Error", "Failed to generate QR code.", "error");
          }
        });
      });


      function randomPassword(length = 12) {
        const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+[]{}|;:,.<>?";
        let pass = "";
        for (let i = 0; i < length; i++) {
          pass += chars.charAt(Math.floor(Math.random() * chars.length));
        }
        return pass;
      }

      generatePasswordBtn?.addEventListener("click", () => {
        passwordOutput.value = randomPassword(16);
      });

      copyPasswordBtn?.addEventListener("click", () => {
        if (!passwordOutput.value) {
          Swal.fire("Info", "No password to copy.", "info");
          return;
        }
        if (navigator.clipboard && window.isSecureContext) {
          navigator.clipboard.writeText(passwordOutput.value).then(() => {
            Swal.fire("Copied!", "Password copied to clipboard.", "success");
          }).catch(() => {
            fallbackCopy();
          });
        } else {
          fallbackCopy();
        }
        function fallbackCopy() {
          passwordOutput.select();
          try {
            document.execCommand("copy");
            Swal.fire("Copied!", "Password copied to clipboard.", "success");
          } catch {
            Swal.fire("Error", "Failed to copy password.", "error");
          }
          window.getSelection().removeAllRanges();
          passwordOutput.blur();
        }
      });

      fetchIpBtn?.addEventListener("click", async () => {
        ipInfoOutput.textContent = "Fetching IP info...";
        try {
          const res = await fetch("https://ipapi.co/json/");
          if (!res.ok) throw new Error("Network error");
          const data = await res.json();
          ipInfoOutput.textContent = JSON.stringify(data, null, 2);
        } catch (e) {
          ipInfoOutput.textContent = "Failed to fetch IP info.";
        }
      });

      /////////////////////////////
      // Load from settings/preferences/notes/localStorage
      /////////////////////////////

      /////////////////////////////
      // Attach keyboard shortcuts (Ctrl+1..9 alphabetical for tabs)
      /////////////////////////////
      (() => {
        const tabKeys = {
          1: "tab-ai",
          2: "tab-data",
          3: "tab-quiz",
          4: "tab-search",
          5: "tab-voice",
          6: "tab-export",
          7: "tab-media",
          8: "tab-html",
          9: "tab-text",
          0: "tab-analytics",
          "-": "tab-map",
          "=": "tab-code",
          "[": "tab-tools",
          "]": "tab-settings",
        };
        Object.entries(tabKeys).forEach(([key, id]) => {
          Mousetrap.bind("ctrl+" + key, (e) => {
            e.preventDefault();
            document.querySelector(`button[aria-controls="${id}"]`)?.click();
          });
        });
      })();

      /////////////////////////////
      // Initialization
      /////////////////////////////
      function init() {
        initTabs();
        loadSettings();
        attachSettingsListeners();
        loadChatMemory();
        loadPreferences();
        loadNotes();
        applySettingsUI();
        renderImagePreviews();
        if (mapContainer) initMap();
        renderAnalytics();

        userInput.focus();
      }

      init();
    });
  </script>
  <!-- Include prettier (optional) for code formatting -->
  <script defer src="https://cdn.jsdelivr.net/npm/prettier@2.8.8/standalone.js"></script>
  <script defer src="https://cdn.jsdelivr.net/npm/prettier@2.8.8/parser-babel.js"></script>
</body>
</html>