diff --git a/static/js/settings.js b/static/js/settings.js
index ea05c04..aa221ca 100644
--- a/static/js/settings.js
+++ b/static/js/settings.js
@@ -33,9 +33,9 @@ function backendComputeDevice(id) {
   const b = backendById(id);
   const text = [id, b?.label, b?.speed, b?.latency, b?.quality, b?.ram, b?.purpose, b?.best_for]
     .filter(Boolean).join(' ').toLowerCase();
-  if (/(cloud|api|elevenlabs|groq)/.test(text)) return 'Cloud';
-  if (/(cpu|metal)/.test(text) && !/(cuda|gpu|vram|rtx|dgx)/.test(text)) return 'CPU';
-  if (/(cuda|gpu|vram|rtx|dgx)/.test(text)) return 'CUDA/GPU';
+  if (/\b(cloud|api|elevenlabs|groq)\b/.test(text)) return 'Cloud';
+  if (/\b(cpu|metal)\b/.test(text) && !/\b(cuda|gpu|vram|rtx|dgx)\b/.test(text)) return 'CPU';
+  if (/\b(cuda|gpu|vram|rtx|dgx)\b/.test(text)) return 'CUDA/GPU';
   return 'Unknown';
 }
 
@@ -240,6 +240,152 @@ function _saveEngineContainerNames() {
 window._saveEngineLocalUrls      = _saveEngineLocalUrls;
 window._saveEngineContainerNames = _saveEngineContainerNames;
 
+
+// ── Settings guidance / tooltips ─────────────────────────────────────────
+const SETTINGS_PAGE_GUIDES = {
+  general: {
+    icon: 'mdi-palette-outline',
+    title: 'Start here',
+    text: 'Choose the theme you prefer. Everything else can stay as-is until you connect or change an engine.'
+  },
+  connections: {
+    icon: 'mdi-lan-connect',
+    title: 'Connect engines first',
+    text: 'Most users only need the Docker Engines page: click Connect, then Use as TTS or Use as STT. Edit URLs here only when a service moved or runs on another host.',
+    steps: ['Use host.docker.internal for containers on the same Docker host.', 'Use 192.168.x.x when calling another machine on your LAN.', 'After changing URLs, Save settings, then refresh the target page.']
+  },
+  playback: {
+    icon: 'mdi-play-circle-outline',
+    title: 'Recommended playback',
+    text: 'Auto is the safest default: it streams when the backend supports it and falls back to normal WAV playback when saving or compatibility matters.'
+  },
+  captures: {
+    icon: 'mdi-record-circle-outline',
+    title: 'Voice capture defaults',
+    text: 'These choices affect microphone transcription and STT-to-TTS workflows. Pick a language only if auto-detect makes mistakes often.'
+  },
+  payloads: {
+    icon: 'mdi-code-json',
+    title: 'Advanced tuning',
+    text: 'Leave these as defaults unless a backend needs special parameters. Invalid JSON prevents settings from saving, so change one box at a time.'
+  },
+  storage: {
+    icon: 'mdi-folder-outline',
+    title: 'Match your volume mounts',
+    text: 'These are container paths, not host paths. In your Portainer stack, /voices should point to your real voice folder.'
+  },
+  apikeys: {
+    icon: 'mdi-key-outline',
+    title: 'Local-first defaults',
+    text: 'Local containers usually do not need real keys. Use sk-local only when a compatible server insists on an Authorization header.'
+  },
+  backup: {
+    icon: 'mdi-backup-restore',
+    title: 'Back up before big changes',
+    text: 'Export voices before moving folders, changing stacks, or testing new voice libraries. Keys are intentionally left out.'
+  },
+  logs: {
+    icon: 'mdi-text-box-outline',
+    title: 'Use logs when something feels stuck',
+    text: 'Refresh after a failed request. Error rows usually say which URL, model, or payload needs attention.'
+  },
+  about: {
+    icon: 'mdi-information-outline',
+    title: 'Version and support info',
+    text: 'Use this page to confirm the running app version and open release notes when behavior changed after an update.'
+  }
+};
+
+const SETTINGS_FIELD_HELP = {
+  's-theme-select': ['Theme', 'Changes only your browser UI. It is saved immediately and does not affect generated audio.'],
+  's-tts-url': ['Voice Clone / Base URL', 'Use this for normal cloned WAV voices. Your 8020 Qwen3 voice clone container usually belongs here.'],
+  's-voice-design-url': ['Voice Design URL', 'Use this for creating prompt-designed voices. Your 8021 Qwen3 Voice Design container usually belongs here.'],
+  's-customvoice-url': ['CustomVoice URL', 'Use this for Qwen3 CustomVoice speaker/style presets. Your 8022 container usually belongs here.'],
+  's-tts-stream-url': ['Streaming URL', 'Use this for lower-latency playback. Your 8023 streaming container usually belongs here.'],
+  's-kokoro-url': ['Kokoro URL', 'Small, fast OpenAI-compatible TTS. Good as a lightweight fallback, but it does not clone your WAV identities.'],
+  's-vibevoice-url': ['VibeVoice URL', 'Simple local TTS service. Good for experiments; not every Voice Creator feature maps to it.'],
+  's-xtts-url': ['XTTS v2 URL', 'Use only if an XTTS API server is running. It can clone from short references but has a different voice model than Qwen3.'],
+  's-nvidia-router-url': ['NVIDIA router URL', 'Router endpoint that can expose NVIDIA speech services through one URL. Handy when Parakeet and Magpie share a gateway.'],
+  's-nvidia-tts-url': ['NVIDIA Magpie TTS URL', 'Direct Magpie TTS endpoint with fixed speakers. Good quality, but not your cloned WAV voice library.'],
+  's-nvidia-asr-url': ['NVIDIA Parakeet ASR URL', 'Direct speech-to-text endpoint. Use this for fast local transcription when Parakeet is running.'],
+  's-nvidia-zeroshot-url': ['NVIDIA Zeroshot NIM URL', 'Experimental clone endpoint that uses an audio prompt. Leave empty unless that NIM is running.'],
+  's-nvidia-flow-url': ['NVIDIA Flow NIM URL', 'Experimental clone endpoint that uses an audio prompt plus transcript. Leave empty unless that NIM is running.'],
+  's-whisper-url': ['Active STT URL', 'Main transcription URL used by the app. The quick buttons below copy known engine URLs into this field.'],
+  's-faster-whisper-url': ['faster-whisper URL', 'Fast local Whisper endpoint, often the best general-purpose STT choice when GPU acceleration is available.'],
+  's-whisper-cpp-url': ['whisper.cpp URL', 'Lightweight Whisper server for CPU or small CUDA setups. Useful fallback when heavier STT is offline.'],
+  's-groq-api-key': ['Groq API key', 'Only needed for Groq cloud STT or LLM. Keep empty if you use only local services.'],
+  's-tts-stream-mode': ['Playback mode', 'Auto is recommended. Streaming feels faster; buffered is more compatible and better for saving files.'],
+  's-tts-backend': ['Request style', 'Choose the payload format expected by the backend connected to the normal TTS URL. Qwen3/OpenAI is the usual local stack default.'],
+  's-stt-language': ['Default language', 'Auto-detect is usually fine. Set this when transcription keeps choosing the wrong language.'],
+  's-stt-preferred-backend': ['Preferred STT backend', 'Overrides the active STT URL only for capture workflows. Leave default if you want one global STT setting.'],
+  's-llm-url': ['LLM base URL', 'OpenAI-compatible chat endpoint used for rewrites, casting, refinement, and voice-design assistance.'],
+  's-auto-refine': ['Auto-refine', 'When enabled, the app sends transcripts to the LLM for cleanup automatically. Leave off if you want raw transcripts.'],
+  's-refine-model': ['Refinement model', 'Optional model override for transcript cleanup. Leave empty to use the current LLM default.'],
+  's-captures-default-voice': ['Default playback voice', 'Preselects a TTS voice in capture workflows so you do not have to choose it every time.'],
+  's-tts-extra-voice-clone': ['Voice Clone params', 'Advanced JSON sent to the 8020 backend. Temperature/top_p/seed are common controls.'],
+  's-tts-extra-streaming': ['Streaming params', 'Advanced JSON sent to the streaming backend. Keep close to Voice Clone params for comparable sound.'],
+  's-tts-extra-customvoice': ['CustomVoice params', 'Advanced JSON sent to CustomVoice. Use only backend-supported fields.'],
+  's-tts-extra-voice-design': ['Voice Design params', 'Advanced JSON sent when generating prompt-designed voices.'],
+  's-tts-extra-nvidia-magpie': ['Magpie params', 'Usually empty. Magpie uses fixed speakers and may reject unknown fields.'],
+  's-tts-extra-nvidia-zeroshot': ['Zeroshot params', 'Optional multipart fields for the clone NIM. The app already sends text, language, and audio prompt.'],
+  's-tts-extra-nvidia-flow': ['Flow params', 'Optional multipart fields for Flow. The app also sends reference transcript when available.'],
+  's-tts-extra-kokoro': ['Kokoro params', 'Usually empty. The selected Kokoro voice carries most of the useful information.'],
+  's-tts-extra-vibevoice': ['VibeVoice params', 'Usually empty. VibeVoice commonly only needs text.'],
+  's-voices-scan-dir': ['Voice scan directory', 'Container path that contains active_voices and hidden_voices. Usually /voices.'],
+  's-output-dir': ['Active voices directory', 'Container path where new cloned or exported voices are saved. Usually /voices/active_voices.'],
+  's-tts-key': ['TTS API key', 'Optional. For local OpenAI-compatible servers, sk-local or empty usually works.'],
+  's-vd-key': ['Voice Design API key', 'Optional. Use only if your Voice Design backend requires Authorization.'],
+  's-whisper-key': ['Whisper API key', 'Optional. Needed for cloud STT, usually empty for local Whisper-compatible containers.']
+};
+
+
+function enhanceSettingsHelp(root = document) {
+  const scope = root && root.querySelectorAll ? root : document;
+  scope.querySelectorAll('.s-settings-page').forEach(page => {
+    const key = page.dataset.page;
+    const guide = SETTINGS_PAGE_GUIDES[key];
+    const card = page.querySelector('.card');
+    const head = card?.querySelector('.s-page-head');
+    if (!guide || !card || !head || card.querySelector('.settings-guide')) return;
+    const box = document.createElement('div');
+    box.className = 'settings-guide';
+    box.innerHTML = `
+      <div class="settings-guide-icon"><span class="mdi ${escHtml(guide.icon)}"></span></div>
+      <div class="settings-guide-body">
+        <strong>${escHtml(guide.title)}</strong>
+        <p>${escHtml(guide.text)}</p>
+        ${guide.steps ? `<ul>${guide.steps.map(s => `<li>${escHtml(s)}</li>`).join('')}</ul>` : ''}
+      </div>`;
+    head.insertAdjacentElement('afterend', box);
+  });
+
+  Object.entries(SETTINGS_FIELD_HELP).forEach(([id, help]) => {
+    const control = scope.getElementById ? scope.getElementById(id) : document.getElementById(id);
+    if (!control) return;
+    const field = control.closest('.s-field');
+    const label = field?.querySelector('label');
+    if (!field || !label) return;
+    const [title, detail] = help;
+    if (!label.querySelector('.s-help-tip')) {
+      const tipId = `${id}-tip`;
+      const wrap = document.createElement('span');
+      wrap.className = 's-help-tip';
+      wrap.innerHTML = `<button type="button" aria-label="Help for ${escHtml(title)}" aria-describedby="${escHtml(tipId)}"><span class="mdi mdi-information-outline" aria-hidden="true"></span></button><span class="s-tooltip" id="${escHtml(tipId)}" role="tooltip">${escHtml(detail)}</span>`;
+      label.appendChild(wrap);
+    }
+    if (!field.querySelector('.s-field-tip')) {
+      const tip = document.createElement('span');
+      tip.className = 's-field-tip';
+      tip.textContent = detail;
+      const hint = field.querySelector('.s-hint');
+      if (hint) hint.insertAdjacentElement('afterend', tip);
+      else field.appendChild(tip);
+    }
+    if (!control.getAttribute('aria-label')) control.setAttribute('aria-label', title);
+    if (!control.getAttribute('title')) control.setAttribute('title', detail);
+  });
+}
+
 async function loadSettings() {
   const s = await fetch('/api/settings').then(r => r.json());
   $('s-whisper-url').value           = s.whisper_url          || '';
@@ -325,6 +471,7 @@ async function loadSettings() {
       (window._voices || []).map(v => `<option value="${escHtml(v.name)}" ${v.name === cur ? 'selected' : ''}>${escHtml(v.display_name || v.name)}</option>`).join('');
   }
   await refreshTtsBackendAvailability();
+  enhanceSettingsHelp(document);
   renderSettingsAbout();
 }
 
@@ -437,6 +584,16 @@ document.addEventListener('change', e => {
   if (e.target.id === 's-theme-select') applyTheme(e.target.value);
 });
 
+
+window.enhanceSettingsHelp = enhanceSettingsHelp;
+setTimeout(() => enhanceSettingsHelp(document), 0);
+const _settingsHelpObserver = new MutationObserver((mutations) => {
+  if (mutations.some(m => Array.from(m.addedNodes || []).some(n => n.nodeType === 1 && (n.matches?.('.s-settings-page') || n.querySelector?.('.s-settings-page'))))) {
+    enhanceSettingsHelp(document);
+  }
+});
+if (document.body) _settingsHelpObserver.observe(document.body, { childList: true, subtree: true });
+
 // ── Voice ID field (tab 3) ────────────────────────────────────────────────
 
 function validateVoiceId(v) { return /^[A-Za-z0-9_\-\.]+$/.test(v); }
diff --git a/static/style.css b/static/style.css
index d295705..10acda2 100644
--- a/static/style.css
+++ b/static/style.css
@@ -432,6 +432,25 @@ audio { width: 100%; }
 .s-eye-btn { background:var(--panel); border:1px solid var(--border); color:var(--subtext); border-radius:var(--radius); padding:0 13px; font-size:15px; cursor:pointer; flex-shrink:0; transition:color .15s; }
 .s-eye-btn:hover { color:var(--text); }
 
+
+.settings-guide { display: grid; grid-template-columns: 34px minmax(0,1fr); gap: 12px; align-items: start; margin: 14px 0 4px; padding: 12px 14px; border: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border)); border-radius: 8px; background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
+.settings-guide-icon { width: 34px; height: 34px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); font-size: 18px; }
+.settings-guide-body { min-width: 0; }
+.settings-guide-body strong { display: block; font-size: 13px; color: var(--text); margin-bottom: 3px; }
+.settings-guide-body p { margin: 0; color: var(--subtext); font-size: 12px; line-height: 1.5; }
+.settings-guide-body ul { margin: 7px 0 0; padding-left: 18px; color: var(--subtext); font-size: 12px; line-height: 1.55; }
+.s-field label { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
+.s-help-tip { position: relative; display: inline-flex; align-items: center; }
+.s-help-tip button { width: 18px; height: 18px; border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border)); border-radius: 50%; background: color-mix(in srgb, var(--accent) 7%, var(--panel)); color: var(--accent); display: inline-flex; align-items: center; justify-content: center; padding: 0; cursor: help; font-size: 12px; line-height: 1; }
+.s-help-tip button:hover, .s-help-tip button:focus-visible { background: var(--accent); color: #fff; }
+.s-tooltip { position: absolute; left: 50%; bottom: calc(100% + 8px); transform: translateX(-50%) translateY(3px); width: min(300px, calc(100vw - 40px)); padding: 9px 10px; border-radius: 7px; background: var(--text); color: var(--bg); font-size: 12px; line-height: 1.45; font-weight: 500; box-shadow: var(--shadow); opacity: 0; pointer-events: none; z-index: 250; transition: opacity .14s ease, transform .14s ease; }
+.s-tooltip::after { content: ''; position: absolute; left: 50%; top: 100%; transform: translateX(-50%); border: 6px solid transparent; border-top-color: var(--text); }
+.s-help-tip:hover .s-tooltip, .s-help-tip:focus-within .s-tooltip { opacity: 1; transform: translateX(-50%) translateY(0); }
+.s-field-tip { display: block; border-left: 3px solid color-mix(in srgb, var(--accent) 32%, var(--border)); padding: 6px 9px; border-radius: 0 6px 6px 0; background: color-mix(in srgb, var(--accent) 4%, var(--panel)); color: var(--subtext); font-size: 12px; line-height: 1.45; }
+.s-field:focus-within .s-field-tip { color: var(--text); background: color-mix(in srgb, var(--accent) 7%, var(--panel)); border-left-color: var(--accent); }
+.s-page-actions { position: sticky; bottom: 0; background: color-mix(in srgb, var(--surface) 94%, transparent); backdrop-filter: blur(8px); margin: 0 -2px -2px; padding: 14px 2px 2px; z-index: 5; }
+@media (max-width: 700px) { .settings-guide { grid-template-columns: 1fr; } .settings-guide-icon { display: none; } .s-tooltip { display: none; } }
+
 /* STT layout */
 .stt-settings-grid { grid-template-columns:minmax(320px,.65fr) minmax(240px,1fr); }
 .settings-mini-actions { margin-top:4px; gap:8px; flex-wrap:wrap; }
