{"id":5832,"date":"2026-06-28T08:20:55","date_gmt":"2026-06-28T08:20:55","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=5832"},"modified":"2026-07-23T04:23:45","modified_gmt":"2026-07-23T04:23:45","slug":"interactive-learning-studio-pro","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/interactive-learning-studio-pro\/","title":{"rendered":"Interactive Learning Studio Pro"},"content":{"rendered":"<div class=\"pth-hero-section\">\n<div class=\"pth-hero-content\">\n<h2>Interactive Learning Studio<\/h2>\n<p>Create crossword puzzles, word searches, drag-sort activities and memory match games free with Interactive Learning Studio Pro \u2014 offline, no login required.<\/p>\n<div id=\"pth-toc-placeholder\"><\/div>\n<\/p>\n<\/div>\n<div class=\"pth-hero-image\">\n    <img data-no-lazy=\"1\"\n         src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/06\/Interactive-Learning-Studio-800x447.jpeg\"\n         width=\"800\"\n         height=\"447\"\n        alt=\"CSV to Label Maker\"\n         fetchpriority=\"high\"\n         loading=\"eager\"\n         decoding=\"async\"\n         style=\"width:100%; height:auto; display:block;\">\n  <\/div>\n<\/div>\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#\ud83d\udd34-why-teachers-and-trainers-choose-this-interactive-learning-studio\">\ud83d\udd34 Why Teachers and Trainers Choose This Interactive Learning Studio<\/a><\/li><li><a href=\"#\ud83d\udfe1-five-activity-types-what-each-one-does-and-when-to-use-it\">\ud83d\udfe1 Five Activity Types \u2014 What Each One Does and When to Use It<\/a><ul><li><a href=\"#\ud83d\udfe2-crossword-creator-assessment-through-recall\">\ud83d\udfe2 Crossword Creator \u2014 Assessment Through Recall<\/a><\/li><li><a href=\"#\ud83d\udfe2-word-search-generator-recognition-before-recall\">\ud83d\udfe2 Word Search Generator \u2014 Recognition Before Recall<\/a><\/li><li><a href=\"#\ud83d\udfe2-drag-sort-sequencing-and-process-thinking\">\ud83d\udfe2 Drag &amp; Sort \u2014 Sequencing and Process Thinking<\/a><\/li><li><a href=\"#\ud83d\udfe2-match-pairs-and-memory-match-associative-learning\">\ud83d\udfe2 Match Pairs and Memory Match \u2014 Associative Learning<\/a><\/li><\/ul><\/li><li><a href=\"#\ud83d\udd34-the-ai-assistant-tab-three-providers-one-workflow\">\ud83d\udd34 The AI Assistant Tab \u2014 Three Providers, One Workflow<\/a><\/li><li><a href=\"#\ud83d\udfe1-exporting-activities-for-classroom-use\">\ud83d\udfe1 Exporting Activities for Classroom Use<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<div id=\"pth-ils-wrapper\">\r\n\r\n<style data-no-optimize=\"1\">\r\n\/* ============================================================\r\n   PTH Interactive Learning Studio Pro v2.0 \u2014 Shell CSS\r\n   Scoped to #pth-ils-wrapper\r\n   ============================================================ *\/\r\n\r\n#pth-ils-wrapper *,\r\n#pth-ils-wrapper *::before,\r\n#pth-ils-wrapper *::after {\r\n  box-sizing: border-box;\r\n  min-width: 0;\r\n}\r\n\r\n#pth-ils-wrapper {\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  background: #f8fafc;\r\n  border-radius: 16px;\r\n  padding: 20px;\r\n  color: #1e293b;\r\n  font-weight: 500;\r\n  opacity: 1;\r\n  display: block;\r\n}\r\n\r\n\/* \u2500\u2500 Header \u2500\u2500 *\/\r\n.pth-ils-header {\r\n  margin-bottom: 16px;\r\n}\r\n.pth-ils-header h2 {\r\n  color: #1d4ed8;\r\n  font-size: 1.5rem;\r\n  font-weight: 800;\r\n  margin: 0 0 6px;\r\n}\r\n.pth-ils-header p {\r\n  color: #334155;\r\n  font-size: 0.88rem;\r\n  margin: 0;\r\n  font-weight: 500;\r\n}\r\n.pth-ils-meta-bar {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 8px;\r\n  flex-wrap: wrap;\r\n  margin-bottom: 10px;\r\n}\r\n.pth-version-badge {\r\n  background: #eff6ff;\r\n  color: #1d4ed8;\r\n  font-size: 0.72rem;\r\n  font-weight: 700;\r\n  padding: 3px 10px;\r\n  border-radius: 20px;\r\n  border: 1px solid #bfdbfe;\r\n}\r\n.pth-status-offline {\r\n  background: #f0fdf4;\r\n  color: #047857;\r\n  font-size: 0.72rem;\r\n  font-weight: 700;\r\n  padding: 3px 10px;\r\n  border-radius: 20px;\r\n  border: 1px solid #bbf7d0;\r\n}\r\n\r\n\/* \u2500\u2500 Global Toolbar \u2500\u2500 *\/\r\n.pth-ils-toolbar {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 8px;\r\n  margin-bottom: 14px;\r\n  padding: 10px 14px;\r\n  background: #fff;\r\n  border: 1px solid #e2e8f0;\r\n  border-radius: 10px;\r\n  align-items: center;\r\n}\r\n.pth-ils-toolbar-label {\r\n  font-size: 0.78rem;\r\n  font-weight: 700;\r\n  color: #334155;\r\n  margin-right: 4px;\r\n}\r\n\r\n\/* \u2500\u2500 Buttons \u2500\u2500 *\/\r\n.pth-ils-btn {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  gap: 5px;\r\n  padding: 8px 14px;\r\n  border-radius: 8px;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  font-size: 0.82rem;\r\n  font-weight: 700;\r\n  cursor: pointer;\r\n  border: none;\r\n  transition: background 0.15s, transform 0.1s;\r\n  line-height: 1;\r\n  white-space: nowrap;\r\n}\r\n.pth-ils-btn:active { transform: scale(0.97); }\r\n.pth-ils-btn-primary  { background: #2563eb; color: #fff; }\r\n.pth-ils-btn-primary:hover  { background: #1d4ed8; }\r\n.pth-ils-btn-success  { background: #059669; color: #fff; }\r\n.pth-ils-btn-success:hover  { background: #047857; }\r\n.pth-ils-btn-danger   { background: #dc2626; color: #fff; }\r\n.pth-ils-btn-danger:hover   { background: #991b1b; }\r\n.pth-ils-btn-purple   { background: #7c3aed; color: #fff; }\r\n.pth-ils-btn-purple:hover   { background: #6d28d9; }\r\n.pth-ils-btn-amber    { background: #d97706; color: #fff; }\r\n.pth-ils-btn-amber:hover    { background: #92400e; }\r\n.pth-ils-btn-outline  {\r\n  background: #fff;\r\n  color: #334155;\r\n  border: 2px solid #e2e8f0;\r\n}\r\n.pth-ils-btn-outline:hover  { border-color: #2563eb; color: #1d4ed8; }\r\n.pth-ils-btn-sm { padding: 6px 11px; font-size: 0.78rem; }\r\n.pth-ils-btn-row {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 8px;\r\n  margin-bottom: 12px;\r\n  align-items: center;\r\n}\r\n\r\n\/* \u2500\u2500 Tab Navigation \u2500\u2500 *\/\r\n.pth-ils-tabs {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 6px;\r\n  margin-bottom: 16px;\r\n  border-bottom: 2px solid #e2e8f0;\r\n  padding-bottom: 10px;\r\n}\r\n.pth-ils-tab-btn {\r\n  background: #fff;\r\n  border: 2px solid #e2e8f0;\r\n  color: #334155;\r\n  font-size: 0.82rem;\r\n  font-weight: 700;\r\n  padding: 8px 14px;\r\n  border-radius: 8px;\r\n  cursor: pointer;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  white-space: nowrap;\r\n  transition: all 0.15s;\r\n}\r\n.pth-ils-tab-btn:hover {\r\n  border-color: #2563eb;\r\n  color: #1d4ed8;\r\n  background: #eff6ff;\r\n}\r\n.pth-ils-tab-btn.pth-ils-active {\r\n  background: #2563eb;\r\n  border-color: #2563eb;\r\n  color: #fff;\r\n}\r\n\r\n\/* \u2500\u2500 Tab Panels \u2500\u2500 *\/\r\n.pth-ils-panel {\r\n  display: none;\r\n  opacity: 1;\r\n}\r\n.pth-ils-panel.pth-ils-panel-active {\r\n  display: block;\r\n}\r\n\r\n\/* \u2500\u2500 Two Column Layout \u2500\u2500 *\/\r\n.pth-ils-layout {\r\n  display: grid;\r\n  grid-template-columns: 1.8fr 1fr;\r\n  gap: 18px;\r\n  align-items: start;\r\n}\r\n.pth-ils-layout.pth-ils-full {\r\n  grid-template-columns: 1fr;\r\n}\r\n.pth-ils-layout.pth-ils-full .pth-ils-sidebar {\r\n  display: none;\r\n}\r\n\r\n\/* \u2500\u2500 Cards \u2500\u2500 *\/\r\n.pth-ils-card {\r\n  background: #fff;\r\n  border: 1px solid #e2e8f0;\r\n  border-radius: 12px;\r\n  padding: 18px;\r\n  margin-bottom: 14px;\r\n}\r\n.pth-ils-card h3 {\r\n  color: #0f172a;\r\n  font-size: 0.95rem;\r\n  font-weight: 800;\r\n  margin: 0 0 12px;\r\n}\r\n.pth-ils-card-dark {\r\n  background: #0f172a;\r\n  border-color: #1e293b;\r\n  border-radius: 10px;\r\n  padding: 14px;\r\n  margin-top: 10px;\r\n}\r\n\r\n\/* \u2500\u2500 Form Elements \u2500\u2500 *\/\r\n.pth-ils-label {\r\n  display: block;\r\n  color: #334155;\r\n  font-size: 0.82rem;\r\n  font-weight: 700;\r\n  margin-bottom: 4px;\r\n}\r\n.pth-ils-input,\r\n.pth-ils-select,\r\n.pth-ils-textarea {\r\n  width: 100%;\r\n  padding: 8px 11px;\r\n  border: 2px solid #e2e8f0;\r\n  border-radius: 8px;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  font-size: 0.88rem;\r\n  color: #1e293b;\r\n  font-weight: 500;\r\n  background: #f8fafc;\r\n  outline: none;\r\n  transition: border-color 0.15s;\r\n  margin-bottom: 10px;\r\n  display: block;\r\n}\r\n.pth-ils-input:focus,\r\n.pth-ils-select:focus,\r\n.pth-ils-textarea:focus {\r\n  border-color: #2563eb;\r\n  background: #fff;\r\n}\r\n.pth-ils-textarea {\r\n  resize: vertical;\r\n  min-height: 130px;\r\n  font-family: monospace;\r\n  font-size: 0.83rem;\r\n  line-height: 1.6;\r\n}\r\n\r\n\/* \u2500\u2500 Info \/ Status Boxes \u2500\u2500 *\/\r\n.pth-ils-info   { background:#eff6ff; border:1px solid #bfdbfe; color:#1d4ed8; }\r\n.pth-ils-ok     { background:#f0fdf4; border:1px solid #bbf7d0; color:#047857; }\r\n.pth-ils-warn   { background:#fefce8; border:1px solid #fef08a; color:#92400e; }\r\n.pth-ils-err    { background:#fef2f2; border:1px solid #fecaca; color:#991b1b; }\r\n.pth-ils-info, .pth-ils-ok, .pth-ils-warn, .pth-ils-err {\r\n  border-radius: 8px;\r\n  padding: 10px 14px;\r\n  font-size: 0.85rem;\r\n  font-weight: 700;\r\n  margin-bottom: 10px;\r\n}\r\n\r\n\/* \u2500\u2500 Code output box \u2500\u2500 *\/\r\n.pth-ils-code-box {\r\n  background: #0f172a;\r\n  border-radius: 8px;\r\n  padding: 12px 14px;\r\n  margin-top: 10px;\r\n}\r\n.pth-ils-code-box textarea {\r\n  width: 100%;\r\n  background: transparent;\r\n  border: none;\r\n  color: #7dd3fc;\r\n  font-family: 'Courier New', monospace;\r\n  font-size: 0.78rem;\r\n  resize: vertical;\r\n  min-height: 100px;\r\n  outline: none;\r\n  line-height: 1.5;\r\n}\r\n\r\n\/* \u2500\u2500 Sidebar stat rows \u2500\u2500 *\/\r\n.pth-ils-stat-row {\r\n  display: flex;\r\n  justify-content: space-between;\r\n  align-items: center;\r\n  padding: 6px 0;\r\n  border-bottom: 1px solid #f1f5f9;\r\n  font-size: 0.83rem;\r\n}\r\n.pth-ils-stat-row:last-child { border-bottom: none; }\r\n.pth-ils-stat-label { color: #334155; font-weight: 600; }\r\n.pth-ils-stat-val   { color: #1d4ed8; font-weight: 800; }\r\n\r\n\/* \u2500\u2500 Toast \u2500\u2500 *\/\r\n#pth-ils-toast-wrap {\r\n  position: fixed;\r\n  bottom: 24px;\r\n  right: 24px;\r\n  z-index: 999999;\r\n  display: flex;\r\n  flex-direction: column;\r\n  gap: 8px;\r\n  pointer-events: none;\r\n}\r\n.pth-ils-toast {\r\n  padding: 11px 18px;\r\n  border-radius: 8px;\r\n  font-size: 0.85rem;\r\n  font-weight: 700;\r\n  color: #fff;\r\n  box-shadow: 0 4px 14px rgba(0,0,0,0.18);\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  animation: pthIlsToastIn 0.25s ease;\r\n  pointer-events: none;\r\n  max-width: 300px;\r\n}\r\n.pth-ils-t-success { background: #059669; }\r\n.pth-ils-t-error   { background: #dc2626; }\r\n.pth-ils-t-info    { background: #2563eb; }\r\n.pth-ils-t-warn    { background: #d97706; }\r\n@keyframes pthIlsToastIn {\r\n  from { opacity: 0; transform: translateY(8px) scale(0.97); }\r\n  to   { opacity: 1; transform: translateY(0) scale(1); }\r\n}\r\n\r\n\/* \u2500\u2500 Divider \u2500\u2500 *\/\r\n.pth-ils-divider {\r\n  border: none;\r\n  border-top: 1px solid #e2e8f0;\r\n  margin: 12px 0;\r\n}\r\n\r\n\/* \u2500\u2500 Responsive \u2500\u2500 *\/\r\n@media (max-width: 768px) {\r\n  #pth-ils-wrapper {\r\n    padding: 10px;\r\n    border-radius: 0;\r\n    background: transparent;\r\n  }\r\n  .pth-ils-layout {\r\n    grid-template-columns: 1fr !important;\r\n  }\r\n  .pth-ils-sidebar { display: none !important; }\r\n  .pth-ils-tab-btn { font-size: 0.74rem; padding: 6px 10px; }\r\n  .pth-ils-header h2 { font-size: 1.2rem; }\r\n}\r\n\r\n\/* \u2500\u2500 PRINT FIX \u2500\u2500 *\/\r\n@media print {\r\n  * {\r\n    -webkit-print-color-adjust: exact !important;\r\n    print-color-adjust: exact !important;\r\n    color-adjust: exact !important;\r\n  }\r\n  body > *:not(#pth-ils-wrapper),\r\n  .site-header,\r\n  .site-footer,\r\n  .wp-block-post-title,\r\n  #wpadminbar,\r\n  nav,\r\n  .pth-ils-header,\r\n  .pth-ils-toolbar,\r\n  .pth-ils-tabs,\r\n  .pth-ils-sidebar,\r\n  .pth-ils-btn-row,\r\n  .pth-ils-card:has(textarea),\r\n  .pth-ils-card:has(select),\r\n  .pth-ils-code-box,\r\n  .related-tools-wrap,\r\n  [class*=\"pth-ils-export\"] {\r\n    display: none !important;\r\n  }\r\n  #pth-ils-wrapper {\r\n    padding: 0 !important;\r\n    background: transparent !important;\r\n  }\r\n  .pth-ils-layout {\r\n    grid-template-columns: 1fr !important;\r\n  }\r\n  .pth-ils-panel {\r\n    display: block !important;\r\n  }\r\n  .pth-ils-panel:not(.pth-ils-panel-active) {\r\n    display: none !important;\r\n  }\r\n}\r\n<\/style>\r\n\r\n<div class=\"pth-ils-header\">\r\n  <div class=\"pth-ils-meta-bar\">\r\n    <span class=\"pth-version-badge\">v2.0<\/span>\r\n    <span class=\"pth-status-offline\">\ud83d\udd12 100% Offline<\/span>\r\n  <\/div>\r\n  <h2>\ud83c\udf93 Interactive Learning Studio Pro<\/h2>\r\n  <p>Create crossword puzzles, word searches, drag-sort activities, matching games & memory card games \u2014 free, offline, no login required.<\/p>\r\n<\/div>\r\n\r\n<div class=\"pth-ils-toolbar\">\r\n  <span class=\"pth-ils-toolbar-label\">Tools:<\/span>\r\n  <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-ils-sample-btn\">\ud83d\udca1 Load Sample<\/button>\r\n  <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-ils-fullwidth-btn\">\u26f6 Full Width<\/button>\r\n  <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-ils-clear-btn\">\ud83d\uddd1\ufe0f Clear<\/button>\r\n<\/div>\r\n\r\n<div class=\"pth-ils-tabs\" role=\"tablist\" aria-label=\"Learning Studio activities\">\r\n  <button class=\"pth-ils-tab-btn pth-ils-active\" data-tab=\"crossword\"  role=\"tab\" aria-selected=\"true\" >\ud83e\udde9 Crossword<\/button>\r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"wordsearch\" role=\"tab\" aria-selected=\"false\">\ud83d\udd0d Word Search<\/button>\r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"sort\"       role=\"tab\" aria-selected=\"false\">\ud83d\udd04 Drag & Sort<\/button>\r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"match\"      role=\"tab\" aria-selected=\"false\">\ud83d\udd17 Match Pairs<\/button>\r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"memory\"     role=\"tab\" aria-selected=\"false\">\ud83c\udfb4 Memory Match<\/button>\r\n  \r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"hotspots\"   role=\"tab\" aria-selected=\"false\">\ud83d\uddbc\ufe0f Image Hotspots<\/button>\r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"blanks\"     role=\"tab\" aria-selected=\"false\">\ud83d\udcdd Fill in Blanks<\/button>\r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"bingo\"      role=\"tab\" aria-selected=\"false\">\ud83d\udd22 Bingo Maker<\/button>\r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"flashcards\" role=\"tab\" aria-selected=\"false\">\ud83d\udcc7 Flashcards<\/button>\r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"cryptogram\" role=\"tab\" aria-selected=\"false\">\ud83d\udd75\ufe0f\u200d\u2642\ufe0f Cryptogram<\/button>\r\n  \r\n  <button class=\"pth-ils-tab-btn\"                data-tab=\"ai\"         role=\"tab\" aria-selected=\"false\">\ud83e\udd16 AI Assistant<\/button>\r\n<\/div>\r\n\r\n<div class=\"pth-ils-panel pth-ils-panel-active\" id=\"pth-tab-crossword\"  role=\"tabpanel\"><\/div>\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-wordsearch\" role=\"tabpanel\"><\/div>\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-sort\"       role=\"tabpanel\"><\/div>\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-match\"      role=\"tabpanel\"><\/div>\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-memory\"     role=\"tabpanel\"><\/div>\r\n\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-hotspots\"   role=\"tabpanel\"><\/div>\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-blanks\"     role=\"tabpanel\"><\/div>\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-bingo\"      role=\"tabpanel\"><\/div>\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-flashcards\" role=\"tabpanel\"><\/div>\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-cryptogram\" role=\"tabpanel\"><\/div>\r\n\r\n<div class=\"pth-ils-panel\"                      id=\"pth-tab-ai\"         role=\"tabpanel\"><\/div>\r\n\r\n<div id=\"pth-ils-toast-wrap\" role=\"status\" aria-live=\"polite\"><\/div>\r\n\r\n<\/div><script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  \/* Shared utilities \u2014 attached to window so tab snippets can use them *\/\r\n  window.pthILS = window.pthILS || {};\r\n\r\n  \/* \u2500\u2500 Toast \u2500\u2500 *\/\r\n  window.pthILS.toast = function (msg, type) {\r\n    var wrap = document.getElementById('pth-ils-toast-wrap');\r\n    if (!wrap) return;\r\n    var t = document.createElement('div');\r\n    t.className = 'pth-ils-toast pth-ils-t-' + (type || 'info');\r\n    t.textContent = msg;\r\n    wrap.appendChild(t);\r\n    setTimeout(function () { if (t.parentNode) t.parentNode.removeChild(t); }, 3000);\r\n  };\r\n\r\n  \/* \u2500\u2500 Helpers \u2500\u2500 *\/\r\n  window.pthILS.el = function (id) { return document.getElementById(id); };\r\n\r\n  window.pthILS.shuffle = function (arr) {\r\n    var a = arr.slice();\r\n    for (var i = a.length - 1; i > 0; i--) {\r\n      var j = Math.floor(Math.random() * (i + 1));\r\n      var tmp = a[i]; a[i] = a[j]; a[j] = tmp;\r\n    }\r\n    return a;\r\n  };\r\n\r\n  window.pthILS.parseLines = function (raw) {\r\n    return raw.split('\\n')\r\n      .map(function (l) { return l.trim(); })\r\n      .filter(function (l) { return l.length > 0; });\r\n  };\r\n\r\n  window.pthILS.parsePairs = function (raw, sep) {\r\n    sep = sep || ':';\r\n    var out = [];\r\n    window.pthILS.parseLines(raw).forEach(function (line) {\r\n      var idx = line.indexOf(sep);\r\n      if (idx > 0) {\r\n        out.push({\r\n          a: line.substring(0, idx).trim(),\r\n          b: line.substring(idx + 1).trim()\r\n        });\r\n      }\r\n    });\r\n    return out;\r\n  };\r\n\r\n  window.pthILS.esc = function (s) {\r\n    return (s || '')\r\n      .replace(\/&\/g, '&amp;')\r\n      .replace(\/\"\/g, '&quot;')\r\n      .replace(\/<\/g, '&lt;')\r\n      .replace(\/>\/g, '&gt;');\r\n  };\r\n\r\n  \/* \u2500\u2500 Copy to clipboard \u2500\u2500 *\/\r\n  window.pthILS.copy = function (text, label) {\r\n    if (navigator.clipboard && navigator.clipboard.writeText) {\r\n      navigator.clipboard.writeText(text).then(function () {\r\n        window.pthILS.toast((label || 'Code') + ' copied!', 'success');\r\n      });\r\n    } else {\r\n      var ta = document.createElement('textarea');\r\n      ta.value = text;\r\n      ta.style.cssText = 'position:fixed;opacity:0;top:0;left:0;';\r\n      document.body.appendChild(ta);\r\n      ta.select();\r\n      document.execCommand('copy');\r\n      document.body.removeChild(ta);\r\n      window.pthILS.toast((label || 'Code') + ' copied!', 'success');\r\n    }\r\n  };\r\n\r\n  \/* \u2500\u2500 Export HTML file download \u2500\u2500 *\/\r\n  window.pthILS.exportHTML = function (htmlContent, filename) {\r\n    \/* Split tags to prevent minifier plugins from breaking the code *\/\r\n    var full = '<' + '!DOCTYPE html><' + 'html lang=\"en\"><' + 'head>' +\r\n      '<' + 'meta charset=\"UTF-8\">' +\r\n      '<' + 'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">' +\r\n      '<' + 'title>' + filename + ' \u2014 PTH Interactive Learning Studio<' + '\/title>' +\r\n      '<' + 'style>*{box-sizing:border-box;}body{font-family:Inter,system-ui,sans-serif;' +\r\n      'margin:24px;background:#f8fafc;color:#1e293b;}<' + '\/style>' +\r\n      '<' + '\/head><' + 'body>' + htmlContent + '<' + '\/body><' + '\/html>';\r\n    var blob = new Blob([full], { type: 'text\/html' });\r\n    var url = URL.createObjectURL(blob);\r\n    var a = document.createElement('a');\r\n    a.href = url;\r\n    a.download = filename + '.html';\r\n    document.body.appendChild(a);\r\n    a.click();\r\n    document.body.removeChild(a);\r\n    setTimeout(function () { URL.revokeObjectURL(url); }, 2000);\r\n    window.pthILS.toast('HTML file downloaded!', 'success');\r\n  };\r\n\r\n  \/* \u2500\u2500 Show HTML code in box + copy \u2500\u2500 *\/\r\n  window.pthILS.showCopyHTML = function (htmlContent, boxId) {\r\n    var box = document.getElementById(boxId);\r\n    if (!box) return;\r\n    box.style.display = 'block';\r\n    var ta = box.querySelector('textarea');\r\n    if (ta) {\r\n      ta.value = htmlContent;\r\n      ta.select();\r\n    }\r\n    window.pthILS.copy(htmlContent, 'HTML code');\r\n  };\r\n\r\n  \/* \u2500\u2500 Canvas PNG export (Kept for Crossword\/WordSearch only) \u2500\u2500 *\/\r\n  window.pthILS.exportPNG = function (gridEl, filename, cellW, cellH) {\r\n    cellW = cellW || 36;\r\n    cellH = cellH || 36;\r\n    if (!gridEl) { window.pthILS.toast('Generate first!', 'error'); return; }\r\n    var rows = parseInt(gridEl.getAttribute('data-rows') || 0);\r\n    var cols = parseInt(gridEl.getAttribute('data-cols') || 0);\r\n    if (!rows || !cols) { window.pthILS.toast('Generate first!', 'error'); return; }\r\n    var pad = 4;\r\n    var canvas = document.createElement('canvas');\r\n    canvas.width  = cols * cellW + pad * 2;\r\n    canvas.height = rows * cellH + pad * 2;\r\n    var ctx = canvas.getContext('2d');\r\n    ctx.fillStyle = '#f8fafc';\r\n    ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n    var cells = gridEl.querySelectorAll('[data-row][data-col]');\r\n    cells.forEach(function (cell) {\r\n      var r  = parseInt(cell.getAttribute('data-row'));\r\n      var c  = parseInt(cell.getAttribute('data-col'));\r\n      var x  = pad + c * cellW;\r\n      var y  = pad + r * cellH;\r\n      var isBlack = cell.classList.contains('pth-ils-cw-black') ||\r\n                    cell.classList.contains('pth-ils-ws-black');\r\n      ctx.fillStyle = isBlack ? '#0f172a' : '#ffffff';\r\n      ctx.fillRect(x, y, cellW - 1, cellH - 1);\r\n      if (!isBlack) {\r\n        ctx.strokeStyle = '#cbd5e1';\r\n        ctx.lineWidth = 1;\r\n        ctx.strokeRect(x + 0.5, y + 0.5, cellW - 2, cellH - 2);\r\n        var letter = (cell.getAttribute('data-letter') || '').toUpperCase();\r\n        if (letter) {\r\n          ctx.fillStyle = '#0f172a';\r\n          ctx.font = 'bold 15px Inter,Arial,sans-serif';\r\n          ctx.textAlign = 'center';\r\n          ctx.textBaseline = 'middle';\r\n          ctx.fillText(letter, x + cellW \/ 2, y + cellH \/ 2);\r\n        }\r\n        var num = cell.getAttribute('data-num') || '';\r\n        if (num) {\r\n          ctx.fillStyle = '#334155';\r\n          ctx.font = '8px Inter,Arial,sans-serif';\r\n          ctx.textAlign = 'left';\r\n          ctx.textBaseline = 'top';\r\n          ctx.fillText(num, x + 2, y + 2);\r\n        }\r\n      }\r\n    });\r\n\r\n    var link = document.createElement('a');\r\n    link.download = filename + '.png';\r\n    link.href = canvas.toDataURL('image\/png');\r\n    document.body.appendChild(link);\r\n    link.click();\r\n    document.body.removeChild(link);\r\n    window.pthILS.toast('PNG exported!', 'success');\r\n  };\r\n\r\n  \/* \u2500\u2500 Active tab tracker \u2500\u2500 *\/\r\n  window.pthILS.activeTab = 'crossword';\r\n\r\n  \/* ============================================================\r\n     TAB SWITCHING\r\n     ============================================================ *\/\r\n  function initTabs() {\r\n    var btns = document.querySelectorAll('#pth-ils-wrapper .pth-ils-tab-btn');\r\n    btns.forEach(function (btn) {\r\n      btn.addEventListener('click', function () {\r\n        var tab = btn.getAttribute('data-tab');\r\n        \/* Update buttons *\/\r\n        btns.forEach(function (b) {\r\n          b.classList.remove('pth-ils-active');\r\n          b.setAttribute('aria-selected', 'false');\r\n        });\r\n        btn.classList.add('pth-ils-active');\r\n        btn.setAttribute('aria-selected', 'true');\r\n        \/* Update panels *\/\r\n        document.querySelectorAll('#pth-ils-wrapper .pth-ils-panel').forEach(function (p) {\r\n          p.classList.remove('pth-ils-panel-active');\r\n        });\r\n        var panel = document.getElementById('pth-tab-' + tab);\r\n        if (panel) panel.classList.add('pth-ils-panel-active');\r\n        window.pthILS.activeTab = tab;\r\n        \/* Fire tab-ready event so tab snippet can react *\/\r\n        document.dispatchEvent(new CustomEvent('pthILSTabActive', { detail: { tab: tab } }));\r\n      });\r\n    });\r\n  }\r\n\r\n  \/* ============================================================\r\n     GLOBAL TOOLBAR\r\n     ============================================================ *\/\r\n  function initToolbar() {\r\n    \/* Full Width *\/\r\n    var fwBtn = document.getElementById('pth-ils-fullwidth-btn');\r\n    if (fwBtn) {\r\n      fwBtn.addEventListener('click', function () {\r\n        var layouts = document.querySelectorAll('#pth-ils-wrapper .pth-ils-layout');\r\n        var isOn = layouts[0] && layouts[0].classList.contains('pth-ils-full');\r\n        layouts.forEach(function (l) { l.classList.toggle('pth-ils-full', !isOn); });\r\n        fwBtn.textContent = isOn ? '\u26f6 Full Width' : '\u26f6 Exit Full Width';\r\n        window.pthILS.toast(isOn ? 'Normal layout.' : 'Full width on.', 'info');\r\n      });\r\n    }\r\n\r\n    \/* Clear \u2014 fires event; each tab snippet listens *\/\r\n    var cBtn = document.getElementById('pth-ils-clear-btn');\r\n    if (cBtn) cBtn.addEventListener('click', function () {\r\n      document.dispatchEvent(new CustomEvent('pthILSClear', { detail: { tab: window.pthILS.activeTab } }));\r\n      window.pthILS.toast('Cleared!', 'info');\r\n    });\r\n\r\n    \/* Sample \u2014 fires event; each tab snippet listens *\/\r\n    var sBtn = document.getElementById('pth-ils-sample-btn');\r\n    if (sBtn) sBtn.addEventListener('click', function () {\r\n      document.dispatchEvent(new CustomEvent('pthILSSample', { detail: { tab: window.pthILS.activeTab } }));\r\n    });\r\n  }\r\n\r\n  \/* ============================================================\r\n     4-LAYER BOOTSTRAP\r\n     ============================================================ *\/\r\n  function runInit() {\r\n    if (window.pthILS.shellReady) return;\r\n    if (!document.getElementById('pth-ils-wrapper')) return;\r\n    window.pthILS.shellReady = true;\r\n    initTabs();\r\n    initToolbar();\r\n  }\r\n\r\n  \/* Layer 1 *\/\r\n  runInit();\r\n  \/* Layer 2 *\/\r\n  if (document.readyState === 'loading') {\r\n    document.addEventListener('DOMContentLoaded', runInit);\r\n  }\r\n  \/* Layer 3 *\/\r\n  window.addEventListener('load', function () { setTimeout(runInit, 50); });\r\n  \/* Layer 4 *\/\r\n  if (!window.pthILS.shellReady && typeof MutationObserver !== 'undefined') {\r\n    var obs = new MutationObserver(function () {\r\n      if (document.getElementById('pth-ils-wrapper')) { obs.disconnect(); runInit(); }\r\n    });\r\n    obs.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n    setTimeout(function () { obs.disconnect(); }, 10000);\r\n  }\r\n\r\n})();\r\n      \r\n\/* Multilingual methods for all tabs *\/\r\nwindow.pthILS.detectScript = function(text) {\r\n  if(!text)return'latin';\r\n  if(\/[\\u0D80-\\u0DFF]\/.test(text))return'sinhala';\r\n  if(\/[\\u0B80-\\u0BFF]\/.test(text))return'tamil';\r\n  if(\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text))return'rtl';\r\n  if(\/[\\u3000-\\u9FFF\\uAC00-\\uD7AF]\/.test(text))return'cjk';\r\n  if(\/[\\u0900-\\u097F]\/.test(text))return'devanagari';\r\n  if(\/[\\u0E00-\\u0E7F]\/.test(text))return'thai';\r\n  if(\/[\\u0980-\\u09FF]\/.test(text))return'bengali';\r\n  return'latin';\r\n};\r\nwindow.pthILS.isRTL=function(t){return\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(t);};\r\nwindow.pthILS.getFontStack=function(s){var f={'sinhala':\"'Noto Sans Sinhala',system-ui\",'tamil':\"'Noto Sans Tamil',system-ui\",'rtl':\"'Noto Sans Arabic',system-ui\",'cjk':\"'Noto Sans CJK SC',system-ui\",'devanagari':\"'Noto Sans Devanagari',system-ui\",'thai':\"'Noto Sans Thai',system-ui\",'bengali':\"'Noto Sans Bengali',system-ui\",'latin':\"'Inter',system-ui\"};return f[s]||f.latin;};\r\nwindow.pthILS.loadedFonts={};\r\nwindow.pthILS.loadFont=function(s){if(window.pthILS.loadedFonts[s])return;window.pthILS.loadedFonts[s]=true;var m={'sinhala':'Noto+Sans+Sinhala','tamil':'Noto+Sans+Tamil','rtl':'Noto+Sans+Arabic','devanagari':'Noto+Sans+Devanagari','thai':'Noto+Sans+Thai','bengali':'Noto+Sans+Bengali','cjk':'Noto+Sans+SC'};if(!m[s])return;var l=document.createElement('link');l.rel='stylesheet';l.href='https:\/\/fonts.googleapis.com\/css2?family='+m[s]+':wght@400;700&display=swap';document.head.appendChild(l);};\r\nwindow.pthILS.autoLangFull=function(ta){if(!ta)return;function a(){var s=window.pthILS.detectScript(ta.value),r=window.pthILS.isRTL(ta.value);window.pthILS.loadFont(s);ta.style.direction=r?'rtl':'ltr';ta.style.textAlign=r?'right':'left';ta.style.fontFamily=window.pthILS.getFontStack(s);}ta.addEventListener('input',a);if(ta.value)a();};\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v2.0 \u2014 Crossword Creator \u2014 v3 FINAL (Popup Lang Selector) -->\r\n\r\n<style>\r\n#pth-tab-crossword {\r\n  --cw-cell-size: 38px;\r\n  --cw-cell-bg: #ffffff;\r\n  --cw-cell-black: #0f172a;\r\n  --cw-cell-correct: #dcfce7;\r\n  --cw-cell-wrong: #fef2f2;\r\n  --cw-cell-revealed: #fefce8;\r\n  --cw-text-color: #0f172a;\r\n  --cw-num-color: #334155;\r\n  --cw-grid-gap: 2px;\r\n  --cw-grid-bg: #0f172a;\r\n  --cw-font-size: 0.88rem;\r\n  --cw-num-size: 0.55rem;\r\n  --cw-across-color: #1d4ed8;\r\n  --cw-down-color: #7c3aed;\r\n}\r\n.pth-cw-customizer {\r\n  display: grid;\r\n  grid-template-columns: repeat(auto-fit, minmax(155px, 1fr));\r\n  gap: 10px; margin-bottom: 14px;\r\n}\r\n.pth-cw-custom-item { display: flex; flex-direction: column; gap: 4px; }\r\n.pth-cw-custom-item label { font-size: 0.75rem; font-weight: 700; color: #334155; }\r\n.pth-cw-custom-item input[type=\"color\"] {\r\n  width: 100%; height: 32px; border: 2px solid #e2e8f0;\r\n  border-radius: 6px; cursor: pointer; padding: 2px;\r\n}\r\n.pth-cw-custom-item input[type=\"range\"] { width: 100%; accent-color: #2563eb; }\r\n.pth-cw-custom-val { font-size: 0.7rem; color: #334155; font-weight: 600; text-align: right; }\r\n.pth-ils-cw-grid {\r\n  display: inline-grid;\r\n  gap: var(--cw-grid-gap);\r\n  background: var(--cw-grid-bg);\r\n  padding: var(--cw-grid-gap);\r\n  border-radius: 4px;\r\n  overflow: auto;\r\n  max-width: 100%;\r\n}\r\n.pth-ils-cw-cell {\r\n  width: var(--cw-cell-size); height: var(--cw-cell-size);\r\n  background: var(--cw-cell-bg);\r\n  display: flex; align-items: center; justify-content: center;\r\n  position: relative;\r\n}\r\n.pth-ils-cw-cell.pth-ils-cw-black    { background: var(--cw-cell-black); }\r\n.pth-ils-cw-cell.pth-ils-cw-correct  { background: var(--cw-cell-correct); }\r\n.pth-ils-cw-cell.pth-ils-cw-wrong    { background: var(--cw-cell-wrong); }\r\n.pth-ils-cw-cell.pth-ils-cw-revealed { background: var(--cw-cell-revealed); }\r\n.pth-ils-cw-num {\r\n  position: absolute; top: 1px; left: 2px;\r\n  font-size: var(--cw-num-size); font-weight: 800;\r\n  color: var(--cw-num-color); line-height: 1; pointer-events: none;\r\n}\r\n.pth-ils-cw-cell input {\r\n  width: 100%; height: 100%; border: none; background: transparent;\r\n  text-align: center; font-size: var(--cw-font-size); font-weight: 800;\r\n  color: var(--cw-text-color); text-transform: uppercase;\r\n  outline: none; font-family: inherit; padding: 0; caret-color: #2563eb;\r\n}\r\n.pth-cw-clues-wrap {\r\n  display: grid; grid-template-columns: 1fr 1fr;\r\n  gap: 14px; margin-top: 14px;\r\n}\r\n.pth-cw-clue-group h4 {\r\n  font-size: 0.82rem; font-weight: 800; margin: 0 0 8px;\r\n  padding: 4px 8px; border-radius: 6px; display: inline-block;\r\n}\r\n.pth-cw-clue-group.across h4 { color: var(--cw-across-color); background: #eff6ff; }\r\n.pth-cw-clue-group.down   h4 { color: var(--cw-down-color);   background: #f5f3ff; }\r\n.pth-cw-clue-item {\r\n  font-size: 0.85rem; color: #1e293b; font-weight: 500;\r\n  padding: 5px 8px; border-radius: 5px; margin-bottom: 4px;\r\n  border-left: 3px solid transparent; line-height: 1.5;\r\n}\r\n.pth-cw-clue-item.cw-clue-done { text-decoration: line-through; color: #047857; opacity: 0.7; }\r\n\/* Language picker button *\/\r\n.pth-cw-lang-pick-btn {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  gap: 8px;\r\n  padding: 9px 16px;\r\n  background: #fff;\r\n  border: 2px solid #e2e8f0;\r\n  border-radius: 8px;\r\n  cursor: pointer;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  font-size: 0.85rem;\r\n  font-weight: 700;\r\n  color: #334155;\r\n  transition: all 0.15s;\r\n  width: 100%;\r\n  margin-bottom: 10px;\r\n}\r\n.pth-cw-lang-pick-btn:hover {\r\n  border-color: #2563eb;\r\n  color: #1d4ed8;\r\n  background: #eff6ff;\r\n}\r\n.pth-cw-lang-pick-flag { font-size: 0.68rem; font-weight: 800; background: #2563eb; color: #fff; border-radius: 5px; padding: 3px 6px; min-width: 26px; text-align: center; letter-spacing: 0.3px; }\r\n.pth-cw-lang-pick-text { flex: 1; text-align: left; }\r\n.pth-cw-lang-pick-arrow { color: #94a3b8; font-size: 0.8rem; }\r\n@media (max-width: 600px) { .pth-cw-clues-wrap { grid-template-columns: 1fr; } }\r\n<\/style>\r\n\r\n<!-- Export template -->\r\n<template id=\"pth-cw-export-tpl\">\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"UTF-8\">\r\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\r\n<title>Crossword Puzzle<\/title>\r\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Noto+Sans+Sinhala:wght@400;700&family=Noto+Sans+Tamil:wght@400;700&family=Noto+Sans+Arabic:wght@400;700&family=Noto+Sans+Devanagari:wght@400;700&family=Noto+Sans+Thai:wght@400;700&family=Noto+Sans+Bengali:wght@400;700&family=Inter:wght@400;600;700;800&display=swap\" rel=\"stylesheet\">\r\n<style>\r\n*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;color-adjust:exact;}\r\nbody{font-family:'Inter',system-ui,sans-serif;margin:0;background:#eef2f9;color:#1e293b;min-height:100vh;display:flex;justify-content:center;padding:32px 16px;}\r\n.cw-page{width:100%;max-width:780px;background:#ffffff;border-radius:18px;box-shadow:0 10px 30px -10px rgba(15,23,42,0.18);padding:30px 34px 34px;}\r\n.cw-head{text-align:center;margin:0 0 18px;}\r\nh1{color:#1d4ed8;font-size:1.55rem;font-weight:800;margin:0 0 6px;}\r\n.cw-sub{color:#334155;font-size:0.85rem;margin:0;}\r\n.cw-meta-row{display:flex;align-items:center;justify-content:center;gap:14px;margin:14px 0 18px;flex-wrap:wrap;}\r\n.cw-grid-outer{display:flex;justify-content:center;overflow-x:auto;padding:4px;margin-bottom:6px;}\r\n.cw-wrap{display:inline-grid;gap:2px;padding:2px;border-radius:6px;}\r\n.cw-cell{display:flex;align-items:center;justify-content:center;position:relative;border:1px solid #cbd5e1;}\r\n.cw-black{border-color:#0f172a;}\r\n.cw-num{position:absolute;top:1px;left:2px;font-size:9px;font-weight:800;pointer-events:none;color:#334155;}\r\n.cw-inp{width:100%;height:100%;border:none;background:transparent;text-align:center;font-weight:800;text-transform:uppercase;outline:none;font-family:inherit;caret-color:#2563eb;}\r\n.cw-correct{background:#dcfce7!important;} .cw-wrong{background:#fef2f2!important;} .cw-revealed{background:#fefce8!important;}\r\n.cw-footer-btns{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:22px 0 4px;padding-top:18px;border-top:2px solid #e2e8f0;}\r\n.cw-btn{padding:9px 18px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.06);}\r\n.cw-btn-a{background:#2563eb;color:#fff;} .cw-btn-b{background:#fff;border:2px solid #e2e8f0;color:#334155;}\r\n.cw-btn-c{background:#7c3aed;color:#fff;}\r\n.cw-btn.active{outline:3px solid #fde68a;}\r\n.cw-score{font-size:0.88rem;font-weight:700;color:#1d4ed8;background:#eff6ff;padding:5px 12px;border-radius:7px;}\r\n.cw-timer{font-size:0.88rem;font-weight:700;color:#334155;background:#f1f5f9;padding:5px 12px;border-radius:7px;}\r\n.cw-clues{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-top:20px;}\r\n.cw-cg{background:#f8fafc;border-radius:10px;padding:14px 16px;}\r\n.cw-cg h4{font-size:0.82rem;font-weight:800;padding:4px 8px;border-radius:5px;display:inline-block;margin:0 0 10px;}\r\n.cw-clue{font-size:0.85rem;color:#1e293b;padding:4px 6px;margin-bottom:3px;line-height:1.5;}\r\n.cw-clue.done{text-decoration:line-through;color:#047857;}\r\n@media(max-width:600px){.cw-clues{grid-template-columns:1fr;}.cw-page{padding:20px 16px 26px;border-radius:12px;}}\r\n@media print{\r\n  body{margin:0;background:#fff;padding:0;display:block;}\r\n  .cw-page{box-shadow:none;border-radius:0;max-width:100%;padding:10px;}\r\n  .cw-footer-btns{display:none!important;}\r\n  .cw-timer{display:none!important;}\r\n  .cw-wrap,.cw-clues{break-inside:avoid;}\r\n}\r\n<\/style>\r\n<\/head>\r\n<body>\r\n<div class=\"cw-page\">\r\n<div class=\"cw-head\">\r\n<h2>&#x1F9E9; Crossword Puzzle<\/h2>\r\n<p class=\"cw-sub\">Fill in the grid using the clues below.<\/p>\r\n<\/div>\r\n<div class=\"cw-meta-row\">\r\n  <span class=\"cw-score\" id=\"cw-sc\"><\/span>\r\n  <span class=\"cw-timer\" id=\"cw-timer\">&#x23F1; 00:00<\/span>\r\n<\/div>\r\n<div class=\"cw-grid-outer\"><div class=\"cw-wrap\" id=\"cw-grid\"><\/div><\/div>\r\n<div class=\"cw-clues\">\r\n  <div class=\"cw-cg\"><h4 id=\"cw-ah\" style=\"color:#1d4ed8;background:#eff6ff;\">&#x2192; Across<\/h4><div id=\"cw-ac\"><\/div><\/div>\r\n  <div class=\"cw-cg\"><h4 id=\"cw-dh\" style=\"color:#7c3aed;background:#f5f3ff;\">&#x2193; Down<\/h4><div id=\"cw-dc\"><\/div><\/div>\r\n<\/div>\r\n<div class=\"cw-footer-btns\">\r\n  <button class=\"cw-btn cw-btn-a\" id=\"btn-check\">&#x2705; Check Answers<\/button>\r\n  <button class=\"cw-btn cw-btn-b\" id=\"btn-reveal\">&#x1F441; Reveal All<\/button>\r\n  <button class=\"cw-btn cw-btn-b\" id=\"btn-reset\">&#x1F504; Reset<\/button>\r\n  <button class=\"cw-btn cw-btn-b\" id=\"btn-answerkey\">&#x1F5DD; Answer Key Mode<\/button>\r\n  <button class=\"cw-btn cw-btn-c\" id=\"btn-print\">&#x1F5A8; Print Puzzle<\/button>\r\n<\/div>\r\n<\/div>\r\n<\/body>\r\n<\/html>\r\n<\/template>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  \/* ============================================================\r\n     MULTILINGUAL METHODS \u2014 self-contained\r\n     Safe: only defines if Shell hasn't added them yet\r\n     ============================================================ *\/\r\n  if (!window.pthILS) window.pthILS = {};\r\n\r\n  if (!window.pthILS.detectScript) {\r\n    window.pthILS.detectScript = function(text) {\r\n      if (!text || !text.trim()) return 'latin';\r\n      if (\/[\\u0D80-\\u0DFF]\/.test(text)) return 'sinhala';\r\n      if (\/[\\u0B80-\\u0BFF]\/.test(text)) return 'tamil';\r\n      if (\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text)) return 'rtl';\r\n      if (\/[\\u3000-\\u9FFF\\uAC00-\\uD7AF]\/.test(text)) return 'cjk';\r\n      if (\/[\\u0900-\\u097F]\/.test(text)) return 'devanagari';\r\n      if (\/[\\u0E00-\\u0E7F]\/.test(text)) return 'thai';\r\n      if (\/[\\u0980-\\u09FF]\/.test(text)) return 'bengali';\r\n      if (\/[\\u1000-\\u109F]\/.test(text)) return 'myanmar';\r\n      if (\/[\\u1780-\\u17FF]\/.test(text)) return 'khmer';\r\n      if (\/[\\u0370-\\u03FF]\/.test(text)) return 'greek';\r\n      if (\/[\\u0400-\\u04FF]\/.test(text)) return 'cyrillic';\r\n      return 'latin';\r\n    };\r\n  }\r\n  if (!window.pthILS.isRTL) {\r\n    window.pthILS.isRTL = function(text) {\r\n      return \/[\\u0591-\\u07FF\\u200F\\u202B\\u202E\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text);\r\n    };\r\n  }\r\n  if (!window.pthILS.getFontStack) {\r\n    window.pthILS.getFontStack = function(script) {\r\n      var f = {\r\n        sinhala:\"'Noto Sans Sinhala','Iskoola Pota',system-ui,sans-serif\",\r\n        tamil:\"'Noto Sans Tamil','Latha',system-ui,sans-serif\",\r\n        rtl:\"'Noto Sans Arabic','Noto Sans Hebrew',system-ui,sans-serif\",\r\n        cjk:\"'Noto Sans CJK SC','Microsoft YaHei',system-ui,sans-serif\",\r\n        devanagari:\"'Noto Sans Devanagari','Mangal',system-ui,sans-serif\",\r\n        thai:\"'Noto Sans Thai','Tahoma',system-ui,sans-serif\",\r\n        bengali:\"'Noto Sans Bengali','Vrinda',system-ui,sans-serif\",\r\n        myanmar:\"'Noto Sans Myanmar',system-ui,sans-serif\",\r\n        khmer:\"'Noto Sans Khmer',system-ui,sans-serif\",\r\n        latin:\"'Inter',system-ui,sans-serif\"\r\n      };\r\n      return f[script] || f.latin;\r\n    };\r\n  }\r\n  if (!window.pthILS.loadedFonts) window.pthILS.loadedFonts = {};\r\n  if (!window.pthILS.loadFont) {\r\n    window.pthILS.loadFont = function(script) {\r\n      if (window.pthILS.loadedFonts[script]) return;\r\n      window.pthILS.loadedFonts[script] = true;\r\n      var m = {\r\n        sinhala:'Noto+Sans+Sinhala:wght@400;700',tamil:'Noto+Sans+Tamil:wght@400;700',\r\n        rtl:'Noto+Sans+Arabic:wght@400;700',devanagari:'Noto+Sans+Devanagari:wght@400;700',\r\n        thai:'Noto+Sans+Thai:wght@400;700',bengali:'Noto+Sans+Bengali:wght@400;700',\r\n        myanmar:'Noto+Sans+Myanmar:wght@400;700',cjk:'Noto+Sans+SC:wght@400;700'\r\n      };\r\n      if (!m[script]) return;\r\n      var l=document.createElement('link');l.rel='stylesheet';\r\n      l.href='https:\/\/fonts.googleapis.com\/css2?family='+m[script]+'&display=swap';\r\n      document.head.appendChild(l);\r\n    };\r\n  }\r\n  if (!window.pthILS.autoLangFull) {\r\n    window.pthILS.autoLangFull = function(ta) {\r\n      if (!ta) return;\r\n      function apply() {\r\n        var s=window.pthILS.detectScript(ta.value),r=window.pthILS.isRTL(ta.value);\r\n        window.pthILS.loadFont(s);\r\n        ta.style.direction=r?'rtl':'ltr';ta.style.textAlign=r?'right':'left';\r\n        ta.style.fontFamily=window.pthILS.getFontStack(s);\r\n      }\r\n      ta.addEventListener('input',apply);if(ta.value)apply();\r\n    };\r\n  }\r\n\r\n  \/* \u2500\u2500 Wait for Shell \u2500\u2500 *\/\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function() {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function() { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  \/* ============================================================\r\n     ALL 33 LANGUAGE DEFINITIONS\r\n     ============================================================ *\/\r\n  var CW_LANGS = [\r\n    {code:'en',  flag:'&#x1F1EC;&#x1F1E7;', native:'English',            en:'English'},\r\n    {code:'si',  flag:'&#x1F1F1;&#x1F1F0;', native:'&#x0DC3;&#x0DD2;&#x0D82;&#x0DC4;&#x0DBD;', en:'Sinhala'},\r\n    {code:'ta',  flag:'&#x1F1EE;&#x1F1F3;', native:'&#xBBA4;&#xBAE4;&#xBBBF;&#xBBB4;&#xBBCD;', en:'Tamil'},\r\n    {code:'zh',  flag:'&#x1F1E8;&#x1F1F3;', native:'&#x4E2D;&#x6587;',   en:'Chinese'},\r\n    {code:'ar',  flag:'&#x1F1F8;&#x1F1E6;', native:'&#x627;&#x644;&#x639;&#x631;&#x628;&#x64A;&#x629;', en:'Arabic'},\r\n    {code:'hi',  flag:'&#x1F1EE;&#x1F1F3;', native:'&#x939;&#x93F;&#x928;&#x94D;&#x926;&#x940;', en:'Hindi'},\r\n    {code:'es',  flag:'&#x1F1EA;&#x1F1F8;', native:'Espa&#xF1;ol',       en:'Spanish'},\r\n    {code:'fr',  flag:'&#x1F1EB;&#x1F1F7;', native:'Fran&#xE7;ais',      en:'French'},\r\n    {code:'pt',  flag:'&#x1F1F5;&#x1F1F9;', native:'Portugu&#xEA;s',     en:'Portuguese'},\r\n    {code:'de',  flag:'&#x1F1E9;&#x1F1EA;', native:'Deutsch',            en:'German'},\r\n    {code:'ja',  flag:'&#x1F1EF;&#x1F1F5;', native:'&#x65E5;&#x672C;&#x8A9E;', en:'Japanese'},\r\n    {code:'ko',  flag:'&#x1F1F0;&#x1F1F7;', native:'&#xD55C;&#xAD6D;&#xC5B4;', en:'Korean'},\r\n    {code:'ru',  flag:'&#x1F1F7;&#x1F1FA;', native:'&#x420;&#x443;&#x441;&#x441;&#x43A;&#x438;&#x439;', en:'Russian'},\r\n    {code:'it',  flag:'&#x1F1EE;&#x1F1F9;', native:'Italiano',           en:'Italian'},\r\n    {code:'tr',  flag:'&#x1F1F9;&#x1F1F7;', native:'T&#xFC;rk&#xE7;e',  en:'Turkish'},\r\n    {code:'id',  flag:'&#x1F1EE;&#x1F1E9;', native:'Bahasa Indonesia',   en:'Indonesian'},\r\n    {code:'ms',  flag:'&#x1F1F2;&#x1F1FE;', native:'Bahasa Melayu',      en:'Malay'},\r\n    {code:'bn',  flag:'&#x1F1E7;&#x1F1E9;', native:'&#x9AC;&#x9BE;&#x982;&#x9B2;&#x9BE;', en:'Bengali'},\r\n    {code:'vi',  flag:'&#x1F1FB;&#x1F1F3;', native:'Ti&#x1EBF;ng Vi&#x1EC7;t', en:'Vietnamese'},\r\n    {code:'th',  flag:'&#x1F1F9;&#x1F1ED;', native:'&#xE20;&#xE32;&#xE29;&#xE32;&#xE44;&#xE17;&#xE22;', en:'Thai'},\r\n    {code:'sw',  flag:'&#x1F1F0;&#x1F1EA;', native:'Kiswahili',          en:'Swahili'},\r\n    {code:'nl',  flag:'&#x1F1F3;&#x1F1F1;', native:'Nederlands',         en:'Dutch'},\r\n    {code:'pl',  flag:'&#x1F1F5;&#x1F1F1;', native:'Polski',             en:'Polish'},\r\n    {code:'uk',  flag:'&#x1F1FA;&#x1F1E6;', native:'&#x423;&#x43A;&#x440;&#x430;&#x457;&#x43D;&#x441;&#x44C;&#x43A;&#x430;', en:'Ukrainian'},\r\n    {code:'el',  flag:'&#x1F1EC;&#x1F1F7;', native:'&#x395;&#x3BB;&#x3BB;&#x3B7;&#x3BD;&#x3B9;&#x3BA;&#x3AC;', en:'Greek'},\r\n    {code:'he',  flag:'&#x1F1EE;&#x1F1F1;', native:'&#x5E2;&#x5D1;&#x5E8;&#x5D9;&#x5EA;', en:'Hebrew'},\r\n    {code:'fa',  flag:'&#x1F1EE;&#x1F1F7;', native:'&#x641;&#x627;&#x631;&#x633;&#x6CC;', en:'Persian'},\r\n    {code:'ur',  flag:'&#x1F1F5;&#x1F1F0;', native:'&#x627;&#x631;&#x62F;&#x648;', en:'Urdu'},\r\n    {code:'ne',  flag:'&#x1F1F3;&#x1F1F5;', native:'&#x928;&#x947;&#x92A;&#x93E;&#x932;&#x940;', en:'Nepali'},\r\n    {code:'sv',  flag:'&#x1F1F8;&#x1F1EA;', native:'Svenska',            en:'Swedish'},\r\n    {code:'ro',  flag:'&#x1F1F7;&#x1F1F4;', native:'Rom&#xE2;n&#x103;', en:'Romanian'},\r\n    {code:'fil', flag:'&#x1F1F5;&#x1F1ED;', native:'Filipino',           en:'Filipino'},\r\n    {code:'af',  flag:'&#x1F1FF;&#x1F1E6;', native:'Afrikaans',          en:'Afrikaans'}\r\n  ];\r\n\r\n  \/* ============================================================\r\n     MULTILINGUAL SAMPLES\r\n     ============================================================ *\/\r\n  var CW_SAMPLES = {\r\n    en:'PYTHON:Popular programming language\\nBROWSER:Chrome or Firefox\\nSERVER:Hosts websites online\\nFUNCTION:Reusable block of code\\nARRAY:Ordered list of values\\nLOOP:Repeats code until condition\\nDEBUG:Find and fix code errors\\nCLOUD:Remote data storage\\nNETWORK:Connected computers\\nDATABASE:Stores organized data',\r\n    si:'PYTHON:\u0da2\u0db1\u0db4\u0dca\u200d\u0dbb\u0dd2\u0dba programming \u0db7\u0dcf\u0dc2\u0dcf\u0dc0\u0d9a\u0dca\\nBROWSER:Chrome \u0dc4\u0ddd Firefox\\nSERVER:\u0dc0\u0dd9\u0db6\u0dca \u0d85\u0da9\u0dc0\u0dd2 host \u0d9a\u0dbb\u0dba\u0dd2\\nFUNCTION:\u0db1\u0dd0\u0dc0\u0dad \u0db7\u0dcf\u0dc0\u0dd2\u0dad\u0dcf \u0d9a\u0dc5 \u0dc4\u0dd0\u0d9a\u0dd2 code\\nARRAY:\u0d85\u0d9c\u0dba\u0db1\u0dca \u0dbd\u0dd0\u0dba\u0dd2\u0dc3\u0dca\u0dad\u0dd4\u0dc0\u0d9a\u0dca\\nLOOP:code \u0db1\u0dd0\u0dc0\u0dad \u0db1\u0dd0\u0dc0\u0dad \u0db0\u0dcf\u0dc0\u0db1\u0dba\\nDEBUG:code \u0daf\u0ddd\u0dc2 \u0dc3\u0ddc\u0dba\u0dcf \u0db1\u0dd2\u0dbb\u0dcf\u0d9a\u0dbb\u0dab\u0dba\\nCLOUD:\u0daf\u0dad\u0dca\u0dad \u0daf\u0dd4\u0dbb\u0dc3\u0dca\u0dae\u0dc0 \u0d9c\u0db6\u0da9\u0dcf \u0d9a\u0dd2\u0dbb\u0dd3\u0db8\\nNETWORK:\u0dc3\u0db8\u0dca\u0db6\u0db1\u0dca\u0db0\u0dd2\u0dad computers\\nDATABASE:\u0daf\u0dad\u0dca\u0dad \u0d9c\u0db6\u0da9\u0dcf \u0d9a\u0dd2\u0dbb\u0dd3\u0db8\u0dda \u0db4\u0daf\u0dca\u0db0\u0dad\u0dd2\u0dba',\r\n    ta:'PYTHON:\u0baa\u0bbf\u0bb0\u0baa\u0bb2\u0bae\u0bbe\u0ba9 \u0ba8\u0bbf\u0bb0\u0bb2\u0bbe\u0b95\u0bcd\u0b95 \u0bae\u0bca\u0bb4\u0bbf\\nBROWSER:Chrome \u0b85\u0bb2\u0bcd\u0bb2\u0ba4\u0bc1 Firefox\\nSERVER:\u0b87\u0ba3\u0bc8\u0baf\u0ba4\u0bb3\u0b99\u0bcd\u0b95\u0bb3\u0bc8 \u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95\u0bbf\u0bb1\u0ba4\u0bc1\\nFUNCTION:\u0bae\u0bc0\u0ba3\u0bcd\u0b9f\u0bc1\u0bae\u0bcd \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0b95\u0bcd\u0b95\u0bc2\u0b9f\u0bbf\u0baf \u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bc1\\nARRAY:\u0bae\u0ba4\u0bbf\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bbf\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\\nLOOP:\u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bcd\u0b9f\u0bc8 \u0bae\u0bc0\u0ba3\u0bcd\u0b9f\u0bc1\u0bae\u0bcd \u0b87\u0baf\u0b95\u0bcd\u0b95\u0bc1\u0ba4\u0bb2\u0bcd\\nDEBUG:\u0baa\u0bbf\u0bb4\u0bc8\u0b95\u0bb3\u0bc8 \u0b9a\u0bb0\u0bbf\u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bb2\u0bcd\\nCLOUD:\u0ba4\u0bca\u0bb2\u0bc8\u0ba4\u0bc2\u0bb0 \u0ba4\u0bb0\u0bb5\u0bc1 \u0b9a\u0bc7\u0bae\u0bbf\u0baa\u0bcd\u0baa\u0bc1\\nNETWORK:\u0b87\u0ba3\u0bc8\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f \u0b95\u0ba3\u0bbf\u0ba9\u0bbf\u0b95\u0bb3\u0bcd\\nDATABASE:\u0ba4\u0bb0\u0bb5\u0bc1 \u0b9a\u0bc7\u0bae\u0bbf\u0baa\u0bcd\u0baa\u0bc1 \u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1',\r\n    zh:'PYTHON:\u6d41\u884c\u7684\u7f16\u7a0b\u8bed\u8a00\\nBROWSER:Chrome\u6216Firefox\u6d4f\u89c8\u5668\\nSERVER:\u6258\u7ba1\u7f51\u7ad9\u7684\u670d\u52a1\u5668\\nFUNCTION:\u53ef\u91cd\u7528\u7684\u4ee3\u7801\u5757\\nARRAY:\u6709\u5e8f\u7684\u503c\u5217\u8868\\nLOOP:\u91cd\u590d\u6267\u884c\u4ee3\u7801\\nDEBUG:\u67e5\u627e\u548c\u4fee\u590d\u4ee3\u7801\u9519\u8bef\\nCLOUD:\u8fdc\u7a0b\u6570\u636e\u5b58\u50a8\\nNETWORK:\u8fde\u63a5\u7684\u8ba1\u7b97\u673a\u7f51\u7edc\\nDATABASE:\u5b58\u50a8\u6709\u7ec4\u7ec7\u6570\u636e',\r\n    ar:'PYTHON:\u0644\u063a\u0629 \u0628\u0631\u0645\u062c\u0629 \u0634\u0627\u0626\u0639\u0629\\nBROWSER:\u0643\u0631\u0648\u0645 \u0623\u0648 \u0641\u0627\u064a\u0631\u0641\u0648\u0643\u0633\\nSERVER:\u064a\u0633\u062a\u0636\u064a\u0641 \u0645\u0648\u0627\u0642\u0639 \u0627\u0644\u0648\u064a\u0628\\nFUNCTION:\u0643\u062a\u0644\u0629 \u0643\u0648\u062f \u0642\u0627\u0628\u0644\u0629 \u0644\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u0627\u0633\u062a\u062e\u062f\u0627\u0645\\nARRAY:\u0642\u0627\u0626\u0645\u0629 \u0645\u0646\u0638\u0645\u0629 \u0645\u0646 \u0627\u0644\u0642\u064a\u0645\\nLOOP:\u064a\u0643\u0631\u0631 \u0627\u0644\u0643\u0648\u062f \u062d\u062a\u0649 \u0627\u0644\u0634\u0631\u0637\\nDEBUG:\u0625\u064a\u062c\u0627\u062f \u0648\u0625\u0635\u0644\u0627\u062d \u0623\u062e\u0637\u0627\u0621 \u0627\u0644\u0643\u0648\u062f\\nCLOUD:\u062a\u062e\u0632\u064a\u0646 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0639\u0646 \u0628\u0639\u062f\\nNETWORK:\u0623\u062c\u0647\u0632\u0629 \u0643\u0645\u0628\u064a\u0648\u062a\u0631 \u0645\u062a\u0635\u0644\u0629\\nDATABASE:\u064a\u062e\u0632\u0646 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0645\u0646\u0638\u0645\u0629',\r\n    hi:'PYTHON:\u0932\u094b\u0915\u092a\u094d\u0930\u093f\u092f \u092a\u094d\u0930\u094b\u0917\u094d\u0930\u093e\u092e\u093f\u0902\u0917 \u092d\u093e\u0937\u093e\\nBROWSER:Chrome \u092f\u093e Firefox\\nSERVER:\u0935\u0947\u092c\u0938\u093e\u0907\u091f \u0939\u094b\u0938\u094d\u091f \u0915\u0930\u0924\u093e \u0939\u0948\\nFUNCTION:\u092a\u0941\u0928: \u0909\u092a\u092f\u094b\u0917\u0940 \u0915\u094b\u0921 \u092c\u094d\u0932\u0949\u0915\\nARRAY:\u092e\u0942\u0932\u094d\u092f\u094b\u0902 \u0915\u0940 \u0915\u094d\u0930\u092e\u092c\u0926\u094d\u0927 \u0938\u0942\u091a\u0940\\nLOOP:\u0936\u0930\u094d\u0924 \u0924\u0915 \u0915\u094b\u0921 \u0926\u094b\u0939\u0930\u093e\u0924\u093e \u0939\u0948\\nDEBUG:\u0915\u094b\u0921 \u0924\u094d\u0930\u0941\u091f\u093f\u092f\u093e\u0902 \u0916\u094b\u091c\u0947\u0902 \u0914\u0930 \u0920\u0940\u0915 \u0915\u0930\u0947\u0902\\nCLOUD:\u0926\u0942\u0930\u0938\u094d\u0925 \u0921\u0947\u091f\u093e \u092d\u0902\u0921\u093e\u0930\u0923\\nNETWORK:\u091c\u0941\u0921\u093c\u0947 \u0939\u0941\u090f \u0915\u0902\u092a\u094d\u092f\u0942\u091f\u0930\\nDATABASE:\u0935\u094d\u092f\u0935\u0938\u094d\u0925\u093f\u0924 \u0921\u0947\u091f\u093e \u0938\u0902\u0917\u094d\u0930\u0939\u0940\u0924 \u0915\u0930\u0924\u093e \u0939\u0948',\r\n    es:'PYTHON:Lenguaje de programaci\u00f3n popular\\nBROWSER:Chrome o Firefox\\nSERVER:Aloja sitios web\\nFUNCTION:Bloque de c\u00f3digo reutilizable\\nARRAY:Lista ordenada de valores\\nLOOP:Repite c\u00f3digo hasta condici\u00f3n\\nDEBUG:Encontrar y corregir errores\\nCLOUD:Almacenamiento remoto de datos\\nNETWORK:Computadoras conectadas\\nDATABASE:Almacena datos organizados',\r\n    fr:'PYTHON:Langage de programmation populaire\\nBROWSER:Chrome ou Firefox\\nSERVER:H\u00e9berge des sites web\\nFUNCTION:Bloc de code r\u00e9utilisable\\nARRAY:Liste ordonn\u00e9e de valeurs\\nLOOP:R\u00e9p\u00e8te le code jusqu\\'\u00e0 condition\\nDEBUG:Trouver et corriger les erreurs\\nCLOUD:Stockage distant de donn\u00e9es\\nNETWORK:Ordinateurs connect\u00e9s\\nDATABASE:Stocke les donn\u00e9es organis\u00e9es',\r\n    pt:'PYTHON:Linguagem de programa\u00e7\u00e3o popular\\nBROWSER:Chrome ou Firefox\\nSERVER:Hospeda sites da web\\nFUNCTION:Bloco de c\u00f3digo reutiliz\u00e1vel\\nARRAY:Lista ordenada de valores\\nLOOP:Repete c\u00f3digo at\u00e9 condi\u00e7\u00e3o\\nDEBUG:Encontrar e corrigir erros\\nCLOUD:Armazenamento remoto\\nNETWORK:Computadores conectados\\nDATABASE:Armazena dados organizados',\r\n    de:'PYTHON:Beliebte Programmiersprache\\nBROWSER:Chrome oder Firefox\\nSERVER:Hostet Webseiten\\nFUNCTION:Wiederverwendbarer Codeblock\\nARRAY:Geordnete Werteliste\\nLOOP:Wiederholt Code bis Bedingung\\nDEBUG:Codefehler finden und beheben\\nCLOUD:Externe Datenspeicherung\\nNETWORK:Verbundene Computer\\nDATABASE:Speichert organisierte Daten',\r\n    ja:'PYTHON:\u4eba\u6c17\u306e\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u8a00\u8a9e\\nBROWSER:Chrome\u307e\u305f\u306fFirefox\\nSERVER:\u30a6\u30a7\u30d6\u30b5\u30a4\u30c8\u3092\u30db\u30b9\u30c8\u3059\u308b\\nFUNCTION:\u518d\u5229\u7528\u53ef\u80fd\u306a\u30b3\u30fc\u30c9\u30d6\u30ed\u30c3\u30af\\nARRAY:\u5024\u306e\u9806\u5e8f\u4ed8\u304d\u30ea\u30b9\u30c8\\nLOOP:\u6761\u4ef6\u307e\u3067\u7e70\u308a\u8fd4\u3059\\nDEBUG:\u30b3\u30fc\u30c9\u30a8\u30e9\u30fc\u3092\u898b\u3064\u3051\u3066\u4fee\u6b63\\nCLOUD:\u30ea\u30e2\u30fc\u30c8\u30c7\u30fc\u30bf\u30b9\u30c8\u30ec\u30fc\u30b8\\nNETWORK:\u63a5\u7d9a\u3055\u308c\u305f\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\\nDATABASE:\u6574\u7406\u3055\u308c\u305f\u30c7\u30fc\u30bf\u3092\u4fdd\u5b58',\r\n    ko:'PYTHON:\uc778\uae30 \ud504\ub85c\uadf8\ub798\ubc0d \uc5b8\uc5b4\\nBROWSER:Chrome \ub610\ub294 Firefox\\nSERVER:\uc6f9\uc0ac\uc774\ud2b8\ub97c \ud638\uc2a4\ud305\\nFUNCTION:\uc7ac\uc0ac\uc6a9 \uac00\ub2a5\ud55c \ucf54\ub4dc \ube14\ub85d\\nARRAY:\uc815\ub82c\ub41c \uac12 \ubaa9\ub85d\\nLOOP:\uc870\uac74\uae4c\uc9c0 \ucf54\ub4dc \ubc18\ubcf5\\nDEBUG:\ucf54\ub4dc \uc624\ub958 \ucc3e\uae30 \ubc0f \uc218\uc815\\nCLOUD:\uc6d0\uaca9 \ub370\uc774\ud130 \uc800\uc7a5\uc18c\\nNETWORK:\uc5f0\uacb0\ub41c \ucef4\ud4e8\ud130\\nDATABASE:\uc815\ub9ac\ub41c \ub370\uc774\ud130 \uc800\uc7a5',\r\n    ru:'PYTHON:\u041f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\\nBROWSER:Chrome \u0438\u043b\u0438 Firefox\\nSERVER:\u0420\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u044b\\nFUNCTION:\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\\nARRAY:\u0423\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a\\nLOOP:\u041f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442 \u043a\u043e\u0434 \u0434\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044f\\nDEBUG:\u041d\u0430\u0439\u0442\u0438 \u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438\\nCLOUD:\u0423\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\\nNETWORK:\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u044b\\nDATABASE:\u0425\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435',\r\n    it:'PYTHON:Linguaggio di programmazione popolare\\nBROWSER:Chrome o Firefox\\nSERVER:Ospita siti web\\nFUNCTION:Blocco di codice riutilizzabile\\nARRAY:Elenco ordinato di valori\\nLOOP:Ripete il codice\\nDEBUG:Trova e correggi errori\\nCLOUD:Archiviazione dati remota\\nNETWORK:Computer connessi\\nDATABASE:Memorizza dati organizzati',\r\n    tr:'PYTHON:Pop\u00fcler programlama dili\\nBROWSER:Chrome veya Firefox\\nSERVER:Web sitelerini bar\u0131nd\u0131r\u0131r\\nFUNCTION:Yeniden kullan\u0131labilir kod\\nARRAY:De\u011ferlerin s\u0131ral\u0131 listesi\\nLOOP:Ko\u015fula kadar kodu tekrarlar\\nDEBUG:Kod hatalar\u0131n\u0131 bul d\u00fczelt\\nCLOUD:Uzak veri depolama\\nNETWORK:Ba\u011fl\u0131 bilgisayarlar\\nDATABASE:D\u00fczenli verileri depolar',\r\n    id:'PYTHON:Bahasa pemrograman populer\\nBROWSER:Chrome atau Firefox\\nSERVER:Meng-host situs web\\nFUNCTION:Blok kode yang dapat digunakan\\nARRAY:Daftar nilai yang terurut\\nLOOP:Mengulang kode sampai kondisi\\nDEBUG:Temukan dan perbaiki kesalahan\\nCLOUD:Penyimpanan data jarak jauh\\nNETWORK:Komputer yang terhubung\\nDATABASE:Menyimpan data terorganisir',\r\n    ms:'PYTHON:Bahasa pengaturcaraan popular\\nBROWSER:Chrome atau Firefox\\nSERVER:Hos laman web\\nFUNCTION:Blok kod yang boleh digunakan\\nARRAY:Senarai nilai tersusun\\nLOOP:Ulang kod sehingga syarat\\nDEBUG:Cari dan betulkan ralat\\nCLOUD:Storan data jauh\\nNETWORK:Komputer disambungkan\\nDATABASE:Simpan data teratur',\r\n    bn:'PYTHON:\u099c\u09a8\u09aa\u09cd\u09b0\u09bf\u09af\u09bc \u09aa\u09cd\u09b0\u09cb\u0997\u09cd\u09b0\u09be\u09ae\u09bf\u0982 \u09ad\u09be\u09b7\u09be\\nBROWSER:Chrome \u09ac\u09be Firefox\\nSERVER:\u0993\u09af\u09bc\u09c7\u09ac\u09b8\u09be\u0987\u099f \u09b9\u09cb\u09b8\u09cd\u099f \u0995\u09b0\u09c7\\nFUNCTION:\u09aa\u09c1\u09a8\u09b0\u09cd\u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0\u09af\u09cb\u0997\u09cd\u09af \u0995\u09cb\u09a1\\nARRAY:\u09ae\u09be\u09a8\u09c7\u09b0 \u09a4\u09be\u09b2\u09bf\u0995\u09be\\nLOOP:\u0995\u09cb\u09a1 \u09aa\u09c1\u09a8\u09b0\u09be\u09ac\u09c3\u09a4\u09cd\u09a4\u09bf \u0995\u09b0\u09c7\\nDEBUG:\u0995\u09cb\u09a1 \u09a4\u09cd\u09b0\u09c1\u099f\u09bf \u09b8\u0982\u09b6\u09cb\u09a7\u09a8\\nCLOUD:\u09a6\u09c2\u09b0\u09ac\u09b0\u09cd\u09a4\u09c0 \u09a1\u09c7\u099f\u09be \u09b8\u099e\u09cd\u099a\u09af\u09bc\\nNETWORK:\u09b8\u0982\u09af\u09c1\u0995\u09cd\u09a4 \u0995\u09ae\u09cd\u09aa\u09bf\u0989\u099f\u09be\u09b0\\nDATABASE:\u09a1\u09c7\u099f\u09be \u09b8\u0982\u09b0\u0995\u09cd\u09b7\u09a3',\r\n    vi:'PYTHON:Ng\u00f4n ng\u1eef l\u1eadp tr\u00ecnh ph\u1ed5 bi\u1ebfn\\nBROWSER:Chrome ho\u1eb7c Firefox\\nSERVER:L\u01b0u tr\u1eef trang web\\nFUNCTION:Kh\u1ed1i m\u00e3 t\u00e1i s\u1eed d\u1ee5ng\\nARRAY:Danh s\u00e1ch gi\u00e1 tr\u1ecb c\u00f3 th\u1ee9 t\u1ef1\\nLOOP:L\u1eb7p l\u1ea1i m\u00e3 \u0111\u1ebfn \u0111i\u1ec1u ki\u1ec7n\\nDEBUG:T\u00ecm v\u00e0 s\u1eeda l\u1ed7i m\u00e3\\nCLOUD:L\u01b0u tr\u1eef d\u1eef li\u1ec7u t\u1eeb xa\\nNETWORK:M\u00e1y t\u00ednh k\u1ebft n\u1ed1i\\nDATABASE:L\u01b0u tr\u1eef d\u1eef li\u1ec7u',\r\n    th:'PYTHON:\u0e20\u0e32\u0e29\u0e32\u0e42\u0e1b\u0e23\u0e41\u0e01\u0e23\u0e21\u0e22\u0e2d\u0e14\u0e19\u0e34\u0e22\u0e21\\nBROWSER:Chrome \u0e2b\u0e23\u0e37\u0e2d Firefox\\nSERVER:\u0e42\u0e2e\u0e2a\u0e15\u0e4c\u0e40\u0e27\u0e47\u0e1a\u0e44\u0e0b\u0e15\u0e4c\\nFUNCTION:\u0e1a\u0e25\u0e47\u0e2d\u0e01\u0e42\u0e04\u0e49\u0e14\u0e17\u0e35\u0e48\u0e43\u0e0a\u0e49\u0e0b\u0e49\u0e33\u0e44\u0e14\u0e49\\nARRAY:\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e04\u0e48\u0e32\u0e17\u0e35\u0e48\u0e21\u0e35\u0e25\u0e33\u0e14\u0e31\u0e1a\\nLOOP:\u0e17\u0e33\u0e0b\u0e49\u0e33\u0e42\u0e04\u0e49\u0e14\u0e08\u0e19\u0e40\u0e07\u0e37\u0e48\u0e2d\u0e19\u0e44\u0e02\\nDEBUG:\u0e04\u0e49\u0e19\u0e2b\u0e32\u0e41\u0e25\u0e30\u0e41\u0e01\u0e49\u0e44\u0e02\u0e02\u0e49\u0e2d\u0e1c\u0e34\u0e14\u0e1e\u0e25\u0e32\u0e14\\nCLOUD:\u0e08\u0e31\u0e14\u0e40\u0e01\u0e47\u0e1a\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e23\u0e30\u0e22\u0e30\u0e44\u0e01\u0e25\\nNETWORK:\u0e04\u0e2d\u0e21\u0e1e\u0e34\u0e27\u0e40\u0e15\u0e2d\u0e23\u0e4c\u0e17\u0e35\u0e48\u0e40\u0e0a\u0e37\u0e48\u0e2d\u0e21\u0e15\u0e48\u0e2d\\nDATABASE:\u0e08\u0e31\u0e14\u0e40\u0e01\u0e47\u0e1a\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25',\r\n    sw:'PYTHON:Lugha maarufu ya programu\\nBROWSER:Chrome au Firefox\\nSERVER:Inashughulikia tovuti\\nFUNCTION:Kipande cha msimbo\\nARRAY:Orodha ya thamani\\nLOOP:Inaendelea hadi hali\\nDEBUG:Tafuta rekebisha makosa\\nCLOUD:Hifadhi ya data mbali\\nNETWORK:Kompyuta zilizounganishwa\\nDATABASE:Hifadhi data',\r\n    nl:'PYTHON:Populaire programmeertaal\\nBROWSER:Chrome of Firefox\\nSERVER:Host websites\\nFUNCTION:Herbruikbaar codeblok\\nARRAY:Geordende lijst waarden\\nLOOP:Herhaalt code tot voorwaarde\\nDEBUG:Zoek en herstel codefouten\\nCLOUD:Externe gegevensopslag\\nNETWORK:Verbonden computers\\nDATABASE:Slaat gegevens op',\r\n    pl:'PYTHON:Popularny j\u0119zyk programowania\\nBROWSER:Chrome lub Firefox\\nSERVER:Hostuje strony internetowe\\nFUNCTION:Blok kodu wielokrotnego u\u017cytku\\nARRAY:Lista warto\u015bci\\nLOOP:Powtarza kod do warunku\\nDEBUG:Znajd\u017a napraw b\u0142\u0119dy\\nCLOUD:Zdalne przechowywanie\\nNETWORK:Po\u0142\u0105czone komputery\\nDATABASE:Przechowuje dane',\r\n    uk:'PYTHON:\u041f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430 \u043c\u043e\u0432\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0443\u0432\u0430\u043d\u043d\u044f\\nBROWSER:Chrome \u0430\u0431\u043e Firefox\\nSERVER:\u0420\u043e\u0437\u043c\u0456\u0449\u0443\u0454 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u0438\\nFUNCTION:\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0443 \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u044f\\nARRAY:\u0412\u043f\u043e\u0440\u044f\u0434\u043a\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a\\nLOOP:\u041f\u043e\u0432\u0442\u043e\u0440\u044e\u0454 \u043a\u043e\u0434 \u0434\u043e \u0443\u043c\u043e\u0432\u0438\\nDEBUG:\u0417\u043d\u0430\u0439\u0434\u0438 \u0432\u0438\u043f\u0440\u0430\u0432 \u043f\u043e\u043c\u0438\u043b\u043a\u0438\\nCLOUD:\u0412\u0456\u0434\u0434\u0430\u043b\u0435\u043d\u0435 \u0437\u0431\u0435\u0440\u0456\u0433\u0430\u043d\u043d\u044f \u0434\u0430\u043d\u0438\u0445\\nNETWORK:\u041f\u0456\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0456 \u043a\u043e\u043c\u043f\\'\u044e\u0442\u0435\u0440\u0438\\nDATABASE:\u0417\u0431\u0435\u0440\u0456\u0433\u0430\u0454 \u0434\u0430\u043d\u0456',\r\n    el:'PYTHON:\u0394\u03b7\u03bc\u03bf\u03c6\u03b9\u03bb\u03ae\u03c2 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03c0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03bf\u03cd\\nBROWSER:Chrome \u03ae Firefox\\nSERVER:\u03a6\u03b9\u03bb\u03bf\u03be\u03b5\u03bd\u03b5\u03af \u03b9\u03c3\u03c4\u03bf\u03c3\u03b5\u03bb\u03af\u03b4\u03b5\u03c2\\nFUNCTION:\u03a4\u03bc\u03ae\u03bc\u03b1 \u03ba\u03ce\u03b4\u03b9\u03ba\u03b1\\nARRAY:\u0394\u03b9\u03b1\u03c4\u03b5\u03c4\u03b1\u03b3\u03bc\u03ad\u03bd\u03b7 \u03bb\u03af\u03c3\u03c4\u03b1\\nLOOP:\u0395\u03c0\u03b1\u03bd\u03b1\u03bb\u03b1\u03bc\u03b2\u03ac\u03bd\u03b5\u03b9 \u03ba\u03ce\u03b4\u03b9\u03ba\u03b1\\nDEBUG:\u0395\u03cd\u03c1\u03b5\u03c3\u03b7 \u03b4\u03b9\u03cc\u03c1\u03b8\u03c9\u03c3\u03b7 \u03c3\u03c6\u03b1\u03bb\u03bc\u03ac\u03c4\u03c9\u03bd\\nCLOUD:\u0391\u03c0\u03bf\u03bc\u03b1\u03ba\u03c1\u03c5\u03c3\u03bc\u03ad\u03bd\u03b7 \u03b1\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7\\nNETWORK:\u03a3\u03c5\u03bd\u03b4\u03b5\u03b4\u03b5\u03bc\u03ad\u03bd\u03bf\u03b9 \u03c5\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03c4\u03ad\u03c2\\nDATABASE:\u0391\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03b5\u03b9 \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1',\r\n    he:'PYTHON:\u05e9\u05e4\u05ea \u05ea\u05db\u05e0\u05d5\u05ea \u05e4\u05d5\u05e4\u05d5\u05dc\u05e8\u05d9\u05ea\\nBROWSER:\u05db\u05e8\u05d5\u05dd \u05d0\u05d5 \u05e4\u05d9\u05d9\u05e8\u05e4\u05d5\u05e7\u05e1\\nSERVER:\u05de\u05d0\u05e8\u05d7 \u05d0\u05ea\u05e8\u05d9\u05dd\\nFUNCTION:\u05d1\u05dc\u05d5\u05e7 \u05e7\u05d5\u05d3 \u05dc\u05e9\u05d9\u05de\u05d5\u05e9 \u05d7\u05d5\u05d6\u05e8\\nARRAY:\u05e8\u05e9\u05d9\u05de\u05d4 \u05de\u05e1\u05d5\u05d3\u05e8\u05ea\\nLOOP:\u05d7\u05d5\u05d6\u05e8 \u05e2\u05dc \u05e7\u05d5\u05d3 \u05e2\u05d3 \u05ea\u05e0\u05d0\u05d9\\nDEBUG:\u05de\u05e6\u05d0 \u05ea\u05e7\u05df \u05e9\u05d2\u05d9\u05d0\u05d5\u05ea \u05e7\u05d5\u05d3\\nCLOUD:\u05d0\u05d7\u05e1\u05d5\u05df \u05e0\u05ea\u05d5\u05e0\u05d9\u05dd \u05de\u05e8\u05d7\u05d5\u05e7\\nNETWORK:\u05de\u05d7\u05e9\u05d1\u05d9\u05dd \u05de\u05d7\u05d5\u05d1\u05e8\u05d9\u05dd\\nDATABASE:\u05de\u05d0\u05d7\u05e1\u05df \u05e0\u05ea\u05d5\u05e0\u05d9\u05dd',\r\n    fa:'PYTHON:\u0632\u0628\u0627\u0646 \u0628\u0631\u0646\u0627\u0645\u0647\u200c\u0646\u0648\u06cc\u0633\u06cc \u0645\u062d\u0628\u0648\u0628\\nBROWSER:\u06a9\u0631\u0648\u0645 \u06cc\u0627 \u0641\u0627\u06cc\u0631\u0641\u0627\u06a9\u0633\\nSERVER:\u0645\u06cc\u0632\u0628\u0627\u0646\u06cc \u0648\u0628\u200c\u0633\u0627\u06cc\u062a\u200c\u0647\u0627\\nFUNCTION:\u0628\u0644\u0648\u06a9 \u06a9\u062f \u0642\u0627\u0628\u0644 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u062c\u062f\u062f\\nARRAY:\u0644\u06cc\u0633\u062a \u0645\u0631\u062a\u0628\\nLOOP:\u062a\u06a9\u0631\u0627\u0631 \u06a9\u062f \u062a\u0627 \u0634\u0631\u0637\\nDEBUG:\u067e\u06cc\u062f\u0627 \u0631\u0641\u0639 \u062e\u0637\u0627\u0647\u0627\u06cc \u06a9\u062f\\nCLOUD:\u0630\u062e\u06cc\u0631\u0647\u200c\u0633\u0627\u0632\u06cc \u0627\u0632 \u0631\u0627\u0647 \u062f\u0648\u0631\\nNETWORK:\u06a9\u0627\u0645\u067e\u06cc\u0648\u062a\u0631\u0647\u0627\u06cc \u0645\u062a\u0635\u0644\\nDATABASE:\u0630\u062e\u06cc\u0631\u0647 \u062f\u0627\u062f\u0647\u200c\u0647\u0627',\r\n    ur:'PYTHON:\u0645\u0642\u0628\u0648\u0644 \u067e\u0631\u0648\u06af\u0631\u0627\u0645\u0646\u06af \u0632\u0628\u0627\u0646\\nBROWSER:\u06a9\u0631\u0648\u0645 \u06cc\u0627 \u0641\u0627\u0626\u0631\u0641\u0627\u06a9\u0633\\nSERVER:\u0648\u06cc\u0628 \u0633\u0627\u0626\u0679\u0633 \u06a9\u06cc \u0645\u06cc\u0632\u0628\u0627\u0646\u06cc\\nFUNCTION:\u062f\u0648\u0628\u0627\u0631\u06c1 \u0642\u0627\u0628\u0644 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0648\u0688\\nARRAY:\u062a\u0631\u062a\u06cc\u0628 \u0634\u062f\u06c1 \u0627\u0642\u062f\u0627\u0631\\nLOOP:\u0634\u0631\u0637 \u062a\u06a9 \u06a9\u0648\u0688 \u062f\u06c1\u0631\u0627\u062a\u0627\\nDEBUG:\u06a9\u0648\u0688 \u063a\u0644\u0637\u06cc\u0627\u06ba \u062a\u0644\u0627\u0634 \u06a9\u0631\u06cc\u06ba\\nCLOUD:\u062f\u0648\u0631 \u0688\u06cc\u0679\u0627 \u0627\u0633\u0679\u0648\u0631\u06cc\u062c\\nNETWORK:\u0645\u0646\u0633\u0644\u06a9 \u06a9\u0645\u067e\u06cc\u0648\u0679\u0631\\nDATABASE:\u0645\u0646\u0638\u0645 \u0688\u06cc\u0679\u0627 \u0645\u062d\u0641\u0648\u0638',\r\n    ne:'PYTHON:\u0932\u094b\u0915\u092a\u094d\u0930\u093f\u092f \u092a\u094d\u0930\u094b\u0917\u094d\u0930\u093e\u092e\u093f\u0919 \u092d\u093e\u0937\u093e\\nBROWSER:Chrome \u0935\u093e Firefox\\nSERVER:\u0935\u0947\u092c\u0938\u093e\u0907\u091f \u0939\u094b\u0938\u094d\u091f \u0917\u0930\u094d\u091b\\nFUNCTION:\u092a\u0941\u0928\u0903 \u092a\u094d\u0930\u092f\u094b\u0917 \u0915\u094b\u0921\\nARRAY:\u0915\u094d\u0930\u092e\u092c\u0926\u094d\u0927 \u0938\u0942\u091a\u0940\\nLOOP:\u0938\u0930\u094d\u0924 \u0938\u092e\u094d\u092e \u0926\u094b\u0939\u094b\u0930\u094d\u092f\u093e\u0909\u0901\u091b\\nDEBUG:\u0915\u094b\u0921 \u0924\u094d\u0930\u0941\u091f\u093f \u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d\\nCLOUD:\u091f\u093e\u0922\u093e\u0915\u094b \u0921\u093e\u091f\u093e \u092d\u0923\u094d\u0921\u093e\u0930\u0923\\nNETWORK:\u091c\u0921\u093e\u0928 \u0915\u092e\u094d\u092a\u094d\u092f\u0941\u091f\u0930\\nDATABASE:\u0921\u093e\u091f\u093e \u092d\u0923\u094d\u0921\u093e\u0930',\r\n    sv:'PYTHON:Popul\u00e4rt programmeringsspr\u00e5k\\nBROWSER:Chrome eller Firefox\\nSERVER:V\u00e4rd f\u00f6r webbplatser\\nFUNCTION:\u00c5teranv\u00e4ndbart kodblock\\nARRAY:Ordnad lista med v\u00e4rden\\nLOOP:Upprepar kod till villkor\\nDEBUG:Hitta \u00e5tg\u00e4rda kodfel\\nCLOUD:Fj\u00e4rrlagring av data\\nNETWORK:Anslutna datorer\\nDATABASE:Lagrar organiserad data',\r\n    ro:'PYTHON:Limbaj de programare popular\\nBROWSER:Chrome sau Firefox\\nSERVER:G\u0103zduie\u0219te site-uri web\\nFUNCTION:Bloc de cod reutilizabil\\nARRAY:List\u0103 ordonat\u0103 de valori\\nLOOP:Repet\u0103 codul\\nDEBUG:G\u0103se\u0219te repar\u0103 erori\\nCLOUD:Stocare date la distan\u021b\u0103\\nNETWORK:Computere conectate\\nDATABASE:Stocheaz\u0103 date',\r\n    fil:'PYTHON:Sikat na programming language\\nBROWSER:Chrome o Firefox\\nSERVER:Nag-host ng mga website\\nFUNCTION:Muling magagamit na code\\nARRAY:Listahan ng mga halaga\\nLOOP:Inuulit ang code\\nDEBUG:Hanapin ayusin ang pagkakamali\\nCLOUD:Remote na imbakan\\nNETWORK:Mga konektadong computer\\nDATABASE:Nag-iimbak ng data',\r\n    af:'PYTHON:Gewilde programmeringstaal\\nBROWSER:Chrome of Firefox\\nSERVER:Huisves webwerwe\\nFUNCTION:Herbruikbare kodeblok\\nARRAY:Geordende lys van waardes\\nLOOP:Herhaal kode tot toestand\\nDEBUG:Vind stel kodefoute reg\\nCLOUD:Afgele\u00eb databerging\\nNETWORK:Verbonde rekenaars\\nDATABASE:Stoor georganiseerde data'\r\n  };\r\n\r\n  \/* Current selected language *\/\r\n  var CW_CURRENT_LANG = { code:'en', flag:'&#x1F1EC;&#x1F1E7;', native:'English', en:'English' };\r\n\r\n  \/* ============================================================\r\n     LANGUAGE POPUP SYSTEM\r\n     ============================================================ *\/\r\n  var langOverlay = null;\r\n\r\n  function buildLangPopup() {\r\n    if (document.getElementById('pth-cw-lang-overlay')) return;\r\n\r\n    \/* Inject CSS *\/\r\n    var style = document.createElement('style');\r\n    style.textContent = [\r\n      '#pth-cw-lang-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;',\r\n        'background:rgba(15,23,42,0.55);z-index:9999998;',\r\n        'align-items:center;justify-content:center;padding:16px;}',\r\n      '#pth-cw-lang-overlay.pth-lo-open{display:flex;}',\r\n      '#pth-cw-lang-modal{background:#fff;border-radius:16px;width:100%;max-width:660px;',\r\n        'max-height:88vh;display:flex;flex-direction:column;',\r\n        'box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}',\r\n      '.pth-lm-head{padding:20px 20px 0;flex-shrink:0;}',\r\n      '.pth-lm-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;',\r\n        'font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-sub{font-size:0.78rem;color:#334155;margin:0 0 12px;',\r\n        'font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-close{position:absolute;top:14px;right:14px;background:#f1f5f9;',\r\n        'border:none;width:32px;height:32px;border-radius:50%;font-size:0.9rem;',\r\n        'cursor:pointer;color:#334155;display:flex;align-items:center;',\r\n        'justify-content:center;font-family:inherit;font-weight:700;}',\r\n      '.pth-lm-close:hover{background:#e2e8f0;}',\r\n      '.pth-lm-search-wrap{padding:0 16px 10px;flex-shrink:0;}',\r\n      '.pth-lm-search{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-family:Inter,system-ui,sans-serif;font-size:0.85rem;color:#1e293b;outline:none;background:#f8fafc;}',\r\n      '.pth-lm-search::placeholder{color:#94a3b8;}',\r\n     '.pth-lm-search:focus{border-color:#2563eb;background-color:#fff;}',\r\n      '.pth-lm-grid-wrap{overflow-y:auto;flex:1;padding:0 8px 8px;}',\r\n      '.pth-lm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}',\r\n      '.pth-lm-item{display:flex;align-items:center;gap:8px;padding:9px 10px;',\r\n        'border-radius:8px;cursor:pointer;border:2px solid transparent;',\r\n        'font-family:Inter,system-ui,sans-serif;background:transparent;',\r\n        'text-align:left;width:100%;transition:background 0.1s;}',\r\n      '.pth-lm-item:hover{background:#f1f5f9;}',\r\n      '.pth-lm-item.pth-lm-sel{background:#eff6ff;border-color:#bfdbfe;}',\r\n      '.pth-lm-flag{font-size:0.62rem;font-weight:800;line-height:1;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;text-align:center;background:#eff6ff;color:#1d4ed8;border-radius:5px;letter-spacing:0.3px;}',\r\n      '.pth-lm-names{display:flex;flex-direction:column;min-width:0;}',\r\n      '.pth-lm-native{font-size:0.82rem;font-weight:700;color:#0f172a;',\r\n        'white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}',\r\n      '.pth-lm-en{font-size:0.7rem;color:#334155;font-weight:500;}',\r\n      '.pth-lm-footer{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;',\r\n        'align-items:center;justify-content:space-between;flex-shrink:0;background:#f8fafc;}',\r\n      '.pth-lm-footer-cur{font-size:0.8rem;color:#334155;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-footer-cur strong{color:#1d4ed8;}',\r\n      '.pth-lm-no-res{text-align:center;padding:24px;color:#334155;',\r\n        'font-size:0.85rem;font-family:Inter,system-ui,sans-serif;display:none;}',\r\n      '@media(max-width:520px){.pth-lm-grid{grid-template-columns:repeat(2,1fr);}',\r\n        '#pth-cw-lang-modal{border-radius:12px;max-height:92vh;}}',\r\n      '@media(max-width:360px){.pth-lm-grid{grid-template-columns:1fr;}}'\r\n    ].join('');\r\n    document.head.appendChild(style);\r\n\r\n    \/* Build modal HTML *\/\r\n    var overlay = document.createElement('div');\r\n    overlay.id = 'pth-cw-lang-overlay';\r\n    overlay.setAttribute('role','dialog');\r\n    overlay.setAttribute('aria-modal','true');\r\n    overlay.setAttribute('aria-label','Choose clue language');\r\n    overlay.innerHTML =\r\n      '<div id=\"pth-cw-lang-modal\">' +\r\n        '<div class=\"pth-lm-head\">' +\r\n          '<p class=\"pth-lm-title\">&#x1F30D; Choose Clue Language<\/p>' +\r\n          '<p class=\"pth-lm-sub\">Select language for sample data and AI-generated clues<\/p>' +\r\n        '<\/div>' +\r\n        '<button class=\"pth-lm-close\" id=\"pth-cw-lm-close\" aria-label=\"Close\">&#x2715;<\/button>' +\r\n        '<div class=\"pth-lm-search-wrap\">' +\r\n          '<input type=\"text\" class=\"pth-lm-search\" id=\"pth-cw-lm-search\"' +\r\n            ' placeholder=\"Search language...\" aria-label=\"Search language\" autocomplete=\"off\">' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-grid-wrap\">' +\r\n          '<div class=\"pth-lm-grid\" id=\"pth-cw-lm-grid\"><\/div>' +\r\n          '<div class=\"pth-lm-no-res\" id=\"pth-cw-lm-nores\">No languages found.<\/div>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-footer\">' +\r\n          '<span class=\"pth-lm-footer-cur\">Selected: <strong id=\"pth-cw-lm-cur\">English<\/strong><\/span>' +\r\n          '<span style=\"font-size:0.72rem;color:#475569;\">&#x1F512; Browser only<\/span>' +\r\n        '<\/div>' +\r\n      '<\/div>';\r\n    document.body.appendChild(overlay);\r\n    langOverlay = overlay;\r\n\r\n    \/* Render language grid *\/\r\n    renderLangGrid('');\r\n\r\n    \/* Search handler *\/\r\n    var searchEl = document.getElementById('pth-cw-lm-search');\r\n    if (searchEl) {\r\n      searchEl.addEventListener('input', function() {\r\n        renderLangGrid(searchEl.value.toLowerCase().trim());\r\n      });\r\n    }\r\n\r\n    \/* Close handlers *\/\r\n    var closeBtn = document.getElementById('pth-cw-lm-close');\r\n    if (closeBtn) closeBtn.addEventListener('click', closeLangPopup);\r\n    overlay.addEventListener('click', function(e) {\r\n      if (e.target === overlay) closeLangPopup();\r\n    });\r\n    document.addEventListener('keydown', function(e) {\r\n      if (e.key === 'Escape') closeLangPopup();\r\n    });\r\n  }\r\n\r\n  function renderLangGrid(query) {\r\n    var grid   = document.getElementById('pth-cw-lm-grid');\r\n    var nores  = document.getElementById('pth-cw-lm-nores');\r\n    if (!grid) return;\r\n    grid.innerHTML = '';\r\n    var filtered = CW_LANGS.filter(function(l) {\r\n      if (!query) return true;\r\n      return l.en.toLowerCase().indexOf(query) !== -1 ||\r\n             l.native.toLowerCase().indexOf(query) !== -1 ||\r\n             l.code.indexOf(query) !== -1;\r\n    });\r\n    if (!filtered.length) {\r\n      if (nores) nores.style.display = 'block';\r\n      return;\r\n    }\r\n    if (nores) nores.style.display = 'none';\r\n    filtered.forEach(function(l) {\r\n      var btn = document.createElement('button');\r\n      btn.className = 'pth-lm-item' + (l.code === CW_CURRENT_LANG.code ? ' pth-lm-sel' : '');\r\n      btn.innerHTML =\r\n        '<span class=\"pth-lm-flag\">' + l.code.toUpperCase() + '<\/span>' +\r\n        '<span class=\"pth-lm-names\">' +\r\n          '<span class=\"pth-lm-native\">' + l.native + '<\/span>' +\r\n          '<span class=\"pth-lm-en\">' + l.en + '<\/span>' +\r\n        '<\/span>';\r\n      btn.addEventListener('click', function() { selectLang(l); });\r\n      grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function selectLang(l) {\r\n    CW_CURRENT_LANG = l;\r\n    \/* Update current label in modal *\/\r\n    var cur = document.getElementById('pth-cw-lm-cur');\r\n    if (cur) cur.innerHTML = l.code.toUpperCase() + ' ' + l.native + ' (' + l.en + ')';\r\n    \/* Update picker button *\/\r\n    updatePickerBtn();\r\n    \/* Load sample if available *\/\r\n    if (CW_SAMPLES[l.code]) {\r\n      var ta = document.getElementById('pth-cw-input');\r\n      if (ta) {\r\n        ta.value = CW_SAMPLES[l.code];\r\n        applyLangToInput(ta, CW_SAMPLES[l.code]);\r\n      }\r\n      window.pthILS.toast('Loaded: ' + l.native + ' (' + l.en + ')', 'success');\r\n    } else {\r\n      window.pthILS.toast(l.en + ' selected! Type your own clues.', 'info');\r\n    }\r\n    \/* Re-render to show selection *\/\r\n    var searchEl = document.getElementById('pth-cw-lm-search');\r\n    renderLangGrid(searchEl ? searchEl.value.toLowerCase().trim() : '');\r\n    closeLangPopup();\r\n  }\r\n\r\n  function openLangPopup() {\r\n    buildLangPopup();\r\n    var overlay = document.getElementById('pth-cw-lang-overlay');\r\n    if (overlay) {\r\n      overlay.classList.add('pth-lo-open');\r\n      var s = document.getElementById('pth-cw-lm-search');\r\n      if (s) { s.value = ''; renderLangGrid(''); setTimeout(function(){ s.focus(); }, 100); }\r\n    }\r\n  }\r\n\r\n  function closeLangPopup() {\r\n    var overlay = document.getElementById('pth-cw-lang-overlay');\r\n    if (overlay) overlay.classList.remove('pth-lo-open');\r\n  }\r\n\r\n  function updatePickerBtn() {\r\n    var btn  = document.getElementById('pth-cw-lang-pick-btn');\r\n    var flag = document.getElementById('pth-cw-pick-flag');\r\n    var text = document.getElementById('pth-cw-pick-text');\r\n    if (flag) flag.innerHTML = CW_CURRENT_LANG.code.toUpperCase();\r\n    if (text) text.innerHTML = CW_CURRENT_LANG.native + ' \u2014 ' + CW_CURRENT_LANG.en;\r\n  }\r\n\r\n  \/* ============================================================\r\n     BUILD TAB HTML\r\n     ============================================================ *\/\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-crossword');\r\n    if (!panel || panel.getAttribute('data-cw-built')) return;\r\n    panel.setAttribute('data-cw-built','1');\r\n\r\n    panel.innerHTML =\r\n      '<div class=\"pth-ils-layout\" id=\"pth-cw-layout\">' +\r\n      '<div class=\"pth-ils-main\">' +\r\n\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F9E9; Crossword Creator<\/h3>' +\r\n\r\n          \/* Language picker button \u2014 single button, opens popup *\/\r\n          '<button class=\"pth-cw-lang-pick-btn\" id=\"pth-cw-lang-pick-btn\" aria-label=\"Choose clue language\">' +\r\n            '<span class=\"pth-cw-lang-pick-flag\" id=\"pth-cw-pick-flag\">EN<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-text\" id=\"pth-cw-pick-text\">English \u2014 Clue Language<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-arrow\">&#x25BC;<\/span>' +\r\n          '<\/button>' +\r\n\r\n          \/* Info *\/\r\n          '<div style=\"font-size:0.78rem;color:#334155;margin-bottom:8px;line-height:1.5;background:#f8fafc;padding:6px 10px;border-radius:6px;border:1px solid #e2e8f0;\">' +\r\n            '&#x2139;&#xFE0F; <strong>Any language for clues!<\/strong> WORD = Latin (A-Z) for grid. Clues = Sinhala, Tamil, Arabic, any script.' +\r\n          '<\/div>' +\r\n\r\n          \/* Textarea *\/\r\n          '<label class=\"pth-ils-label\" for=\"pth-cw-input\">Enter WORD : Clue pairs &#x2014; one per line<\/label>' +\r\n          '<p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 6px;font-style:italic;\">&#x2139;&#xFE0F; The text below is just an example placeholder (not real data) &#x2014; type your own WORD:Clue pairs, or click &#x1F4A1; <strong>Load Sample<\/strong> above to fill in working examples.<\/p>' +\r\n          '<textarea class=\"pth-ils-textarea\" id=\"pth-cw-input\" aria-label=\"Word clue pairs\" style=\"min-height:160px;\"' +\r\n            ' placeholder=\"PYTHON:Popular programming language&#10;BROWSER:Chrome or Firefox&#10;SERVER:Hosts websites online&#10;FUNCTION:Reusable block of code&#10;ARRAY:Ordered list of values&#10;LOOP:Repeats code until condition&#10;DEBUG:Find and fix code errors&#10;CLOUD:Remote data storage\"><\/textarea>' +\r\n\r\n          \/* Buttons *\/\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-cw-gen-btn\">&#x26A1; Generate<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-cw-check-btn\">&#x2705; Check Answers<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-cw-reveal-btn\">&#x1F441; Reveal All<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-cw-reset-btn\">&#x1F504; Reset Grid<\/button>' +\r\n          '<\/div>' +\r\n          '<div id=\"pth-cw-status\" class=\"pth-ils-info\" style=\"display:none;\"><\/div>' +\r\n        '<\/div>' +\r\n\r\n        \/* Grid *\/\r\n        '<div class=\"pth-ils-card\" id=\"pth-cw-grid-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F9E9; Crossword Grid<\/h3>' +\r\n          '<div id=\"pth-cw-grid-wrap\" style=\"overflow-x:auto;\"><\/div>' +\r\n          '<div id=\"pth-cw-clues-wrap\"><\/div>' +\r\n        '<\/div>' +\r\n\r\n        \/* Export *\/\r\n        '<div class=\"pth-ils-card\" id=\"pth-cw-export-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F4E4; Export<\/h3>' +\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-cw-png-btn\">&#x1F5BC; Export PNG<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-cw-html-btn\">&#x1F4C4; Download HTML<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-cw-copy-btn\">&#x1F4CB; Copy HTML Code<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-cw-print-btn\">&#x1F5A8; Print Puzzle<\/button>' +\r\n          '<\/div>' +\r\n          '<div class=\"pth-ils-code-box\" id=\"pth-cw-code-box\" style=\"display:none;\">' +\r\n            '<textarea id=\"pth-cw-code-ta\" readonly aria-label=\"HTML code\" style=\"min-height:120px;\"><\/textarea>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n        \/* Customizer *\/\r\n        '<div class=\"pth-ils-card\" id=\"pth-cw-custom-card\">' +\r\n          '<h3>&#x1F3A8; Customize<\/h3>' +\r\n          '<div class=\"pth-cw-customizer\">' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-cell-size\">Cell Size<\/label><input type=\"range\" id=\"pth-cw-cell-size\" min=\"28\" max=\"56\" value=\"38\" aria-label=\"Cell size\"><span class=\"pth-cw-custom-val\" id=\"pth-cw-cell-size-val\">38px<\/span><\/div>' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-font-size\">Letter Size<\/label><input type=\"range\" id=\"pth-cw-font-size\" min=\"10\" max=\"22\" value=\"14\" aria-label=\"Font size\"><span class=\"pth-cw-custom-val\" id=\"pth-cw-font-size-val\">14px<\/span><\/div>' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-col-cell\">Cell BG<\/label><input type=\"color\" id=\"pth-cw-col-cell\" value=\"#ffffff\" aria-label=\"Cell bg\"><\/div>' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-col-black\">Black Cell<\/label><input type=\"color\" id=\"pth-cw-col-black\" value=\"#0f172a\" aria-label=\"Black cell\"><\/div>' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-col-text\">Letter Color<\/label><input type=\"color\" id=\"pth-cw-col-text\" value=\"#0f172a\" aria-label=\"Letter color\"><\/div>' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-col-correct\">Correct Cell<\/label><input type=\"color\" id=\"pth-cw-col-correct\" value=\"#dcfce7\" aria-label=\"Correct color\"><\/div>' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-col-wrong\">Wrong Cell<\/label><input type=\"color\" id=\"pth-cw-col-wrong\" value=\"#fef2f2\" aria-label=\"Wrong color\"><\/div>' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-col-across\">Across Color<\/label><input type=\"color\" id=\"pth-cw-col-across\" value=\"#1d4ed8\" aria-label=\"Across color\"><\/div>' +\r\n            '<div class=\"pth-cw-custom-item\"><label for=\"pth-cw-col-down\">Down Color<\/label><input type=\"color\" id=\"pth-cw-col-down\" value=\"#7c3aed\" aria-label=\"Down color\"><\/div>' +\r\n          '<\/div>' +\r\n          '<button class=\"pth-ils-btn pth-ils-btn-outline pth-ils-btn-sm\" id=\"pth-cw-reset-theme-btn\">&#x21BA; Reset Defaults<\/button>' +\r\n        '<\/div>' +\r\n\r\n      '<\/div>' + \/* end main *\/\r\n\r\n      '<div class=\"pth-ils-sidebar\">' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4A1; How to Use<\/h3>' +\r\n          '<p style=\"font-size:0.82rem;color:#334155;line-height:1.6;margin:0;\">' +\r\n            '1. Click the <strong>language button<\/strong> to choose clue language.<br>' +\r\n            '2. Or type <strong>WORD:Clue<\/strong> pairs manually.<br>' +\r\n            '3. Clues = any language! &#x1F30D;<br>' +\r\n            '4. Click <strong>&#x26A1; Generate<\/strong>.<br>' +\r\n            '5. Solve grid. Check answers.<br>' +\r\n            '6. Export PNG or HTML to share.' +\r\n          '<\/p>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4CA; Stats<\/h3>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Words placed<\/span><span class=\"pth-ils-stat-val\" id=\"pth-cw-s-placed\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Skipped<\/span><span class=\"pth-ils-stat-val\" id=\"pth-cw-s-skipped\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Grid size<\/span><span class=\"pth-ils-stat-val\" id=\"pth-cw-s-size\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Correct<\/span><span class=\"pth-ils-stat-val\" id=\"pth-cw-s-correct\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Score<\/span><span class=\"pth-ils-stat-val\" id=\"pth-cw-s-score\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Clue script<\/span><span class=\"pth-ils-stat-val\" id=\"pth-cw-s-lang\">&#8212;<\/span><\/div>' +\r\n        '<\/div>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n  }\r\n\r\n  \/* ============================================================\r\n     CROSSWORD ENGINE\r\n     ============================================================ *\/\r\n  var CW = {\r\n    grid:[], placed:[], acrossClues:[], downClues:[],\r\n    minR:0, maxR:0, minC:0, maxC:0, SIZE:21, skipped:[],\r\n    clueScript:'latin', clueRTL:false\r\n  };\r\n\r\n  function cwCanPlace(grid,word,row,col,dir,SIZE){\r\n    var wl=word.length;\r\n    if(dir==='across'){if(col+wl>SIZE)return false;if(col>0&&!grid[row][col-1].black)return false;if(col+wl<SIZE&&!grid[row][col+wl].black)return false;}\r\n    else{if(row+wl>SIZE)return false;if(row>0&&!grid[row-1][col].black)return false;if(row+wl<SIZE&&!grid[row+wl][col].black)return false;}\r\n    var hasI=CW.placed.length===0;\r\n    for(var i=0;i<wl;i++){\r\n      var r=dir==='down'?row+i:row,c=dir==='across'?col+i:col,cell=grid[r][c];\r\n      if(!cell.black){if(cell.letter!==word[i])return false;hasI=true;}\r\n      else{if(dir==='across'){if(r>0&&!grid[r-1][c].black)return false;if(r<SIZE-1&&!grid[r+1][c].black)return false;}\r\n           else{if(c>0&&!grid[r][c-1].black)return false;if(c<SIZE-1&&!grid[r][c+1].black)return false;}}\r\n    }\r\n    return hasI;\r\n  }\r\n\r\n  function cwTryPlace(grid,word,dir){\r\n    var SIZE=CW.SIZE,wl=word.length;\r\n    if(CW.placed.length===0){\r\n      var sr=Math.floor(SIZE\/2),sc=Math.floor((SIZE-wl)\/2);\r\n      for(var i=0;i<wl;i++){grid[sr][sc+i].letter=word[i];grid[sr][sc+i].black=false;}\r\n      CW.placed.push({word:word,row:sr,col:sc,dir:'across'});return true;\r\n    }\r\n    var shuffled=window.pthILS.shuffle(CW.placed.slice());\r\n    for(var pi=0;pi<shuffled.length;pi++){\r\n      var pw=shuffled[pi];\r\n      for(var wi=0;wi<wl;wi++){\r\n        for(var pwi=0;pwi<pw.word.length;pwi++){\r\n          if(word[wi]!==pw.word[pwi])continue;\r\n          var nr,nc;\r\n          if(pw.dir==='across'&&dir==='down'){nr=pw.row-wi;nc=pw.col+pwi;}\r\n          else if(pw.dir==='down'&&dir==='across'){nr=pw.row+pwi;nc=pw.col-wi;}\r\n          else{continue;}\r\n          if(nr<0||nc<0)continue;\r\n          if(dir==='down'&&nr+wl>SIZE)continue;\r\n          if(dir==='across'&&nc+wl>SIZE)continue;\r\n          if(cwCanPlace(grid,word,nr,nc,dir,SIZE)){\r\n            for(var li=0;li<wl;li++){var gr=dir==='down'?nr+li:nr,gc=dir==='across'?nc+li:nc;grid[gr][gc].letter=word[li];grid[gr][gc].black=false;}\r\n            CW.placed.push({word:word,row:nr,col:nc,dir:dir});return true;\r\n          }\r\n        }\r\n      }\r\n    }\r\n    return false;\r\n  }\r\n\r\n  function cwGenerate(){\r\n    var raw=(document.getElementById('pth-cw-input')||{}).value||'';\r\n    var pairs=window.pthILS.parsePairs(raw,':');\r\n    if(pairs.length<2){window.pthILS.toast('Enter at least 2 WORD:Clue pairs.','error');return;}\r\n    if(pairs.length>20)pairs=pairs.slice(0,20);\r\n    pairs=pairs.map(function(p){return{a:p.a.replace(\/[^A-Za-z]\/g,'').toUpperCase(),b:p.b.trim()};}).filter(function(p){return p.a.length>=2;});\r\n    if(pairs[0]&&pairs[0].b){CW.clueScript=window.pthILS.detectScript(pairs[0].b);CW.clueRTL=window.pthILS.isRTL(pairs[0].b);window.pthILS.loadFont(CW.clueScript);}\r\n    pairs.sort(function(a,b){return b.a.length-a.a.length;});\r\n    CW.grid=[];CW.placed=[];CW.skipped=[];\r\n    var SIZE=CW.SIZE;\r\n    for(var r=0;r<SIZE;r++){CW.grid[r]=[];for(var c=0;c<SIZE;c++)CW.grid[r][c]={letter:'',black:true,num:0};}\r\n    pairs.forEach(function(p,idx){\r\n      var dir=idx%2===0?'across':'down';\r\n      var ok=cwTryPlace(CW.grid,p.a,dir)||cwTryPlace(CW.grid,p.a,dir==='across'?'down':'across');\r\n      if(!ok)CW.skipped.push(p.a);\r\n    });\r\n    var minR=SIZE,maxR=0,minC=SIZE,maxC=0;\r\n    for(var r2=0;r2<SIZE;r2++)for(var c2=0;c2<SIZE;c2++)if(!CW.grid[r2][c2].black){if(r2<minR)minR=r2;if(r2>maxR)maxR=r2;if(c2<minC)minC=c2;if(c2>maxC)maxC=c2;}\r\n    minR=Math.max(0,minR-1);minC=Math.max(0,minC-1);maxR=Math.min(SIZE-1,maxR+1);maxC=Math.min(SIZE-1,maxC+1);\r\n    CW.minR=minR;CW.maxR=maxR;CW.minC=minC;CW.maxC=maxC;\r\n    var num=1;CW.acrossClues=[];CW.downClues=[];\r\n    for(var rn=minR;rn<=maxR;rn++){\r\n      for(var cn=minC;cn<=maxC;cn++){\r\n        if(CW.grid[rn][cn].black)continue;\r\n        var isA=(cn===minC||CW.grid[rn][cn-1].black)&&cn+1<=maxC&&!CW.grid[rn][cn+1].black;\r\n        var isD=(rn===minR||CW.grid[rn-1][cn].black)&&rn+1<=maxR&&!CW.grid[rn+1][cn].black;\r\n        if(isA||isD){\r\n          CW.grid[rn][cn].num=num;\r\n          if(isA){var maw=CW.placed.filter(function(pw){return pw.dir==='across'&&pw.row===rn&&pw.col===cn;})[0];if(maw){var paw=pairs.filter(function(p){return p.a===maw.word;})[0];CW.acrossClues.push({num:num,word:maw.word,clue:paw?paw.b:maw.word});}}\r\n          if(isD){var mdw=CW.placed.filter(function(pw){return pw.dir==='down'&&pw.row===rn&&pw.col===cn;})[0];if(mdw){var pdw=pairs.filter(function(p){return p.a===mdw.word;})[0];CW.downClues.push({num:num,word:mdw.word,clue:pdw?pdw.b:mdw.word});}}\r\n          num++;\r\n        }\r\n      }\r\n    }\r\n    cwRender();\r\n    var e=function(id){return document.getElementById(id);};\r\n    if(e('pth-cw-s-placed'))e('pth-cw-s-placed').textContent=CW.placed.length;\r\n    if(e('pth-cw-s-skipped'))e('pth-cw-s-skipped').textContent=CW.skipped.length;\r\n    if(e('pth-cw-s-size'))e('pth-cw-s-size').textContent=(maxR-minR+1)+'x'+(maxC-minC+1);\r\n    if(e('pth-cw-s-lang'))e('pth-cw-s-lang').textContent=CW.clueScript+(CW.clueRTL?' RTL':'');\r\n    var st=e('pth-cw-status');if(st){st.style.display='block';st.textContent=CW.placed.length+' words placed'+(CW.skipped.length?' | Skipped: '+CW.skipped.join(', '):'')+'.'; }\r\n    e('pth-cw-grid-card').style.display='block';e('pth-cw-export-card').style.display='block';\r\n    window.pthILS.toast('Crossword ready! '+CW.placed.length+' words.','success');\r\n  }\r\n\r\n  function cwRender(){\r\n    var minR=CW.minR,maxR=CW.maxR,minC=CW.minC,maxC=CW.maxC,rows=maxR-minR+1,cols=maxC-minC+1;\r\n    var wrap=document.getElementById('pth-cw-grid-wrap');if(!wrap)return;\r\n    var gd=document.createElement('div');\r\n    gd.className='pth-ils-cw-grid';gd.style.gridTemplateColumns='repeat('+cols+', var(--cw-cell-size))';\r\n    gd.setAttribute('data-rows',rows);gd.setAttribute('data-cols',cols);gd.id='pth-cw-grid-el';\r\n    for(var r=minR;r<=maxR;r++){\r\n      for(var c=minC;c<=maxC;c++){\r\n        var cell=CW.grid[r][c];\r\n        var div=document.createElement('div');\r\n        div.className='pth-ils-cw-cell'+(cell.black?' pth-ils-cw-black':'');\r\n        div.setAttribute('data-row',r-minR);div.setAttribute('data-col',c-minC);\r\n        div.setAttribute('data-letter',cell.black?'':cell.letter);\r\n        if(cell.num)div.setAttribute('data-num',cell.num);\r\n        if(!cell.black){\r\n          if(cell.num){var ns=document.createElement('span');ns.className='pth-ils-cw-num';ns.textContent=cell.num;div.appendChild(ns);}\r\n          var inp=document.createElement('input');inp.type='text';inp.maxLength=1;\r\n          inp.setAttribute('aria-label','Cell '+(r-minR)+','+(c-minC));inp.setAttribute('data-answer',cell.letter);\r\n          inp.addEventListener('input',function(e){\r\n            e.target.value=e.target.value.toUpperCase().replace(\/[^A-Z]\/g,'');\r\n            e.target.parentNode.classList.remove('pth-ils-cw-correct','pth-ils-cw-wrong','pth-ils-cw-revealed');\r\n            if(e.target.value){var nx=e.target.parentNode.nextElementSibling;while(nx&&nx.classList.contains('pth-ils-cw-black'))nx=nx.nextElementSibling;if(nx){var ni=nx.querySelector('input');if(ni)ni.focus();}}\r\n          });\r\n          inp.addEventListener('keydown',function(e){if(e.key==='Backspace'&&!e.target.value){var pv=e.target.parentNode.previousElementSibling;while(pv&&pv.classList.contains('pth-ils-cw-black'))pv=pv.previousElementSibling;if(pv){var pi=pv.querySelector('input');if(pi){pi.value='';pi.focus();}}}});\r\n          div.appendChild(inp);\r\n        }\r\n        gd.appendChild(div);\r\n      }\r\n    }\r\n    wrap.innerHTML='';wrap.appendChild(gd);cwRenderClues();\r\n  }\r\n\r\n  function cwRenderClues(){\r\n    var cw=document.getElementById('pth-cw-clues-wrap');if(!cw)return;\r\n    function buildItem(cl){\r\n      var cs=window.pthILS.detectScript(cl.clue),cr=window.pthILS.isRTL(cl.clue),cf=window.pthILS.getFontStack(cs);\r\n      return '<div class=\"pth-cw-clue-item\"><strong>'+cl.num+'.<\/strong> <span style=\"font-family:'+cf+';direction:'+(cr?'rtl':'ltr')+';display:inline-block;unicode-bidi:embed;\">'+window.pthILS.esc(cl.clue)+'<\/span><\/div>';\r\n    }\r\n    var h='<div class=\"pth-cw-clues-wrap\"><div class=\"pth-cw-clue-group across\"><h4>&#x2192; Across<\/h4>';\r\n    CW.acrossClues.forEach(function(cl){h+=buildItem(cl);});\r\n    h+='<\/div><div class=\"pth-cw-clue-group down\"><h4>&#x2193; Down<\/h4>';\r\n    CW.downClues.forEach(function(cl){h+=buildItem(cl);});\r\n    h+='<\/div><\/div>';\r\n    cw.innerHTML=h;\r\n  }\r\n\r\n  function cwCheck(){\r\n    var inputs=document.querySelectorAll('#pth-cw-grid-el input');\r\n    if(!inputs.length){window.pthILS.toast('Generate first!','error');return;}\r\n    var correct=0,total=inputs.length;\r\n    inputs.forEach(function(inp){\r\n      var ans=inp.getAttribute('data-answer')||'',val=(inp.value||'').toUpperCase();\r\n      var cell=inp.parentNode;cell.classList.remove('pth-ils-cw-correct','pth-ils-cw-wrong','pth-ils-cw-revealed');\r\n      if(val){if(val===ans){cell.classList.add('pth-ils-cw-correct');correct++;}else cell.classList.add('pth-ils-cw-wrong');}\r\n    });\r\n    var sc=document.getElementById('pth-cw-s-correct');if(sc)sc.textContent=correct+'\/'+total;\r\n    var ss=document.getElementById('pth-cw-s-score');if(ss)ss.textContent=Math.round(correct\/total*100)+'%';\r\n    if(correct===total){document.querySelectorAll('.pth-cw-clue-item').forEach(function(el){el.classList.add('cw-clue-done');});window.pthILS.toast('Perfect! All correct!','success');}\r\n    else{window.pthILS.toast(correct+'\/'+total+' correct.',correct>total\/2?'info':'warn');}\r\n  }\r\n\r\n  function cwReveal(){\r\n    var inputs=document.querySelectorAll('#pth-cw-grid-el input');\r\n    if(!inputs.length){window.pthILS.toast('Generate first!','error');return;}\r\n    inputs.forEach(function(inp){inp.value=inp.getAttribute('data-answer')||'';inp.parentNode.classList.remove('pth-ils-cw-correct','pth-ils-cw-wrong');inp.parentNode.classList.add('pth-ils-cw-revealed');});\r\n    window.pthILS.toast('All revealed!','info');\r\n  }\r\n\r\n  function cwResetGrid(){\r\n    document.querySelectorAll('#pth-cw-grid-el input').forEach(function(inp){inp.value='';inp.parentNode.classList.remove('pth-ils-cw-correct','pth-ils-cw-wrong','pth-ils-cw-revealed');});\r\n    var sc=document.getElementById('pth-cw-s-correct');if(sc)sc.textContent='&#8212;';\r\n    var ss=document.getElementById('pth-cw-s-score');if(ss)ss.textContent='&#8212;';\r\n    window.pthILS.toast('Grid reset!','info');\r\n  }\r\n\r\n  \/* ============================================================\r\n     EXPORT HTML\r\n     ============================================================ *\/\r\n  function applyLangToInput(ta,sampleText){\r\n    if(!ta||!sampleText)return;\r\n    var firstLine=(sampleText.split('\\n')[0]||'');\r\n    var clueText=firstLine.indexOf(':')>0?firstLine.split(':')[1]:firstLine;\r\n    var script=window.pthILS.detectScript(clueText),isRTL=window.pthILS.isRTL(clueText);\r\n    window.pthILS.loadFont(script);\r\n    ta.style.fontFamily=window.pthILS.getFontStack(script);\r\n    ta.style.direction=isRTL?'rtl':'ltr';ta.style.textAlign=isRTL?'right':'left';\r\n  }\r\n\r\n  function cwBuildExportHTML(){\r\n    if(!CW.placed.length)return'';\r\n    var tpl=document.getElementById('pth-cw-export-tpl');if(!tpl)return'';\r\n    var tmp=document.createElement('div');tmp.appendChild(tpl.content.cloneNode(true));var doc=tmp.innerHTML;\r\n    var panel=document.getElementById('pth-tab-crossword');\r\n    var cs=panel?getComputedStyle(panel):{};\r\n    function cv(n,d){return(cs.getPropertyValue&&cs.getPropertyValue(n).trim())||d;}\r\n    var cellSz=cv('--cw-cell-size','38px'),cellBg=cv('--cw-cell-bg','#ffffff'),cellBk=cv('--cw-cell-black','#0f172a');\r\n    var txtCol=cv('--cw-text-color','#0f172a'),numCol=cv('--cw-num-color','#334155');\r\n    var corCol=cv('--cw-cell-correct','#dcfce7'),wrgCol=cv('--cw-cell-wrong','#fef2f2');\r\n    var rvlCol=cv('--cw-cell-revealed','#fefce8'),fntSz=cv('--cw-font-size','0.88rem');\r\n    var numSz=cv('--cw-num-size','0.55rem'),acCol=cv('--cw-across-color','#1d4ed8'),dnCol=cv('--cw-down-color','#7c3aed');\r\n    var minR=CW.minR,maxR=CW.maxR,minC=CW.minC,maxC=CW.maxC,cols=maxC-minC+1;\r\n\r\n    function escHTML(s){return String(s==null?'':s).replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;');}\r\n\r\n    \/* Pre-render grid + clues as STATIC markup at build time (no runtime JSON parsing needed \u2014\r\n       this is the v3.1 fix for the blank-grid bug when the downloaded file is opened directly). *\/\r\n    var cellsHTML='';\r\n    for(var r=minR;r<=maxR;r++){\r\n      for(var c=minC;c<=maxC;c++){\r\n        var cell=CW.grid[r][c];\r\n        if(cell.black){cellsHTML+='<div class=\"cw-cell cw-black\"><\/div>';}\r\n        else{\r\n          var ans=escHTML(cell.letter||'');\r\n          var numHTML=cell.num?'<span class=\"cw-num\">'+cell.num+'<\/span>':'';\r\n          cellsHTML+='<div class=\"cw-cell\" data-ans=\"'+ans+'\">'+numHTML+'<input class=\"cw-inp\" type=\"text\" maxlength=\"1\" autocomplete=\"off\" aria-label=\"Answer letter\"><\/div>';\r\n        }\r\n      }\r\n    }\r\n    function cluesHTML(list){\r\n      var h='';\r\n      for(var i=0;i<list.length;i++){\r\n        var cl=list[i];\r\n        var scr=window.pthILS.detectScript(cl.clue),rtl=window.pthILS.isRTL(cl.clue);\r\n        var font=window.pthILS.getFontStack(scr);\r\n        h+='<div class=\"cw-clue\"><strong>'+cl.num+'.<\/strong> <span style=\"font-family:'+font+';direction:'+(rtl?'rtl':'ltr')+';display:inline-block;unicode-bidi:embed;\">'+escHTML(cl.clue)+'<\/span><\/div>';\r\n      }\r\n      return h;\r\n    }\r\n    var acHTML=cluesHTML(CW.acrossClues);\r\n    var dcHTML=cluesHTML(CW.downClues);\r\n\r\n    var dynCSS='.cw-wrap{background:'+cellBk+';grid-template-columns:repeat('+cols+','+cellSz+');}.cw-cell{width:'+cellSz+';height:'+cellSz+';background:'+cellBg+';}.cw-black{background:'+cellBk+'!important;}.cw-num{font-size:'+numSz+';color:'+numCol+';}.cw-inp{font-size:'+fntSz+';color:'+txtCol+';}.cw-correct{background:'+corCol+'!important;}.cw-wrong{background:'+wrgCol+'!important;}.cw-revealed{background:'+rvlCol+'!important;}.cw-cg:first-child h4{color:'+acCol+';background:#eff6ff;}.cw-cg:last-child h4{color:'+dnCol+';background:#f5f3ff;}';\r\n    doc=doc.replace('<\/style>',dynCSS+'<\/style>');\r\n    doc=doc.replace('<div class=\"cw-wrap\" id=\"cw-grid\"><\/div>','<div class=\"cw-wrap\" id=\"cw-grid\">'+cellsHTML+'<\/div>');\r\n    doc=doc.replace('<div id=\"cw-ac\"><\/div>','<div id=\"cw-ac\">'+acHTML+'<\/div>');\r\n    doc=doc.replace('<div id=\"cw-dc\"><\/div>','<div id=\"cw-dc\">'+dcHTML+'<\/div>');\r\n\r\n    \/* Runtime script now ONLY wires interactivity \u2014 grid\/clues are already in the HTML above. *\/\r\n    var sc=[\r\n      '(function(){',\r\n      'var tStart=Date.now();var tEl=document.getElementById(\"cw-timer\");',\r\n      'if(tEl){setInterval(function(){var s=Math.floor((Date.now()-tStart)\/1000),m=Math.floor(s\/60),ss=s%60;tEl.textContent=\"\\\\u23F1 \"+(m<10?\"0\":\"\")+m+\":\"+(ss<10?\"0\":\"\")+ss;},1000);}',\r\n      'var inputs=document.querySelectorAll(\".cw-inp\");',\r\n      'for(var i=0;i<inputs.length;i++){(function(inp){',\r\n      'inp.addEventListener(\"input\",function(e){e.target.value=e.target.value.toUpperCase().replace(\/[^A-Z]\/g,\"\");var div=e.target.parentNode;div.classList.remove(\"cw-correct\",\"cw-wrong\",\"cw-revealed\");if(e.target.value){var cells=Array.prototype.slice.call(document.querySelectorAll(\".cw-cell\")),idx=cells.indexOf(div);for(var j=idx+1;j<cells.length;j++){if(!cells[j].classList.contains(\"cw-black\")){var ni=cells[j].querySelector(\"input\");if(ni){ni.focus();}break;}}}});',\r\n      'inp.addEventListener(\"keydown\",function(e){if(e.key===\"Backspace\"&&!e.target.value){var div=e.target.parentNode,cells=Array.prototype.slice.call(document.querySelectorAll(\".cw-cell\")),idx=cells.indexOf(div);for(var j=idx-1;j>=0;j--){if(!cells[j].classList.contains(\"cw-black\")){var pi=cells[j].querySelector(\"input\");if(pi){pi.value=\"\";pi.focus();}break;}}}});',\r\n      '})(inputs[i]);}',\r\n      'function checkAll(){var c=document.querySelectorAll(\".cw-cell:not(.cw-black)\"),tot=c.length,cor=0;c.forEach(function(cell){var inp=cell.querySelector(\"input\");if(!inp)return;var ans=cell.getAttribute(\"data-ans\")||\"\",val=(inp.value||\"\").toUpperCase();cell.classList.remove(\"cw-correct\",\"cw-wrong\",\"cw-revealed\");if(val){if(val===ans){cell.classList.add(\"cw-correct\");cor++;}else cell.classList.add(\"cw-wrong\");}});var sc=document.getElementById(\"cw-sc\");if(sc)sc.textContent=cor+\"\/\"+tot+\" (\"+Math.round(cor\/tot*100)+\"%)\";}',\r\n      'document.getElementById(\"btn-check\").addEventListener(\"click\",checkAll);',\r\n      'document.getElementById(\"btn-reveal\").addEventListener(\"click\",function(){document.querySelectorAll(\".cw-cell:not(.cw-black)\").forEach(function(cell){var inp=cell.querySelector(\"input\");if(inp)inp.value=cell.getAttribute(\"data-ans\")||\"\";cell.classList.remove(\"cw-correct\",\"cw-wrong\");cell.classList.add(\"cw-revealed\");});});',\r\n      'document.getElementById(\"btn-reset\").addEventListener(\"click\",function(){document.querySelectorAll(\".cw-cell:not(.cw-black)\").forEach(function(cell){var inp=cell.querySelector(\"input\");if(inp)inp.value=\"\";cell.classList.remove(\"cw-correct\",\"cw-wrong\",\"cw-revealed\");});var sc=document.getElementById(\"cw-sc\");if(sc)sc.textContent=\"\";});',\r\n      'var akOn=false;',\r\n      'document.getElementById(\"btn-answerkey\").addEventListener(\"click\",function(e){akOn=!akOn;e.target.classList.toggle(\"active\",akOn);if(akOn){document.querySelectorAll(\".cw-cell:not(.cw-black)\").forEach(function(cell){var inp=cell.querySelector(\"input\");if(inp)inp.value=cell.getAttribute(\"data-ans\")||\"\";cell.classList.add(\"cw-revealed\");});e.target.textContent=\"Hide Answer Key\";}else{document.querySelectorAll(\".cw-cell:not(.cw-black)\").forEach(function(cell){cell.classList.remove(\"cw-revealed\");});e.target.textContent=\"Answer Key Mode\";}});',\r\n      'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n    \/* v3.5 FIX: the export template fragment strips document-structuring tags entirely on\r\n       clone (they are not allowed inside template fragments \u2014 browsers silently drop them).\r\n       That made the old \"find closing body marker, insert script before it\" logic never\r\n       match anything, so the script was NEVER added to any downloaded\/printed file \u2014\r\n       buttons looked present but had zero event listeners. Fix: append the script directly to the\r\n       end of the string. Browsers auto-reconstruct the missing wrapper elements correctly\r\n       regardless (already proven by the grid\/styles rendering fine), so this is 100% reliable. *\/\r\n    var so='<'+'script'+'>';\r\n    var sc2='<'+'\/'+'script'+'>';\r\n    doc=doc+so+sc+sc2;\r\n    return doc;\r\n  }\r\n\r\n  \/* ============================================================\r\n     CUSTOMIZER\r\n     ============================================================ *\/\r\n  var cwDef={'pth-cw-cell-size':38,'pth-cw-font-size':14,'pth-cw-col-cell':'#ffffff','pth-cw-col-black':'#0f172a','pth-cw-col-text':'#0f172a','pth-cw-col-correct':'#dcfce7','pth-cw-col-wrong':'#fef2f2','pth-cw-col-across':'#1d4ed8','pth-cw-col-down':'#7c3aed'};\r\n  function applyCustom(id,val){\r\n    var p=document.getElementById('pth-tab-crossword');if(!p)return;\r\n    var m={'pth-cw-cell-size':function(v){p.style.setProperty('--cw-cell-size',v+'px');},'pth-cw-font-size':function(v){p.style.setProperty('--cw-font-size',v+'px');},'pth-cw-col-cell':function(v){p.style.setProperty('--cw-cell-bg',v);},'pth-cw-col-black':function(v){p.style.setProperty('--cw-cell-black',v);p.style.setProperty('--cw-grid-bg',v);},'pth-cw-col-text':function(v){p.style.setProperty('--cw-text-color',v);},'pth-cw-col-correct':function(v){p.style.setProperty('--cw-cell-correct',v);},'pth-cw-col-wrong':function(v){p.style.setProperty('--cw-cell-wrong',v);},'pth-cw-col-across':function(v){p.style.setProperty('--cw-across-color',v);},'pth-cw-col-down':function(v){p.style.setProperty('--cw-down-color',v);}};\r\n    if(m[id])m[id](val);\r\n  }\r\n  function initCustomizer(){\r\n    ['pth-cw-cell-size','pth-cw-font-size'].forEach(function(id){var inp=document.getElementById(id),val=document.getElementById(id+'-val');if(!inp)return;inp.addEventListener('input',function(){if(val)val.textContent=inp.value+'px';applyCustom(id,inp.value);});});\r\n    ['pth-cw-col-cell','pth-cw-col-black','pth-cw-col-text','pth-cw-col-correct','pth-cw-col-wrong','pth-cw-col-across','pth-cw-col-down'].forEach(function(id){var inp=document.getElementById(id);if(!inp)return;inp.addEventListener('input',function(){applyCustom(id,inp.value);});});\r\n    var rb=document.getElementById('pth-cw-reset-theme-btn');\r\n    if(rb)rb.addEventListener('click',function(){Object.keys(cwDef).forEach(function(id){var inp=document.getElementById(id);if(inp){inp.value=cwDef[id];applyCustom(id,cwDef[id]);}var v=document.getElementById(id+'-val');if(v)v.textContent=cwDef[id]+'px';});window.pthILS.toast('Theme reset.','info');});\r\n  }\r\n\r\n  \/* ============================================================\r\n     AI CARD\r\n     ============================================================ *\/\r\n  function injectAICard(){\r\n    var sidebar=document.querySelector('#pth-tab-crossword .pth-ils-sidebar');\r\n    if(!sidebar||document.getElementById('pth-cw-ai-card'))return;\r\n    var card=document.createElement('div');card.className='pth-ils-card';card.id='pth-cw-ai-card';\r\n    card.style.cssText='background:#f5f3ff;border-color:#ddd6fe;';\r\n    card.innerHTML=\r\n      '<h3 style=\"color:#6d28d9;\">&#x1F916; AI Word Generator<\/h3>'+\r\n      '<p style=\"font-size:0.8rem;color:#334155;line-height:1.5;margin:0 0 8px;\">Topic in any language &#x2192; AI generates WORD:Clue pairs!<\/p>'+\r\n      '<label class=\"pth-ils-label\" for=\"pth-cw-ai-key\">&#x1F511; Anthropic API Key<\/label>'+\r\n      '<input type=\"password\" class=\"pth-ils-input\" id=\"pth-cw-ai-key\" placeholder=\"sk-ant-...\" aria-label=\"API key\" style=\"font-family:monospace;font-size:0.8rem;\">'+\r\n      '<label class=\"pth-ils-label\" for=\"pth-cw-ai-topic\">&#x1F4DA; Topic (any language)<\/label>'+\r\n      '<input type=\"text\" class=\"pth-ils-input\" id=\"pth-cw-ai-topic\" placeholder=\"Solar System \/ &#x0DC3;&#x0DDC;&#x0DBD;&#x0DA4; &#x0DB8;&#x0DAB;&#x0DA9;&#x0DBD;\" aria-label=\"Topic\">'+\r\n      '<label class=\"pth-ils-label\">&#x1F30D; Clue Language<\/label>'+\r\n      '<div style=\"background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;padding:8px 12px;margin-bottom:10px;font-size:0.82rem;font-weight:700;color:#1d4ed8;cursor:pointer;\" id=\"pth-cw-ai-lang-show\">'+\r\n        '&#x1F30D; Using: <span id=\"pth-cw-ai-lang-name\">English<\/span> &#x2014; <span style=\"color:#2563eb;text-decoration:underline;\">Change language above &#x2191;<\/span>'+\r\n      '<\/div>'+\r\n      '<label class=\"pth-ils-label\" for=\"pth-cw-ai-count\">&#x1F522; Word Count<\/label>'+\r\n      '<select class=\"pth-ils-select\" id=\"pth-cw-ai-count\" aria-label=\"Word count\">'+\r\n        '<option value=\"8\">8 words<\/option><option value=\"10\" selected>10 words<\/option>'+\r\n        '<option value=\"12\">12 words<\/option><option value=\"15\">15 words<\/option>'+\r\n      '<\/select>'+\r\n      '<button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-cw-ai-gen-btn\" style=\"width:100%;justify-content:center;\">&#x2728; Generate with AI<\/button>'+\r\n      '<div id=\"pth-cw-ai-status\" style=\"display:none;margin-top:10px;border-radius:8px;padding:10px 12px;font-size:0.8rem;font-weight:700;line-height:1.5;\"><\/div>'+\r\n      '<p style=\"font-size:0.72rem;color:#6d28d9;margin:8px 0 0;\">&#x1F512; Key stays in your browser only.<\/p>';\r\n    sidebar.appendChild(card);\r\n\r\n    \/* Update AI lang display when CW_CURRENT_LANG changes *\/\r\n    function updateAILang(){var el=document.getElementById('pth-cw-ai-lang-name');if(el)el.innerHTML=CW_CURRENT_LANG.native+' ('+CW_CURRENT_LANG.en+')';}\r\n    updateAILang();\r\n\r\n    document.getElementById('pth-cw-ai-gen-btn').addEventListener('click',function(){\r\n      var key=(document.getElementById('pth-cw-ai-key')||{}).value||'';\r\n      var topic=(document.getElementById('pth-cw-ai-topic')||{}).value||'';\r\n      var count=parseInt((document.getElementById('pth-cw-ai-count')||{}).value||'10');\r\n      var btn=document.getElementById('pth-cw-ai-gen-btn');\r\n      var clueLang=CW_CURRENT_LANG.en;\r\n      if(key.indexOf('sk-ant-')!==0){aiSt('error','Enter valid API key (sk-ant-...)');return;}\r\n      if(!topic.trim()){aiSt('error','Enter a topic.');return;}\r\n      btn.textContent='Generating...';btn.disabled=true;\r\n      aiSt('info','Generating '+count+' pairs in '+clueLang+' for \"'+topic+'\"...');\r\n      var prompt='Generate exactly '+count+' crossword word-clue pairs about \"'+topic+'\".\\nRULES:\\n1. WORD (before colon): single English\/Latin word, A-Z only, 3-12 letters, NO spaces.\\n2. CLUE (after colon): write in '+clueLang+' language.\\n3. Output ONLY lines like: WORD:Clue in '+clueLang+'\\nNo numbering. No extra text. Just WORD:Clue lines.';\r\n      fetch('https:\/\/api.anthropic.com\/v1\/messages',{method:'POST',\r\n        headers:{'Content-Type':'application\/json','x-api-key':key,'anthropic-version':'2023-06-01','anthropic-dangerous-direct-browser-calls':'true'},\r\n        body:JSON.stringify({model:'claude-sonnet-4-6',max_tokens:1000,messages:[{role:'user',content:prompt}]})\r\n      }).then(function(r){return r.json();}).then(function(data){\r\n        btn.textContent='&#x2728; Generate with AI';btn.disabled=false;\r\n        if(data.error){aiSt('error',data.error.message);return;}\r\n        var text=(data.content&&data.content[0]&&data.content[0].text)||'';\r\n        var lines=text.split('\\n').map(function(l){return l.trim();}).filter(function(l){var idx=l.indexOf(':');if(idx<2)return false;return \/^[A-Za-z]{3,12}$\/.test(l.substring(0,idx).trim());});\r\n        if(!lines.length){aiSt('error','Unexpected format. Try again.');return;}\r\n        var ta=document.getElementById('pth-cw-input');\r\n        if(ta){ta.value=lines.join('\\n');applyLangToInput(ta,lines[0]);}\r\n        aiSt('success',lines.length+' pairs ready in '+clueLang+'! Click Generate.');\r\n        window.pthILS.toast('AI: '+lines.length+' pairs!','success');\r\n        var gb=document.getElementById('pth-cw-gen-btn');if(gb)gb.scrollIntoView({behavior:'smooth',block:'center'});\r\n      }).catch(function(err){btn.textContent='&#x2728; Generate with AI';btn.disabled=false;aiSt('error','Network error: '+err.message);});\r\n    });\r\n    function aiSt(type,msg){var el=document.getElementById('pth-cw-ai-status');if(!el)return;var c={error:'background:#fef2f2;border:1px solid #fecaca;color:#991b1b;',success:'background:#f0fdf4;border:1px solid #bbf7d0;color:#047857;',info:'background:#eff6ff;border:1px solid #bfdbfe;color:#1d4ed8;'}[type]||'';el.style.cssText='display:block;border-radius:8px;padding:10px 12px;font-size:0.8rem;font-weight:700;line-height:1.5;'+c;el.textContent=msg;}\r\n  }\r\n\r\n  \/* ============================================================\r\n     WIRE EVENTS\r\n     ============================================================ *\/\r\n  function wireEvents(){\r\n    var b=function(id,fn){var el=document.getElementById(id);if(el)el.addEventListener('click',fn);};\r\n    b('pth-cw-gen-btn',cwGenerate);b('pth-cw-check-btn',cwCheck);b('pth-cw-reveal-btn',cwReveal);b('pth-cw-reset-btn',cwResetGrid);\r\n    b('pth-cw-png-btn',function(){window.pthILS.exportPNG(document.getElementById('pth-cw-grid-el'),'crossword-puzzle');});\r\n    b('pth-cw-html-btn',function(){\r\n      if(!CW.placed.length){window.pthILS.toast('Generate first!','error');return;}\r\n      try{\r\n        var html=cwBuildExportHTML();\r\n        var blob=new Blob([html],{type:'text\/html'});\r\n        var url=URL.createObjectURL(blob);\r\n        var a=document.createElement('a');\r\n        a.href=url;a.download='crossword-puzzle.html';\r\n        document.body.appendChild(a);a.click();document.body.removeChild(a);\r\n        setTimeout(function(){URL.revokeObjectURL(url);},2000);\r\n        window.pthILS.toast('HTML file downloaded!','success');\r\n      }catch(err){window.pthILS.toast('Download failed: '+err.message,'error');}\r\n    });\r\n    b('pth-cw-copy-btn',function(){if(!CW.placed.length){window.pthILS.toast('Generate first!','error');return;}window.pthILS.showCopyHTML(cwBuildExportHTML(),'pth-cw-code-box');});\r\n    b('pth-cw-print-btn',function(){\r\n      if(!CW.placed.length){window.pthILS.toast('Generate first!','error');return;}\r\n      var html=cwBuildExportHTML();\r\n      var w=window.open('','_blank');\r\n      if(!w){window.pthILS.toast('Popup blocked! Allow popups for this site to print.','error');return;}\r\n      w.document.open();w.document.write(html);w.document.close();\r\n      var printed=false;\r\n      function doPrint(){if(printed)return;printed=true;w.focus();w.print();}\r\n      w.addEventListener('load',function(){setTimeout(doPrint,150);});\r\n      setTimeout(doPrint,1200);\r\n    });\r\n\r\n    \/* Language picker button \u2192 open popup *\/\r\n    b('pth-cw-lang-pick-btn', openLangPopup);\r\n\r\n    \/* Auto-detect language as user types *\/\r\n    var ta=document.getElementById('pth-cw-input');\r\n    if(ta)window.pthILS.autoLangFull(ta);\r\n\r\n    \/* Global events *\/\r\n    document.addEventListener('pthILSClear',function(e){\r\n      if(e.detail.tab!=='crossword')return;\r\n      var ta2=document.getElementById('pth-cw-input');\r\n      if(ta2){ta2.value='';ta2.style.direction='ltr';ta2.style.fontFamily='';ta2.style.textAlign='left';}\r\n      var gw=document.getElementById('pth-cw-grid-wrap');if(gw)gw.innerHTML='';\r\n      var cw2=document.getElementById('pth-cw-clues-wrap');if(cw2)cw2.innerHTML='';\r\n      var gc=document.getElementById('pth-cw-grid-card');if(gc)gc.style.display='none';\r\n      var ec=document.getElementById('pth-cw-export-card');if(ec)ec.style.display='none';\r\n      var st=document.getElementById('pth-cw-status');if(st)st.style.display='none';\r\n      CW.placed=[];CW.acrossClues=[];CW.downClues=[];\r\n      ['pth-cw-s-placed','pth-cw-s-skipped','pth-cw-s-size','pth-cw-s-correct','pth-cw-s-score','pth-cw-s-lang'].forEach(function(id){var el=document.getElementById(id);if(el)el.textContent='&#8212;';});\r\n    });\r\n    document.addEventListener('pthILSSample',function(e){\r\n      if(e.detail.tab!=='crossword')return;\r\n      var ta3=document.getElementById('pth-cw-input');\r\n      if(ta3){ta3.value=CW_SAMPLES.en;ta3.style.direction='ltr';ta3.style.fontFamily='';ta3.style.textAlign='left';window.pthILS.toast('Sample loaded! Click Generate.','success');}\r\n    });\r\n    document.addEventListener('pthILSAIFill',function(e){\r\n      if(e.detail.target!=='crossword')return;\r\n      var ta4=document.getElementById('pth-cw-input');\r\n      if(ta4&&e.detail.content){ta4.value=e.detail.content;applyLangToInput(ta4,e.detail.content);var cwBtn=document.querySelector('.pth-ils-tab-btn[data-tab=\"crossword\"]');if(cwBtn)cwBtn.click();window.pthILS.toast('AI content loaded! Click Generate.','success');}\r\n    });\r\n  }\r\n\r\n  \/* \u2500\u2500 INIT \u2500\u2500 *\/\r\n  function init(){\r\n    buildTabHTML();\r\n    setTimeout(function(){initCustomizer();wireEvents();injectAICard();},150);\r\n  }\r\n\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v2.0 \u2014 Word Search Tab -->\r\n\r\n<style>\r\n\/* Word Search specific styles *\/\r\n.pth-ils-ws-grid {\r\n  display: inline-grid;\r\n  gap: 1px;\r\n  background: #e2e8f0;\r\n  padding: 2px;\r\n  border-radius: 6px;\r\n  overflow: auto;\r\n  max-width: 100%;\r\n  user-select: none;\r\n  -webkit-user-select: none;\r\n}\r\n.pth-ils-ws-cell {\r\n  width: 32px;\r\n  height: 32px;\r\n  background: #fff;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  font-size: 0.85rem;\r\n  font-weight: 700;\r\n  color: #0f172a;\r\n  cursor: pointer;\r\n  border-radius: 2px;\r\n  transition: background 0.08s;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n.pth-ils-ws-cell.ws-selecting { background: #bfdbfe; color: #1d4ed8; }\r\n.pth-ils-ws-cell.ws-found     { background: #bbf7d0; color: #047857; }\r\n.pth-ils-ws-cell.ws-revealed  { background: #fef08a; color: #92400e; }\r\n.pth-ils-ws-cell.ws-hint      { background: #fde68a; color: #92400e; outline: 2px solid #f59e0b; }\r\n\r\n.pth-ws-word-list {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 7px;\r\n  margin-top: 14px;\r\n}\r\n.pth-ws-word-tag {\r\n  background: #eff6ff;\r\n  color: #1d4ed8;\r\n  border: 1px solid #bfdbfe;\r\n  font-size: 0.8rem;\r\n  font-weight: 700;\r\n  padding: 4px 10px;\r\n  border-radius: 20px;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n.pth-ws-word-tag.ws-found-word {\r\n  background: #f0fdf4;\r\n  color: #047857;\r\n  border-color: #bbf7d0;\r\n  text-decoration: line-through;\r\n  opacity: 0.7;\r\n}\r\n\r\n\/* Timer display *\/\r\n.pth-ws-timer-box {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  gap: 8px;\r\n  background: #fef9c3;\r\n  border: 1px solid #fde047;\r\n  color: #92400e;\r\n  font-size: 0.88rem;\r\n  font-weight: 700;\r\n  padding: 8px 14px;\r\n  border-radius: 8px;\r\n  margin-bottom: 10px;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n.pth-ws-timer-box.ws-timer-done {\r\n  background: #f0fdf4;\r\n  border-color: #bbf7d0;\r\n  color: #047857;\r\n}\r\n\r\n@media (max-width: 480px) {\r\n  .pth-ils-ws-cell { width: 26px; height: 26px; font-size: 0.75rem; }\r\n}\r\n\/* Language picker button (shared visual style with Crossword tab) *\/\r\n.pth-cw-lang-pick-btn {\r\n  display: inline-flex; align-items: center; gap: 8px;\r\n  padding: 9px 16px; background: #fff; border: 2px solid #e2e8f0;\r\n  border-radius: 8px; cursor: pointer; font-family: 'Inter', system-ui, sans-serif;\r\n  font-size: 0.85rem; font-weight: 700; color: #334155;\r\n  transition: all 0.15s; width: 100%; margin-bottom: 10px;\r\n}\r\n.pth-cw-lang-pick-btn:hover { border-color: #2563eb; color: #1d4ed8; background: #eff6ff; }\r\n.pth-cw-lang-pick-flag { font-size: 0.68rem; font-weight: 800; background: #2563eb; color: #fff; border-radius: 5px; padding: 3px 6px; min-width: 26px; text-align: center; letter-spacing: 0.3px; }\r\n.pth-cw-lang-pick-text { flex: 1; text-align: left; }\r\n.pth-cw-lang-pick-arrow { color: #94a3b8; font-size: 0.8rem; }\r\n<\/style>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  \/* \u2500\u2500 Wait for Shell \u2500\u2500 *\/\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function () {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function () { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  \/* ============================================================\r\n     MULTILINGUAL METHODS \u2014 self-contained (safe: only defines if\r\n     Shell or another tab hasn't added them yet)\r\n     ============================================================ *\/\r\n  if (!window.pthILS) window.pthILS = {};\r\n  if (!window.pthILS.detectScript) {\r\n    window.pthILS.detectScript = function(text) {\r\n      if (!text || !text.trim()) return 'latin';\r\n      if (\/[\\u0D80-\\u0DFF]\/.test(text)) return 'sinhala';\r\n      if (\/[\\u0B80-\\u0BFF]\/.test(text)) return 'tamil';\r\n      if (\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text)) return 'rtl';\r\n      if (\/[\\u3000-\\u9FFF\\uAC00-\\uD7AF]\/.test(text)) return 'cjk';\r\n      if (\/[\\u0900-\\u097F]\/.test(text)) return 'devanagari';\r\n      if (\/[\\u0E00-\\u0E7F]\/.test(text)) return 'thai';\r\n      if (\/[\\u0980-\\u09FF]\/.test(text)) return 'bengali';\r\n      if (\/[\\u1000-\\u109F]\/.test(text)) return 'myanmar';\r\n      if (\/[\\u1780-\\u17FF]\/.test(text)) return 'khmer';\r\n      if (\/[\\u0370-\\u03FF]\/.test(text)) return 'greek';\r\n      if (\/[\\u0400-\\u04FF]\/.test(text)) return 'cyrillic';\r\n      return 'latin';\r\n    };\r\n  }\r\n  if (!window.pthILS.isRTL) {\r\n    window.pthILS.isRTL = function(text) {\r\n      return \/[\\u0591-\\u07FF\\u200F\\u202B\\u202E\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text);\r\n    };\r\n  }\r\n  if (!window.pthILS.getFontStack) {\r\n    window.pthILS.getFontStack = function(script) {\r\n      var f = {\r\n        sinhala:\"'Noto Sans Sinhala','Iskoola Pota',system-ui,sans-serif\",\r\n        tamil:\"'Noto Sans Tamil','Latha',system-ui,sans-serif\",\r\n        rtl:\"'Noto Sans Arabic','Noto Sans Hebrew',system-ui,sans-serif\",\r\n        cjk:\"'Noto Sans CJK SC','Microsoft YaHei',system-ui,sans-serif\",\r\n        devanagari:\"'Noto Sans Devanagari','Mangal',system-ui,sans-serif\",\r\n        thai:\"'Noto Sans Thai','Tahoma',system-ui,sans-serif\",\r\n        bengali:\"'Noto Sans Bengali','Vrinda',system-ui,sans-serif\",\r\n        myanmar:\"'Noto Sans Myanmar',system-ui,sans-serif\",\r\n        khmer:\"'Noto Sans Khmer',system-ui,sans-serif\",\r\n        latin:\"'Inter',system-ui,sans-serif\"\r\n      };\r\n      return f[script] || f.latin;\r\n    };\r\n  }\r\n  if (!window.pthILS.loadedFonts) window.pthILS.loadedFonts = {};\r\n  if (!window.pthILS.loadFont) {\r\n    window.pthILS.loadFont = function(script) {\r\n      if (window.pthILS.loadedFonts[script]) return;\r\n      window.pthILS.loadedFonts[script] = true;\r\n      var m = {\r\n        sinhala:'Noto+Sans+Sinhala:wght@400;700',tamil:'Noto+Sans+Tamil:wght@400;700',\r\n        rtl:'Noto+Sans+Arabic:wght@400;700',devanagari:'Noto+Sans+Devanagari:wght@400;700',\r\n        thai:'Noto+Sans+Thai:wght@400;700',bengali:'Noto+Sans+Bengali:wght@400;700',\r\n        myanmar:'Noto+Sans+Myanmar:wght@400;700',cjk:'Noto+Sans+SC:wght@400;700'\r\n      };\r\n      if (!m[script]) return;\r\n      var l=document.createElement('link');l.rel='stylesheet';\r\n      l.href='https:\/\/fonts.googleapis.com\/css2?family='+m[script]+'&display=swap';\r\n      document.head.appendChild(l);\r\n    };\r\n  }\r\n\r\n  \/* ============================================================\r\n     ALL 33 LANGUAGE DEFINITIONS (same list as Crossword tab)\r\n     ============================================================ *\/\r\n  var WS_LANGS = [\r\n    {code:'en',  flag:'&#x1F1EC;&#x1F1E7;', native:'English',            en:'English'},\r\n    {code:'si',  flag:'&#x1F1F1;&#x1F1F0;', native:'&#x0DC3;&#x0DD2;&#x0D82;&#x0DC4;&#x0DBD;', en:'Sinhala'},\r\n    {code:'ta',  flag:'&#x1F1EE;&#x1F1F3;', native:'&#xBBA4;&#xBAE4;&#xBBBF;&#xBBB4;&#xBBCD;', en:'Tamil'},\r\n    {code:'zh',  flag:'&#x1F1E8;&#x1F1F3;', native:'&#x4E2D;&#x6587;',   en:'Chinese'},\r\n    {code:'ar',  flag:'&#x1F1F8;&#x1F1E6;', native:'&#x627;&#x644;&#x639;&#x631;&#x628;&#x64A;&#x629;', en:'Arabic'},\r\n    {code:'hi',  flag:'&#x1F1EE;&#x1F1F3;', native:'&#x939;&#x93F;&#x928;&#x94D;&#x926;&#x940;', en:'Hindi'},\r\n    {code:'es',  flag:'&#x1F1EA;&#x1F1F8;', native:'Espa&#xF1;ol',       en:'Spanish'},\r\n    {code:'fr',  flag:'&#x1F1EB;&#x1F1F7;', native:'Fran&#xE7;ais',      en:'French'},\r\n    {code:'pt',  flag:'&#x1F1F5;&#x1F1F9;', native:'Portugu&#xEA;s',     en:'Portuguese'},\r\n    {code:'de',  flag:'&#x1F1E9;&#x1F1EA;', native:'Deutsch',            en:'German'},\r\n    {code:'ja',  flag:'&#x1F1EF;&#x1F1F5;', native:'&#x65E5;&#x672C;&#x8A9E;', en:'Japanese'},\r\n    {code:'ko',  flag:'&#x1F1F0;&#x1F1F7;', native:'&#xD55C;&#xAD6D;&#xC5B4;', en:'Korean'},\r\n    {code:'ru',  flag:'&#x1F1F7;&#x1F1FA;', native:'&#x420;&#x443;&#x441;&#x441;&#x43A;&#x438;&#x439;', en:'Russian'},\r\n    {code:'it',  flag:'&#x1F1EE;&#x1F1F9;', native:'Italiano',           en:'Italian'},\r\n    {code:'tr',  flag:'&#x1F1F9;&#x1F1F7;', native:'T&#xFC;rk&#xE7;e',  en:'Turkish'},\r\n    {code:'id',  flag:'&#x1F1EE;&#x1F1E9;', native:'Bahasa Indonesia',   en:'Indonesian'},\r\n    {code:'ms',  flag:'&#x1F1F2;&#x1F1FE;', native:'Bahasa Melayu',      en:'Malay'},\r\n    {code:'bn',  flag:'&#x1F1E7;&#x1F1E9;', native:'&#x9AC;&#x9BE;&#x982;&#x9B2;&#x9BE;', en:'Bengali'},\r\n    {code:'vi',  flag:'&#x1F1FB;&#x1F1F3;', native:'Ti&#x1EBF;ng Vi&#x1EC7;t', en:'Vietnamese'},\r\n    {code:'th',  flag:'&#x1F1F9;&#x1F1ED;', native:'&#xE20;&#xE32;&#xE29;&#xE32;&#xE44;&#xE17;&#xE22;', en:'Thai'},\r\n    {code:'sw',  flag:'&#x1F1F0;&#x1F1EA;', native:'Kiswahili',          en:'Swahili'},\r\n    {code:'nl',  flag:'&#x1F1F3;&#x1F1F1;', native:'Nederlands',         en:'Dutch'},\r\n    {code:'pl',  flag:'&#x1F1F5;&#x1F1F1;', native:'Polski',             en:'Polish'},\r\n    {code:'uk',  flag:'&#x1F1FA;&#x1F1E6;', native:'&#x423;&#x43A;&#x440;&#x430;&#x457;&#x43D;&#x441;&#x44C;&#x43A;&#x430;', en:'Ukrainian'},\r\n    {code:'el',  flag:'&#x1F1EC;&#x1F1F7;', native:'&#x395;&#x3BB;&#x3BB;&#x3B7;&#x3BD;&#x3B9;&#x3BA;&#x3AC;', en:'Greek'},\r\n    {code:'he',  flag:'&#x1F1EE;&#x1F1F1;', native:'&#x5E2;&#x5D1;&#x5E8;&#x5D9;&#x5EA;', en:'Hebrew'},\r\n    {code:'fa',  flag:'&#x1F1EE;&#x1F1F7;', native:'&#x641;&#x627;&#x631;&#x633;&#x6CC;', en:'Persian'},\r\n    {code:'ur',  flag:'&#x1F1F5;&#x1F1F0;', native:'&#x627;&#x631;&#x62F;&#x648;', en:'Urdu'},\r\n    {code:'ne',  flag:'&#x1F1F3;&#x1F1F5;', native:'&#x928;&#x947;&#x92A;&#x93E;&#x932;&#x940;', en:'Nepali'},\r\n    {code:'sv',  flag:'&#x1F1F8;&#x1F1EA;', native:'Svenska',            en:'Swedish'},\r\n    {code:'ro',  flag:'&#x1F1F7;&#x1F1F4;', native:'Rom&#xE2;n&#x103;', en:'Romanian'},\r\n    {code:'fil', flag:'&#x1F1F5;&#x1F1ED;', native:'Filipino',           en:'Filipino'},\r\n    {code:'af',  flag:'&#x1F1FF;&#x1F1E6;', native:'Afrikaans',          en:'Afrikaans'}\r\n  ];\r\n\r\n  \/* Word-list samples (just words, no clues \u2014 used when language picked) *\/\r\n  var WS_SAMPLES = {\r\n    en:'PYTHON\\nJAVASCRIPT\\nBROWSER\\nSERVER\\nFUNCTION\\nVARIABLE\\nARRAY\\nLOOP\\nDEBUG\\nCLOUD',\r\n    si:'\\u0DB4\\u0DDA\\u0DAD\\u0DB1\\u0DCA\\nQ\\u0DAD\\u0DAD\\u0DCA\\u0DAD\\u0DCA\\u0DC0\\u0DBA\\nQ\\u0DBD\\u0DD9\\u0D9A\\u0DC3\\nQ\\u0DC4\\u0DDD\\u0DBB\\u0DCA\\u0DA9\\u0DC0\\u0DDA\\nQ\\u0DC3\\u0DCF\\u0DBD\\u0DD2\\u0DCA\\u0DBD\\u0DD2\\nQ\\u0DC0\\u0DCF\\u0DBA\\u0DD4\\nQ\\u0DAA\\u0DBD\\u0DA7\\u0DD4\\u0DC0\\nQ\\u0DBA\\u0DB1\\u0DCA\\u0DDA\\u0DAD\\u0DCA\\u0DBB',\r\n    zh:'\\u8BCD\\u8BED\\u4E00\\n\\u8BCD\\u8BED\\u4E8C\\n\\u8BCD\\u8BED\\u4E09',\r\n    ar:'\\u0643\\u0644\\u0645\\u0629\\u0648\\u0627\\u062D\\u062F\\u0629\\n\\u0643\\u0644\\u0645\\u0629\\u0627\\u062B\\u0646\\u062A\\u064A\\u0646',\r\n    es:'PYTHON\\nNAVEGADOR\\nSERVIDOR\\nFUNCION\\nVARIABLE\\nMATRIZ\\nBUCLE\\nNUBE',\r\n    fr:'PYTHON\\nNAVIGATEUR\\nSERVEUR\\nFONCTION\\nVARIABLE\\nTABLEAU\\nBOUCLE\\nNUAGE',\r\n    de:'PYTHON\\nBROWSER\\nSERVER\\nFUNKTION\\nVARIABLE\\nSCHLEIFE\\nWOLKE',\r\n    pt:'PYTHON\\nNAVEGADOR\\nSERVIDOR\\nFUNCAO\\nVARIAVEL\\nLISTA\\nNUVEM',\r\n    ja:'\\u30D1\\u30BD\\u30B3\\u30F3\\n\\u30D6\\u30E9\\u30A6\\u30B6\\n\\u30B5\\u30FC\\u30D0\\u30FC',\r\n    ko:'\\uCEF4\\uD4E8\\uD130\\n\\uBE0C\\uB77C\\uC6B0\\uC800\\n\\uC11C\\uBC84',\r\n    ru:'PYTHON\\nBROWSER\\nSERVER\\nFUNKCIA\\nMASSIV\\nCIKL\\nOBLAKO',\r\n    hi:'\\u092A\\u093E\\u0907\\u0925\\u0928\\n\\u092C\\u094D\\u0930\\u093E\\u0909\\u091C\\u093C\\u0930\\n\\u0938\\u0930\\u094D\\u0935\\u0930'\r\n  };\r\n\r\n  \/* Current selected language *\/\r\n  var WS_CURRENT_LANG = { code:'en', flag:'&#x1F1EC;&#x1F1E7;', native:'English', en:'English' };\r\n\r\n  function applyLangToInput(ta, sampleText){\r\n    if(!ta||!sampleText)return;\r\n    var firstLine=(sampleText.split('\\n')[0]||'');\r\n    var script=window.pthILS.detectScript(firstLine),isRTL=window.pthILS.isRTL(firstLine);\r\n    window.pthILS.loadFont(script);\r\n    ta.style.fontFamily=window.pthILS.getFontStack(script);\r\n    ta.style.direction=isRTL?'rtl':'ltr';ta.style.textAlign=isRTL?'right':'left';\r\n  }\r\n\r\n  \/* ============================================================\r\n     LANGUAGE POPUP SYSTEM (mirrors Crossword tab \u2014 global overlay\r\n     namespaced with ws- prefix so it can coexist with other tabs)\r\n     ============================================================ *\/\r\n  function buildLangPopup() {\r\n    if (document.getElementById('pth-ws-lang-overlay')) return;\r\n    var style = document.createElement('style');\r\n    style.textContent = [\r\n      '#pth-ws-lang-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;',\r\n        'background:rgba(15,23,42,0.55);z-index:9999998;',\r\n        'align-items:center;justify-content:center;padding:16px;}',\r\n      '#pth-ws-lang-overlay.pth-lo-open{display:flex;}',\r\n      '#pth-ws-lang-modal{background:#fff;border-radius:16px;width:100%;max-width:660px;',\r\n        'max-height:88vh;display:flex;flex-direction:column;',\r\n        'box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}',\r\n      '.pth-lm-head{padding:20px 20px 0;flex-shrink:0;}',\r\n      '.pth-lm-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;',\r\n        'font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-sub{font-size:0.78rem;color:#334155;margin:0 0 12px;',\r\n        'font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-close{position:absolute;top:14px;right:14px;background:#f1f5f9;',\r\n        'border:none;width:32px;height:32px;border-radius:50%;font-size:0.9rem;',\r\n        'cursor:pointer;color:#334155;display:flex;align-items:center;',\r\n        'justify-content:center;font-family:inherit;font-weight:700;}',\r\n      '.pth-lm-close:hover{background:#e2e8f0;}',\r\n      '.pth-lm-search-wrap{padding:0 16px 10px;flex-shrink:0;}',\r\n      '.pth-lm-search{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-family:Inter,system-ui,sans-serif;font-size:0.85rem;color:#1e293b;outline:none;background:#f8fafc;}',\r\n      '.pth-lm-search::placeholder{color:#94a3b8;}',\r\n      '.pth-lm-search:focus{border-color:#2563eb;background-color:#fff;}',\r\n      '.pth-lm-grid-wrap{overflow-y:auto;flex:1;padding:0 8px 8px;}',\r\n      '.pth-lm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}',\r\n      '.pth-lm-item{display:flex;align-items:center;gap:8px;padding:9px 10px;',\r\n        'border-radius:8px;cursor:pointer;border:2px solid transparent;',\r\n        'font-family:Inter,system-ui,sans-serif;background:transparent;',\r\n        'text-align:left;width:100%;transition:background 0.1s;}',\r\n      '.pth-lm-item:hover{background:#f1f5f9;}',\r\n      '.pth-lm-item.pth-lm-sel{background:#eff6ff;border-color:#bfdbfe;}',\r\n      '.pth-lm-flag{font-size:0.62rem;font-weight:800;line-height:1;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;text-align:center;background:#eff6ff;color:#1d4ed8;border-radius:5px;letter-spacing:0.3px;}',\r\n      '.pth-lm-names{display:flex;flex-direction:column;min-width:0;}',\r\n      '.pth-lm-native{font-size:0.82rem;font-weight:700;color:#0f172a;',\r\n        'white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}',\r\n      '.pth-lm-en{font-size:0.7rem;color:#334155;font-weight:500;}',\r\n      '.pth-lm-footer{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;',\r\n        'align-items:center;justify-content:space-between;flex-shrink:0;background:#f8fafc;}',\r\n      '.pth-lm-footer-cur{font-size:0.8rem;color:#334155;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-footer-cur strong{color:#1d4ed8;}',\r\n      '.pth-lm-no-res{text-align:center;padding:24px;color:#334155;',\r\n        'font-size:0.85rem;font-family:Inter,system-ui,sans-serif;display:none;}',\r\n      '@media(max-width:520px){.pth-lm-grid{grid-template-columns:repeat(2,1fr);}',\r\n        '#pth-ws-lang-modal{border-radius:12px;max-height:92vh;}}',\r\n      '@media(max-width:360px){.pth-lm-grid{grid-template-columns:1fr;}}'\r\n    ].join('');\r\n    document.head.appendChild(style);\r\n\r\n    var overlay = document.createElement('div');\r\n    overlay.id = 'pth-ws-lang-overlay';\r\n    overlay.setAttribute('role','dialog');\r\n    overlay.setAttribute('aria-modal','true');\r\n    overlay.setAttribute('aria-label','Choose word list language');\r\n    overlay.innerHTML =\r\n      '<div id=\"pth-ws-lang-modal\">' +\r\n        '<div class=\"pth-lm-head\">' +\r\n          '<p class=\"pth-lm-title\">&#x1F30D; Choose Word List Language<\/p>' +\r\n          '<p class=\"pth-lm-sub\">Select language for sample words<\/p>' +\r\n        '<\/div>' +\r\n        '<button class=\"pth-lm-close\" id=\"pth-ws-lm-close\" aria-label=\"Close\">&#x2715;<\/button>' +\r\n        '<div class=\"pth-lm-search-wrap\">' +\r\n          '<input type=\"text\" class=\"pth-lm-search\" id=\"pth-ws-lm-search\"' +\r\n            ' placeholder=\"Search language...\" aria-label=\"Search language\" autocomplete=\"off\">' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-grid-wrap\">' +\r\n          '<div class=\"pth-lm-grid\" id=\"pth-ws-lm-grid\"><\/div>' +\r\n          '<div class=\"pth-lm-no-res\" id=\"pth-ws-lm-nores\">No languages found.<\/div>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-footer\">' +\r\n          '<span class=\"pth-lm-footer-cur\">Selected: <strong id=\"pth-ws-lm-cur\">English<\/strong><\/span>' +\r\n          '<span style=\"font-size:0.72rem;color:#475569;\">&#x1F512; Browser only<\/span>' +\r\n        '<\/div>' +\r\n      '<\/div>';\r\n    document.body.appendChild(overlay);\r\n\r\n    renderLangGrid('');\r\n    var searchEl = document.getElementById('pth-ws-lm-search');\r\n    if (searchEl) {\r\n      searchEl.addEventListener('input', function() { renderLangGrid(searchEl.value.toLowerCase().trim()); });\r\n    }\r\n    var closeBtn = document.getElementById('pth-ws-lm-close');\r\n    if (closeBtn) closeBtn.addEventListener('click', closeLangPopup);\r\n    overlay.addEventListener('click', function(e) { if (e.target === overlay) closeLangPopup(); });\r\n    document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeLangPopup(); });\r\n  }\r\n\r\n  function renderLangGrid(query) {\r\n    var grid = document.getElementById('pth-ws-lm-grid');\r\n    var nores = document.getElementById('pth-ws-lm-nores');\r\n    if (!grid) return;\r\n    grid.innerHTML = '';\r\n    var filtered = WS_LANGS.filter(function(l) {\r\n      if (!query) return true;\r\n      return l.en.toLowerCase().indexOf(query) !== -1 ||\r\n             l.native.toLowerCase().indexOf(query) !== -1 ||\r\n             l.code.indexOf(query) !== -1;\r\n    });\r\n    if (!filtered.length) { if (nores) nores.style.display = 'block'; return; }\r\n    if (nores) nores.style.display = 'none';\r\n    filtered.forEach(function(l) {\r\n      var btn = document.createElement('button');\r\n      btn.className = 'pth-lm-item' + (l.code === WS_CURRENT_LANG.code ? ' pth-lm-sel' : '');\r\n      btn.innerHTML =\r\n        '<span class=\"pth-lm-flag\">' + l.code.toUpperCase() + '<\/span>' +\r\n        '<span class=\"pth-lm-names\">' +\r\n          '<span class=\"pth-lm-native\">' + l.native + '<\/span>' +\r\n          '<span class=\"pth-lm-en\">' + l.en + '<\/span>' +\r\n        '<\/span>';\r\n      btn.addEventListener('click', function() { selectLang(l); });\r\n      grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function selectLang(l) {\r\n    WS_CURRENT_LANG = l;\r\n    var cur = document.getElementById('pth-ws-lm-cur');\r\n    if (cur) cur.innerHTML = l.code.toUpperCase() + ' ' + l.native + ' (' + l.en + ')';\r\n    updatePickerBtn();\r\n    if (WS_SAMPLES[l.code]) {\r\n      var ta = document.getElementById('pth-ws-input');\r\n      if (ta) { ta.value = WS_SAMPLES[l.code]; applyLangToInput(ta, WS_SAMPLES[l.code]); }\r\n      window.pthILS.toast('Loaded: ' + l.native + ' (' + l.en + ')', 'success');\r\n    } else {\r\n      window.pthILS.toast(l.en + ' selected! Type your own words.', 'info');\r\n    }\r\n    var searchEl = document.getElementById('pth-ws-lm-search');\r\n    renderLangGrid(searchEl ? searchEl.value.toLowerCase().trim() : '');\r\n    closeLangPopup();\r\n  }\r\n\r\n  function openLangPopup() {\r\n    buildLangPopup();\r\n    var overlay = document.getElementById('pth-ws-lang-overlay');\r\n    if (overlay) {\r\n      overlay.classList.add('pth-lo-open');\r\n      var s = document.getElementById('pth-ws-lm-search');\r\n      if (s) { s.value=''; renderLangGrid(''); setTimeout(function(){ s.focus(); }, 100); }\r\n    }\r\n  }\r\n\r\n  function closeLangPopup() {\r\n    var overlay = document.getElementById('pth-ws-lang-overlay');\r\n    if (overlay) overlay.classList.remove('pth-lo-open');\r\n  }\r\n\r\n  function updatePickerBtn() {\r\n    var btn  = document.getElementById('pth-ws-lang-pick-btn');\r\n    var flag = document.getElementById('pth-ws-pick-flag');\r\n    var text = document.getElementById('pth-ws-pick-text');\r\n    if (flag) flag.innerHTML = WS_CURRENT_LANG.code.toUpperCase();\r\n    if (text) text.innerHTML = WS_CURRENT_LANG.native + ' \u2014 ' + WS_CURRENT_LANG.en;\r\n  }\r\n\r\n  \/* ============================================================\r\n     BUILD TAB HTML\r\n     ============================================================ *\/\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-wordsearch');\r\n    if (!panel || panel.getAttribute('data-ws-built')) return;\r\n    panel.setAttribute('data-ws-built', '1');\r\n\r\n    panel.innerHTML =\r\n      '<div class=\"pth-ils-layout\" id=\"pth-ws-layout\">' +\r\n      '<div class=\"pth-ils-main\">' +\r\n\r\n        \/* Input card *\/\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F50D; Word Search Generator<\/h3>' +\r\n          '<button class=\"pth-cw-lang-pick-btn\" id=\"pth-ws-lang-pick-btn\" aria-label=\"Choose word list language\">' +\r\n            '<span class=\"pth-cw-lang-pick-flag\" id=\"pth-ws-pick-flag\">EN<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-text\" id=\"pth-ws-pick-text\">English \u2014 Word Language<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-arrow\">&#x25BC;<\/span>' +\r\n          '<\/button>' +\r\n          '<label class=\"pth-ils-label\" for=\"pth-ws-input\">Enter words to hide &#x2014; one per line (max 20)<\/label>' +\r\n          '<p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 6px;font-style:italic;\">&#x2139;&#xFE0F; The text below is just an example placeholder (not real data) &#x2014; type your own words, or click &#x1F4A1; <strong>Load Sample<\/strong> above to fill in working examples.<\/p>' +\r\n          '<textarea class=\"pth-ils-textarea\" id=\"pth-ws-input\" aria-label=\"Words to hide\" style=\"min-height:130px;\"' +\r\n            ' placeholder=\"PYTHON&#10;JAVASCRIPT&#10;BROWSER&#10;SERVER&#10;FUNCTION&#10;VARIABLE&#10;ARRAY&#10;LOOP&#10;DEBUG&#10;CLOUD\"><\/textarea>' +\r\n\r\n          '<div style=\"display:flex;gap:10px;flex-wrap:wrap;margin-bottom:10px;\">' +\r\n            '<div style=\"flex:1;min-width:130px;\">' +\r\n              '<label class=\"pth-ils-label\" for=\"pth-ws-size\">Grid Size<\/label>' +\r\n              '<select class=\"pth-ils-select\" id=\"pth-ws-size\" aria-label=\"Grid size\">' +\r\n                '<option value=\"8\">8 x 8<\/option>' +\r\n                '<option value=\"10\">10 x 10<\/option>' +\r\n                '<option value=\"12\" selected>12 x 12<\/option>' +\r\n                '<option value=\"15\">15 x 15<\/option>' +\r\n                '<option value=\"18\">18 x 18<\/option>' +\r\n              '<\/select>' +\r\n            '<\/div>' +\r\n            '<div style=\"flex:1;min-width:130px;\">' +\r\n              '<label class=\"pth-ils-label\" for=\"pth-ws-dirs\">Directions<\/label>' +\r\n              '<select class=\"pth-ils-select\" id=\"pth-ws-dirs\" aria-label=\"Word directions\">' +\r\n                '<option value=\"hv\">Horizontal + Vertical<\/option>' +\r\n                '<option value=\"hvd\" selected>All (incl. Diagonal)<\/option>' +\r\n                '<option value=\"h\">Horizontal Only<\/option>' +\r\n              '<\/select>' +\r\n            '<\/div>' +\r\n          '<\/div>' +\r\n\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-ws-gen-btn\">&#x26A1; Generate<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-ws-timer-btn\">&#x23F1; Start Timer<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-ws-reveal-btn\">&#x1F441; Reveal Words<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-ws-reset-btn\">&#x1F504; Reset<\/button>' +\r\n          '<\/div>' +\r\n          '<div id=\"pth-ws-status\" class=\"pth-ils-info\" style=\"display:none;\"><\/div>' +\r\n        '<\/div>' +\r\n\r\n        \/* Grid output *\/\r\n        '<div class=\"pth-ils-card\" id=\"pth-ws-grid-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F50D; Word Search Puzzle<\/h3>' +\r\n          '<div id=\"pth-ws-timer-disp\" style=\"display:none;\"><\/div>' +\r\n          '<div id=\"pth-ws-grid-wrap\" style=\"overflow-x:auto;\"><\/div>' +\r\n          '<div id=\"pth-ws-word-list\"><\/div>' +\r\n        '<\/div>' +\r\n\r\n        \/* Export card *\/\r\n        '<div class=\"pth-ils-card\" id=\"pth-ws-export-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F4E4; Export<\/h3>' +\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-ws-png-btn\">&#x1F5BC; Export PNG<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-ws-html-btn\">&#x1F4C4; Download HTML<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-ws-copy-btn\">&#x1F4CB; Copy HTML Code<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-ws-print-btn\">&#x1F5A8; Print Puzzle<\/button>' +\r\n          '<\/div>' +\r\n          '<div class=\"pth-ils-code-box\" id=\"pth-ws-code-box\" style=\"display:none;\">' +\r\n            '<textarea id=\"pth-ws-code-ta\" readonly aria-label=\"HTML code\" style=\"min-height:100px;\"><\/textarea>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n      '<\/div>' + \/* end main *\/\r\n\r\n      \/* SIDEBAR *\/\r\n      '<div class=\"pth-ils-sidebar\">' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4A1; How to Use<\/h3>' +\r\n          '<p style=\"font-size:0.82rem;color:#334155;line-height:1.6;margin:0;\">' +\r\n            '1. Enter words (one per line).<br>' +\r\n            '2. Choose grid size + directions.<br>' +\r\n            '3. Click <strong>&#x26A1; Generate<\/strong>.<br>' +\r\n            '4. <strong>Click and drag<\/strong> on grid to select words.<br>' +\r\n            '5. Start timer for a challenge!<br>' +\r\n            '6. Export PNG for printing.' +\r\n          '<\/p>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4CA; Stats<\/h3>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Words placed<\/span><span class=\"pth-ils-stat-val\" id=\"pth-ws-s-placed\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Words found<\/span><span class=\"pth-ils-stat-val\" id=\"pth-ws-s-found\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Grid size<\/span><span class=\"pth-ils-stat-val\" id=\"pth-ws-s-grid\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Best time<\/span><span class=\"pth-ils-stat-val\" id=\"pth-ws-s-best\">&#8212;<\/span><\/div>' +\r\n        '<\/div>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n  }\r\n\r\n  \/* ============================================================\r\n     WORD SEARCH ENGINE\r\n     ============================================================ *\/\r\n  var WS = {\r\n    grid: [], words: [], placed: [], foundWords: [],\r\n    size: 12, timerInterval: null, timerSecs: 0,\r\n    timerRunning: false, bestTime: null,\r\n    \/* Selection state *\/\r\n    selecting: false, startCell: null, currentCells: []\r\n  };\r\n\r\n  var WS_DIRS_MAP = {\r\n    h:   [[0,1]],\r\n    hv:  [[0,1],[1,0],[0,-1],[-1,0]],\r\n    hvd: [[0,1],[1,0],[0,-1],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]\r\n  };\r\n\r\n  var ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\r\n\r\n  function wsGenerate() {\r\n    var raw   = (document.getElementById('pth-ws-input')||{}).value || '';\r\n    var words = window.pthILS.parseLines(raw)\r\n      .map(function(w){ return w.toUpperCase().replace(\/[^A-Z]\/g,''); })\r\n      .filter(function(w){ return w.length >= 2; });\r\n\r\n    if (!words.length) { window.pthILS.toast('Enter at least one word.','error'); return; }\r\n    if (words.length > 20) words = words.slice(0,20);\r\n\r\n    var size  = parseInt((document.getElementById('pth-ws-size')||{}).value || '12');\r\n    var dirKey= (document.getElementById('pth-ws-dirs')||{}).value || 'hvd';\r\n    var dirs  = WS_DIRS_MAP[dirKey] || WS_DIRS_MAP.hvd;\r\n\r\n    \/* Init empty grid *\/\r\n    var grid = [];\r\n    for (var r = 0; r < size; r++) {\r\n      grid[r] = [];\r\n      for (var c = 0; c < size; c++) grid[r][c] = { letter:'', wordIdx:-1 };\r\n    }\r\n\r\n    var placed = [];\r\n    words.forEach(function(word, wi) {\r\n      var ok = false;\r\n      for (var attempt = 0; attempt < 300 && !ok; attempt++) {\r\n        var dir = dirs[Math.floor(Math.random() * dirs.length)];\r\n        var dr = dir[0], dc = dir[1];\r\n        var sr = Math.floor(Math.random() * size);\r\n        var sc = Math.floor(Math.random() * size);\r\n        var er = sr + dr * (word.length - 1);\r\n        var ec = sc + dc * (word.length - 1);\r\n        if (er < 0 || er >= size || ec < 0 || ec >= size) continue;\r\n        \/* Check conflicts *\/\r\n        var canPlace = true;\r\n        for (var i = 0; i < word.length && canPlace; i++) {\r\n          var gr = sr + dr*i, gc = sc + dc*i;\r\n          if (grid[gr][gc].letter && grid[gr][gc].letter !== word[i]) canPlace = false;\r\n        }\r\n        if (!canPlace) continue;\r\n        \/* Place word *\/\r\n        var cells = [];\r\n        for (var i = 0; i < word.length; i++) {\r\n          var gr = sr + dr*i, gc = sc + dc*i;\r\n          grid[gr][gc].letter = word[i];\r\n          grid[gr][gc].wordIdx = wi;\r\n          cells.push({ r:gr, c:gc });\r\n        }\r\n        placed.push({ word:word, cells:cells, dir:[dr,dc] });\r\n        ok = true;\r\n      }\r\n      if (!ok) placed.push({ word:word, cells:[], failed:true });\r\n    });\r\n\r\n    \/* Fill remaining cells *\/\r\n    for (var r = 0; r < size; r++) {\r\n      for (var c = 0; c < size; c++) {\r\n        if (!grid[r][c].letter) grid[r][c].letter = ALPHA[Math.floor(Math.random()*26)];\r\n      }\r\n    }\r\n\r\n    WS.grid = grid; WS.words = words; WS.placed = placed;\r\n    WS.size = size; WS.foundWords = [];\r\n    WS.selecting = false; WS.startCell = null; WS.currentCells = [];\r\n\r\n    wsRender();\r\n    wsStopTimer();\r\n\r\n    var placedCount = placed.filter(function(p){ return !p.failed; }).length;\r\n    var sp = document.getElementById('pth-ws-s-placed'); if (sp) sp.textContent = placedCount;\r\n    var sf = document.getElementById('pth-ws-s-found');  if (sf) sf.textContent = '0 \/ ' + placedCount;\r\n    var sg = document.getElementById('pth-ws-s-grid');   if (sg) sg.textContent = size + ' x ' + size;\r\n\r\n    document.getElementById('pth-ws-grid-card').style.display   = 'block';\r\n    document.getElementById('pth-ws-export-card').style.display = 'block';\r\n\r\n    var st = document.getElementById('pth-ws-status');\r\n    if (st) { st.style.display='block'; st.textContent = placedCount + ' words hidden in ' + size + 'x' + size + ' grid!'; }\r\n\r\n    window.pthILS.toast('Word Search ready! ' + placedCount + ' words hidden.', 'success');\r\n  }\r\n\r\n  \/* \u2500\u2500 Render grid \u2500\u2500 *\/\r\n  function wsRender() {\r\n    var wrap = document.getElementById('pth-ws-grid-wrap');\r\n    if (!wrap) return;\r\n    var size = WS.size;\r\n\r\n    var gridDiv = document.createElement('div');\r\n    gridDiv.className = 'pth-ils-ws-grid';\r\n    gridDiv.style.gridTemplateColumns = 'repeat(' + size + ', 32px)';\r\n    gridDiv.setAttribute('data-rows', size);\r\n    gridDiv.setAttribute('data-cols', size);\r\n    gridDiv.id = 'pth-ws-grid-el';\r\n\r\n    for (var r = 0; r < size; r++) {\r\n      for (var c = 0; c < size; c++) {\r\n        var cell = document.createElement('div');\r\n        cell.className = 'pth-ils-ws-cell';\r\n        cell.textContent = WS.grid[r][c].letter;\r\n        cell.setAttribute('data-r', r);\r\n        cell.setAttribute('data-c', c);\r\n        cell.setAttribute('data-letter', WS.grid[r][c].letter);\r\n        gridDiv.appendChild(cell);\r\n      }\r\n    }\r\n\r\n    wrap.innerHTML = '';\r\n    wrap.appendChild(gridDiv);\r\n\r\n    \/* Attach pointer events *\/\r\n    wsAttachEvents(gridDiv);\r\n\r\n    \/* Word list *\/\r\n    var wl = document.getElementById('pth-ws-word-list');\r\n    if (wl) {\r\n      var html = '<div class=\"pth-ws-word-list\">';\r\n      WS.placed.forEach(function(p) {\r\n        if (!p.failed) html += '<span class=\"pth-ws-word-tag\" id=\"pth-ws-tag-' + p.word + '\" style=\"cursor:pointer;\" title=\"Click for a hint\">' + p.word + '<\/span>';\r\n      });\r\n      html += '<\/div>';\r\n      wl.innerHTML = html;\r\n      \/* Click-to-hint: briefly highlight the real path for that word *\/\r\n      WS.placed.forEach(function(p) {\r\n        if (p.failed) return;\r\n        var tag = document.getElementById('pth-ws-tag-' + p.word);\r\n        if (!tag) return;\r\n        tag.addEventListener('click', function() {\r\n          if (WS.foundWords.indexOf(p.word) !== -1) return;\r\n          p.cells.forEach(function(pos) {\r\n            var el = document.querySelector('#pth-ws-grid-el [data-r=\"'+pos.r+'\"][data-c=\"'+pos.c+'\"]');\r\n            if (el) el.classList.add('ws-hint');\r\n          });\r\n          setTimeout(function() {\r\n            p.cells.forEach(function(pos) {\r\n              var el = document.querySelector('#pth-ws-grid-el [data-r=\"'+pos.r+'\"][data-c=\"'+pos.c+'\"]');\r\n              if (el) el.classList.remove('ws-hint');\r\n            });\r\n          }, 1200);\r\n        });\r\n      });\r\n    }\r\n  }\r\n\r\n  \/* \u2500\u2500 Pointer events (mouse + touch unified) \u2500\u2500 *\/\r\n  function wsAttachEvents(gridDiv) {\r\n    \/* Mouse *\/\r\n    gridDiv.addEventListener('mousedown', function(e) {\r\n      var cell = e.target.closest ? e.target.closest('.pth-ils-ws-cell') : (e.target.classList.contains('pth-ils-ws-cell') ? e.target : null);\r\n      if (!cell) return;\r\n      e.preventDefault();\r\n      WS.selecting = true;\r\n      WS.startCell = cell;\r\n      WS.currentCells = [cell];\r\n      wsHighlightSelecting([cell]);\r\n    });\r\n\r\n    gridDiv.addEventListener('mouseover', function(e) {\r\n      if (!WS.selecting) return;\r\n      var cell = e.target.closest ? e.target.closest('.pth-ils-ws-cell') : (e.target.classList.contains('pth-ils-ws-cell') ? e.target : null);\r\n      if (!cell) return;\r\n      var lineCells = wsGetLineCells(WS.startCell, cell);\r\n      WS.currentCells = lineCells;\r\n      wsHighlightSelecting(lineCells);\r\n    });\r\n\r\n    document.addEventListener('mouseup', function() {\r\n      if (!WS.selecting) return;\r\n      WS.selecting = false;\r\n      wsCheckSelection(WS.currentCells);\r\n    });\r\n\r\n    \/* Touch *\/\r\n    gridDiv.addEventListener('touchstart', function(e) {\r\n      var touch = e.touches[0];\r\n      var cell  = document.elementFromPoint(touch.clientX, touch.clientY);\r\n      if (!cell || !cell.classList.contains('pth-ils-ws-cell')) return;\r\n      WS.selecting = true;\r\n      WS.startCell = cell;\r\n      WS.currentCells = [cell];\r\n      wsHighlightSelecting([cell]);\r\n    }, { passive: true });\r\n\r\n    gridDiv.addEventListener('touchmove', function(e) {\r\n      if (!WS.selecting) return;\r\n      var touch = e.touches[0];\r\n      var cell  = document.elementFromPoint(touch.clientX, touch.clientY);\r\n      if (!cell || !cell.classList.contains('pth-ils-ws-cell')) return;\r\n      var lineCells = wsGetLineCells(WS.startCell, cell);\r\n      WS.currentCells = lineCells;\r\n      wsHighlightSelecting(lineCells);\r\n    }, { passive: true });\r\n\r\n    gridDiv.addEventListener('touchend', function() {\r\n      if (!WS.selecting) return;\r\n      WS.selecting = false;\r\n      wsCheckSelection(WS.currentCells);\r\n    });\r\n  }\r\n\r\n  function wsGetLineCells(startCell, endCell) {\r\n    if (!startCell || !endCell) return startCell ? [startCell] : [];\r\n    var r1 = parseInt(startCell.getAttribute('data-r'));\r\n    var c1 = parseInt(startCell.getAttribute('data-c'));\r\n    var r2 = parseInt(endCell.getAttribute('data-r'));\r\n    var c2 = parseInt(endCell.getAttribute('data-c'));\r\n    var dr = r2 - r1, dc = c2 - c1;\r\n    var len = Math.max(Math.abs(dr), Math.abs(dc));\r\n    if (len === 0) return [startCell];\r\n    \/* Snap to nearest valid direction *\/\r\n    var bestDir = null, bestScore = -1;\r\n    var allDirs = [[0,1],[1,0],[0,-1],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]];\r\n    allDirs.forEach(function(d) {\r\n      var dot = dr*d[0] + dc*d[1];\r\n      var mag = Math.sqrt(dr*dr+dc*dc) * Math.sqrt(d[0]*d[0]+d[1]*d[1]);\r\n      var score = mag > 0 ? dot\/mag : 0;\r\n      if (score > bestScore) { bestScore=score; bestDir=d; }\r\n    });\r\n    if (!bestDir) return [startCell];\r\n    var stepR = bestDir[0], stepC = bestDir[1];\r\n    var cells = [];\r\n    var gridEl = document.getElementById('pth-ws-grid-el');\r\n    for (var i = 0; i <= len; i++) {\r\n      var cr = r1 + stepR*i, cc = c1 + stepC*i;\r\n      if (cr < 0 || cr >= WS.size || cc < 0 || cc >= WS.size) break;\r\n      var el = gridEl ? gridEl.querySelector('[data-r=\"'+cr+'\"][data-c=\"'+cc+'\"]') : null;\r\n      if (el) cells.push(el);\r\n    }\r\n    return cells.length ? cells : [startCell];\r\n  }\r\n\r\n  function wsHighlightSelecting(cells) {\r\n    \/* Clear previous selecting *\/\r\n    var allCells = document.querySelectorAll('#pth-ws-grid-el .pth-ils-ws-cell');\r\n    allCells.forEach(function(c) { c.classList.remove('ws-selecting'); });\r\n    cells.forEach(function(c) { c.classList.add('ws-selecting'); });\r\n  }\r\n\r\n  function wsCheckSelection(cells) {\r\n    \/* Clear selecting state *\/\r\n    cells.forEach(function(c) { c.classList.remove('ws-selecting'); });\r\n\r\n    if (!cells.length) return;\r\n\r\n    \/* Build selected word (forward and reverse) *\/\r\n    var word    = cells.map(function(c){ return c.getAttribute('data-letter')||''; }).join('');\r\n    var wordRev = word.split('').reverse().join('');\r\n\r\n    \/* Check against placed words *\/\r\n    var matched = null;\r\n    WS.placed.forEach(function(p) {\r\n      if (p.failed) return;\r\n      if (WS.foundWords.indexOf(p.word) !== -1) return;\r\n      if (p.word === word || p.word === wordRev) matched = p;\r\n    });\r\n\r\n    if (matched) {\r\n      WS.foundWords.push(matched.word);\r\n      \/* Highlight found cells green *\/\r\n      cells.forEach(function(c) { c.classList.add('ws-found'); });\r\n      \/* Strike word in list *\/\r\n      var tag = document.getElementById('pth-ws-tag-' + matched.word);\r\n      if (tag) tag.classList.add('ws-found-word');\r\n      \/* Update stats *\/\r\n      var placedCount = WS.placed.filter(function(p){ return !p.failed; }).length;\r\n      var sf = document.getElementById('pth-ws-s-found');\r\n      if (sf) sf.textContent = WS.foundWords.length + ' \/ ' + placedCount;\r\n      window.pthILS.toast('Found: ' + matched.word + '!', 'success');\r\n      \/* Check win *\/\r\n      if (WS.foundWords.length === placedCount) {\r\n        wsStopTimer();\r\n        var time = WS.timerSecs;\r\n        if (WS.bestTime === null || time < WS.bestTime) {\r\n          WS.bestTime = time;\r\n          var sb = document.getElementById('pth-ws-s-best');\r\n          if (sb) sb.textContent = time + 's';\r\n        }\r\n        window.pthILS.toast('All words found! Amazing!', 'success');\r\n      }\r\n    }\r\n    WS.currentCells = [];\r\n  }\r\n\r\n  \/* \u2500\u2500 Timer \u2500\u2500 *\/\r\n  function wsStartTimer() {\r\n    WS.timerSecs = 0;\r\n    WS.timerRunning = true;\r\n    var btn  = document.getElementById('pth-ws-timer-btn');\r\n    var disp = document.getElementById('pth-ws-timer-disp');\r\n    if (btn)  btn.innerHTML   = '&#x23F9; Stop Timer';\r\n    if (disp) { disp.style.display='block'; disp.className='pth-ws-timer-box'; disp.innerHTML  ='&#x23F1; 0s'; }\r\n    WS.timerInterval = setInterval(function() {\r\n      WS.timerSecs++;\r\n      if (disp) disp.innerHTML   = '&#x23F1; ' + WS.timerSecs + 's';\r\n    }, 1000);\r\n  }\r\n\r\n  function wsStopTimer() {\r\n    clearInterval(WS.timerInterval);\r\n    WS.timerRunning = false;\r\n    var btn  = document.getElementById('pth-ws-timer-btn');\r\n    var disp = document.getElementById('pth-ws-timer-disp');\r\n    if (btn) btn.innerHTML   = '&#x23F1; Start Timer';\r\n    if (disp && WS.timerSecs > 0) {\r\n      disp.className = 'pth-ws-timer-box ws-timer-done';\r\n      disp.innerHTML  = '&#x2705; Stopped: ' + WS.timerSecs + 's';\r\n    }\r\n  }\r\n\r\n  \/* \u2500\u2500 Reveal \u2500\u2500 *\/\r\n  function wsReveal() {\r\n    WS.placed.forEach(function(p) {\r\n      if (p.failed || WS.foundWords.indexOf(p.word) !== -1) return;\r\n      p.cells.forEach(function(pos) {\r\n        var el = document.querySelector('#pth-ws-grid-el [data-r=\"'+pos.r+'\"][data-c=\"'+pos.c+'\"]');\r\n        if (el) el.classList.add('ws-revealed');\r\n      });\r\n    });\r\n    window.pthILS.toast('Words revealed!', 'info');\r\n  }\r\n\r\n  \/* ============================================================\r\n     EXPORT\r\n     ============================================================ *\/\r\n  function wsBuildHTML() {\r\n    if (!WS.placed.length) return '';\r\n    var size = WS.size;\r\n    \/* Build grid data *\/\r\n    var gridData = [];\r\n    for (var r = 0; r < size; r++) {\r\n      for (var c = 0; c < size; c++) {\r\n        gridData.push(WS.grid[r][c].letter || '');\r\n      }\r\n    }\r\n    var words = WS.placed.filter(function(p){ return !p.failed; }).map(function(p){ return p.word; });\r\n    var wordCells = WS.placed.filter(function(p){ return !p.failed; }).map(function(p){ return p.cells; });\r\n\r\n    var html =\r\n      '<style>' +\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;color-adjust:exact;}' +\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;background:#eef2f9;color:#1e293b;min-height:100vh;display:flex;justify-content:center;padding:32px 16px;}' +\r\n      '.ws-page{width:100%;max-width:640px;background:#fff;border-radius:18px;box-shadow:0 10px 30px -10px rgba(15,23,42,0.18);padding:30px 34px 34px;}' +\r\n      '.ws-head{text-align:center;margin:0 0 14px;}' +\r\n      'h1{color:#1d4ed8;font-size:1.5rem;font-weight:800;margin:0 0 6px;}' +\r\n      '.ws-sub{color:#334155;font-size:0.85rem;margin:0;}' +\r\n      '.ws-meta-row{display:flex;align-items:center;justify-content:center;gap:14px;margin:14px 0 18px;flex-wrap:wrap;}' +\r\n      '.ws-score{font-size:0.88rem;font-weight:700;color:#1d4ed8;background:#eff6ff;padding:5px 12px;border-radius:7px;}' +\r\n      '.ws-timer{font-size:0.88rem;font-weight:700;color:#334155;background:#f1f5f9;padding:5px 12px;border-radius:7px;}' +\r\n      '.ws-grid-outer{display:flex;justify-content:center;overflow-x:auto;padding:4px;}' +\r\n      '.ws-grid{display:inline-grid;gap:1px;background:#e2e8f0;padding:2px;border-radius:6px;user-select:none;}' +\r\n      '.ws-cell{width:30px;height:30px;background:#fff;display:flex;align-items:center;justify-content:center;font-size:0.82rem;font-weight:700;color:#0f172a;cursor:pointer;border-radius:2px;}' +\r\n      '.ws-cell.sel{background:#bfdbfe;color:#1d4ed8;}' +\r\n      '.ws-cell.found{background:#bbf7d0;color:#047857;}' +\r\n      '.ws-cell.revealed{background:#fef08a;color:#92400e;}' +\r\n      '.ws-words{display:flex;flex-wrap:wrap;gap:7px;margin-top:18px;justify-content:center;}' +\r\n      '.ws-tag{background:#eff6ff;color:#1d4ed8;border:1px solid #bfdbfe;font-size:0.8rem;font-weight:700;padding:4px 10px;border-radius:20px;cursor:pointer;}' +\r\n      '.ws-tag.done{background:#f0fdf4;color:#047857;border-color:#bbf7d0;text-decoration:line-through;opacity:0.7;cursor:default;}' +\r\n      '.ws-cell.hint{background:#fde68a;color:#92400e;outline:2px solid #f59e0b;}' +\r\n      '.ws-footer-btns{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:22px 0 4px;padding-top:18px;border-top:2px solid #e2e8f0;}' +\r\n      '.ws-btn{padding:9px 18px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.06);}' +\r\n      '.ws-btn-b{background:#fff;border:2px solid #e2e8f0;color:#334155;}' +\r\n      '.ws-btn-c{background:#7c3aed;color:#fff;}' +\r\n      '.ws-btn.active{outline:3px solid #fde68a;}' +\r\n      '@media(max-width:480px){.ws-page{padding:20px 16px 26px;border-radius:12px;}}' +\r\n      '@media print{body{margin:0;background:#fff;padding:0;display:block;}.ws-page{box-shadow:none;border-radius:0;max-width:100%;padding:10px;}.ws-footer-btns,.ws-timer{display:none!important;}.ws-grid,.ws-words{break-inside:avoid;}}' +\r\n      '<\/style>' +\r\n      '<div class=\"ws-page\">' +\r\n      '<div class=\"ws-head\">' +\r\n      '<h2>&#x1F50D; Word Search Puzzle<\/h2>' +\r\n      '<p class=\"ws-sub\">Click and drag to select hidden words.<\/p>' +\r\n      '<\/div>' +\r\n      '<div class=\"ws-meta-row\">' +\r\n      '<span class=\"ws-score\">Found: <span id=\"ws-found\">0<\/span> \/ ' + words.length + '<\/span>' +\r\n      '<span class=\"ws-timer\" id=\"ws-timer\">&#x23F1; 00:00<\/span>' +\r\n      '<\/div>' +\r\n      '<div class=\"ws-grid-outer\"><div class=\"ws-grid\" id=\"ws-grid\" style=\"grid-template-columns:repeat(' + size + ',30px);\"><\/div><\/div>' +\r\n      '<div class=\"ws-words\" id=\"ws-words\"><\/div>' +\r\n      '<div id=\"ws-win\" style=\"display:none;margin-top:16px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;padding:12px;color:#047857;font-weight:700;text-align:center;\">&#x1F389; All words found!<\/div>' +\r\n      '<div class=\"ws-footer-btns\">' +\r\n      '<button class=\"ws-btn ws-btn-b\" id=\"btn-reveal\">&#x1F441; Reveal Words<\/button>' +\r\n      '<button class=\"ws-btn ws-btn-b\" id=\"btn-reset\">&#x1F504; Reset<\/button>' +\r\n      '<button class=\"ws-btn ws-btn-b\" id=\"btn-answerkey\">&#x1F5DD; Answer Key Mode<\/button>' +\r\n      '<button class=\"ws-btn ws-btn-c\" id=\"btn-print\">&#x1F5A8; Print Puzzle<\/button>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n\r\n    \/* Inline script for exported file *\/\r\n    var sc = [\r\n      '(function(){',\r\n        'var gd=' + JSON.stringify(gridData) + ';',\r\n        'var words=' + JSON.stringify(words) + ';',\r\n        'var wordCells=' + JSON.stringify(wordCells) + ';',\r\n        'var size=' + size + ';',\r\n        'var found=[],sel=false,startEl=null,curCells=[],akOn=false;',\r\n        'var g=document.getElementById(\"ws-grid\");',\r\n        'var wl=document.getElementById(\"ws-words\");',\r\n        'var tStart=Date.now();var tEl=document.getElementById(\"ws-timer\");',\r\n        'if(tEl){setInterval(function(){var s=Math.floor((Date.now()-tStart)\/1000),m=Math.floor(s\/60),ss=s%60;tEl.textContent=\"\\\\u23F1 \"+(m<10?\"0\":\"\")+m+\":\"+(ss<10?\"0\":\"\")+ss;},1000);}',\r\n        \/* Build grid *\/\r\n        'function buildGrid(){',\r\n          'g.innerHTML=\"\";',\r\n          'gd.forEach(function(letter,idx){',\r\n            'var d=document.createElement(\"div\");d.className=\"ws-cell\";',\r\n            'd.textContent=letter;d.setAttribute(\"data-i\",idx);',\r\n            'd.setAttribute(\"data-r\",Math.floor(idx\/size));',\r\n            'd.setAttribute(\"data-c\",idx%size);',\r\n            'g.appendChild(d);',\r\n          '});',\r\n        '}',\r\n        'buildGrid();',\r\n        \/* Build word list *\/\r\n        'words.forEach(function(w,wi){',\r\n          'var s=document.createElement(\"span\");s.className=\"ws-tag\";s.id=\"wt-\"+w;s.textContent=w;wl.appendChild(s);',\r\n          '(function(word,cellList){',\r\n            's.addEventListener(\"click\",function(){',\r\n              'if(found.indexOf(word)!==-1)return;',\r\n              'cellList.forEach(function(pos){var el=g.querySelector(\"[data-r=\\'\"+pos.r+\"\\'][data-c=\\'\"+pos.c+\"\\']\");if(el)el.classList.add(\"hint\");});',\r\n              'setTimeout(function(){cellList.forEach(function(pos){var el=g.querySelector(\"[data-r=\\'\"+pos.r+\"\\'][data-c=\\'\"+pos.c+\"\\']\");if(el)el.classList.remove(\"hint\");});},1200);',\r\n            '});',\r\n          '})(w,wordCells[wi]);',\r\n        '});',\r\n        \/* Helper: get line cells *\/\r\n        'function getLine(s,e){',\r\n          'var r1=parseInt(s.getAttribute(\"data-r\")),c1=parseInt(s.getAttribute(\"data-c\"));',\r\n          'var r2=parseInt(e.getAttribute(\"data-r\")),c2=parseInt(e.getAttribute(\"data-c\"));',\r\n          'var dr=r2-r1,dc=c2-c1,len=Math.max(Math.abs(dr),Math.abs(dc));',\r\n          'if(len===0)return[s];',\r\n          'var dirs=[[0,1],[1,0],[0,-1],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]];',\r\n          'var best=dirs[0],bs=-2;',\r\n          'dirs.forEach(function(d){var dot=dr*d[0]+dc*d[1],mag=Math.sqrt(dr*dr+dc*dc);var sc2=mag>0?dot\/mag:0;if(sc2>bs){bs=sc2;best=d;}});',\r\n          'var cells=[];',\r\n          'for(var i=0;i<=len;i++){',\r\n            'var cr=r1+best[0]*i,cc=c1+best[1]*i;',\r\n            'if(cr<0||cr>=size||cc<0||cc>=size)break;',\r\n            'var el=g.querySelector(\"[data-r=\\'\"+cr+\"\\'][data-c=\\'\"+cc+\"\\']\");',\r\n            'if(el)cells.push(el);',\r\n          '}',\r\n          'return cells.length?cells:[s];',\r\n        '}',\r\n        \/* Check selection *\/\r\n        'function checkSel(cells){',\r\n          'cells.forEach(function(c){c.classList.remove(\"sel\");});',\r\n          'if(!cells.length)return;',\r\n          'var w=cells.map(function(c){return c.textContent;}).join(\"\");',\r\n          'var wr=w.split(\"\").reverse().join(\"\");',\r\n          'var match=null;',\r\n          'words.forEach(function(word){if(found.indexOf(word)===-1&&(word===w||word===wr))match=word;});',\r\n          'if(match){',\r\n            'found.push(match);',\r\n            'cells.forEach(function(c){c.classList.add(\"found\");});',\r\n            'var tag=document.getElementById(\"wt-\"+match);if(tag)tag.className=\"ws-tag done\";',\r\n            'var fd=document.getElementById(\"ws-found\");if(fd)fd.textContent=found.length;',\r\n            'if(found.length===words.length){var win=document.getElementById(\"ws-win\");if(win)win.style.display=\"block\";}',\r\n          '}',\r\n          'curCells=[];',\r\n        '}',\r\n        \/* Pointer events \u2014 works for mouse AND touch *\/\r\n        'g.addEventListener(\"pointerdown\",function(e){var c=e.target;if(!c.classList.contains(\"ws-cell\"))return;sel=true;startEl=c;curCells=[c];c.classList.add(\"sel\");g.setPointerCapture(e.pointerId);});',\r\n        'g.addEventListener(\"pointermove\",function(e){if(!sel)return;var c=document.elementFromPoint(e.clientX,e.clientY);if(!c||!c.classList.contains(\"ws-cell\"))return;var line=getLine(startEl,c);g.querySelectorAll(\".sel\").forEach(function(x){x.classList.remove(\"sel\");});line.forEach(function(x){x.classList.add(\"sel\");});curCells=line;});',\r\n        'g.addEventListener(\"pointerup\",function(){if(!sel)return;sel=false;checkSel(curCells);});',\r\n        \/* Reveal \/ Reset \/ Answer Key \/ Print *\/\r\n        'function revealWordCells(){',\r\n          'wordCells.forEach(function(cellList,wi){',\r\n            'if(found.indexOf(words[wi])!==-1)return;',\r\n            'cellList.forEach(function(pos){',\r\n              'var el=g.querySelector(\"[data-r=\\'\"+pos.r+\"\\'][data-c=\\'\"+pos.c+\"\\']\");',\r\n              'if(el)el.classList.add(\"revealed\");',\r\n            '});',\r\n          '});',\r\n        '}',\r\n        'document.getElementById(\"btn-reveal\").addEventListener(\"click\",revealWordCells);',\r\n        'document.getElementById(\"btn-reset\").addEventListener(\"click\",function(){found=[];buildGrid();wl.querySelectorAll(\".ws-tag\").forEach(function(t){t.className=\"ws-tag\";});var fd=document.getElementById(\"ws-found\");if(fd)fd.textContent=\"0\";var win=document.getElementById(\"ws-win\");if(win)win.style.display=\"none\";});',\r\n        'document.getElementById(\"btn-answerkey\").addEventListener(\"click\",function(e){akOn=!akOn;e.target.classList.toggle(\"active\",akOn);if(akOn){revealWordCells();e.target.textContent=\"Hide Answer Key\";}else{g.querySelectorAll(\".ws-cell\").forEach(function(c){c.classList.remove(\"revealed\");});e.target.textContent=\"Answer Key Mode\";}});',\r\n        'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n\r\n    var so = '<' + 'script' + '>';\r\n    var sc2 = '<' + '\/' + 'script' + '>';\r\n    var docOpen = '<' + '!DOCTYPE html>' + '<' + 'html lang=\"en\">' + '<' + 'head>' +\r\n      '<' + 'meta charset=\"UTF-8\">' +\r\n      '<' + 'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">' +\r\n      '<' + 'title>Word Search Puzzle<' + '\/title>' +\r\n      '<' + '\/head>' + '<' + 'body>';\r\n    var docClose = '<' + '\/' + 'body>' + '<' + '\/' + 'html>';\r\n    return docOpen + html + so + sc + sc2 + docClose;\r\n  }\r\n\r\n  \/* ============================================================\r\n     WIRE EVENTS\r\n     ============================================================ *\/\r\n  function wireEvents() {\r\n    var b = function(id,fn){ var el=document.getElementById(id); if(el)el.addEventListener('click',fn); };\r\n\r\n    b('pth-ws-gen-btn',    wsGenerate);\r\n    b('pth-ws-reveal-btn', wsReveal);\r\n    b('pth-ws-lang-pick-btn', openLangPopup);\r\n    b('pth-ws-reset-btn', function() {\r\n      if (!WS.placed.length) { window.pthILS.toast('Generate first!','error'); return; }\r\n      document.querySelectorAll('#pth-ws-grid-el .pth-ils-ws-cell').forEach(function(c){\r\n        c.classList.remove('ws-selecting','ws-found','ws-revealed');\r\n      });\r\n      WS.foundWords = [];\r\n      var fd = document.getElementById('pth-ws-s-found'); if (fd) fd.textContent = '0 \/ ' + WS.placed.length;\r\n      document.querySelectorAll('.pth-ws-word-tag').forEach(function(t){ t.classList.remove('ws-found-word'); });\r\n      window.pthILS.toast('Puzzle reset!','info');\r\n    });\r\n    b('pth-ws-timer-btn',  function() {\r\n      if (WS.timerRunning) wsStopTimer(); else wsStartTimer();\r\n    });\r\n\r\n    b('pth-ws-png-btn', function() {\r\n      var g = document.getElementById('pth-ws-grid-el');\r\n      if (!g) { window.pthILS.toast('Generate first!','error'); return; }\r\n      window.pthILS.exportPNG(g, 'word-search', 30, 30);\r\n    });\r\n\r\n    b('pth-ws-html-btn', function() {\r\n      var c = wsBuildHTML();\r\n      if (!c) { window.pthILS.toast('Generate first!','error'); return; }\r\n      try {\r\n        var blob=new Blob([c],{type:'text\/html'});\r\n        var url=URL.createObjectURL(blob);\r\n        var a=document.createElement('a');\r\n        a.href=url;a.download='word-search-puzzle.html';\r\n        document.body.appendChild(a);a.click();document.body.removeChild(a);\r\n        setTimeout(function(){URL.revokeObjectURL(url);},2000);\r\n        window.pthILS.toast('HTML file downloaded!','success');\r\n      } catch(err) { window.pthILS.toast('Download failed: '+err.message,'error'); }\r\n    });\r\n\r\n    b('pth-ws-print-btn', function() {\r\n      var c = wsBuildHTML();\r\n      if (!c) { window.pthILS.toast('Generate first!','error'); return; }\r\n      var w = window.open('','_blank');\r\n      if (!w) { window.pthILS.toast('Popup blocked! Allow popups for this site to print.','error'); return; }\r\n      w.document.open();w.document.write(c);w.document.close();\r\n      var printed=false;\r\n      function doPrint(){ if(printed)return; printed=true; w.focus(); w.print(); }\r\n      w.addEventListener('load', function(){ setTimeout(doPrint,150); });\r\n      setTimeout(doPrint,1200);\r\n    });\r\n\r\n    b('pth-ws-copy-btn', function() {\r\n      var c = wsBuildHTML();\r\n      if (!c) { window.pthILS.toast('Generate first!','error'); return; }\r\n      window.pthILS.showCopyHTML(c, 'pth-ws-code-box');\r\n    });\r\n\r\n    \/* Global events *\/\r\n    document.addEventListener('pthILSClear', function(e) {\r\n      if (e.detail.tab !== 'wordsearch') return;\r\n      var ta = document.getElementById('pth-ws-input');\r\n      if (ta) ta.value = '';\r\n      var gw = document.getElementById('pth-ws-grid-wrap'); if (gw) gw.innerHTML = '';\r\n      var wl = document.getElementById('pth-ws-word-list'); if (wl) wl.innerHTML = '';\r\n      var gc = document.getElementById('pth-ws-grid-card');   if (gc) gc.style.display='none';\r\n      var ec = document.getElementById('pth-ws-export-card'); if (ec) ec.style.display='none';\r\n      var st = document.getElementById('pth-ws-status');      if (st) st.style.display='none';\r\n      var td = document.getElementById('pth-ws-timer-disp');  if (td) td.style.display='none';\r\n      wsStopTimer();\r\n      WS.placed=[]; WS.foundWords=[]; WS.timerSecs=0;\r\n      ['pth-ws-s-placed','pth-ws-s-found','pth-ws-s-grid'].forEach(function(id){\r\n        var el=document.getElementById(id); if(el)el.textContent='&#8212;';\r\n      });\r\n    });\r\n\r\n    document.addEventListener('pthILSSample', function(e) {\r\n      if (e.detail.tab !== 'wordsearch') return;\r\n      var ta = document.getElementById('pth-ws-input');\r\n      if (ta) {\r\n        ta.value = 'PYTHON\\nJAVASCRIPT\\nBROWSER\\nSERVER\\nFUNCTION\\nVARIABLE\\nARRAY\\nLOOP\\nDEBUG\\nCLOUD';\r\n        window.pthILS.toast('Sample loaded! Click Generate.','success');\r\n      }\r\n    });\r\n  }\r\n\r\n  \/* \u2500\u2500 INIT \u2500\u2500 *\/\r\n  function init() {\r\n    buildTabHTML();\r\n    setTimeout(function() { wireEvents(); }, 100);\r\n  }\r\n\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v2.0 \u2014 Drag & Sort Tab -->\r\n\r\n<style>\r\n.pth-sort-list { list-style: none; padding: 0; margin: 0; }\r\n.pth-sort-item {\r\n  background: #fff;\r\n  border: 2px solid #e2e8f0;\r\n  border-radius: 8px;\r\n  padding: 11px 14px;\r\n  margin-bottom: 8px;\r\n  cursor: grab;\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 10px;\r\n  font-size: 0.9rem;\r\n  font-weight: 600;\r\n  color: #1e293b;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;\r\n  touch-action: none;\r\n}\r\n.pth-sort-item:active { cursor: grabbing; }\r\n.pth-sort-item.sort-dragging {\r\n  opacity: 0.5;\r\n  border-color: #2563eb;\r\n  box-shadow: 0 4px 12px rgba(37,99,235,0.15);\r\n}\r\n.pth-sort-item.sort-over {\r\n  border-color: #2563eb;\r\n  box-shadow: 0 0 0 3px #bfdbfe;\r\n}\r\n.pth-sort-item.sort-correct { border-color: #059669; background: #f0fdf4; color: #047857; }\r\n.pth-sort-item.sort-wrong   { border-color: #dc2626; background: #fef2f2; color: #991b1b; }\r\n.pth-sort-handle {\r\n  color: #94a3b8;\r\n  font-size: 1.1rem;\r\n  flex-shrink: 0;\r\n  cursor: grab;\r\n}\r\n.pth-sort-num {\r\n  background: #2563eb;\r\n  color: #fff;\r\n  width: 24px;\r\n  height: 24px;\r\n  border-radius: 50%;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  font-size: 0.72rem;\r\n  font-weight: 800;\r\n  flex-shrink: 0;\r\n}\r\n.pth-sort-mode-bar {\r\n  display: flex;\r\n  gap: 8px;\r\n  margin-bottom: 12px;\r\n}\r\n.pth-sort-mode-bar button {\r\n  flex: 1;\r\n}\r\n\/* Language picker button (shared visual style) *\/\r\n.pth-cw-lang-pick-btn {\r\n  display: inline-flex; align-items: center; gap: 8px;\r\n  padding: 9px 16px; background: #fff; border: 2px solid #e2e8f0;\r\n  border-radius: 8px; cursor: pointer; font-family: 'Inter', system-ui, sans-serif;\r\n  font-size: 0.85rem; font-weight: 700; color: #334155;\r\n  transition: all 0.15s; width: 100%; margin-bottom: 10px;\r\n}\r\n.pth-cw-lang-pick-btn:hover { border-color: #2563eb; color: #1d4ed8; background: #eff6ff; }\r\n.pth-cw-lang-pick-flag { font-size: 0.68rem; font-weight: 800; background: #2563eb; color: #fff; border-radius: 5px; padding: 3px 6px; min-width: 26px; text-align: center; letter-spacing: 0.3px; }\r\n.pth-cw-lang-pick-text { flex: 1; text-align: left; }\r\n.pth-cw-lang-pick-arrow { color: #94a3b8; font-size: 0.8rem; }\r\n<\/style>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function () {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function () { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  \/* ============================================================\r\n     MULTILINGUAL METHODS \u2014 self-contained\r\n     ============================================================ *\/\r\n  if (!window.pthILS) window.pthILS = {};\r\n  if (!window.pthILS.detectScript) {\r\n    window.pthILS.detectScript = function(text) {\r\n      if (!text || !text.trim()) return 'latin';\r\n      if (\/[\\u0D80-\\u0DFF]\/.test(text)) return 'sinhala';\r\n      if (\/[\\u0B80-\\u0BFF]\/.test(text)) return 'tamil';\r\n      if (\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text)) return 'rtl';\r\n      if (\/[\\u3000-\\u9FFF\\uAC00-\\uD7AF]\/.test(text)) return 'cjk';\r\n      if (\/[\\u0900-\\u097F]\/.test(text)) return 'devanagari';\r\n      if (\/[\\u0E00-\\u0E7F]\/.test(text)) return 'thai';\r\n      if (\/[\\u0980-\\u09FF]\/.test(text)) return 'bengali';\r\n      if (\/[\\u1000-\\u109F]\/.test(text)) return 'myanmar';\r\n      if (\/[\\u1780-\\u17FF]\/.test(text)) return 'khmer';\r\n      if (\/[\\u0370-\\u03FF]\/.test(text)) return 'greek';\r\n      if (\/[\\u0400-\\u04FF]\/.test(text)) return 'cyrillic';\r\n      return 'latin';\r\n    };\r\n  }\r\n  if (!window.pthILS.isRTL) {\r\n    window.pthILS.isRTL = function(text) {\r\n      return \/[\\u0591-\\u07FF\\u200F\\u202B\\u202E\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text);\r\n    };\r\n  }\r\n  if (!window.pthILS.getFontStack) {\r\n    window.pthILS.getFontStack = function(script) {\r\n      var f = {\r\n        sinhala:\"'Noto Sans Sinhala','Iskoola Pota',system-ui,sans-serif\",\r\n        tamil:\"'Noto Sans Tamil','Latha',system-ui,sans-serif\",\r\n        rtl:\"'Noto Sans Arabic','Noto Sans Hebrew',system-ui,sans-serif\",\r\n        cjk:\"'Noto Sans CJK SC','Microsoft YaHei',system-ui,sans-serif\",\r\n        devanagari:\"'Noto Sans Devanagari','Mangal',system-ui,sans-serif\",\r\n        thai:\"'Noto Sans Thai','Tahoma',system-ui,sans-serif\",\r\n        bengali:\"'Noto Sans Bengali','Vrinda',system-ui,sans-serif\",\r\n        myanmar:\"'Noto Sans Myanmar',system-ui,sans-serif\",\r\n        khmer:\"'Noto Sans Khmer',system-ui,sans-serif\",\r\n        latin:\"'Inter',system-ui,sans-serif\"\r\n      };\r\n      return f[script] || f.latin;\r\n    };\r\n  }\r\n  if (!window.pthILS.loadedFonts) window.pthILS.loadedFonts = {};\r\n  if (!window.pthILS.loadFont) {\r\n    window.pthILS.loadFont = function(script) {\r\n      if (window.pthILS.loadedFonts[script]) return;\r\n      window.pthILS.loadedFonts[script] = true;\r\n      var m = {\r\n        sinhala:'Noto+Sans+Sinhala:wght@400;700',tamil:'Noto+Sans+Tamil:wght@400;700',\r\n        rtl:'Noto+Sans+Arabic:wght@400;700',devanagari:'Noto+Sans+Devanagari:wght@400;700',\r\n        thai:'Noto+Sans+Thai:wght@400;700',bengali:'Noto+Sans+Bengali:wght@400;700',\r\n        myanmar:'Noto+Sans+Myanmar:wght@400;700',cjk:'Noto+Sans+SC:wght@400;700'\r\n      };\r\n      if (!m[script]) return;\r\n      var l=document.createElement('link');l.rel='stylesheet';\r\n      l.href='https:\/\/fonts.googleapis.com\/css2?family='+m[script]+'&display=swap';\r\n      document.head.appendChild(l);\r\n    };\r\n  }\r\n\r\n  var SORT_LANGS = [\r\n    {code:'en', native:'English', en:'English'},\r\n    {code:'si', native:'\\u0DC3\\u0DD2\\u0982\\u0DC4\\u0DBD', en:'Sinhala'},\r\n    {code:'ta', native:'\\u0BA4\\u0BAE\\u0BBF\\u0BB4\\u0BCD', en:'Tamil'},\r\n    {code:'zh', native:'\\u4E2D\\u6587', en:'Chinese'},\r\n    {code:'ar', native:'\\u0627\\u0644\\u0639\\u0631\\u0628\\u064A\\u0629', en:'Arabic'},\r\n    {code:'hi', native:'\\u0939\\u093F\\u0928\\u094D\\u0926\\u0940', en:'Hindi'},\r\n    {code:'es', native:'Espa\\u00F1ol', en:'Spanish'},\r\n    {code:'fr', native:'Fran\\u00E7ais', en:'French'},\r\n    {code:'pt', native:'Portugu\\u00EAs', en:'Portuguese'},\r\n    {code:'de', native:'Deutsch', en:'German'},\r\n    {code:'ja', native:'\\u65E5\\u672C\\u8A9E', en:'Japanese'},\r\n    {code:'ko', native:'\\uD55C\\uAD6D\\uC5B4', en:'Korean'},\r\n    {code:'ru', native:'\\u0420\\u0443\\u0441\\u0441\\u043A\\u0438\\u0439', en:'Russian'},\r\n    {code:'it', native:'Italiano', en:'Italian'},\r\n    {code:'tr', native:\"T\\u00FCrk\\u00E7e\", en:'Turkish'},\r\n    {code:'id', native:'Bahasa Indonesia', en:'Indonesian'},\r\n    {code:'ms', native:'Bahasa Melayu', en:'Malay'},\r\n    {code:'bn', native:'\\u09AC\\u09BE\\u0982\\u09B2\\u09BE', en:'Bengali'},\r\n    {code:'vi', native:\"Ti\\u1EBFng Vi\\u1EC7t\", en:'Vietnamese'},\r\n    {code:'th', native:'\\u0E44\\u0E17\\u0E22', en:'Thai'},\r\n    {code:'sw', native:'Kiswahili', en:'Swahili'},\r\n    {code:'nl', native:'Nederlands', en:'Dutch'},\r\n    {code:'pl', native:'Polski', en:'Polish'},\r\n    {code:'uk', native:'\\u0423\\u043A\\u0440\\u0430\\u0457\\u043D\\u0441\\u044C\\u043A\\u0430', en:'Ukrainian'},\r\n    {code:'el', native:'\\u0395\\u03BB\\u03BB\\u03B7\\u03BD\\u03B9\\u03BA\\u03AC', en:'Greek'},\r\n    {code:'he', native:'\\u05E2\\u05D1\\u05E8\\u05D9\\u05EA', en:'Hebrew'},\r\n    {code:'fa', native:'\\u0641\\u0627\\u0631\\u0633\\u06CC', en:'Persian'},\r\n    {code:'ur', native:'\\u0627\\u0631\\u062F\\u0648', en:'Urdu'},\r\n    {code:'ne', native:'\\u0928\\u0947\\u092A\\u093E\\u0932\\u0940', en:'Nepali'},\r\n    {code:'sv', native:'Svenska', en:'Swedish'},\r\n    {code:'ro', native:\"Rom\\u00E2n\\u0103\", en:'Romanian'},\r\n    {code:'fil', native:'Filipino', en:'Filipino'},\r\n    {code:'af', native:'Afrikaans', en:'Afrikaans'}\r\n  ];\r\n\r\n  \/* Sample sentences\/steps by language and mode *\/\r\n  var SORT_SAMPLES = {\r\n    step: {\r\n      en:'First, gather your ingredients.\\nPreheat the oven to 180\\u00B0C.\\nMix flour, sugar, and butter.\\nAdd eggs and stir until smooth.\\nPour into a baking tin.\\nBake for 25 minutes.\\nLet cool before serving.',\r\n      si:'\\u0DB8\\u0DD3\\u0DBA\\u0DCA \\u0DC3\\u0DAD\\u0DD4\\u0DC0\\u0DCA \\u0D9C\\u0DB1\\u0DC3\\u0DD0\\u0DAF\\u0DD9\\u0DB1\\u0DCA\\u0DB1.\\n\\u0D85\\u0DC0\\u0DCF\\u0DB1\\u0DCA \\u0DC0\\u0DD2\\u0DC0\\u0DC8\\u0DAD 180\\u00B0C\\u0DA7 \\u0DA0\\u0DD4\\u0DAF\\u0DCA \\u0DAD\\u0DBA\\u0DBB\\u0DD2.\\n\\u0D9C\\u0DDD\\u0DAF\\u0DD4, \\u0DC3\\u0DD4\\u0D9C\\u0DBB\\u0DCF \\u0DC3\\u0DC4 \\u0DAB\\u0DD9\\u0DB1\\u0DBA\\u0DD2.',\r\n      zh:'\\u9996\\u5148\\u51C6\\u5907\\u6750\\u6599\\u3002\\n\\u9884\\u70ED\\u70E4\\u7BB1\\u3002\\n\\u6DF7\\u5408\\u9762\\u7C89\\u3001\\u7CD6\\u548C\\u9EC4\\u6CB9\\u3002',\r\n      ar:'\\u0623\\u0648\\u0644\\u0627\\u064B\\u060C \\u0627\\u062C\\u0645\\u0639 \\u0627\\u0644\\u0645\\u0643\\u0648\\u0646\\u0627\\u062A.\\n\\u0633\\u062E\\u0651\\u0646 \\u0627\\u0644\\u0641\\u0631\\u0646.',\r\n      es:'Primero, re\\u00FAne los ingredientes.\\nPrecalienta el horno a 180\\u00B0C.\\nMezcla harina, az\\u00FAcar y mantequilla.\\nA\\u00F1ade huevos y revuelve.\\nVierte en un molde.\\nHornea por 25 minutos.\\nDeja enfriar antes de servir.',\r\n      fr:\"D'abord, r\\u00E9unissez les ingr\\u00E9dients.\\nPr\\u00E9chauffez le four \\u00E0 180\\u00B0C.\\nM\\u00E9langez farine, sucre et beurre.\\nAjoutez les \\u0153ufs.\\nVersez dans un moule.\\nCuisez 25 minutes.\\nLaissez refroidir.\",\r\n      de:'Zuerst die Zutaten bereitstellen.\\nOfen auf 180\\u00B0C vorheizen.\\nMehl, Zucker und Butter mischen.\\nEier hinzuf\\u00FCgen.\\nIn eine Form gie\\u00DFen.\\n25 Minuten backen.\\nAbk\\u00FChlen lassen.',\r\n      hi:'\\u092A\\u0939\\u0932\\u0947, \\u0938\\u093E\\u092E\\u0917\\u094D\\u0930\\u0940 \\u0907\\u0915\\u091F\\u094D\\u0920\\u093E \\u0915\\u0930\\u0947\\u0902\\u0964\\n\\u0913\\u0935\\u0928 \\u0915\\u094B 180\\u00B0C \\u092A\\u0930 \\u092A\\u094D\\u0930\\u0940\\u0939\\u0940\\u091F \\u0915\\u0930\\u0947\\u0902\\u0964'\r\n    },\r\n    sentence: {\r\n      en:'The sun rises in the east.\\nBirds begin to sing in the morning.\\nPeople wake up and start their day.\\nThe city becomes busy with activity.\\nBy noon the streets are full of people.',\r\n      si:'\\u0DC3\\u0DD6\\u0DBB\\u0DCA\\u0DBA\\u0DBA\\u0DCF \\u0DB4\\u0DD3\\u0DBB\\u0DA9\\u0DD2\\u0DB1\\u0DCA \\u0D8B\\u0DAF\\u0DCF\\u0DC0\\u0DDA\\u0DBA\\u0DD2.\\n\\u0DB4\\u0DD9\\u0DC0\\u0DBA\\u0DDA \\u0D9C\\u0DD2\\u0DBD\\u0DD2\\u0DC4\\u0DD4 \\u0D9C\\u0DD3 \\u0D9C\\u0DCF\\u0DBA\\u0DB1\\u0DCA \\u0D9A\\u0DBB\\u0DBA\\u0DD2.',\r\n      zh:'\\u592A\\u9633\\u4ECE\\u4E1C\\u65B9\\u5347\\u8D77\\u3002\\n\\u9CE5\\u513F\\u5728\\u65E9\\u4E0A\\u5F00\\u59CB\\u9E23\\u53EB\\u3002',\r\n      es:'El sol sale por el este.\\nLos p\\u00E1jaros comienzan a cantar por la ma\\u00F1ana.\\nLa gente despierta y comienza su d\\u00EDa.\\nLa ciudad se llena de actividad.\\nAl mediod\\u00EDa las calles est\\u00E1n llenas de gente.',\r\n      fr:\"Le soleil se l\\u00E8ve \\u00E0 l'est.\\nLes oiseaux commencent \\u00E0 chanter le matin.\\nLes gens se r\\u00E9veillent et commencent leur journ\\u00E9e.\",\r\n      de:'Die Sonne geht im Osten auf.\\nV\\u00F6gel beginnen morgens zu singen.\\nDie Menschen wachen auf und beginnen ihren Tag.'\r\n    }\r\n  };\r\n\r\n  var SORT_CURRENT_LANG = { code:'en', native:'English', en:'English' };\r\n\r\n  function applyLangToInput(ta, sampleText){\r\n    if(!ta||!sampleText)return;\r\n    var firstLine=(sampleText.split('\\n')[0]||'');\r\n    var script=window.pthILS.detectScript(firstLine),isRTL=window.pthILS.isRTL(firstLine);\r\n    window.pthILS.loadFont(script);\r\n    ta.style.fontFamily=window.pthILS.getFontStack(script);\r\n    ta.style.direction=isRTL?'rtl':'ltr';ta.style.textAlign=isRTL?'right':'left';\r\n  }\r\n\r\n  function buildLangPopup() {\r\n    if (document.getElementById('pth-sort-lang-overlay')) return;\r\n    var style = document.createElement('style');\r\n    style.textContent = [\r\n      '#pth-sort-lang-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;',\r\n        'background:rgba(15,23,42,0.55);z-index:9999998;',\r\n        'align-items:center;justify-content:center;padding:16px;}',\r\n      '#pth-sort-lang-overlay.pth-lo-open{display:flex;}',\r\n      '#pth-sort-lang-modal{background:#fff;border-radius:16px;width:100%;max-width:660px;',\r\n        'max-height:88vh;display:flex;flex-direction:column;',\r\n        'box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}',\r\n      '.pth-lm-head{padding:20px 20px 0;flex-shrink:0;}',\r\n      '.pth-lm-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-sub{font-size:0.78rem;color:#334155;margin:0 0 12px;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-close{position:absolute;top:14px;right:14px;background:#f1f5f9;border:none;width:32px;height:32px;border-radius:50%;font-size:0.9rem;cursor:pointer;color:#334155;display:flex;align-items:center;justify-content:center;font-family:inherit;font-weight:700;}',\r\n      '.pth-lm-close:hover{background:#e2e8f0;}',\r\n      '.pth-lm-search-wrap{padding:0 16px 10px;flex-shrink:0;}',\r\n      '.pth-lm-search{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-family:Inter,system-ui,sans-serif;font-size:0.85rem;color:#1e293b;outline:none;background:#f8fafc;}',\r\n      '.pth-lm-search::placeholder{color:#94a3b8;}',\r\n      '.pth-lm-search:focus{border-color:#2563eb;background-color:#fff;}',\r\n      '.pth-lm-grid-wrap{overflow-y:auto;flex:1;padding:0 8px 8px;}',\r\n      '.pth-lm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}',\r\n      '.pth-lm-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:8px;cursor:pointer;border:2px solid transparent;font-family:Inter,system-ui,sans-serif;background:transparent;text-align:left;width:100%;transition:background 0.1s;}',\r\n      '.pth-lm-item:hover{background:#f1f5f9;}',\r\n      '.pth-lm-item.pth-lm-sel{background:#eff6ff;border-color:#bfdbfe;}',\r\n      '.pth-lm-flag{font-size:0.62rem;font-weight:800;line-height:1;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;text-align:center;background:#eff6ff;color:#1d4ed8;border-radius:5px;letter-spacing:0.3px;}',\r\n      '.pth-lm-names{display:flex;flex-direction:column;min-width:0;}',\r\n      '.pth-lm-native{font-size:0.82rem;font-weight:700;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}',\r\n      '.pth-lm-en{font-size:0.7rem;color:#334155;font-weight:500;}',\r\n      '.pth-lm-footer{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;background:#f8fafc;}',\r\n      '.pth-lm-footer-cur{font-size:0.8rem;color:#334155;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-footer-cur strong{color:#1d4ed8;}',\r\n      '.pth-lm-no-res{text-align:center;padding:24px;color:#334155;font-size:0.85rem;font-family:Inter,system-ui,sans-serif;display:none;}',\r\n      '@media(max-width:520px){.pth-lm-grid{grid-template-columns:repeat(2,1fr);}#pth-sort-lang-modal{border-radius:12px;max-height:92vh;}}',\r\n      '@media(max-width:360px){.pth-lm-grid{grid-template-columns:1fr;}}'\r\n    ].join('');\r\n    document.head.appendChild(style);\r\n\r\n    var overlay = document.createElement('div');\r\n    overlay.id = 'pth-sort-lang-overlay';\r\n    overlay.setAttribute('role','dialog');\r\n    overlay.setAttribute('aria-modal','true');\r\n    overlay.setAttribute('aria-label','Choose item language');\r\n    overlay.innerHTML =\r\n      '<div id=\"pth-sort-lang-modal\">' +\r\n        '<div class=\"pth-lm-head\">' +\r\n          '<p class=\"pth-lm-title\">&#x1F30D; Choose Item Language<\/p>' +\r\n          '<p class=\"pth-lm-sub\">Select language for sample sentences\/steps<\/p>' +\r\n        '<\/div>' +\r\n        '<button class=\"pth-lm-close\" id=\"pth-sort-lm-close\" aria-label=\"Close\">&#x2715;<\/button>' +\r\n        '<div class=\"pth-lm-search-wrap\">' +\r\n          '<input type=\"text\" class=\"pth-lm-search\" id=\"pth-sort-lm-search\" placeholder=\"Search language...\" aria-label=\"Search language\" autocomplete=\"off\">' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-grid-wrap\">' +\r\n          '<div class=\"pth-lm-grid\" id=\"pth-sort-lm-grid\"><\/div>' +\r\n          '<div class=\"pth-lm-no-res\" id=\"pth-sort-lm-nores\">No languages found.<\/div>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-footer\">' +\r\n          '<span class=\"pth-lm-footer-cur\">Selected: <strong id=\"pth-sort-lm-cur\">English<\/strong><\/span>' +\r\n          '<span style=\"font-size:0.72rem;color:#475569;\">&#x1F512; Browser only<\/span>' +\r\n        '<\/div>' +\r\n      '<\/div>';\r\n    document.body.appendChild(overlay);\r\n\r\n    renderLangGrid('');\r\n    var searchEl = document.getElementById('pth-sort-lm-search');\r\n    if (searchEl) searchEl.addEventListener('input', function() { renderLangGrid(searchEl.value.toLowerCase().trim()); });\r\n    var closeBtn = document.getElementById('pth-sort-lm-close');\r\n    if (closeBtn) closeBtn.addEventListener('click', closeLangPopup);\r\n    overlay.addEventListener('click', function(e) { if (e.target === overlay) closeLangPopup(); });\r\n    document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeLangPopup(); });\r\n  }\r\n\r\n  function renderLangGrid(query) {\r\n    var grid = document.getElementById('pth-sort-lm-grid');\r\n    var nores = document.getElementById('pth-sort-lm-nores');\r\n    if (!grid) return;\r\n    grid.innerHTML = '';\r\n    var filtered = SORT_LANGS.filter(function(l) {\r\n      if (!query) return true;\r\n      return l.en.toLowerCase().indexOf(query) !== -1 || l.native.toLowerCase().indexOf(query) !== -1 || l.code.indexOf(query) !== -1;\r\n    });\r\n    if (!filtered.length) { if (nores) nores.style.display = 'block'; return; }\r\n    if (nores) nores.style.display = 'none';\r\n    filtered.forEach(function(l) {\r\n      var btn = document.createElement('button');\r\n      btn.className = 'pth-lm-item' + (l.code === SORT_CURRENT_LANG.code ? ' pth-lm-sel' : '');\r\n      btn.innerHTML =\r\n        '<span class=\"pth-lm-flag\">' + l.code.toUpperCase() + '<\/span>' +\r\n        '<span class=\"pth-lm-names\"><span class=\"pth-lm-native\">' + l.native + '<\/span><span class=\"pth-lm-en\">' + l.en + '<\/span><\/span>';\r\n      btn.addEventListener('click', function() { selectLang(l); });\r\n      grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function selectLang(l) {\r\n    SORT_CURRENT_LANG = l;\r\n    var cur = document.getElementById('pth-sort-lm-cur');\r\n    if (cur) cur.innerHTML = l.code.toUpperCase() + ' ' + l.native + ' (' + l.en + ')';\r\n    updatePickerBtn();\r\n    var samples = SORT_SAMPLES[SORT.mode] || SORT_SAMPLES.step;\r\n    if (samples[l.code]) {\r\n      var ta = document.getElementById('pth-sort-input');\r\n      if (ta) { ta.value = samples[l.code]; applyLangToInput(ta, samples[l.code]); }\r\n      window.pthILS.toast('Loaded: ' + l.native + ' (' + l.en + ')', 'success');\r\n    } else {\r\n      window.pthILS.toast(l.en + ' selected! Type your own items.', 'info');\r\n    }\r\n    var searchEl = document.getElementById('pth-sort-lm-search');\r\n    renderLangGrid(searchEl ? searchEl.value.toLowerCase().trim() : '');\r\n    closeLangPopup();\r\n  }\r\n\r\n  function openLangPopup() {\r\n    buildLangPopup();\r\n    var overlay = document.getElementById('pth-sort-lang-overlay');\r\n    if (overlay) {\r\n      overlay.classList.add('pth-lo-open');\r\n      var s = document.getElementById('pth-sort-lm-search');\r\n      if (s) { s.value=''; renderLangGrid(''); setTimeout(function(){ s.focus(); }, 100); }\r\n    }\r\n  }\r\n\r\n  function closeLangPopup() {\r\n    var overlay = document.getElementById('pth-sort-lang-overlay');\r\n    if (overlay) overlay.classList.remove('pth-lo-open');\r\n  }\r\n\r\n  function updatePickerBtn() {\r\n    var flag = document.getElementById('pth-sort-pick-flag');\r\n    var text = document.getElementById('pth-sort-pick-text');\r\n    if (flag) flag.innerHTML = SORT_CURRENT_LANG.code.toUpperCase();\r\n    if (text) text.innerHTML = SORT_CURRENT_LANG.native + ' \u2014 ' + SORT_CURRENT_LANG.en;\r\n  }\r\n\r\n  var SORT = { items: [], correct: [], mode: 'step', dragSrc: null, touchItem: null, touchY: 0 };\r\n\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-sort');\r\n    if (!panel || panel.getAttribute('data-sort-built')) return;\r\n    panel.setAttribute('data-sort-built', '1');\r\n\r\n    panel.innerHTML =\r\n      '<div class=\"pth-ils-layout\" id=\"pth-sort-layout\">' +\r\n      '<div class=\"pth-ils-main\">' +\r\n\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F501; Drag &amp; Sort Challenge<\/h3>' +\r\n          '<button class=\"pth-cw-lang-pick-btn\" id=\"pth-sort-lang-pick-btn\" aria-label=\"Choose item language\">' +\r\n            '<span class=\"pth-cw-lang-pick-flag\" id=\"pth-sort-pick-flag\">EN<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-text\" id=\"pth-sort-pick-text\">English \u2014 Item Language<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-arrow\">&#x25BC;<\/span>' +\r\n          '<\/button>' +\r\n\r\n          \/* Mode selector *\/\r\n          '<div class=\"pth-sort-mode-bar\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-sort-mode-sentence\">&#x1F4DD; Sentence Sorter<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-primary\"  id=\"pth-sort-mode-step\">&#x1F4CB; Step Sequencer<\/button>' +\r\n          '<\/div>' +\r\n\r\n          '<label class=\"pth-ils-label\" for=\"pth-sort-input\">Enter items in <strong>correct<\/strong> order &#x2014; one per line<\/label>' +\r\n          '<p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 6px;font-style:italic;\">&#x2139;&#xFE0F; The text below is just an example placeholder (not real data) &#x2014; type your own items, or click &#x1F4A1; <strong>Load Sample<\/strong> above to fill in working examples.<\/p>' +\r\n          '<textarea class=\"pth-ils-textarea\" id=\"pth-sort-input\" aria-label=\"Items in correct order\" style=\"min-height:140px;\"' +\r\n            ' placeholder=\"First, gather your ingredients.&#10;Preheat the oven to 180\u00b0C.&#10;Mix flour, sugar, and butter.&#10;Add eggs and stir until smooth.&#10;Pour into a baking tin.&#10;Bake for 25 minutes.&#10;Let cool before serving.\"><\/textarea>' +\r\n\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-sort-gen-btn\">&#x26A1; Create Activity<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-sort-check-btn\">&#x2705; Check Order<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-sort-shuffle-btn\">&#x1F500; Reshuffle<\/button>' +\r\n          '<\/div>' +\r\n          '<div id=\"pth-sort-status\" class=\"pth-ils-info\" style=\"display:none;\"><\/div>' +\r\n        '<\/div>' +\r\n\r\n        \/* Sortable list output *\/\r\n        '<div class=\"pth-ils-card\" id=\"pth-sort-output-card\" style=\"display:none;\">' +\r\n          '<h3 id=\"pth-sort-output-title\">&#x1F501; Sort the Steps<\/h3>' +\r\n          '<div id=\"pth-sort-list\"><\/div>' +\r\n        '<\/div>' +\r\n\r\n        \/* Export card *\/\r\n        '<div class=\"pth-ils-card\" id=\"pth-sort-export-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F4E4; Export<\/h3>' +\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-sort-html-btn\">&#x1F4C4; Download HTML<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-sort-copy-btn\">&#x1F4CB; Copy HTML Code<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-sort-print-btn\">&#x1F5A8; Print Activity<\/button>' +\r\n          '<\/div>' +\r\n          '<div class=\"pth-ils-code-box\" id=\"pth-sort-code-box\" style=\"display:none;\">' +\r\n            '<textarea id=\"pth-sort-code-ta\" readonly aria-label=\"HTML code\" style=\"min-height:100px;\"><\/textarea>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n      '<\/div>' + \/* end main *\/\r\n\r\n      '<div class=\"pth-ils-sidebar\">' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4A1; How to Use<\/h3>' +\r\n          '<p style=\"font-size:0.82rem;color:#334155;line-height:1.6;margin:0;\">' +\r\n            '1. Choose <strong>Sentence Sorter<\/strong> or <strong>Step Sequencer<\/strong>.<br>' +\r\n            '2. Enter items in the <em>correct<\/em> order.<br>' +\r\n            '3. Click <strong>&#x26A1; Create Activity<\/strong> &#x2014; items scramble.<br>' +\r\n            '4. <strong>Drag<\/strong> to reorder (touch works too!).<br>' +\r\n            '5. Click <strong>&#x2705; Check Order<\/strong> to score.' +\r\n          '<\/p>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4CA; Score<\/h3>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Correct<\/span><span class=\"pth-ils-stat-val\" id=\"pth-sort-s-correct\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Total<\/span><span class=\"pth-ils-stat-val\" id=\"pth-sort-s-total\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Score<\/span><span class=\"pth-ils-stat-val\" id=\"pth-sort-s-score\">&#8212;<\/span><\/div>' +\r\n        '<\/div>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n  }\r\n\r\n  function sortGenerate() {\r\n    var raw   = (document.getElementById('pth-sort-input')||{}).value || '';\r\n    var items = window.pthILS.parseLines(raw);\r\n    if (items.length < 2) { window.pthILS.toast('Enter at least 2 items.','error'); return; }\r\n    SORT.correct = items.slice();\r\n    SORT.items   = window.pthILS.shuffle(items.slice());\r\n    sortRender();\r\n    document.getElementById('pth-sort-output-card').style.display  = 'block';\r\n    document.getElementById('pth-sort-export-card').style.display  = 'block';\r\n    var title = document.getElementById('pth-sort-output-title');\r\n    if (title) title.innerHTML = SORT.mode === 'step' ? '&#x1F4CB; Sort the Steps' : '&#x1F4DD; Sort the Sentences';\r\n    var st = document.getElementById('pth-sort-status');\r\n    if (st) { st.style.display='block'; st.textContent = items.length + ' items scrambled. Drag to reorder!'; }\r\n    var st2 = document.getElementById('pth-sort-s-total'); if (st2) st2.textContent = items.length;\r\n    window.pthILS.toast('Activity created! Drag to reorder.','success');\r\n  }\r\n\r\n  function sortRender() {\r\n    var list = document.getElementById('pth-sort-list');\r\n    if (!list) return;\r\n    list.innerHTML = '';\r\n\r\n    SORT.items.forEach(function(item, idx) {\r\n      var div = document.createElement('div');\r\n      div.className = 'pth-sort-item';\r\n      div.setAttribute('draggable','true');\r\n      div.setAttribute('data-idx', idx);\r\n\r\n      var handle = document.createElement('span');\r\n      handle.className   = 'pth-sort-handle';\r\n      handle.textContent = '\\u283F'; \/* \u283f *\/\r\n      handle.setAttribute('aria-hidden','true');\r\n\r\n      var num = document.createElement('span');\r\n      num.className   = 'pth-sort-num';\r\n      num.textContent = idx + 1;\r\n\r\n      var text = document.createElement('span');\r\n      text.style.flex = '1';\r\n      text.textContent = item;\r\n\r\n      div.appendChild(handle);\r\n      div.appendChild(num);\r\n      div.appendChild(text);\r\n\r\n      \/* HTML5 drag events *\/\r\n      div.addEventListener('dragstart', function(e) {\r\n        SORT.dragSrc = div;\r\n        div.classList.add('sort-dragging');\r\n        e.dataTransfer.effectAllowed = 'move';\r\n        e.dataTransfer.setData('text\/plain', idx);\r\n      });\r\n      div.addEventListener('dragend', function() {\r\n        div.classList.remove('sort-dragging');\r\n        document.querySelectorAll('#pth-sort-list .sort-over').forEach(function(el){ el.classList.remove('sort-over'); });\r\n      });\r\n      div.addEventListener('dragover', function(e) {\r\n        e.preventDefault();\r\n        e.dataTransfer.dropEffect = 'move';\r\n        if (div !== SORT.dragSrc) div.classList.add('sort-over');\r\n      });\r\n      div.addEventListener('dragleave', function() { div.classList.remove('sort-over'); });\r\n      div.addEventListener('drop', function(e) {\r\n        e.preventDefault();\r\n        div.classList.remove('sort-over');\r\n        if (!SORT.dragSrc || SORT.dragSrc === div) return;\r\n        var allItems = Array.from(list.querySelectorAll('.pth-sort-item'));\r\n        var fromIdx  = allItems.indexOf(SORT.dragSrc);\r\n        var toIdx    = allItems.indexOf(div);\r\n        if (fromIdx < 0 || toIdx < 0) return;\r\n        var moved = SORT.items.splice(fromIdx, 1)[0];\r\n        SORT.items.splice(toIdx, 0, moved);\r\n        sortRender();\r\n      });\r\n\r\n      \/* Touch drag \u2014 pointer events approach *\/\r\n      div.addEventListener('pointerdown', function(e) {\r\n        if (e.button !== undefined && e.button !== 0) return;\r\n        SORT.touchItem = div;\r\n        SORT.touchY    = e.clientY;\r\n        div.setPointerCapture(e.pointerId);\r\n      });\r\n      div.addEventListener('pointermove', function(e) {\r\n        if (SORT.touchItem !== div) return;\r\n        var dy = e.clientY - SORT.touchY;\r\n        if (Math.abs(dy) < 5) return;\r\n        \/* Find target by position *\/\r\n        var allItems = Array.from(list.querySelectorAll('.pth-sort-item'));\r\n        var rect     = div.getBoundingClientRect();\r\n        var midY     = rect.top + rect.height \/ 2 + dy;\r\n        allItems.forEach(function(el) { el.classList.remove('sort-over'); });\r\n        var target = null;\r\n        allItems.forEach(function(el) {\r\n          var r = el.getBoundingClientRect();\r\n          if (midY >= r.top && midY <= r.bottom && el !== div) target = el;\r\n        });\r\n        if (target) target.classList.add('sort-over');\r\n      });\r\n      div.addEventListener('pointerup', function() {\r\n        if (SORT.touchItem !== div) return;\r\n        SORT.touchItem = null;\r\n        var allItems = Array.from(list.querySelectorAll('.pth-sort-item'));\r\n        var overEl   = list.querySelector('.sort-over');\r\n        if (overEl && overEl !== div) {\r\n          var fromIdx = allItems.indexOf(div);\r\n          var toIdx   = allItems.indexOf(overEl);\r\n          if (fromIdx >= 0 && toIdx >= 0) {\r\n            var moved = SORT.items.splice(fromIdx, 1)[0];\r\n            SORT.items.splice(toIdx, 0, moved);\r\n            sortRender();\r\n            return;\r\n          }\r\n        }\r\n        allItems.forEach(function(el){ el.classList.remove('sort-over'); });\r\n      });\r\n\r\n      list.appendChild(div);\r\n    });\r\n  }\r\n\r\n  function sortCheck() {\r\n    if (!SORT.items.length) { window.pthILS.toast('Create activity first!','error'); return; }\r\n    var allDivs = document.querySelectorAll('#pth-sort-list .pth-sort-item');\r\n    var correct = 0;\r\n    allDivs.forEach(function(div, i) {\r\n      div.classList.remove('sort-correct','sort-wrong');\r\n      if (SORT.items[i] === SORT.correct[i]) { div.classList.add('sort-correct'); correct++; }\r\n      else div.classList.add('sort-wrong');\r\n    });\r\n    var pct = Math.round(correct \/ SORT.correct.length * 100);\r\n    var sc  = document.getElementById('pth-sort-s-correct'); if (sc) sc.textContent = correct;\r\n    var ss  = document.getElementById('pth-sort-s-score');   if (ss) ss.textContent = pct + '%';\r\n    var st  = document.getElementById('pth-sort-status');\r\n    if (st) { st.style.display='block'; st.textContent = correct + ' \/ ' + SORT.correct.length + ' in correct position (' + pct + '%)'; }\r\n    if (pct === 100) window.pthILS.toast('&#x1F389; Perfect order!','success');\r\n    else window.pthILS.toast(correct + '\/' + SORT.correct.length + ' correct.', pct >= 50 ? 'info' : 'warn');\r\n  }\r\n\r\n  function sortReshuffle() {\r\n    if (!SORT.correct.length) { window.pthILS.toast('Create activity first!','error'); return; }\r\n    SORT.items = window.pthILS.shuffle(SORT.correct.slice());\r\n    sortRender();\r\n    document.querySelectorAll('#pth-sort-list .pth-sort-item').forEach(function(el){\r\n      el.classList.remove('sort-correct','sort-wrong');\r\n    });\r\n    var sc = document.getElementById('pth-sort-s-correct'); if (sc) sc.textContent = '&#8212;';\r\n    var ss = document.getElementById('pth-sort-s-score');   if (ss) ss.textContent = '&#8212;';\r\n    window.pthILS.toast('Reshuffled!','info');\r\n  }\r\n\r\n  function sortBuildHTML() {\r\n    if (!SORT.correct.length) return '';\r\n    var shuffled = window.pthILS.shuffle(SORT.correct.slice());\r\n    var correctJSON = JSON.stringify(SORT.correct);\r\n    var html =\r\n      '<style>' +\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;color-adjust:exact;}' +\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;background:#eef2f9;color:#1e293b;min-height:100vh;display:flex;justify-content:center;padding:32px 16px;}' +\r\n      '.ds-page{width:100%;max-width:640px;background:#fff;border-radius:18px;box-shadow:0 10px 30px -10px rgba(15,23,42,0.18);padding:30px 34px 34px;}' +\r\n      '.ds-head{text-align:center;margin:0 0 14px;}' +\r\n      'h1{color:#1d4ed8;font-size:1.5rem;font-weight:800;margin:0 0 6px;}' +\r\n      '.ds-sub{color:#334155;font-size:0.85rem;margin:0;}' +\r\n      '.ds-meta-row{display:flex;align-items:center;justify-content:center;gap:14px;margin:14px 0 18px;flex-wrap:wrap;}' +\r\n      '.score{font-size:0.88rem;font-weight:700;color:#1d4ed8;background:#eff6ff;padding:5px 12px;border-radius:7px;}' +\r\n      '.ds-timer{font-size:0.88rem;font-weight:700;color:#334155;background:#f1f5f9;padding:5px 12px;border-radius:7px;}' +\r\n      '.si{background:#fff;border:2px solid #e2e8f0;border-radius:8px;padding:11px 14px;margin-bottom:8px;cursor:grab;display:flex;align-items:center;gap:10px;font-size:0.9rem;font-weight:600;color:#1e293b;touch-action:none;}' +\r\n      '.si.ov{border-color:#2563eb;box-shadow:0 0 0 3px #bfdbfe;}' +\r\n      '.si.ok{border-color:#059669;background:#f0fdf4;color:#047857;}' +\r\n      '.si.no{border-color:#dc2626;background:#fef2f2;color:#991b1b;}' +\r\n      '.sn{background:#2563eb;color:#fff;width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:0.7rem;font-weight:800;flex-shrink:0;}' +\r\n      '.ds-footer-btns{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:22px 0 4px;padding-top:18px;border-top:2px solid #e2e8f0;}' +\r\n      '.btn{padding:9px 18px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.06);}' +\r\n      '.btn-a{background:#2563eb;color:#fff;}.btn-b{background:#fff;border:2px solid #e2e8f0;color:#334155;}' +\r\n      '.btn-c{background:#7c3aed;color:#fff;}' +\r\n      '.btn.active{outline:3px solid #fde68a;}' +\r\n      '@media(max-width:480px){.ds-page{padding:20px 16px 26px;border-radius:12px;}}' +\r\n      '@media print{body{margin:0;background:#fff;padding:0;display:block;}.ds-page{box-shadow:none;border-radius:0;max-width:100%;padding:10px;}.ds-footer-btns,.ds-timer{display:none!important;}#list{break-inside:avoid;}}' +\r\n      '<\/style>' +\r\n      '<div class=\"ds-page\">' +\r\n      '<div class=\"ds-head\">' +\r\n      '<h2>&#x1F501; Drag &amp; Sort Challenge<\/h2>' +\r\n      '<p class=\"ds-sub\">Drag items into the correct order.<\/p>' +\r\n      '<\/div>' +\r\n      '<div class=\"ds-meta-row\">' +\r\n      '<span class=\"score\" id=\"sc\"><\/span>' +\r\n      '<span class=\"ds-timer\" id=\"ds-timer\">&#x23F1; 00:00<\/span>' +\r\n      '<\/div>' +\r\n      '<div id=\"list\"><\/div>' +\r\n      '<div class=\"ds-footer-btns\">' +\r\n      '<button class=\"btn btn-a\" id=\"btn-check\">&#x2705; Check Order<\/button>' +\r\n      '<button class=\"btn btn-b\" id=\"btn-shuffle\">&#x1F500; Reshuffle<\/button>' +\r\n      '<button class=\"btn btn-b\" id=\"btn-answerkey\">&#x1F5DD; Answer Key Mode<\/button>' +\r\n      '<button class=\"btn btn-c\" id=\"btn-print\">&#x1F5A8; Print Activity<\/button>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n\r\n    var sc = [\r\n      '(function(){',\r\n        'var correct=' + correctJSON + ';',\r\n        'var items=' + JSON.stringify(shuffled) + ';',\r\n        'var drag=null,touItem=null,akOn=false;',\r\n        'var tStart=Date.now();var tEl=document.getElementById(\"ds-timer\");',\r\n        'if(tEl){setInterval(function(){var s=Math.floor((Date.now()-tStart)\/1000),m=Math.floor(s\/60),ss=s%60;tEl.textContent=\"\\\\u23F1 \"+(m<10?\"0\":\"\")+m+\":\"+(ss<10?\"0\":\"\")+ss;},1000);}',\r\n        'function render(){',\r\n          'var list=document.getElementById(\"list\");list.innerHTML=\"\";',\r\n          'items.forEach(function(item,i){',\r\n            'var d=document.createElement(\"div\");d.className=\"si\";d.setAttribute(\"draggable\",\"true\");d.setAttribute(\"data-i\",i);',\r\n            'var n=document.createElement(\"span\");n.className=\"sn\";n.textContent=i+1;',\r\n            'var t=document.createElement(\"span\");t.style.flex=\"1\";t.textContent=item;',\r\n            'd.appendChild(n);d.appendChild(t);',\r\n            'd.addEventListener(\"dragstart\",function(){drag=d;d.style.opacity=\"0.5\";});',\r\n            'd.addEventListener(\"dragend\",function(){d.style.opacity=\"1\";list.querySelectorAll(\".ov\").forEach(function(x){x.classList.remove(\"ov\");});});',\r\n            'd.addEventListener(\"dragover\",function(e){e.preventDefault();if(d!==drag)d.classList.add(\"ov\");});',\r\n            'd.addEventListener(\"dragleave\",function(){d.classList.remove(\"ov\");});',\r\n            'd.addEventListener(\"drop\",function(e){e.preventDefault();d.classList.remove(\"ov\");if(!drag||drag===d)return;',\r\n              'var all=Array.from(list.querySelectorAll(\".si\"));',\r\n              'var fi=all.indexOf(drag),ti=all.indexOf(d);',\r\n              'if(fi<0||ti<0)return;var m=items.splice(fi,1)[0];items.splice(ti,0,m);render();});',\r\n            'd.addEventListener(\"pointerdown\",function(e){touItem=d;d.setPointerCapture(e.pointerId);});',\r\n            'd.addEventListener(\"pointermove\",function(e){if(touItem!==d)return;var all=Array.from(list.querySelectorAll(\".si\"));all.forEach(function(x){x.classList.remove(\"ov\");});var r=d.getBoundingClientRect(),mid=r.top+r.height\/2+(e.clientY-r.top-r.height\/2);all.forEach(function(x){var xr=x.getBoundingClientRect();if(e.clientY>=xr.top&&e.clientY<=xr.bottom&&x!==d)x.classList.add(\"ov\");});});',\r\n            'd.addEventListener(\"pointerup\",function(){if(touItem!==d)return;touItem=null;var all=Array.from(list.querySelectorAll(\".si\"));var ov=list.querySelector(\".ov\");if(ov&&ov!==d){var fi=all.indexOf(d),ti=all.indexOf(ov);if(fi>=0&&ti>=0){var m=items.splice(fi,1)[0];items.splice(ti,0,m);render();return;}}all.forEach(function(x){x.classList.remove(\"ov\");});});',\r\n            'list.appendChild(d);',\r\n          '});',\r\n        '}',\r\n        'function chk(){var all=document.querySelectorAll(\".si\"),c=0;all.forEach(function(d,i){d.classList.remove(\"ok\",\"no\");if(items[i]===correct[i]){d.classList.add(\"ok\");c++;}else d.classList.add(\"no\");});var sc=document.getElementById(\"sc\");if(sc)sc.textContent=c+\"\/\"+correct.length+\" (\"+Math.round(c\/correct.length*100)+\"%)\";}',\r\n        'function shuf(){items=items.slice().sort(function(){return Math.random()-0.5;});render();var sc=document.getElementById(\"sc\");if(sc)sc.textContent=\"\";}',\r\n        'document.getElementById(\"btn-check\").addEventListener(\"click\",chk);',\r\n        'document.getElementById(\"btn-shuffle\").addEventListener(\"click\",shuf);',\r\n        'document.getElementById(\"btn-answerkey\").addEventListener(\"click\",function(e){akOn=!akOn;e.target.classList.toggle(\"active\",akOn);if(akOn){items=correct.slice();render();var all=document.querySelectorAll(\".si\");all.forEach(function(d){d.classList.add(\"ok\");});e.target.textContent=\"Hide Answer Key\";}else{shuf();e.target.textContent=\"Answer Key Mode\";}});',\r\n        'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n        'render();',\r\n      '})();'\r\n    ].join('');\r\n\r\n    var so='<'+'script'+'>';\r\n    var sc2='<'+'\/'+'script'+'>';\r\n    var docOpen='<'+'!DOCTYPE html>'+'<'+'html lang=\"en\">'+'<'+'head>'+\r\n      '<'+'meta charset=\"UTF-8\">'+\r\n      '<'+'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">'+\r\n      '<'+'title>Drag and Sort<'+'\/title>'+\r\n      '<'+'\/head>'+'<'+'body>';\r\n    var docClose='<'+'\/'+'body>'+'<'+'\/'+'html>';\r\n    return docOpen + html + so + sc + sc2 + docClose;\r\n  }\r\n\r\n  function wireEvents() {\r\n    var b = function(id,fn){ var el=document.getElementById(id); if(el)el.addEventListener('click',fn); };\r\n\r\n    b('pth-sort-gen-btn',     sortGenerate);\r\n    b('pth-sort-check-btn',   sortCheck);\r\n    b('pth-sort-shuffle-btn', sortReshuffle);\r\n    b('pth-sort-lang-pick-btn', openLangPopup);\r\n\r\n    b('pth-sort-mode-sentence', function(){\r\n      SORT.mode = 'sentence';\r\n      document.getElementById('pth-sort-mode-sentence').className = 'pth-ils-btn pth-ils-btn-primary';\r\n      document.getElementById('pth-sort-mode-step').className     = 'pth-ils-btn pth-ils-btn-outline';\r\n      var ta = document.getElementById('pth-sort-input');\r\n      if (ta) ta.placeholder = 'The sun rises in the east.\\nBirds begin to sing in the morning.\\nPeople wake up and start their day.\\nThe city becomes busy with activity.\\nBy noon the streets are full of people.';\r\n    });\r\n    b('pth-sort-mode-step', function(){\r\n      SORT.mode = 'step';\r\n      document.getElementById('pth-sort-mode-step').className     = 'pth-ils-btn pth-ils-btn-primary';\r\n      document.getElementById('pth-sort-mode-sentence').className = 'pth-ils-btn pth-ils-btn-outline';\r\n      var ta = document.getElementById('pth-sort-input');\r\n      if (ta) ta.placeholder = 'First, gather your ingredients.\\nPreheat the oven to 180\u00b0C.\\nMix flour, sugar, and butter.\\nAdd eggs and stir until smooth.\\nPour into a baking tin.\\nBake for 25 minutes.\\nLet cool before serving.';\r\n    });\r\n\r\n    b('pth-sort-html-btn', function(){\r\n      var c = sortBuildHTML(); if(!c){window.pthILS.toast('Create activity first!','error');return;}\r\n      try {\r\n        var blob=new Blob([c],{type:'text\/html'});\r\n        var url=URL.createObjectURL(blob);\r\n        var a=document.createElement('a');\r\n        a.href=url;a.download='drag-sort-activity.html';\r\n        document.body.appendChild(a);a.click();document.body.removeChild(a);\r\n        setTimeout(function(){URL.revokeObjectURL(url);},2000);\r\n        window.pthILS.toast('HTML file downloaded!','success');\r\n      } catch(err) { window.pthILS.toast('Download failed: '+err.message,'error'); }\r\n    });\r\n    b('pth-sort-print-btn', function(){\r\n      var c = sortBuildHTML(); if(!c){window.pthILS.toast('Create activity first!','error');return;}\r\n      var w = window.open('','_blank');\r\n      if (!w) { window.pthILS.toast('Popup blocked! Allow popups for this site to print.','error'); return; }\r\n      w.document.open();w.document.write(c);w.document.close();\r\n      var printed=false;\r\n      function doPrint(){ if(printed)return; printed=true; w.focus(); w.print(); }\r\n      w.addEventListener('load', function(){ setTimeout(doPrint,150); });\r\n      setTimeout(doPrint,1200);\r\n    });\r\n    b('pth-sort-copy-btn', function(){\r\n      var c = sortBuildHTML(); if(!c){window.pthILS.toast('Create activity first!','error');return;}\r\n      window.pthILS.showCopyHTML(c,'pth-sort-code-box');\r\n    });\r\n\r\n    document.addEventListener('pthILSClear', function(e) {\r\n      if (e.detail.tab !== 'sort') return;\r\n      var ta = document.getElementById('pth-sort-input'); if (ta) ta.value='';\r\n      var oc = document.getElementById('pth-sort-output-card');  if(oc)oc.style.display='none';\r\n      var ec = document.getElementById('pth-sort-export-card');  if(ec)ec.style.display='none';\r\n      var st = document.getElementById('pth-sort-status');       if(st)st.style.display='none';\r\n      SORT.items=[]; SORT.correct=[];\r\n      ['pth-sort-s-correct','pth-sort-s-total','pth-sort-s-score'].forEach(function(id){\r\n        var el=document.getElementById(id); if(el)el.textContent='&#8212;';\r\n      });\r\n    });\r\n\r\n    document.addEventListener('pthILSSample', function(e) {\r\n      if (e.detail.tab !== 'sort') return;\r\n      var ta = document.getElementById('pth-sort-input');\r\n      if (ta) {\r\n        ta.value = SORT.mode === 'step'\r\n          ? 'Open your code editor.\\nCreate a new HTML file.\\nAdd the DOCTYPE declaration.\\nWrite the HTML structure.\\nAdd CSS styles.\\nWrite JavaScript logic.\\nTest in the browser.\\nFix any bugs found.'\r\n          : 'The alarm clock rings early in the morning.\\nShe gets out of bed and brushes her teeth.\\nShe makes a cup of tea in the kitchen.\\nShe reads the news while having breakfast.\\nShe leaves home and walks to the bus stop.';\r\n        window.pthILS.toast('Sample loaded! Click Create Activity.','success');\r\n      }\r\n    });\r\n  }\r\n\r\n  function init() {\r\n    buildTabHTML();\r\n    setTimeout(function(){ wireEvents(); }, 100);\r\n  }\r\n\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v2.0 \u2014 Match Pairs Tab -->\r\n\r\n<style>\r\n.pth-match-grid {\r\n  display: grid;\r\n  grid-template-columns: 1fr 1fr;\r\n  gap: 8px;\r\n  margin-top: 8px;\r\n}\r\n.pth-match-col-head {\r\n  font-size: 0.75rem;\r\n  font-weight: 800;\r\n  color: #334155;\r\n  text-transform: uppercase;\r\n  letter-spacing: 0.5px;\r\n  padding: 4px 8px;\r\n  text-align: center;\r\n}\r\n.pth-match-card {\r\n  background: #fff;\r\n  border: 2px solid #e2e8f0;\r\n  border-radius: 8px;\r\n  padding: 12px;\r\n  text-align: center;\r\n  cursor: pointer;\r\n  font-size: 0.88rem;\r\n  font-weight: 700;\r\n  color: #1e293b;\r\n  min-height: 56px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  word-break: break-word;\r\n  transition: border-color 0.15s, background 0.15s;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  line-height: 1.4;\r\n}\r\n.pth-match-card:hover       { border-color: #2563eb; background: #eff6ff; }\r\n.pth-match-card.mc-selected { border-color: #2563eb; background: #dbeafe; color: #1d4ed8; }\r\n.pth-match-card.mc-correct  { border-color: #059669; background: #f0fdf4; color: #047857; cursor: default; }\r\n.pth-match-card.mc-wrong    { border-color: #dc2626; background: #fef2f2; }\r\n\r\n.pth-match-stats {\r\n  display: flex;\r\n  gap: 10px;\r\n  flex-wrap: wrap;\r\n  margin-bottom: 12px;\r\n}\r\n.pth-match-stat {\r\n  background: #eff6ff;\r\n  border: 1px solid #bfdbfe;\r\n  border-radius: 8px;\r\n  padding: 8px 14px;\r\n  font-size: 0.82rem;\r\n  font-weight: 700;\r\n  color: #1d4ed8;\r\n  text-align: center;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n\/* Language picker button *\/\r\n.pth-cw-lang-pick-btn {\r\n  display: inline-flex; align-items: center; gap: 8px;\r\n  padding: 9px 16px; background: #fff; border: 2px solid #e2e8f0;\r\n  border-radius: 8px; cursor: pointer; font-family: 'Inter', system-ui, sans-serif;\r\n  font-size: 0.85rem; font-weight: 700; color: #334155;\r\n  transition: all 0.15s; width: 100%; margin-bottom: 10px;\r\n}\r\n.pth-cw-lang-pick-btn:hover { border-color: #2563eb; color: #1d4ed8; background: #eff6ff; }\r\n.pth-cw-lang-pick-flag { font-size: 0.68rem; font-weight: 800; background: #2563eb; color: #fff; border-radius: 5px; padding: 3px 6px; min-width: 26px; text-align: center; letter-spacing: 0.3px; }\r\n.pth-cw-lang-pick-text { flex: 1; text-align: left; }\r\n.pth-cw-lang-pick-arrow { color: #94a3b8; font-size: 0.8rem; }\r\n<\/style>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function () {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function () { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  \/* ============================================================\r\n     MULTILINGUAL METHODS \u2014 self-contained\r\n     ============================================================ *\/\r\n  if (!window.pthILS) window.pthILS = {};\r\n  if (!window.pthILS.detectScript) {\r\n    window.pthILS.detectScript = function(text) {\r\n      if (!text || !text.trim()) return 'latin';\r\n      if (\/[\\u0D80-\\u0DFF]\/.test(text)) return 'sinhala';\r\n      if (\/[\\u0B80-\\u0BFF]\/.test(text)) return 'tamil';\r\n      if (\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text)) return 'rtl';\r\n      if (\/[\\u3000-\\u9FFF\\uAC00-\\uD7AF]\/.test(text)) return 'cjk';\r\n      if (\/[\\u0900-\\u097F]\/.test(text)) return 'devanagari';\r\n      if (\/[\\u0E00-\\u0E7F]\/.test(text)) return 'thai';\r\n      if (\/[\\u0980-\\u09FF]\/.test(text)) return 'bengali';\r\n      if (\/[\\u1000-\\u109F]\/.test(text)) return 'myanmar';\r\n      if (\/[\\u1780-\\u17FF]\/.test(text)) return 'khmer';\r\n      if (\/[\\u0370-\\u03FF]\/.test(text)) return 'greek';\r\n      if (\/[\\u0400-\\u04FF]\/.test(text)) return 'cyrillic';\r\n      return 'latin';\r\n    };\r\n  }\r\n  if (!window.pthILS.isRTL) {\r\n    window.pthILS.isRTL = function(text) {\r\n      return \/[\\u0591-\\u07FF\\u200F\\u202B\\u202E\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text);\r\n    };\r\n  }\r\n  if (!window.pthILS.getFontStack) {\r\n    window.pthILS.getFontStack = function(script) {\r\n      var f = {\r\n        sinhala:\"'Noto Sans Sinhala','Iskoola Pota',system-ui,sans-serif\",\r\n        tamil:\"'Noto Sans Tamil','Latha',system-ui,sans-serif\",\r\n        rtl:\"'Noto Sans Arabic','Noto Sans Hebrew',system-ui,sans-serif\",\r\n        cjk:\"'Noto Sans CJK SC','Microsoft YaHei',system-ui,sans-serif\",\r\n        devanagari:\"'Noto Sans Devanagari','Mangal',system-ui,sans-serif\",\r\n        thai:\"'Noto Sans Thai','Tahoma',system-ui,sans-serif\",\r\n        bengali:\"'Noto Sans Bengali','Vrinda',system-ui,sans-serif\",\r\n        myanmar:\"'Noto Sans Myanmar',system-ui,sans-serif\",\r\n        khmer:\"'Noto Sans Khmer',system-ui,sans-serif\",\r\n        latin:\"'Inter',system-ui,sans-serif\"\r\n      };\r\n      return f[script] || f.latin;\r\n    };\r\n  }\r\n  if (!window.pthILS.loadedFonts) window.pthILS.loadedFonts = {};\r\n  if (!window.pthILS.loadFont) {\r\n    window.pthILS.loadFont = function(script) {\r\n      if (window.pthILS.loadedFonts[script]) return;\r\n      window.pthILS.loadedFonts[script] = true;\r\n      var m = {\r\n        sinhala:'Noto+Sans+Sinhala:wght@400;700',tamil:'Noto+Sans+Tamil:wght@400;700',\r\n        rtl:'Noto+Sans+Arabic:wght@400;700',devanagari:'Noto+Sans+Devanagari:wght@400;700',\r\n        thai:'Noto+Sans+Thai:wght@400;700',bengali:'Noto+Sans+Bengali:wght@400;700',\r\n        myanmar:'Noto+Sans+Myanmar:wght@400;700',cjk:'Noto+Sans+SC:wght@400;700'\r\n      };\r\n      if (!m[script]) return;\r\n      var l=document.createElement('link');l.rel='stylesheet';\r\n      l.href='https:\/\/fonts.googleapis.com\/css2?family='+m[script]+'&display=swap';\r\n      document.head.appendChild(l);\r\n    };\r\n  }\r\n\r\n  var MATCH_LANGS = [\r\n    {code:'en', native:'English', en:'English'},\r\n    {code:'si', native:'\\u0DC3\\u0DD2\\u0982\\u0DC4\\u0DBD', en:'Sinhala'},\r\n    {code:'ta', native:'\\u0BA4\\u0BAE\\u0BBF\\u0BB4\\u0BCD', en:'Tamil'},\r\n    {code:'zh', native:'\\u4E2D\\u6587', en:'Chinese'},\r\n    {code:'ar', native:'\\u0627\\u0644\\u0639\\u0631\\u0628\\u064A\\u0629', en:'Arabic'},\r\n    {code:'hi', native:'\\u0939\\u093F\\u0928\\u094D\\u0926\\u0940', en:'Hindi'},\r\n    {code:'es', native:'Espa\\u00F1ol', en:'Spanish'},\r\n    {code:'fr', native:'Fran\\u00E7ais', en:'French'},\r\n    {code:'pt', native:'Portugu\\u00EAs', en:'Portuguese'},\r\n    {code:'de', native:'Deutsch', en:'German'},\r\n    {code:'ja', native:'\\u65E5\\u672C\\u8A9E', en:'Japanese'},\r\n    {code:'ko', native:'\\uD55C\\uAD6D\\uC5B4', en:'Korean'},\r\n    {code:'ru', native:'\\u0420\\u0443\\u0441\\u0441\\u043A\\u0438\\u0439', en:'Russian'},\r\n    {code:'it', native:'Italiano', en:'Italian'},\r\n    {code:'tr', native:\"T\\u00FCrk\\u00E7e\", en:'Turkish'},\r\n    {code:'id', native:'Bahasa Indonesia', en:'Indonesian'},\r\n    {code:'ms', native:'Bahasa Melayu', en:'Malay'},\r\n    {code:'bn', native:'\\u09AC\\u09BE\\u0982\\u09B2\\u09BE', en:'Bengali'},\r\n    {code:'vi', native:\"Ti\\u1EBFng Vi\\u1EC7t\", en:'Vietnamese'},\r\n    {code:'th', native:'\\u0E44\\u0E17\\u0E22', en:'Thai'},\r\n    {code:'sw', native:'Kiswahili', en:'Swahili'},\r\n    {code:'nl', native:'Nederlands', en:'Dutch'},\r\n    {code:'pl', native:'Polski', en:'Polish'},\r\n    {code:'uk', native:'\\u0423\\u043A\\u0440\\u0430\\u0457\\u043D\\u0441\\u044C\\u043A\\u0430', en:'Ukrainian'},\r\n    {code:'el', native:'\\u0395\\u03BB\\u03BB\\u03B7\\u03BD\\u03B9\\u03BA\\u03AC', en:'Greek'},\r\n    {code:'he', native:'\\u05E2\\u05D1\\u05E8\\u05D9\\u05EA', en:'Hebrew'},\r\n    {code:'fa', native:'\\u0641\\u0627\\u0631\\u0633\\u06CC', en:'Persian'},\r\n    {code:'ur', native:'\\u0627\\u0631\\u062F\\u0648', en:'Urdu'},\r\n    {code:'ne', native:'\\u0928\\u0947\\u092A\\u093E\\u0932\\u0940', en:'Nepali'},\r\n    {code:'sv', native:'Svenska', en:'Swedish'},\r\n    {code:'ro', native:\"Rom\\u00E2n\\u0103\", en:'Romanian'},\r\n    {code:'fil', native:'Filipino', en:'Filipino'},\r\n    {code:'af', native:'Afrikaans', en:'Afrikaans'}\r\n  ];\r\n\r\n  var MATCH_SAMPLES = {\r\n    en:'HTML:HyperText Markup Language\\nCSS:Cascading Style Sheets\\nJS:JavaScript scripting language\\nAPI:Application Programming Interface\\nURL:Uniform Resource Locator\\nDNS:Domain Name System\\nHTTP:Web transfer protocol\\nSQL:Database query language',\r\n    si:'\\u0DC3\\u0DD6\\u0DBB\\u0DCA\\u0DBA\\u0DBA\\u0DCF:\\u0DB4\\u0DD9\\u0DC0\\u0DBA\\u0DDA \\u0D9C\\u0DD2\\u0DBD\\u0DD2\\u0DC4\\u0DD4\\u0DC0\\u0DD9\\u0DBA\\u0DD2\\n\\u0D85\\u0DBD\\u0DD2\\u0DC0\\u0DDA\\u0DBA \\u0D9C\\D9A\\u0DDA\\u0DBA\\u0DD2:\\u0DAF\\u0DC0\\u0DC3\\u0DC4 \\u0DA0\\u0DB1\\u0DCA\\u0DA0\\u0DBD\\u0DD9\\u0DBA\\u0DD2',\r\n    zh:'\\u8BCD\\u6C47\\u4E00:\\u91CA\\u4E49\\u4E00\\n\\u8BCD\\u6C47\\u4E8C:\\u91CA\\u4E49\\u4E8C',\r\n    ar:'\\u0643\\u0644\\u0645\\u0629:\\u062A\\u0639\\u0631\\u064A\\u0641',\r\n    es:'HTML:Lenguaje de marcado\\nCSS:Hojas de estilo\\nJS:Lenguaje de programaci\\u00F3n\\nAPI:Interfaz de programaci\\u00F3n',\r\n    fr:'HTML:Langage de balisage\\nCSS:Feuilles de style\\nJS:Langage de script\\nAPI:Interface de programmation',\r\n    de:'HTML:Auszeichnungssprache\\nCSS:Stilvorlagen\\nJS:Skriptsprache\\nAPI:Programmierschnittstelle',\r\n    pt:'HTML:Linguagem de marca\\u00E7\\u00E3o\\nCSS:Folhas de estilo\\nJS:Linguagem de script',\r\n    ja:'HTML:\\u30DE\\u30FC\\u30AF\\u30A2\\u30C3\\u30D7\\u8A00\\u8A9E\\nCSS:\\u30B9\\u30BF\\u30A4\\u30EB\\u30B7\\u30FC\\u30C8',\r\n    ko:'HTML:\\uB9C8\\uD06C\\uC5C5 \\uC5B8\\uC5B4\\nCSS:\\uC2A4\\uD0C0\\uC77C \\uC2DC\\uD2B8',\r\n    ru:'HTML:\\u042F\\u0437\\u044B\\u043A \\u0440\\u0430\\u0437\\u043C\\u0435\\u0442\\u043A\\u0438\\nCSS:\\u0422\\u0430\\u0431\\u043B\\u0438\\u0446\\u044B \\u0441\\u0442\\u0438\\u043B\\u0435\\u0439',\r\n    hi:'HTML:\\u092E\\u093E\\u0930\\u094D\\u0915\\u0905\\u092A \\u092D\\u093E\\u0937\\u093E\\nCSS:\\u0938\\u094D\\u091F\\u093E\\u0907\\u0932 \\u0936\\u0940\\u091F'\r\n  };\r\n\r\n  var MATCH_CURRENT_LANG = { code:'en', native:'English', en:'English' };\r\n\r\n  function applyLangToInput(ta, sampleText){\r\n    if(!ta||!sampleText)return;\r\n    var firstLine=(sampleText.split('\\n')[0]||'');\r\n    var script=window.pthILS.detectScript(firstLine),isRTL=window.pthILS.isRTL(firstLine);\r\n    window.pthILS.loadFont(script);\r\n    ta.style.fontFamily=window.pthILS.getFontStack(script);\r\n    ta.style.direction=isRTL?'rtl':'ltr';ta.style.textAlign=isRTL?'right':'left';\r\n  }\r\n\r\n  function buildLangPopup() {\r\n    if (document.getElementById('pth-match-lang-overlay')) return;\r\n    var style = document.createElement('style');\r\n    style.textContent = [\r\n      '#pth-match-lang-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(15,23,42,0.55);z-index:9999998;align-items:center;justify-content:center;padding:16px;}',\r\n      '#pth-match-lang-overlay.pth-lo-open{display:flex;}',\r\n      '#pth-match-lang-modal{background:#fff;border-radius:16px;width:100%;max-width:660px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}',\r\n      '.pth-lm-head{padding:20px 20px 0;flex-shrink:0;}',\r\n      '.pth-lm-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-sub{font-size:0.78rem;color:#334155;margin:0 0 12px;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-close{position:absolute;top:14px;right:14px;background:#f1f5f9;border:none;width:32px;height:32px;border-radius:50%;font-size:0.9rem;cursor:pointer;color:#334155;display:flex;align-items:center;justify-content:center;font-family:inherit;font-weight:700;}',\r\n      '.pth-lm-close:hover{background:#e2e8f0;}',\r\n      '.pth-lm-search-wrap{padding:0 16px 10px;flex-shrink:0;}',\r\n      '.pth-lm-search{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-family:Inter,system-ui,sans-serif;font-size:0.85rem;color:#1e293b;outline:none;background:#f8fafc;}',\r\n      '.pth-lm-search::placeholder{color:#94a3b8;}',\r\n      '.pth-lm-search:focus{border-color:#2563eb;background-color:#fff;}',\r\n      '.pth-lm-grid-wrap{overflow-y:auto;flex:1;padding:0 8px 8px;}',\r\n      '.pth-lm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}',\r\n      '.pth-lm-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:8px;cursor:pointer;border:2px solid transparent;font-family:Inter,system-ui,sans-serif;background:transparent;text-align:left;width:100%;transition:background 0.1s;}',\r\n      '.pth-lm-item:hover{background:#f1f5f9;}',\r\n      '.pth-lm-item.pth-lm-sel{background:#eff6ff;border-color:#bfdbfe;}',\r\n      '.pth-lm-flag{font-size:0.62rem;font-weight:800;line-height:1;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;text-align:center;background:#eff6ff;color:#1d4ed8;border-radius:5px;letter-spacing:0.3px;}',\r\n      '.pth-lm-names{display:flex;flex-direction:column;min-width:0;}',\r\n      '.pth-lm-native{font-size:0.82rem;font-weight:700;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}',\r\n      '.pth-lm-en{font-size:0.7rem;color:#334155;font-weight:500;}',\r\n      '.pth-lm-footer{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;background:#f8fafc;}',\r\n      '.pth-lm-footer-cur{font-size:0.8rem;color:#334155;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-footer-cur strong{color:#1d4ed8;}',\r\n      '.pth-lm-no-res{text-align:center;padding:24px;color:#334155;font-size:0.85rem;font-family:Inter,system-ui,sans-serif;display:none;}',\r\n      '@media(max-width:520px){.pth-lm-grid{grid-template-columns:repeat(2,1fr);}#pth-match-lang-modal{border-radius:12px;max-height:92vh;}}',\r\n      '@media(max-width:360px){.pth-lm-grid{grid-template-columns:1fr;}}'\r\n    ].join('');\r\n    document.head.appendChild(style);\r\n\r\n    var overlay = document.createElement('div');\r\n    overlay.id = 'pth-match-lang-overlay';\r\n    overlay.setAttribute('role','dialog');\r\n    overlay.setAttribute('aria-modal','true');\r\n    overlay.setAttribute('aria-label','Choose pair language');\r\n    overlay.innerHTML =\r\n      '<div id=\"pth-match-lang-modal\">' +\r\n        '<div class=\"pth-lm-head\">' +\r\n          '<p class=\"pth-lm-title\">&#x1F30D; Choose Pair Language<\/p>' +\r\n          '<p class=\"pth-lm-sub\">Select language for sample term:definition pairs<\/p>' +\r\n        '<\/div>' +\r\n        '<button class=\"pth-lm-close\" id=\"pth-match-lm-close\" aria-label=\"Close\">&#x2715;<\/button>' +\r\n        '<div class=\"pth-lm-search-wrap\">' +\r\n          '<input type=\"text\" class=\"pth-lm-search\" id=\"pth-match-lm-search\" placeholder=\"Search language...\" aria-label=\"Search language\" autocomplete=\"off\">' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-grid-wrap\">' +\r\n          '<div class=\"pth-lm-grid\" id=\"pth-match-lm-grid\"><\/div>' +\r\n          '<div class=\"pth-lm-no-res\" id=\"pth-match-lm-nores\">No languages found.<\/div>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-footer\">' +\r\n          '<span class=\"pth-lm-footer-cur\">Selected: <strong id=\"pth-match-lm-cur\">English<\/strong><\/span>' +\r\n          '<span style=\"font-size:0.72rem;color:#475569;\">&#x1F512; Browser only<\/span>' +\r\n        '<\/div>' +\r\n      '<\/div>';\r\n    document.body.appendChild(overlay);\r\n\r\n    renderLangGrid('');\r\n    var searchEl = document.getElementById('pth-match-lm-search');\r\n    if (searchEl) searchEl.addEventListener('input', function() { renderLangGrid(searchEl.value.toLowerCase().trim()); });\r\n    var closeBtn = document.getElementById('pth-match-lm-close');\r\n    if (closeBtn) closeBtn.addEventListener('click', closeLangPopup);\r\n    overlay.addEventListener('click', function(e) { if (e.target === overlay) closeLangPopup(); });\r\n    document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeLangPopup(); });\r\n  }\r\n\r\n  function renderLangGrid(query) {\r\n    var grid = document.getElementById('pth-match-lm-grid');\r\n    var nores = document.getElementById('pth-match-lm-nores');\r\n    if (!grid) return;\r\n    grid.innerHTML = '';\r\n    var filtered = MATCH_LANGS.filter(function(l) {\r\n      if (!query) return true;\r\n      return l.en.toLowerCase().indexOf(query) !== -1 || l.native.toLowerCase().indexOf(query) !== -1 || l.code.indexOf(query) !== -1;\r\n    });\r\n    if (!filtered.length) { if (nores) nores.style.display = 'block'; return; }\r\n    if (nores) nores.style.display = 'none';\r\n    filtered.forEach(function(l) {\r\n      var btn = document.createElement('button');\r\n      btn.className = 'pth-lm-item' + (l.code === MATCH_CURRENT_LANG.code ? ' pth-lm-sel' : '');\r\n      btn.innerHTML =\r\n        '<span class=\"pth-lm-flag\">' + l.code.toUpperCase() + '<\/span>' +\r\n        '<span class=\"pth-lm-names\"><span class=\"pth-lm-native\">' + l.native + '<\/span><span class=\"pth-lm-en\">' + l.en + '<\/span><\/span>';\r\n      btn.addEventListener('click', function() { selectLang(l); });\r\n      grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function selectLang(l) {\r\n    MATCH_CURRENT_LANG = l;\r\n    var cur = document.getElementById('pth-match-lm-cur');\r\n    if (cur) cur.innerHTML = l.code.toUpperCase() + ' ' + l.native + ' (' + l.en + ')';\r\n    updatePickerBtn();\r\n    if (MATCH_SAMPLES[l.code]) {\r\n      var ta = document.getElementById('pth-match-input');\r\n      if (ta) { ta.value = MATCH_SAMPLES[l.code]; applyLangToInput(ta, MATCH_SAMPLES[l.code]); }\r\n      window.pthILS.toast('Loaded: ' + l.native + ' (' + l.en + ')', 'success');\r\n    } else {\r\n      window.pthILS.toast(l.en + ' selected! Type your own pairs.', 'info');\r\n    }\r\n    var searchEl = document.getElementById('pth-match-lm-search');\r\n    renderLangGrid(searchEl ? searchEl.value.toLowerCase().trim() : '');\r\n    closeLangPopup();\r\n  }\r\n\r\n  function openLangPopup() {\r\n    buildLangPopup();\r\n    var overlay = document.getElementById('pth-match-lang-overlay');\r\n    if (overlay) {\r\n      overlay.classList.add('pth-lo-open');\r\n      var s = document.getElementById('pth-match-lm-search');\r\n      if (s) { s.value=''; renderLangGrid(''); setTimeout(function(){ s.focus(); }, 100); }\r\n    }\r\n  }\r\n\r\n  function closeLangPopup() {\r\n    var overlay = document.getElementById('pth-match-lang-overlay');\r\n    if (overlay) overlay.classList.remove('pth-lo-open');\r\n  }\r\n\r\n  function updatePickerBtn() {\r\n    var flag = document.getElementById('pth-match-pick-flag');\r\n    var text = document.getElementById('pth-match-pick-text');\r\n    if (flag) flag.innerHTML = MATCH_CURRENT_LANG.code.toUpperCase();\r\n    if (text) text.innerHTML = MATCH_CURRENT_LANG.native + ' \u2014 ' + MATCH_CURRENT_LANG.en;\r\n  }\r\n\r\n  var MATCH = {\r\n    pairs: [], matched: 0, attempts: 0,\r\n    selected: null, timerInterval: null, timerSecs: 0\r\n  };\r\n\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-match');\r\n    if (!panel || panel.getAttribute('data-match-built')) return;\r\n    panel.setAttribute('data-match-built','1');\r\n\r\n    panel.innerHTML =\r\n      '<div class=\"pth-ils-layout\" id=\"pth-match-layout\">' +\r\n      '<div class=\"pth-ils-main\">' +\r\n\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F517; Match the Pairs<\/h3>' +\r\n          '<button class=\"pth-cw-lang-pick-btn\" id=\"pth-match-lang-pick-btn\" aria-label=\"Choose pair language\">' +\r\n            '<span class=\"pth-cw-lang-pick-flag\" id=\"pth-match-pick-flag\">EN<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-text\" id=\"pth-match-pick-text\">English \u2014 Pair Language<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-arrow\">&#x25BC;<\/span>' +\r\n          '<\/button>' +\r\n          '<label class=\"pth-ils-label\" for=\"pth-match-input\">Enter Term : Definition pairs &#x2014; one per line<\/label>' +\r\n          '<p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 6px;font-style:italic;\">&#x2139;&#xFE0F; The text below is just an example placeholder (not real data) &#x2014; type your own Term:Definition pairs, or click &#x1F4A1; <strong>Load Sample<\/strong> above to fill in working examples.<\/p>' +\r\n          '<textarea class=\"pth-ils-textarea\" id=\"pth-match-input\" aria-label=\"Term and definition pairs\" style=\"min-height:130px;\"' +\r\n            ' placeholder=\"HTML:HyperText Markup Language&#10;CSS:Cascading Style Sheets&#10;JS:JavaScript \u2014 scripting language&#10;API:Application Programming Interface&#10;URL:Uniform Resource Locator&#10;DNS:Domain Name System&#10;HTTP:Web transfer protocol&#10;SQL:Database query language\"><\/textarea>' +\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-match-gen-btn\">&#x26A1; Create Game<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-match-reveal-btn\">&#x1F441; Reveal Answers<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-match-reset-btn\">&#x1F504; Reset<\/button>' +\r\n          '<\/div>' +\r\n          '<div id=\"pth-match-status\" class=\"pth-ils-info\" style=\"display:none;\"><\/div>' +\r\n        '<\/div>' +\r\n\r\n        '<div class=\"pth-ils-card\" id=\"pth-match-game-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F517; Match the Pairs<\/h3>' +\r\n          '<div class=\"pth-match-stats\">' +\r\n            '<div class=\"pth-match-stat\">&#x23F1; <span id=\"pth-match-timer\">0s<\/span><\/div>' +\r\n            '<div class=\"pth-match-stat\">&#x2705; <span id=\"pth-match-matched\">0<\/span> \/ <span id=\"pth-match-total\">0<\/span><\/div>' +\r\n            '<div class=\"pth-match-stat\">&#x1F3AF; Attempts: <span id=\"pth-match-attempts\">0<\/span><\/div>' +\r\n          '<\/div>' +\r\n          '<div id=\"pth-match-win\" style=\"display:none;\" class=\"pth-ils-ok\">&#x1F389; All pairs matched!<\/div>' +\r\n          '<div class=\"pth-match-grid\" id=\"pth-match-grid\">' +\r\n            '<div class=\"pth-match-col-head\">TERMS<\/div>' +\r\n            '<div class=\"pth-match-col-head\">DEFINITIONS<\/div>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n        '<div class=\"pth-ils-card\" id=\"pth-match-export-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F4E4; Export<\/h3>' +\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-match-html-btn\">&#x1F4C4; Download HTML<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-match-copy-btn\">&#x1F4CB; Copy HTML Code<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-match-print-btn\">&#x1F5A8; Print Activity<\/button>' +\r\n          '<\/div>' +\r\n          '<div class=\"pth-ils-code-box\" id=\"pth-match-code-box\" style=\"display:none;\">' +\r\n            '<textarea id=\"pth-match-code-ta\" readonly aria-label=\"HTML code\" style=\"min-height:100px;\"><\/textarea>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n      '<\/div>' +\r\n\r\n      '<div class=\"pth-ils-sidebar\">' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4A1; How to Use<\/h3>' +\r\n          '<p style=\"font-size:0.82rem;color:#334155;line-height:1.6;margin:0;\">' +\r\n            '1. Enter <strong>Term:Definition<\/strong> pairs.<br>' +\r\n            '2. Click <strong>&#x26A1; Create Game<\/strong>.<br>' +\r\n            '3. Click a <strong>term<\/strong> then click its matching <strong>definition<\/strong>.<br>' +\r\n            '4. Green = correct pair &#x2705;<br>' +\r\n            '5. Match all pairs to win! &#x1F3C6;' +\r\n          '<\/p>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4CA; Stats<\/h3>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Pairs<\/span><span class=\"pth-ils-stat-val\" id=\"pth-match-s-pairs\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Attempts<\/span><span class=\"pth-ils-stat-val\" id=\"pth-match-s-att\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Best time<\/span><span class=\"pth-ils-stat-val\" id=\"pth-match-s-best\">&#8212;<\/span><\/div>' +\r\n        '<\/div>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n  }\r\n\r\n  function matchGenerate() {\r\n    var raw   = (document.getElementById('pth-match-input')||{}).value || '';\r\n    var pairs = window.pthILS.parsePairs(raw, ':');\r\n    if (pairs.length < 2) { window.pthILS.toast('Enter at least 2 Term:Definition pairs.','error'); return; }\r\n    if (pairs.length > 16) pairs = pairs.slice(0, 16);\r\n    MATCH.pairs    = pairs;\r\n    MATCH.matched  = 0;\r\n    MATCH.attempts = 0;\r\n    MATCH.selected = null;\r\n    clearInterval(MATCH.timerInterval);\r\n    MATCH.timerSecs = 0;\r\n\r\n    matchRenderGrid();\r\n    document.getElementById('pth-match-game-card').style.display   = 'block';\r\n    document.getElementById('pth-match-export-card').style.display = 'block';\r\n\r\n    \/* Start timer *\/\r\n    var td = document.getElementById('pth-match-timer'); if (td) td.textContent = '0s';\r\n    MATCH.timerInterval = setInterval(function() {\r\n      MATCH.timerSecs++;\r\n      var t = document.getElementById('pth-match-timer'); if (t) t.textContent = MATCH.timerSecs + 's';\r\n    }, 1000);\r\n\r\n    var tot = document.getElementById('pth-match-total'); if (tot) tot.textContent = pairs.length;\r\n    var sp  = document.getElementById('pth-match-s-pairs'); if (sp) sp.textContent = pairs.length;\r\n    var win = document.getElementById('pth-match-win'); if (win) win.style.display = 'none';\r\n\r\n    window.pthILS.toast('Game created! Match all pairs.','success');\r\n  }\r\n\r\n  function matchRenderGrid() {\r\n    var pairs  = MATCH.pairs;\r\n    var grid   = document.getElementById('pth-match-grid'); if (!grid) return;\r\n    \/* Remove old cards *\/\r\n    var oldCards = grid.querySelectorAll('.pth-match-card'); oldCards.forEach(function(c){ c.parentNode.removeChild(c); });\r\n\r\n    \/* Shuffle terms and defs independently *\/\r\n    var terms = window.pthILS.shuffle(pairs.map(function(p,i){ return { text:p.a, id:i }; }));\r\n    var defs  = window.pthILS.shuffle(pairs.map(function(p,i){ return { text:p.b, id:i }; }));\r\n\r\n    var maxLen = Math.max(terms.length, defs.length);\r\n    for (var i = 0; i < maxLen; i++) {\r\n      \/* Term card *\/\r\n      if (terms[i]) {\r\n        var tc = buildCard(terms[i].text, terms[i].id, 'term');\r\n        grid.appendChild(tc);\r\n      } else { grid.appendChild(document.createElement('div')); }\r\n      \/* Def card *\/\r\n      if (defs[i]) {\r\n        var dc = buildCard(defs[i].text, defs[i].id, 'def');\r\n        grid.appendChild(dc);\r\n      } else { grid.appendChild(document.createElement('div')); }\r\n    }\r\n  }\r\n\r\n  function matchReveal() {\r\n    if (!MATCH.pairs.length) { window.pthILS.toast('Create game first!','error'); return; }\r\n    var grid = document.getElementById('pth-match-grid'); if (!grid) return;\r\n    var oldCards = grid.querySelectorAll('.pth-match-card'); oldCards.forEach(function(c){ c.parentNode.removeChild(c); });\r\n\r\n    \/* Rebuild the grid using the TRUE pair order (not the shuffled positions), so\r\n       each row visually shows the correct term next to its correct definition. *\/\r\n    MATCH.pairs.forEach(function(p, i) {\r\n      var tc = buildCard(p.a, i, 'term');\r\n      var dc = buildCard(p.b, i, 'def');\r\n      tc.classList.add('mc-correct'); tc.style.pointerEvents = 'none';\r\n      dc.classList.add('mc-correct'); dc.style.pointerEvents = 'none';\r\n      grid.appendChild(tc);\r\n      grid.appendChild(dc);\r\n    });\r\n\r\n    clearInterval(MATCH.timerInterval);\r\n    MATCH.matched = MATCH.pairs.length;\r\n    var m = document.getElementById('pth-match-matched'); if (m) m.textContent = MATCH.matched;\r\n    var win = document.getElementById('pth-match-win'); if (win) win.style.display = 'block';\r\n    window.pthILS.toast('Answers revealed!','info');\r\n  }\r\n\r\n  function buildCard(text, id, side) {\r\n    var div = document.createElement('div');\r\n    div.className = 'pth-match-card';\r\n    div.setAttribute('data-id', id);\r\n    div.setAttribute('data-side', side);\r\n    div.setAttribute('role','button');\r\n    div.setAttribute('tabindex','0');\r\n    div.setAttribute('aria-label', (side==='term'?'Term: ':'Definition: ') + text);\r\n\r\n    \/* Apply multilingual font if shell has it *\/\r\n    if (window.pthILS.detectScript) {\r\n      var script = window.pthILS.detectScript(text);\r\n      var isRTL  = window.pthILS.isRTL ? window.pthILS.isRTL(text) : false;\r\n      if (window.pthILS.loadFont) window.pthILS.loadFont(script);\r\n      if (window.pthILS.getFontStack) div.style.fontFamily = window.pthILS.getFontStack(script);\r\n      if (isRTL) div.style.direction = 'rtl';\r\n    }\r\n\r\n    div.textContent = text;\r\n    div.addEventListener('click', function(){ matchOnClick(div); });\r\n    div.addEventListener('keydown', function(e){ if(e.key==='Enter'||e.key===' ') matchOnClick(div); });\r\n    return div;\r\n  }\r\n\r\n  function matchOnClick(card) {\r\n    if (card.classList.contains('mc-correct')) return;\r\n\r\n    if (!MATCH.selected) {\r\n      MATCH.selected = card;\r\n      card.classList.add('mc-selected');\r\n      return;\r\n    }\r\n\r\n    var s1 = MATCH.selected.getAttribute('data-side');\r\n    var s2 = card.getAttribute('data-side');\r\n    var id1= parseInt(MATCH.selected.getAttribute('data-id'));\r\n    var id2= parseInt(card.getAttribute('data-id'));\r\n\r\n    \/* Same side \u2014 switch selection *\/\r\n    if (s1 === s2) {\r\n      MATCH.selected.classList.remove('mc-selected');\r\n      MATCH.selected = card;\r\n      card.classList.add('mc-selected');\r\n      return;\r\n    }\r\n\r\n    MATCH.attempts++;\r\n    var attEl = document.getElementById('pth-match-attempts'); if (attEl) attEl.textContent = MATCH.attempts;\r\n    var saEl  = document.getElementById('pth-match-s-att');    if (saEl)  saEl.textContent  = MATCH.attempts;\r\n\r\n    if (id1 === id2) {\r\n      \/* Correct! *\/\r\n      MATCH.selected.classList.remove('mc-selected');\r\n      MATCH.selected.classList.add('mc-correct');\r\n      card.classList.add('mc-correct');\r\n      MATCH.selected.style.pointerEvents = 'none';\r\n      card.style.pointerEvents           = 'none';\r\n      MATCH.matched++;\r\n      var m = document.getElementById('pth-match-matched'); if (m) m.textContent = MATCH.matched;\r\n      window.pthILS.toast('Correct! &#x2705;','success');\r\n\r\n      if (MATCH.matched === MATCH.pairs.length) {\r\n        clearInterval(MATCH.timerInterval);\r\n        var win = document.getElementById('pth-match-win'); if (win) win.style.display = 'block';\r\n        var best = document.getElementById('pth-match-s-best'); if (best) best.textContent = MATCH.timerSecs + 's';\r\n        window.pthILS.toast('&#x1F389; All pairs matched!','success');\r\n      }\r\n    } else {\r\n      \/* Wrong *\/\r\n      var prev = MATCH.selected;\r\n      prev.classList.add('mc-wrong'); card.classList.add('mc-wrong');\r\n      setTimeout(function(){\r\n        prev.classList.remove('mc-wrong','mc-selected');\r\n        card.classList.remove('mc-wrong');\r\n      }, 700);\r\n      window.pthILS.toast('Not a match. Try again!','error');\r\n    }\r\n    MATCH.selected = null;\r\n  }\r\n\r\n  function matchBuildHTML() {\r\n    if (!MATCH.pairs.length) return '';\r\n    var pairs = MATCH.pairs;\r\n    var terms = window.pthILS.shuffle(pairs.map(function(p,i){ return {t:p.a,id:i}; }));\r\n    var defs  = window.pthILS.shuffle(pairs.map(function(p,i){ return {t:p.b,id:i}; }));\r\n    var pairsJSON = JSON.stringify(pairs);\r\n    var termsJSON = JSON.stringify(terms);\r\n    var defsJSON  = JSON.stringify(defs);\r\n\r\n    var html =\r\n      '<style>' +\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;color-adjust:exact;}' +\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;background:#eef2f9;color:#1e293b;min-height:100vh;display:flex;justify-content:center;padding:32px 16px;}' +\r\n      '.mp-page{width:100%;max-width:640px;background:#fff;border-radius:18px;box-shadow:0 10px 30px -10px rgba(15,23,42,0.18);padding:30px 34px 34px;}' +\r\n      '.mp-head{text-align:center;margin:0 0 14px;}' +\r\n      'h1{color:#1d4ed8;font-size:1.5rem;font-weight:800;margin:0 0 6px;}' +\r\n      '.mp-sub{color:#334155;font-size:0.85rem;margin:0;}' +\r\n      '.stats{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin-bottom:18px;}' +\r\n      '.stat{background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;padding:8px 14px;font-size:0.82rem;font-weight:700;color:#1d4ed8;}' +\r\n      '.grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;}' +\r\n      '.col-h{font-size:0.75rem;font-weight:800;color:#334155;text-transform:uppercase;text-align:center;padding:4px;}' +\r\n      '.card{background:#fff;border:2px solid #e2e8f0;border-radius:8px;padding:12px;text-align:center;cursor:pointer;font-size:0.88rem;font-weight:700;color:#1e293b;min-height:56px;display:flex;align-items:center;justify-content:center;word-break:break-word;transition:all 0.15s;}' +\r\n      '.card:hover{border-color:#2563eb;background:#eff6ff;}' +\r\n      '.card.sel{border-color:#2563eb;background:#dbeafe;color:#1d4ed8;}' +\r\n      '.card.ok{border-color:#059669;background:#f0fdf4;color:#047857;cursor:default;}' +\r\n      '.card.no{border-color:#dc2626;background:#fef2f2;}' +\r\n      '.win{display:none;margin-top:16px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;padding:12px;color:#047857;font-weight:700;text-align:center;}' +\r\n      '.mp-footer-btns{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:22px 0 4px;padding-top:18px;border-top:2px solid #e2e8f0;}' +\r\n      '.btn{padding:9px 18px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.06);}' +\r\n      '.btn-b{background:#fff;border:2px solid #e2e8f0;color:#334155;}' +\r\n      '.btn-c{background:#7c3aed;color:#fff;}' +\r\n      '.btn.active{outline:3px solid #fde68a;}' +\r\n      '@media(max-width:480px){.mp-page{padding:20px 16px 26px;border-radius:12px;}}' +\r\n      '@media print{body{margin:0;background:#fff;padding:0;display:block;}.mp-page{box-shadow:none;border-radius:0;max-width:100%;padding:10px;}.mp-footer-btns,#mt{display:none!important;}.grid{break-inside:avoid;}}' +\r\n      '<\/style>' +\r\n      '<div class=\"mp-page\">' +\r\n      '<div class=\"mp-head\">' +\r\n      '<h2>&#x1F517; Match the Pairs<\/h2>' +\r\n      '<p class=\"mp-sub\">Click a term, then click its matching definition.<\/p>' +\r\n      '<\/div>' +\r\n      '<div class=\"stats\"><div class=\"stat\">&#x23F1; <span id=\"mt\">0s<\/span><\/div><div class=\"stat\">&#x2705; <span id=\"mm\">0<\/span>\/' + pairs.length + '<\/div><div class=\"stat\">&#x1F3AF; <span id=\"ma\">0<\/span> attempts<\/div><\/div>' +\r\n      '<div class=\"win\" id=\"win\">&#x1F389; All pairs matched!<\/div>' +\r\n      '<div class=\"grid\" id=\"grid\"><div class=\"col-h\">TERMS<\/div><div class=\"col-h\">DEFINITIONS<\/div><\/div>' +\r\n      '<div class=\"mp-footer-btns\">' +\r\n      '<button class=\"btn btn-b\" id=\"btn-reset\">&#x1F504; Reset<\/button>' +\r\n      '<button class=\"btn btn-b\" id=\"btn-answerkey\">&#x1F5DD; Answer Key Mode<\/button>' +\r\n      '<button class=\"btn btn-c\" id=\"btn-print\">&#x1F5A8; Print Activity<\/button>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n\r\n    var sc = [\r\n      '(function(){',\r\n        'var pairs=' + pairsJSON + ';',\r\n        'var terms=' + termsJSON + ';',\r\n        'var defs='  + defsJSON  + ';',\r\n        'var sel=null,matched=0,attempts=0,secs=0,akOn=false,ti=null;',\r\n        'function startTimer(){clearInterval(ti);secs=0;ti=setInterval(function(){secs++;var t=document.getElementById(\"mt\");if(t)t.textContent=secs+\"s\";},1000);}',\r\n        'startTimer();',\r\n        'var g=document.getElementById(\"grid\");',\r\n        'function buildGrid(){',\r\n          'g.innerHTML=\"\";',\r\n          'var th=document.createElement(\"div\");th.className=\"col-h\";th.textContent=\"TERMS\";g.appendChild(th);',\r\n          'var dh=document.createElement(\"div\");dh.className=\"col-h\";dh.textContent=\"DEFINITIONS\";g.appendChild(dh);',\r\n          'var maxL=Math.max(terms.length,defs.length);',\r\n          'for(var i=0;i<maxL;i++){',\r\n            'var tc=mk(terms[i],\"t\"),dc=mk(defs[i],\"d\");',\r\n            'g.appendChild(tc||document.createElement(\"div\"));',\r\n            'g.appendChild(dc||document.createElement(\"div\"));',\r\n          '}',\r\n        '}',\r\n        'buildGrid();',\r\n        'function mk(item,side){if(!item)return null;',\r\n          'var d=document.createElement(\"div\");d.className=\"card\";',\r\n          'd.setAttribute(\"data-id\",item.id);d.setAttribute(\"data-side\",side);',\r\n          'd.textContent=item.t;',\r\n          'd.addEventListener(\"click\",function(){click(d);});',\r\n          'return d;}',\r\n        'function click(c){if(c.classList.contains(\"ok\")||akOn)return;',\r\n          'if(!sel){sel=c;c.classList.add(\"sel\");return;}',\r\n          'var s1=sel.getAttribute(\"data-side\"),s2=c.getAttribute(\"data-side\");',\r\n          'var i1=parseInt(sel.getAttribute(\"data-id\")),i2=parseInt(c.getAttribute(\"data-id\"));',\r\n          'if(s1===s2){sel.classList.remove(\"sel\");sel=c;c.classList.add(\"sel\");return;}',\r\n          'attempts++;var ma=document.getElementById(\"ma\");if(ma)ma.textContent=attempts;',\r\n          'if(i1===i2){sel.classList.remove(\"sel\");sel.classList.add(\"ok\");c.classList.add(\"ok\");',\r\n            'sel.style.pointerEvents=\"none\";c.style.pointerEvents=\"none\";',\r\n            'matched++;var mm=document.getElementById(\"mm\");if(mm)mm.textContent=matched;',\r\n            'if(matched===pairs.length){clearInterval(ti);var w=document.getElementById(\"win\");if(w)w.style.display=\"block\";}}',\r\n          'else{var pv=sel;pv.classList.add(\"no\");c.classList.add(\"no\");',\r\n            'setTimeout(function(){pv.classList.remove(\"no\",\"sel\");c.classList.remove(\"no\");},700);}',\r\n          'sel=null;}',\r\n        'document.getElementById(\"btn-reset\").addEventListener(\"click\",function(){sel=null;matched=0;attempts=0;akOn=false;',\r\n          'var mm=document.getElementById(\"mm\");if(mm)mm.textContent=\"0\";',\r\n          'var ma=document.getElementById(\"ma\");if(ma)ma.textContent=\"0\";',\r\n          'var w=document.getElementById(\"win\");if(w)w.style.display=\"none\";',\r\n          'var ak=document.getElementById(\"btn-answerkey\");if(ak){ak.classList.remove(\"active\");ak.textContent=\"\\\\uD83D\\\\uDDDD Answer Key Mode\";}',\r\n          'buildGrid();startTimer();});',\r\n        'document.getElementById(\"btn-answerkey\").addEventListener(\"click\",function(e){akOn=!akOn;e.target.classList.toggle(\"active\",akOn);',\r\n          'if(akOn){g.innerHTML=\"\";',\r\n            'var th=document.createElement(\"div\");th.className=\"col-h\";th.textContent=\"TERMS\";g.appendChild(th);',\r\n            'var dh=document.createElement(\"div\");dh.className=\"col-h\";dh.textContent=\"DEFINITIONS\";g.appendChild(dh);',\r\n            'pairs.forEach(function(p,i){',\r\n              'var tc=mk({t:p.a,id:i},\"t\"),dc=mk({t:p.b,id:i},\"d\");',\r\n              'tc.classList.add(\"ok\");tc.style.pointerEvents=\"none\";',\r\n              'dc.classList.add(\"ok\");dc.style.pointerEvents=\"none\";',\r\n              'g.appendChild(tc);g.appendChild(dc);',\r\n            '});',\r\n            'e.target.textContent=\"Hide Answer Key\";}',\r\n          'else{buildGrid();sel=null;e.target.textContent=\"Answer Key Mode\";}',\r\n        '});',\r\n        'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n\r\n    var so='<'+'script'+'>';\r\n    var sc2='<'+'\/'+'script'+'>';\r\n    var docOpen='<'+'!DOCTYPE html>'+'<'+'html lang=\"en\">'+'<'+'head>'+\r\n      '<'+'meta charset=\"UTF-8\">'+\r\n      '<'+'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">'+\r\n      '<'+'title>Match the Pairs<'+'\/title>'+\r\n      '<'+'\/head>'+'<'+'body>';\r\n    var docClose='<'+'\/'+'body>'+'<'+'\/'+'html>';\r\n    return docOpen + html + so + sc + sc2 + docClose;\r\n  }\r\n\r\n  function wireEvents() {\r\n    var b = function(id,fn){ var el=document.getElementById(id); if(el)el.addEventListener('click',fn); };\r\n    b('pth-match-gen-btn',   matchGenerate);\r\n    b('pth-match-reveal-btn', matchReveal);\r\n    b('pth-match-lang-pick-btn', openLangPopup);\r\n    b('pth-match-reset-btn', function() {\r\n      if (!MATCH.pairs.length) { window.pthILS.toast('Create game first!','error'); return; }\r\n      matchRenderGrid();\r\n      MATCH.matched = 0; MATCH.attempts = 0; MATCH.selected = null;\r\n      clearInterval(MATCH.timerInterval);\r\n      MATCH.timerSecs = 0;\r\n      var td = document.getElementById('pth-match-timer'); if (td) td.textContent = '0s';\r\n      MATCH.timerInterval = setInterval(function() {\r\n        MATCH.timerSecs++;\r\n        var t = document.getElementById('pth-match-timer'); if (t) t.textContent = MATCH.timerSecs + 's';\r\n      }, 1000);\r\n      var m = document.getElementById('pth-match-matched'); if (m) m.textContent = '0';\r\n      var att = document.getElementById('pth-match-attempts'); if (att) att.textContent = '0';\r\n      var win = document.getElementById('pth-match-win'); if (win) win.style.display = 'none';\r\n      window.pthILS.toast('Game reset!','info');\r\n    });\r\n    b('pth-match-html-btn', function(){\r\n      var c=matchBuildHTML();if(!c){window.pthILS.toast('Create game first!','error');return;}\r\n      try {\r\n        var blob=new Blob([c],{type:'text\/html'});\r\n        var url=URL.createObjectURL(blob);\r\n        var a=document.createElement('a');\r\n        a.href=url;a.download='match-pairs.html';\r\n        document.body.appendChild(a);a.click();document.body.removeChild(a);\r\n        setTimeout(function(){URL.revokeObjectURL(url);},2000);\r\n        window.pthILS.toast('HTML file downloaded!','success');\r\n      } catch(err) { window.pthILS.toast('Download failed: '+err.message,'error'); }\r\n    });\r\n    b('pth-match-print-btn', function(){\r\n      var c=matchBuildHTML();if(!c){window.pthILS.toast('Create game first!','error');return;}\r\n      var w = window.open('','_blank');\r\n      if (!w) { window.pthILS.toast('Popup blocked! Allow popups for this site to print.','error'); return; }\r\n      w.document.open();w.document.write(c);w.document.close();\r\n      var printed=false;\r\n      function doPrint(){ if(printed)return; printed=true; w.focus(); w.print(); }\r\n      w.addEventListener('load', function(){ setTimeout(doPrint,150); });\r\n      setTimeout(doPrint,1200);\r\n    });\r\n    b('pth-match-copy-btn',  function(){ var c=matchBuildHTML();if(!c){window.pthILS.toast('Create game first!','error');return;}window.pthILS.showCopyHTML(c,'pth-match-code-box'); });\r\n\r\n    document.addEventListener('pthILSClear', function(e) {\r\n      if (e.detail.tab !== 'match') return;\r\n      var ta=document.getElementById('pth-match-input'); if(ta)ta.value='';\r\n      var gc=document.getElementById('pth-match-game-card');   if(gc)gc.style.display='none';\r\n      var ec=document.getElementById('pth-match-export-card'); if(ec)ec.style.display='none';\r\n      clearInterval(MATCH.timerInterval);\r\n      MATCH.pairs=[]; MATCH.matched=0; MATCH.attempts=0; MATCH.selected=null;\r\n    });\r\n\r\n    document.addEventListener('pthILSSample', function(e) {\r\n      if (e.detail.tab !== 'match') return;\r\n      var ta=document.getElementById('pth-match-input');\r\n      if(ta){ ta.value='HTML:HyperText Markup Language\\nCSS:Cascading Style Sheets\\nJS:JavaScript scripting language\\nPHP:Server-side scripting\\nSQL:Database queries\\nGit:Version control\\nAPI:Data communication bridge\\nJSON:Data interchange format'; applyLangToInput(ta, ta.value); window.pthILS.toast('Sample loaded! Click Create Game.','success'); }\r\n    });\r\n  }\r\n\r\n  function init() { buildTabHTML(); setTimeout(function(){ wireEvents(); }, 100); }\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v2.0 \u2014 Memory Match Tab -->\r\n\r\n<style>\r\n.pth-mem-grid {\r\n  display: grid;\r\n  grid-template-columns: repeat(4, 1fr);\r\n  gap: 10px;\r\n  margin-bottom: 14px;\r\n}\r\n.pth-mem-card {\r\n  height: 80px;\r\n  border-radius: 8px;\r\n  cursor: pointer;\r\n  perspective: 600px;\r\n}\r\n.pth-mem-inner {\r\n  width: 100%;\r\n  height: 100%;\r\n  position: relative;\r\n  transform-style: preserve-3d;\r\n  transition: transform 0.35s ease;\r\n  border-radius: 8px;\r\n}\r\n.pth-mem-card.mem-flipped .pth-mem-inner {\r\n  transform: rotateY(180deg);\r\n}\r\n.pth-mem-front,\r\n.pth-mem-back {\r\n  position: absolute;\r\n  width: 100%;\r\n  height: 100%;\r\n  backface-visibility: hidden;\r\n  -webkit-backface-visibility: hidden;\r\n  border-radius: 8px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  font-size: 0.82rem;\r\n  font-weight: 700;\r\n  padding: 8px;\r\n  text-align: center;\r\n  word-break: break-word;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  line-height: 1.3;\r\n}\r\n.pth-mem-front {\r\n  background: #2563eb;\r\n  color: #fff;\r\n  font-size: 1.5rem;\r\n}\r\n.pth-mem-back {\r\n  background: #fff;\r\n  border: 2px solid #e2e8f0;\r\n  color: #0f172a;\r\n  transform: rotateY(180deg);\r\n}\r\n.pth-mem-card.mem-matched .pth-mem-back {\r\n  background: #f0fdf4;\r\n  border-color: #059669;\r\n  color: #047857;\r\n}\r\n.pth-mem-stats {\r\n  display: flex;\r\n  gap: 10px;\r\n  flex-wrap: wrap;\r\n  margin-bottom: 12px;\r\n}\r\n.pth-mem-stat {\r\n  background: #eff6ff;\r\n  border: 1px solid #bfdbfe;\r\n  border-radius: 8px;\r\n  padding: 8px 14px;\r\n  font-size: 0.82rem;\r\n  font-weight: 700;\r\n  color: #1d4ed8;\r\n  text-align: center;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n@media (max-width: 480px) {\r\n  .pth-mem-grid { grid-template-columns: repeat(3, 1fr); }\r\n  .pth-mem-card { height: 70px; }\r\n}\r\n\/* Language picker button *\/\r\n.pth-cw-lang-pick-btn {\r\n  display: inline-flex; align-items: center; gap: 8px;\r\n  padding: 9px 16px; background: #fff; border: 2px solid #e2e8f0;\r\n  border-radius: 8px; cursor: pointer; font-family: 'Inter', system-ui, sans-serif;\r\n  font-size: 0.85rem; font-weight: 700; color: #334155;\r\n  transition: all 0.15s; width: 100%; margin-bottom: 10px;\r\n}\r\n.pth-cw-lang-pick-btn:hover { border-color: #2563eb; color: #1d4ed8; background: #eff6ff; }\r\n.pth-cw-lang-pick-flag { font-size: 0.68rem; font-weight: 800; background: #2563eb; color: #fff; border-radius: 5px; padding: 3px 6px; min-width: 26px; text-align: center; letter-spacing: 0.3px; }\r\n.pth-cw-lang-pick-text { flex: 1; text-align: left; }\r\n.pth-cw-lang-pick-arrow { color: #94a3b8; font-size: 0.8rem; }\r\n<\/style>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function () {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function () { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  \/* ============================================================\r\n     MULTILINGUAL METHODS \u2014 self-contained\r\n     ============================================================ *\/\r\n  if (!window.pthILS) window.pthILS = {};\r\n  if (!window.pthILS.detectScript) {\r\n    window.pthILS.detectScript = function(text) {\r\n      if (!text || !text.trim()) return 'latin';\r\n      if (\/[\\u0D80-\\u0DFF]\/.test(text)) return 'sinhala';\r\n      if (\/[\\u0B80-\\u0BFF]\/.test(text)) return 'tamil';\r\n      if (\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text)) return 'rtl';\r\n      if (\/[\\u3000-\\u9FFF\\uAC00-\\uD7AF]\/.test(text)) return 'cjk';\r\n      if (\/[\\u0900-\\u097F]\/.test(text)) return 'devanagari';\r\n      if (\/[\\u0E00-\\u0E7F]\/.test(text)) return 'thai';\r\n      if (\/[\\u0980-\\u09FF]\/.test(text)) return 'bengali';\r\n      if (\/[\\u1000-\\u109F]\/.test(text)) return 'myanmar';\r\n      if (\/[\\u1780-\\u17FF]\/.test(text)) return 'khmer';\r\n      if (\/[\\u0370-\\u03FF]\/.test(text)) return 'greek';\r\n      if (\/[\\u0400-\\u04FF]\/.test(text)) return 'cyrillic';\r\n      return 'latin';\r\n    };\r\n  }\r\n  if (!window.pthILS.isRTL) {\r\n    window.pthILS.isRTL = function(text) {\r\n      return \/[\\u0591-\\u07FF\\u200F\\u202B\\u202E\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(text);\r\n    };\r\n  }\r\n  if (!window.pthILS.getFontStack) {\r\n    window.pthILS.getFontStack = function(script) {\r\n      var f = {\r\n        sinhala:\"'Noto Sans Sinhala','Iskoola Pota',system-ui,sans-serif\",\r\n        tamil:\"'Noto Sans Tamil','Latha',system-ui,sans-serif\",\r\n        rtl:\"'Noto Sans Arabic','Noto Sans Hebrew',system-ui,sans-serif\",\r\n        cjk:\"'Noto Sans CJK SC','Microsoft YaHei',system-ui,sans-serif\",\r\n        devanagari:\"'Noto Sans Devanagari','Mangal',system-ui,sans-serif\",\r\n        thai:\"'Noto Sans Thai','Tahoma',system-ui,sans-serif\",\r\n        bengali:\"'Noto Sans Bengali','Vrinda',system-ui,sans-serif\",\r\n        myanmar:\"'Noto Sans Myanmar',system-ui,sans-serif\",\r\n        khmer:\"'Noto Sans Khmer',system-ui,sans-serif\",\r\n        latin:\"'Inter',system-ui,sans-serif\"\r\n      };\r\n      return f[script] || f.latin;\r\n    };\r\n  }\r\n  if (!window.pthILS.loadedFonts) window.pthILS.loadedFonts = {};\r\n  if (!window.pthILS.loadFont) {\r\n    window.pthILS.loadFont = function(script) {\r\n      if (window.pthILS.loadedFonts[script]) return;\r\n      window.pthILS.loadedFonts[script] = true;\r\n      var m = {\r\n        sinhala:'Noto+Sans+Sinhala:wght@400;700',tamil:'Noto+Sans+Tamil:wght@400;700',\r\n        rtl:'Noto+Sans+Arabic:wght@400;700',devanagari:'Noto+Sans+Devanagari:wght@400;700',\r\n        thai:'Noto+Sans+Thai:wght@400;700',bengali:'Noto+Sans+Bengali:wght@400;700',\r\n        myanmar:'Noto+Sans+Myanmar:wght@400;700',cjk:'Noto+Sans+SC:wght@400;700'\r\n      };\r\n      if (!m[script]) return;\r\n      var l=document.createElement('link');l.rel='stylesheet';\r\n      l.href='https:\/\/fonts.googleapis.com\/css2?family='+m[script]+'&display=swap';\r\n      document.head.appendChild(l);\r\n    };\r\n  }\r\n\r\n  var MEM_LANGS = [\r\n    {code:'en', native:'English', en:'English'},\r\n    {code:'si', native:'\\u0DC3\\u0DD2\\u0982\\u0DC4\\u0DBD', en:'Sinhala'},\r\n    {code:'ta', native:'\\u0BA4\\u0BAE\\u0BBF\\u0BB4\\u0BCD', en:'Tamil'},\r\n    {code:'zh', native:'\\u4E2D\\u6587', en:'Chinese'},\r\n    {code:'ar', native:'\\u0627\\u0644\\u0639\\u0631\\u0628\\u064A\\u0629', en:'Arabic'},\r\n    {code:'hi', native:'\\u0939\\u093F\\u0928\\u094D\\u0926\\u0940', en:'Hindi'},\r\n    {code:'es', native:'Espa\\u00F1ol', en:'Spanish'},\r\n    {code:'fr', native:'Fran\\u00E7ais', en:'French'},\r\n    {code:'pt', native:'Portugu\\u00EAs', en:'Portuguese'},\r\n    {code:'de', native:'Deutsch', en:'German'},\r\n    {code:'ja', native:'\\u65E5\\u672C\\u8A9E', en:'Japanese'},\r\n    {code:'ko', native:'\\uD55C\\uAD6D\\uC5B4', en:'Korean'},\r\n    {code:'ru', native:'\\u0420\\u0443\\u0441\\u0441\\u043A\\u0438\\u0439', en:'Russian'},\r\n    {code:'it', native:'Italiano', en:'Italian'},\r\n    {code:'tr', native:\"T\\u00FCrk\\u00E7e\", en:'Turkish'},\r\n    {code:'id', native:'Bahasa Indonesia', en:'Indonesian'},\r\n    {code:'ms', native:'Bahasa Melayu', en:'Malay'},\r\n    {code:'bn', native:'\\u09AC\\u09BE\\u0982\\u09B2\\u09BE', en:'Bengali'},\r\n    {code:'vi', native:\"Ti\\u1EBFng Vi\\u1EC7t\", en:'Vietnamese'},\r\n    {code:'th', native:'\\u0E44\\u0E17\\u0E22', en:'Thai'},\r\n    {code:'sw', native:'Kiswahili', en:'Swahili'},\r\n    {code:'nl', native:'Nederlands', en:'Dutch'},\r\n    {code:'pl', native:'Polski', en:'Polish'},\r\n    {code:'uk', native:'\\u0423\\u043A\\u0440\\u0430\\u0457\\u043D\\u0441\\u044C\\u043A\\u0430', en:'Ukrainian'},\r\n    {code:'el', native:'\\u0395\\u03BB\\u03BB\\u03B7\\u03BD\\u03B9\\u03BA\\u03AC', en:'Greek'},\r\n    {code:'he', native:'\\u05E2\\u05D1\\u05E8\\u05D9\\u05EA', en:'Hebrew'},\r\n    {code:'fa', native:'\\u0641\\u0627\\u0631\\u0633\\u06CC', en:'Persian'},\r\n    {code:'ur', native:'\\u0627\\u0631\\u062F\\u0648', en:'Urdu'},\r\n    {code:'ne', native:'\\u0928\\u0947\\u092A\\u093E\\u0932\\u0940', en:'Nepali'},\r\n    {code:'sv', native:'Svenska', en:'Swedish'},\r\n    {code:'ro', native:\"Rom\\u00E2n\\u0103\", en:'Romanian'},\r\n    {code:'fil', native:'Filipino', en:'Filipino'},\r\n    {code:'af', native:'Afrikaans', en:'Afrikaans'}\r\n  ];\r\n\r\n  var MEM_SAMPLES = {\r\n    en:'Dog:\\uD83D\\uDC15\\nCat:\\uD83D\\uDC31\\nSun:\\u2600\\uFE0F\\nMoon:\\uD83C\\uDF19\\nTree:\\uD83C\\uDF33\\nFish:\\uD83D\\uDC1F\\nStar:\\u2B50\\nHeart:\\u2764\\uFE0F',\r\n    si:'\\u0DC3\\u0DD6\\u0DB1\\u0D9B\\u0DCF:\\uD83D\\uDC15\\n\\u0DB6\\u0DCA\\u0DBA\\u0DBA\\u0DCF:\\uD83D\\uDC31',\r\n    zh:'\\u72D7:\\uD83D\\uDC15\\n\\u732B:\\uD83D\\uDC31\\n\\u592A\\u9633:\\u2600\\uFE0F\\n\\u6708\\u4EAE:\\uD83C\\uDF19',\r\n    ar:'\\u0643\\u0644\\u0628:\\uD83D\\uDC15\\n\\u0642\\u0637:\\uD83D\\uDC31',\r\n    es:'Perro:\\uD83D\\uDC15\\nGato:\\uD83D\\uDC31\\nSol:\\u2600\\uFE0F\\nLuna:\\uD83C\\uDF19\\n\\u00C1rbol:\\uD83C\\uDF33\\nPez:\\uD83D\\uDC1F',\r\n    fr:'Chien:\\uD83D\\uDC15\\nChat:\\uD83D\\uDC31\\nSoleil:\\u2600\\uFE0F\\nLune:\\uD83C\\uDF19\\nArbre:\\uD83C\\uDF33',\r\n    de:'Hund:\\uD83D\\uDC15\\nKatze:\\uD83D\\uDC31\\nSonne:\\u2600\\uFE0F\\nMond:\\uD83C\\uDF19\\nBaum:\\uD83C\\uDF33',\r\n    pt:'Cachorro:\\uD83D\\uDC15\\nGato:\\uD83D\\uDC31\\nSol:\\u2600\\uFE0F\\nLua:\\uD83C\\uDF19',\r\n    ja:'\\u72AC:\\uD83D\\uDC15\\n\\u732B:\\uD83D\\uDC31\\n\\u592A\\u967D:\\u2600\\uFE0F',\r\n    ko:'\\uAC1C:\\uD83D\\uDC15\\n\\uACE0\\uC591\\uC774:\\uD83D\\uDC31',\r\n    ru:'\\u0421\\u043E\\u0431\\u0430\\u043A\\u0430:\\uD83D\\uDC15\\n\\u041A\\u043E\\u0448\\u043A\\u0430:\\uD83D\\uDC31',\r\n    hi:'\\u0915\\u0941\\u0924\\u094D\\u0924\\u093E:\\uD83D\\uDC15\\n\\u092C\\u093F\\u0932\\u094D\\u0932\\u0940:\\uD83D\\uDC31'\r\n  };\r\n\r\n  var MEM_CURRENT_LANG = { code:'en', native:'English', en:'English' };\r\n\r\n  function applyLangToInput(ta, sampleText){\r\n    if(!ta||!sampleText)return;\r\n    var firstLine=(sampleText.split('\\n')[0]||'');\r\n    var script=window.pthILS.detectScript(firstLine),isRTL=window.pthILS.isRTL(firstLine);\r\n    window.pthILS.loadFont(script);\r\n    ta.style.fontFamily=window.pthILS.getFontStack(script);\r\n    ta.style.direction=isRTL?'rtl':'ltr';ta.style.textAlign=isRTL?'right':'left';\r\n  }\r\n\r\n  function buildLangPopup() {\r\n    if (document.getElementById('pth-mem-lang-overlay')) return;\r\n    var style = document.createElement('style');\r\n    style.textContent = [\r\n      '#pth-mem-lang-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(15,23,42,0.55);z-index:9999998;align-items:center;justify-content:center;padding:16px;}',\r\n      '#pth-mem-lang-overlay.pth-lo-open{display:flex;}',\r\n      '#pth-mem-lang-modal{background:#fff;border-radius:16px;width:100%;max-width:660px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}',\r\n      '.pth-lm-head{padding:20px 20px 0;flex-shrink:0;}',\r\n      '.pth-lm-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-sub{font-size:0.78rem;color:#334155;margin:0 0 12px;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-close{position:absolute;top:14px;right:14px;background:#f1f5f9;border:none;width:32px;height:32px;border-radius:50%;font-size:0.9rem;cursor:pointer;color:#334155;display:flex;align-items:center;justify-content:center;font-family:inherit;font-weight:700;}',\r\n      '.pth-lm-close:hover{background:#e2e8f0;}',\r\n      '.pth-lm-search-wrap{padding:0 16px 10px;flex-shrink:0;}',\r\n      '.pth-lm-search{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-family:Inter,system-ui,sans-serif;font-size:0.85rem;color:#1e293b;outline:none;background:#f8fafc;}',\r\n      '.pth-lm-search::placeholder{color:#94a3b8;}',\r\n      '.pth-lm-search:focus{border-color:#2563eb;background-color:#fff;}',\r\n      '.pth-lm-grid-wrap{overflow-y:auto;flex:1;padding:0 8px 8px;}',\r\n      '.pth-lm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}',\r\n      '.pth-lm-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:8px;cursor:pointer;border:2px solid transparent;font-family:Inter,system-ui,sans-serif;background:transparent;text-align:left;width:100%;transition:background 0.1s;}',\r\n      '.pth-lm-item:hover{background:#f1f5f9;}',\r\n      '.pth-lm-item.pth-lm-sel{background:#eff6ff;border-color:#bfdbfe;}',\r\n      '.pth-lm-flag{font-size:0.62rem;font-weight:800;line-height:1;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;text-align:center;background:#eff6ff;color:#1d4ed8;border-radius:5px;letter-spacing:0.3px;}',\r\n      '.pth-lm-names{display:flex;flex-direction:column;min-width:0;}',\r\n      '.pth-lm-native{font-size:0.82rem;font-weight:700;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}',\r\n      '.pth-lm-en{font-size:0.7rem;color:#334155;font-weight:500;}',\r\n      '.pth-lm-footer{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;background:#f8fafc;}',\r\n      '.pth-lm-footer-cur{font-size:0.8rem;color:#334155;font-family:Inter,system-ui,sans-serif;}',\r\n      '.pth-lm-footer-cur strong{color:#1d4ed8;}',\r\n      '.pth-lm-no-res{text-align:center;padding:24px;color:#334155;font-size:0.85rem;font-family:Inter,system-ui,sans-serif;display:none;}',\r\n      '@media(max-width:520px){.pth-lm-grid{grid-template-columns:repeat(2,1fr);}#pth-mem-lang-modal{border-radius:12px;max-height:92vh;}}',\r\n      '@media(max-width:360px){.pth-lm-grid{grid-template-columns:1fr;}}'\r\n    ].join('');\r\n    document.head.appendChild(style);\r\n\r\n    var overlay = document.createElement('div');\r\n    overlay.id = 'pth-mem-lang-overlay';\r\n    overlay.setAttribute('role','dialog');\r\n    overlay.setAttribute('aria-modal','true');\r\n    overlay.setAttribute('aria-label','Choose card language');\r\n    overlay.innerHTML =\r\n      '<div id=\"pth-mem-lang-modal\">' +\r\n        '<div class=\"pth-lm-head\">' +\r\n          '<p class=\"pth-lm-title\">&#x1F30D; Choose Card Language<\/p>' +\r\n          '<p class=\"pth-lm-sub\">Select language for sample Term:Match pairs<\/p>' +\r\n        '<\/div>' +\r\n        '<button class=\"pth-lm-close\" id=\"pth-mem-lm-close\" aria-label=\"Close\">&#x2715;<\/button>' +\r\n        '<div class=\"pth-lm-search-wrap\">' +\r\n          '<input type=\"text\" class=\"pth-lm-search\" id=\"pth-mem-lm-search\" placeholder=\"Search language...\" aria-label=\"Search language\" autocomplete=\"off\">' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-grid-wrap\">' +\r\n          '<div class=\"pth-lm-grid\" id=\"pth-mem-lm-grid\"><\/div>' +\r\n          '<div class=\"pth-lm-no-res\" id=\"pth-mem-lm-nores\">No languages found.<\/div>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-lm-footer\">' +\r\n          '<span class=\"pth-lm-footer-cur\">Selected: <strong id=\"pth-mem-lm-cur\">English<\/strong><\/span>' +\r\n          '<span style=\"font-size:0.72rem;color:#475569;\">&#x1F512; Browser only<\/span>' +\r\n        '<\/div>' +\r\n      '<\/div>';\r\n    document.body.appendChild(overlay);\r\n\r\n    renderLangGrid('');\r\n    var searchEl = document.getElementById('pth-mem-lm-search');\r\n    if (searchEl) searchEl.addEventListener('input', function() { renderLangGrid(searchEl.value.toLowerCase().trim()); });\r\n    var closeBtn = document.getElementById('pth-mem-lm-close');\r\n    if (closeBtn) closeBtn.addEventListener('click', closeLangPopup);\r\n    overlay.addEventListener('click', function(e) { if (e.target === overlay) closeLangPopup(); });\r\n    document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeLangPopup(); });\r\n  }\r\n\r\n  function renderLangGrid(query) {\r\n    var grid = document.getElementById('pth-mem-lm-grid');\r\n    var nores = document.getElementById('pth-mem-lm-nores');\r\n    if (!grid) return;\r\n    grid.innerHTML = '';\r\n    var filtered = MEM_LANGS.filter(function(l) {\r\n      if (!query) return true;\r\n      return l.en.toLowerCase().indexOf(query) !== -1 || l.native.toLowerCase().indexOf(query) !== -1 || l.code.indexOf(query) !== -1;\r\n    });\r\n    if (!filtered.length) { if (nores) nores.style.display = 'block'; return; }\r\n    if (nores) nores.style.display = 'none';\r\n    filtered.forEach(function(l) {\r\n      var btn = document.createElement('button');\r\n      btn.className = 'pth-lm-item' + (l.code === MEM_CURRENT_LANG.code ? ' pth-lm-sel' : '');\r\n      btn.innerHTML =\r\n        '<span class=\"pth-lm-flag\">' + l.code.toUpperCase() + '<\/span>' +\r\n        '<span class=\"pth-lm-names\"><span class=\"pth-lm-native\">' + l.native + '<\/span><span class=\"pth-lm-en\">' + l.en + '<\/span><\/span>';\r\n      btn.addEventListener('click', function() { selectLang(l); });\r\n      grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function selectLang(l) {\r\n    MEM_CURRENT_LANG = l;\r\n    var cur = document.getElementById('pth-mem-lm-cur');\r\n    if (cur) cur.innerHTML = l.code.toUpperCase() + ' ' + l.native + ' (' + l.en + ')';\r\n    updatePickerBtn();\r\n    if (MEM_SAMPLES[l.code]) {\r\n      var ta = document.getElementById('pth-mem-input');\r\n      if (ta) { ta.value = MEM_SAMPLES[l.code]; applyLangToInput(ta, MEM_SAMPLES[l.code]); }\r\n      window.pthILS.toast('Loaded: ' + l.native + ' (' + l.en + ')', 'success');\r\n    } else {\r\n      window.pthILS.toast(l.en + ' selected! Type your own pairs.', 'info');\r\n    }\r\n    var searchEl = document.getElementById('pth-mem-lm-search');\r\n    renderLangGrid(searchEl ? searchEl.value.toLowerCase().trim() : '');\r\n    closeLangPopup();\r\n  }\r\n\r\n  function openLangPopup() {\r\n    buildLangPopup();\r\n    var overlay = document.getElementById('pth-mem-lang-overlay');\r\n    if (overlay) {\r\n      overlay.classList.add('pth-lo-open');\r\n      var s = document.getElementById('pth-mem-lm-search');\r\n      if (s) { s.value=''; renderLangGrid(''); setTimeout(function(){ s.focus(); }, 100); }\r\n    }\r\n  }\r\n\r\n  function closeLangPopup() {\r\n    var overlay = document.getElementById('pth-mem-lang-overlay');\r\n    if (overlay) overlay.classList.remove('pth-lo-open');\r\n  }\r\n\r\n  function updatePickerBtn() {\r\n    var flag = document.getElementById('pth-mem-pick-flag');\r\n    var text = document.getElementById('pth-mem-pick-text');\r\n    if (flag) flag.innerHTML = MEM_CURRENT_LANG.code.toUpperCase();\r\n    if (text) text.innerHTML = MEM_CURRENT_LANG.native + ' \u2014 ' + MEM_CURRENT_LANG.en;\r\n  }\r\n\r\n  var MEM = {\r\n    pairs:[], cards:[], flipped:[], matched:0, flips:0,\r\n    timer:null, secs:0, locked:false,\r\n    bestTime:null, bestFlips:null\r\n  };\r\n\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-memory');\r\n    if (!panel || panel.getAttribute('data-mem-built')) return;\r\n    panel.setAttribute('data-mem-built','1');\r\n\r\n    panel.innerHTML =\r\n      '<div class=\"pth-ils-layout\" id=\"pth-mem-layout\">' +\r\n      '<div class=\"pth-ils-main\">' +\r\n\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F3B4; Memory Match Game<\/h3>' +\r\n          '<button class=\"pth-cw-lang-pick-btn\" id=\"pth-mem-lang-pick-btn\" aria-label=\"Choose card language\">' +\r\n            '<span class=\"pth-cw-lang-pick-flag\" id=\"pth-mem-pick-flag\">EN<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-text\" id=\"pth-mem-pick-text\">English \u2014 Card Language<\/span>' +\r\n            '<span class=\"pth-cw-lang-pick-arrow\">&#x25BC;<\/span>' +\r\n          '<\/button>' +\r\n          '<label class=\"pth-ils-label\" for=\"pth-mem-input\">Enter Term : Match pairs &#x2014; one per line (max 16)<\/label>' +\r\n          '<p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 6px;font-style:italic;\">&#x2139;&#xFE0F; The text below is just an example placeholder (not real data) &#x2014; type your own Term:Match pairs, or click &#x1F4A1; <strong>Load Sample<\/strong> above to fill in working examples.<\/p>' +\r\n          '<textarea class=\"pth-ils-textarea\" id=\"pth-mem-input\" aria-label=\"Term and match pairs\" style=\"min-height:130px;\"' +\r\n            ' placeholder=\"Dog:&#x1F415;&#10;Cat:&#x1F431;&#10;Sun:&#x2600;&#xFE0F;&#10;Moon:&#x1F319;&#10;Tree:&#x1F333;&#10;Fish:&#x1F41F;&#10;Star:&#x2B50;&#10;Heart:&#x2764;&#xFE0F;\"><\/textarea>' +\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-mem-start-btn\">&#x26A1; Start Game<\/button>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n        '<div class=\"pth-ils-card\" id=\"pth-mem-game-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F3B4; Memory Match<\/h3>' +\r\n          '<div class=\"pth-mem-stats\">' +\r\n            '<div class=\"pth-mem-stat\">&#x23F1; <span id=\"pth-mem-time\">0s<\/span><\/div>' +\r\n            '<div class=\"pth-mem-stat\">&#x1F504; Flips: <span id=\"pth-mem-flips\">0<\/span><\/div>' +\r\n            '<div class=\"pth-mem-stat\">&#x2705; <span id=\"pth-mem-matched\">0<\/span> \/ <span id=\"pth-mem-total\">0<\/span><\/div>' +\r\n          '<\/div>' +\r\n          '<div id=\"pth-mem-win\" style=\"display:none;\" class=\"pth-ils-ok\">&#x1F389; All pairs matched!<\/div>' +\r\n          '<div class=\"pth-mem-grid\" id=\"pth-mem-grid\"><\/div>' +\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-mem-reveal-btn\">&#x1F441; Reveal All<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-mem-restart-btn\">&#x1F504; Restart<\/button>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n        '<div class=\"pth-ils-card\" id=\"pth-mem-export-card\" style=\"display:none;\">' +\r\n          '<h3>&#x1F4E4; Export<\/h3>' +\r\n          '<div class=\"pth-ils-btn-row\">' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-mem-html-btn\">&#x1F4C4; Download HTML<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-mem-copy-btn\">&#x1F4CB; Copy HTML Code<\/button>' +\r\n            '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-mem-print-btn\">&#x1F5A8; Print Activity<\/button>' +\r\n          '<\/div>' +\r\n          '<div class=\"pth-ils-code-box\" id=\"pth-mem-code-box\" style=\"display:none;\">' +\r\n            '<textarea id=\"pth-mem-code-ta\" readonly aria-label=\"HTML code\" style=\"min-height:100px;\"><\/textarea>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n      '<\/div>' +\r\n\r\n      '<div class=\"pth-ils-sidebar\">' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4A1; How to Use<\/h3>' +\r\n          '<p style=\"font-size:0.82rem;color:#334155;line-height:1.6;margin:0;\">' +\r\n            '1. Enter <strong>Term:Match<\/strong> pairs.<br>' +\r\n            '2. Use emoji for fun cards! &#x1F3AE;<br>' +\r\n            '3. Click <strong>&#x26A1; Start Game<\/strong>.<br>' +\r\n            '4. Click cards to flip and find matches.<br>' +\r\n            '5. Match all pairs to win! &#x1F3C6;' +\r\n          '<\/p>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F3C6; Best Score<\/h3>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Best time<\/span><span class=\"pth-ils-stat-val\" id=\"pth-mem-best-time\">&#8212;<\/span><\/div>' +\r\n          '<div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Best flips<\/span><span class=\"pth-ils-stat-val\" id=\"pth-mem-best-flips\">&#8212;<\/span><\/div>' +\r\n        '<\/div>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n  }\r\n\r\n  function memStart() {\r\n    var raw   = (document.getElementById('pth-mem-input')||{}).value || '';\r\n    var pairs = window.pthILS.parsePairs(raw, ':');\r\n    if (pairs.length < 2) { window.pthILS.toast('Enter at least 2 Term:Match pairs.','error'); return; }\r\n    if (pairs.length > 16) pairs = pairs.slice(0, 16);\r\n    MEM.pairs = pairs;\r\n    memLaunch();\r\n  }\r\n\r\n  function memLaunch() {\r\n    var pairs = MEM.pairs;\r\n    \/* Build card array \u2014 2 cards per pair *\/\r\n    var cards = [];\r\n    pairs.forEach(function(p, i) {\r\n      cards.push({ id: i*2,   pairId: i, text: p.a, side: 'term'  });\r\n      cards.push({ id: i*2+1, pairId: i, text: p.b, side: 'match' });\r\n    });\r\n    MEM.cards   = window.pthILS.shuffle(cards);\r\n    MEM.flipped = [];\r\n    MEM.matched = 0;\r\n    MEM.flips   = 0;\r\n    MEM.locked  = false;\r\n    MEM.secs    = 0;\r\n    clearInterval(MEM.timer);\r\n\r\n    document.getElementById('pth-mem-game-card').style.display   = 'block';\r\n    document.getElementById('pth-mem-export-card').style.display = 'block';\r\n    var win = document.getElementById('pth-mem-win'); if (win) win.style.display='none';\r\n\r\n    memRenderGrid();\r\n\r\n    var tot = document.getElementById('pth-mem-total');   if (tot) tot.textContent = pairs.length;\r\n    var mc  = document.getElementById('pth-mem-matched'); if (mc)  mc.textContent  = 0;\r\n    var fl  = document.getElementById('pth-mem-flips');   if (fl)  fl.textContent  = 0;\r\n    var ti  = document.getElementById('pth-mem-time');    if (ti)  ti.textContent  = '0s';\r\n\r\n    MEM.timer = setInterval(function() {\r\n      MEM.secs++;\r\n      var t = document.getElementById('pth-mem-time'); if (t) t.textContent = MEM.secs + 's';\r\n    }, 1000);\r\n\r\n    window.pthILS.toast('Game started! Find matching pairs.','success');\r\n  }\r\n\r\n  function memRenderGrid() {\r\n    var grid = document.getElementById('pth-mem-grid'); if (!grid) return;\r\n    var cols = MEM.cards.length <= 8 ? 4 : MEM.cards.length <= 12 ? 4 : 4;\r\n    grid.style.gridTemplateColumns = 'repeat(' + cols + ', 1fr)';\r\n    grid.innerHTML = '';\r\n\r\n    MEM.cards.forEach(function(card, idx) {\r\n      var div = document.createElement('div');\r\n      div.className = 'pth-mem-card';\r\n      div.setAttribute('data-idx', idx);\r\n      div.setAttribute('role','button');\r\n      div.setAttribute('tabindex','0');\r\n      div.setAttribute('aria-label', 'Memory card ' + (idx+1));\r\n\r\n      var inner = document.createElement('div');\r\n      inner.className = 'pth-mem-inner';\r\n\r\n      var front = document.createElement('div');\r\n      front.className = 'pth-mem-front';\r\n      front.textContent = '\\uD83C\\uDCCF'; \/* \ud83c\udccf *\/\r\n\r\n      var back = document.createElement('div');\r\n      back.className = 'pth-mem-back';\r\n\r\n      \/* Multilingual font support *\/\r\n      if (window.pthILS.detectScript) {\r\n        var script = window.pthILS.detectScript(card.text);\r\n        var isRTL  = window.pthILS.isRTL ? window.pthILS.isRTL(card.text) : false;\r\n        if (window.pthILS.loadFont) window.pthILS.loadFont(script);\r\n        if (window.pthILS.getFontStack) back.style.fontFamily = window.pthILS.getFontStack(script);\r\n        if (isRTL) back.style.direction = 'rtl';\r\n      }\r\n      back.textContent = card.text;\r\n\r\n      inner.appendChild(front);\r\n      inner.appendChild(back);\r\n      div.appendChild(inner);\r\n\r\n      div.addEventListener('click', function(){ memFlip(idx); });\r\n      div.addEventListener('keydown', function(e){ if(e.key==='Enter'||e.key===' ') memFlip(idx); });\r\n      grid.appendChild(div);\r\n    });\r\n  }\r\n\r\n  function memFlip(idx) {\r\n    if (MEM.locked) return;\r\n    var card = MEM.cards[idx]; if (!card) return;\r\n    var grid = document.getElementById('pth-mem-grid'); if (!grid) return;\r\n    var cardEl = grid.querySelector('[data-idx=\"'+idx+'\"]'); if (!cardEl) return;\r\n    if (cardEl.classList.contains('mem-flipped') || cardEl.classList.contains('mem-matched')) return;\r\n\r\n    cardEl.classList.add('mem-flipped');\r\n    MEM.flipped.push(idx);\r\n    MEM.flips++;\r\n    var fl = document.getElementById('pth-mem-flips'); if (fl) fl.textContent = MEM.flips;\r\n\r\n    if (MEM.flipped.length === 2) {\r\n      MEM.locked = true;\r\n      var idx1 = MEM.flipped[0], idx2 = MEM.flipped[1];\r\n      var c1   = MEM.cards[idx1], c2 = MEM.cards[idx2];\r\n\r\n      if (c1.pairId === c2.pairId) {\r\n        \/* Match! *\/\r\n        setTimeout(function() {\r\n          var g = document.getElementById('pth-mem-grid'); if (!g) return;\r\n          var e1 = g.querySelector('[data-idx=\"'+idx1+'\"]');\r\n          var e2 = g.querySelector('[data-idx=\"'+idx2+'\"]');\r\n          if (e1) e1.classList.add('mem-matched');\r\n          if (e2) e2.classList.add('mem-matched');\r\n          MEM.matched++;\r\n          MEM.flipped = [];\r\n          MEM.locked  = false;\r\n          var mc = document.getElementById('pth-mem-matched'); if (mc) mc.textContent = MEM.matched;\r\n          window.pthILS.toast('Match! &#x2705;','success');\r\n          if (MEM.matched === MEM.pairs.length) memWin();\r\n        }, 500);\r\n      } else {\r\n        \/* No match \u2014 flip back *\/\r\n        setTimeout(function() {\r\n          var g = document.getElementById('pth-mem-grid'); if (!g) return;\r\n          var e1 = g.querySelector('[data-idx=\"'+idx1+'\"]');\r\n          var e2 = g.querySelector('[data-idx=\"'+idx2+'\"]');\r\n          if (e1) e1.classList.remove('mem-flipped');\r\n          if (e2) e2.classList.remove('mem-flipped');\r\n          MEM.flipped = [];\r\n          MEM.locked  = false;\r\n        }, 900);\r\n      }\r\n    }\r\n  }\r\n\r\n  function memReveal() {\r\n    if (!MEM.cards.length) { window.pthILS.toast('Start a game first!','error'); return; }\r\n    clearInterval(MEM.timer);\r\n    var grid = document.getElementById('pth-mem-grid'); if (!grid) return;\r\n    var els = grid.querySelectorAll('.pth-mem-card');\r\n    els.forEach(function(el) {\r\n      el.classList.add('mem-flipped','mem-matched');\r\n    });\r\n    MEM.matched = MEM.pairs.length;\r\n    var mc = document.getElementById('pth-mem-matched'); if (mc) mc.textContent = MEM.matched;\r\n    var win = document.getElementById('pth-mem-win'); if (win) { win.style.display='block'; win.textContent = '\\uD83D\\uDC41 All cards revealed'; }\r\n    window.pthILS.toast('All cards revealed!','info');\r\n  }\r\n\r\n  function memWin() {\r\n    clearInterval(MEM.timer);\r\n    var t = MEM.secs, f = MEM.flips;\r\n    if (MEM.bestTime === null || t < MEM.bestTime) {\r\n      MEM.bestTime = t;\r\n      var bt = document.getElementById('pth-mem-best-time'); if (bt) bt.textContent = t + 's';\r\n    }\r\n    if (MEM.bestFlips === null || f < MEM.bestFlips) {\r\n      MEM.bestFlips = f;\r\n      var bf = document.getElementById('pth-mem-best-flips'); if (bf) bf.textContent = f;\r\n    }\r\n    var win = document.getElementById('pth-mem-win');\r\n    if (win) { win.style.display='block'; win.textContent = '\\uD83C\\uDF89 All matched! Time: ' + t + 's | Flips: ' + f; }\r\n    window.pthILS.toast('\\uD83C\\uDF89 All pairs matched!','success');\r\n  }\r\n\r\n  function memBuildHTML() {\r\n    if (!MEM.pairs.length) return '';\r\n    var pairs = MEM.pairs;\r\n    var pairsJSON = JSON.stringify(pairs);\r\n\r\n    var html =\r\n      '<style>' +\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;color-adjust:exact;}' +\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;background:#eef2f9;color:#1e293b;min-height:100vh;display:flex;justify-content:center;padding:32px 16px;}' +\r\n      '.mm-page{width:100%;max-width:640px;background:#fff;border-radius:18px;box-shadow:0 10px 30px -10px rgba(15,23,42,0.18);padding:30px 34px 34px;}' +\r\n      '.mm-head{text-align:center;margin:0 0 14px;}' +\r\n      'h1{color:#1d4ed8;font-size:1.5rem;font-weight:800;margin:0 0 6px;}' +\r\n      '.mm-sub{color:#334155;font-size:0.85rem;margin:0;}' +\r\n      '.stats{display:flex;gap:10px;margin-bottom:18px;flex-wrap:wrap;justify-content:center;}' +\r\n      '.stat{background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;padding:8px 14px;font-size:0.82rem;font-weight:700;color:#1d4ed8;}' +\r\n      '.grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;}' +\r\n      '.card{height:80px;border-radius:8px;cursor:pointer;perspective:600px;}' +\r\n      '.inner{width:100%;height:100%;position:relative;transform-style:preserve-3d;transition:transform 0.35s;border-radius:8px;}' +\r\n      '.card.flipped .inner{transform:rotateY(180deg);}' +\r\n      '.front,.back{position:absolute;width:100%;height:100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:0.82rem;font-weight:700;padding:8px;text-align:center;word-break:break-word;}' +\r\n      '.front{background:#2563eb;color:#fff;font-size:1.5rem;}' +\r\n      '.back{background:#fff;border:2px solid #e2e8f0;color:#0f172a;transform:rotateY(180deg);}' +\r\n      '.card.matched .back{background:#f0fdf4;border-color:#059669;color:#047857;}' +\r\n      '.win{display:none;margin-top:16px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;padding:12px;color:#047857;font-weight:700;text-align:center;}' +\r\n      '.mm-footer-btns{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:22px 0 4px;padding-top:18px;border-top:2px solid #e2e8f0;}' +\r\n      '.btn{padding:9px 18px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.06);}' +\r\n      '.btn-b{background:#fff;border:2px solid #e2e8f0;color:#334155;}' +\r\n      '.btn-c{background:#7c3aed;color:#fff;}' +\r\n      '@media(max-width:480px){.grid{grid-template-columns:repeat(3,1fr);}.mm-page{padding:20px 16px 26px;border-radius:12px;}}' +\r\n      '@media print{body{margin:0;background:#fff;padding:0;display:block;}.mm-page{box-shadow:none;border-radius:0;max-width:100%;padding:10px;}.mm-footer-btns,#mt{display:none!important;}.grid{break-inside:avoid;}.card .inner{transform:rotateY(180deg)!important;}}' +\r\n      '<\/style>' +\r\n      '<div class=\"mm-page\">' +\r\n      '<div class=\"mm-head\">' +\r\n      '<h2>&#x1F3B4; Memory Match Game<\/h2>' +\r\n      '<p class=\"mm-sub\">Flip cards to find matching pairs.<\/p>' +\r\n      '<\/div>' +\r\n      '<div class=\"stats\"><div class=\"stat\">&#x23F1; <span id=\"mt\">0s<\/span><\/div><div class=\"stat\">&#x1F504; <span id=\"mf\">0<\/span> flips<\/div><div class=\"stat\">&#x2705; <span id=\"mm\">0<\/span>\/' + pairs.length + '<\/div><\/div>' +\r\n      '<div class=\"win\" id=\"win\"><\/div>' +\r\n      '<div class=\"grid\" id=\"grid\"><\/div>' +\r\n      '<div class=\"mm-footer-btns\">' +\r\n      '<button class=\"btn btn-b\" id=\"btn-reveal\">&#x1F441; Reveal All<\/button>' +\r\n      '<button class=\"btn btn-b\" id=\"btn-restart\">&#x1F504; Restart<\/button>' +\r\n      '<button class=\"btn btn-c\" id=\"btn-print\">&#x1F5A8; Print Activity<\/button>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n\r\n    var sc = [\r\n      '(function(){',\r\n        'var pairs=' + pairsJSON + ';',\r\n        'var cards=[],flipped=[],matched=0,flips=0,locked=false,secs=0,ti=null;',\r\n        'var g=document.getElementById(\"grid\");',\r\n        'function startTimer(){clearInterval(ti);secs=0;ti=setInterval(function(){secs++;var t=document.getElementById(\"mt\");if(t)t.textContent=secs+\"s\";},1000);}',\r\n        'function buildCards(){',\r\n          'cards=[];pairs.forEach(function(p,i){cards.push({id:i*2,pi:i,t:p.a});cards.push({id:i*2+1,pi:i,t:p.b});});',\r\n          'cards=cards.sort(function(){return Math.random()-0.5;});',\r\n          'flipped=[];matched=0;flips=0;locked=false;',\r\n          'var mf=document.getElementById(\"mf\");if(mf)mf.textContent=\"0\";',\r\n          'var mm=document.getElementById(\"mm\");if(mm)mm.textContent=\"0\";',\r\n          'var w=document.getElementById(\"win\");if(w)w.style.display=\"none\";',\r\n          'g.innerHTML=\"\";',\r\n          'cards.forEach(function(card,idx){',\r\n            'var d=document.createElement(\"div\");d.className=\"card\";d.setAttribute(\"data-idx\",idx);',\r\n            'var inner=document.createElement(\"div\");inner.className=\"inner\";',\r\n            'var f=document.createElement(\"div\");f.className=\"front\";f.textContent=\"\\uD83C\\uDCCF\";',\r\n            'var b=document.createElement(\"div\");b.className=\"back\";b.textContent=card.t;',\r\n            'inner.appendChild(f);inner.appendChild(b);d.appendChild(inner);',\r\n            'd.addEventListener(\"click\",function(){',\r\n              'if(locked||d.classList.contains(\"flipped\")||d.classList.contains(\"matched\"))return;',\r\n              'd.classList.add(\"flipped\");flipped.push(idx);flips++;',\r\n              'var mf=document.getElementById(\"mf\");if(mf)mf.textContent=flips;',\r\n              'if(flipped.length===2){locked=true;',\r\n                'var i1=flipped[0],i2=flipped[1];',\r\n                'var c1=cards[i1],c2=cards[i2];',\r\n                'if(c1.pi===c2.pi){setTimeout(function(){',\r\n                  'var e1=g.querySelector(\"[data-idx=\\'\"+i1+\"\\']\");',\r\n                  'var e2=g.querySelector(\"[data-idx=\\'\"+i2+\"\\']\");',\r\n                  'if(e1)e1.classList.add(\"matched\");if(e2)e2.classList.add(\"matched\");',\r\n                  'matched++;var mm=document.getElementById(\"mm\");if(mm)mm.textContent=matched;',\r\n                  'flipped=[];locked=false;',\r\n                  'if(matched===pairs.length){clearInterval(ti);var w=document.getElementById(\"win\");if(w){w.style.display=\"block\";w.textContent=\"\\uD83C\\uDF89 All matched! Time: \"+secs+\"s | Flips: \"+flips;}}',\r\n                '},500);}',\r\n                'else{setTimeout(function(){',\r\n                  'var e1=g.querySelector(\"[data-idx=\\'\"+i1+\"\\']\");',\r\n                  'var e2=g.querySelector(\"[data-idx=\\'\"+i2+\"\\']\");',\r\n                  'if(e1)e1.classList.remove(\"flipped\");if(e2)e2.classList.remove(\"flipped\");',\r\n                  'flipped=[];locked=false;',\r\n                '},900);}',\r\n              '}',\r\n            '});',\r\n            'g.appendChild(d);',\r\n          '});',\r\n        '}',\r\n        'buildCards();startTimer();',\r\n        'document.getElementById(\"btn-reveal\").addEventListener(\"click\",function(){',\r\n          'clearInterval(ti);',\r\n          'g.querySelectorAll(\".card\").forEach(function(c){c.classList.add(\"flipped\",\"matched\");});',\r\n          'matched=pairs.length;var mm=document.getElementById(\"mm\");if(mm)mm.textContent=matched;',\r\n          'var w=document.getElementById(\"win\");if(w){w.style.display=\"block\";w.textContent=\"\\uD83D\\uDC41 All cards revealed\";}',\r\n        '});',\r\n        'document.getElementById(\"btn-restart\").addEventListener(\"click\",function(){buildCards();startTimer();});',\r\n        'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n\r\n    var so='<'+'script'+'>';\r\n    var sc2='<'+'\/'+'script'+'>';\r\n    var docOpen='<'+'!DOCTYPE html>'+'<'+'html lang=\"en\">'+'<'+'head>'+\r\n      '<'+'meta charset=\"UTF-8\">'+\r\n      '<'+'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">'+\r\n      '<'+'title>Memory Match Game<'+'\/title>'+\r\n      '<'+'\/head>'+'<'+'body>';\r\n    var docClose='<'+'\/'+'body>'+'<'+'\/'+'html>';\r\n    return docOpen + html + so + sc + sc2 + docClose;\r\n  }\r\n\r\n  function wireEvents() {\r\n    var b = function(id,fn){ var el=document.getElementById(id); if(el)el.addEventListener('click',fn); };\r\n    b('pth-mem-start-btn',   memStart);\r\n    b('pth-mem-lang-pick-btn', openLangPopup);\r\n    b('pth-mem-reveal-btn',  memReveal);\r\n    b('pth-mem-restart-btn', function(){ if(!MEM.pairs.length){window.pthILS.toast('Start a game first!','error');return;} clearInterval(MEM.timer); memLaunch(); });\r\n    b('pth-mem-html-btn', function(){\r\n      var c=memBuildHTML();if(!c){window.pthILS.toast('Start game first!','error');return;}\r\n      try {\r\n        var blob=new Blob([c],{type:'text\/html'});\r\n        var url=URL.createObjectURL(blob);\r\n        var a=document.createElement('a');\r\n        a.href=url;a.download='memory-match-game.html';\r\n        document.body.appendChild(a);a.click();document.body.removeChild(a);\r\n        setTimeout(function(){URL.revokeObjectURL(url);},2000);\r\n        window.pthILS.toast('HTML file downloaded!','success');\r\n      } catch(err) { window.pthILS.toast('Download failed: '+err.message,'error'); }\r\n    });\r\n    b('pth-mem-print-btn', function(){\r\n      var c=memBuildHTML();if(!c){window.pthILS.toast('Start game first!','error');return;}\r\n      var w = window.open('','_blank');\r\n      if (!w) { window.pthILS.toast('Popup blocked! Allow popups for this site to print.','error'); return; }\r\n      w.document.open();w.document.write(c);w.document.close();\r\n      var printed=false;\r\n      function doPrint(){ if(printed)return; printed=true; w.focus(); w.print(); }\r\n      w.addEventListener('load', function(){ setTimeout(doPrint,150); });\r\n      setTimeout(doPrint,1200);\r\n    });\r\n    b('pth-mem-copy-btn',    function(){ var c=memBuildHTML();if(!c){window.pthILS.toast('Start game first!','error');return;}window.pthILS.showCopyHTML(c,'pth-mem-code-box'); });\r\n\r\n    document.addEventListener('pthILSClear', function(e) {\r\n      if (e.detail.tab !== 'memory') return;\r\n      var ta=document.getElementById('pth-mem-input'); if(ta)ta.value='';\r\n      var gc=document.getElementById('pth-mem-game-card');   if(gc)gc.style.display='none';\r\n      var ec=document.getElementById('pth-mem-export-card'); if(ec)ec.style.display='none';\r\n      clearInterval(MEM.timer);\r\n      MEM.pairs=[]; MEM.matched=0; MEM.flips=0; MEM.secs=0;\r\n    });\r\n\r\n    document.addEventListener('pthILSSample', function(e) {\r\n      if (e.detail.tab !== 'memory') return;\r\n      var ta=document.getElementById('pth-mem-input');\r\n      if(ta){ ta.value='Apple:\\uD83C\\uDF4E\\nBanana:\\uD83C\\uDF4C\\nGrapes:\\uD83C\\uDF47\\nOrange:\\uD83C\\uDF4A\\nStrawberry:\\uD83C\\uDF53\\nPineapple:\\uD83C\\uDF4D\\nWatermelon:\\uD83C\\uDF49\\nMango:\\uD83E\\uDD6D'; applyLangToInput(ta, ta.value); window.pthILS.toast('Sample loaded! Click Start Game.','success'); }\r\n    });\r\n  }\r\n\r\n  function init() { buildTabHTML(); setTimeout(function(){ wireEvents(); }, 100); }\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v2.0 \u2014 AI Assistant Tab v2 (Multi-Platform) -->\r\n\r\n<style>\r\n\/* \u2500\u2500 Provider tabs \u2500\u2500 *\/\r\n.pth-ai-pvtabs {\r\n  display: grid;\r\n  grid-template-columns: repeat(3, 1fr);\r\n  gap: 8px;\r\n  margin-bottom: 14px;\r\n}\r\n.pth-ai-pvtab {\r\n  border: 2px solid #e2e8f0;\r\n  background: #f8fafc;\r\n  border-radius: 10px;\r\n  padding: 10px 6px;\r\n  cursor: pointer;\r\n  text-align: center;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  transition: border-color 0.15s, background 0.15s;\r\n}\r\n.pth-ai-pvtab:hover   { border-color: #6d28d9; background: #f5f3ff; }\r\n.pth-ai-pvtab.pv-sel  { border-color: #6d28d9; background: #ede9fe; }\r\n.pth-ai-pvicon { font-size: 1.4rem; display: block; margin-bottom: 4px; }\r\n.pth-ai-pvname { font-size: 0.78rem; font-weight: 800; color: #0f172a; display: block; }\r\n.pth-ai-pvtag  {\r\n  font-size: 0.62rem; font-weight: 700; padding: 1px 7px;\r\n  border-radius: 999px; display: inline-block; margin-top: 3px;\r\n}\r\n.pth-ai-pvtag.free { background: rgba(16,185,129,.12); color: #047857; border: 1px solid rgba(16,185,129,.25); }\r\n.pth-ai-pvtag.paid { background: rgba(245,158,11,.1);  color: #92400e; border: 1px solid rgba(245,158,11,.25); }\r\n\r\n\/* \u2500\u2500 Key input area \u2500\u2500 *\/\r\n.pth-ai-pvinfo {\r\n  background: #f8fafc;\r\n  border: 1px solid #e2e8f0;\r\n  border-radius: 8px;\r\n  padding: 10px 14px;\r\n  margin-bottom: 12px;\r\n  font-size: 0.78rem;\r\n  color: #334155;\r\n  line-height: 1.7;\r\n}\r\n.pth-ai-pvinfo strong { color: #6d28d9; }\r\n.pth-ai-pvinfo a      { color: #2563eb; text-decoration: none; font-weight: 700; }\r\n.pth-ai-key-wrap { position: relative; margin-bottom: 10px; }\r\n.pth-ai-kinput {\r\n  width: 100%;\r\n  padding: 10px 44px 10px 12px;\r\n  border: 2px solid #e2e8f0;\r\n  border-radius: 8px;\r\n  font-family: 'Courier New', monospace;\r\n  font-size: 0.82rem;\r\n  color: #0f172a;\r\n  background: #fff;\r\n  outline: none;\r\n  transition: border-color 0.15s;\r\n  box-sizing: border-box;\r\n}\r\n.pth-ai-kinput:focus { border-color: #6d28d9; box-shadow: 0 0 0 3px rgba(109,40,217,0.1); }\r\n.pth-ai-eyebtn {\r\n  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);\r\n  background: none; border: none; cursor: pointer; color: #94a3b8;\r\n  font-size: 1rem; padding: 4px; font-family: inherit;\r\n}\r\n.pth-ai-eyebtn:hover { color: #334155; }\r\n.pth-ai-save-row {\r\n  display: flex; gap: 8px; align-items: center; margin-bottom: 6px;\r\n}\r\n.pth-ai-save-btn {\r\n  background: #6d28d9; color: #fff; border: none;\r\n  padding: 8px 18px; border-radius: 7px;\r\n  font-family: inherit; font-size: 0.82rem; font-weight: 700;\r\n  cursor: pointer; white-space: nowrap;\r\n}\r\n.pth-ai-save-btn:hover { background: #5b21b6; }\r\n.pth-ai-key-status {\r\n  font-size: 0.75rem; font-weight: 700; padding: 3px 10px;\r\n  border-radius: 20px; display: none;\r\n}\r\n.pth-ai-key-status.ks-ok  { background: #f0fdf4; color: #047857; border: 1px solid #bbf7d0; display: inline-block; }\r\n.pth-ai-key-status.ks-no  { background: #fef2f2; color: #991b1b; border: 1px solid #fecaca; display: inline-block; }\r\n\r\n\/* \u2500\u2500 Target activity tabs \u2500\u2500 *\/\r\n.pth-ai-target-grid {\r\n  display: grid;\r\n  grid-template-columns: repeat(5, 1fr);\r\n  gap: 8px;\r\n  margin-bottom: 14px;\r\n}\r\n@media (max-width: 768px) { .pth-ai-target-grid { grid-template-columns: repeat(3, 1fr); } }\r\n@media (max-width: 480px) { .pth-ai-target-grid { grid-template-columns: repeat(2, 1fr); } }\r\n.pth-ai-target-btn {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 8px;\r\n  padding: 9px 11px;\r\n  background: #fff;\r\n  border: 2px solid #e2e8f0;\r\n  border-radius: 8px;\r\n  cursor: pointer;\r\n  font-family: 'Inter', system-ui, sans-serif;\r\n  font-size: 0.8rem;\r\n  font-weight: 700;\r\n  color: #334155;\r\n  transition: all 0.15s;\r\n  text-align: left;\r\n}\r\n.pth-ai-target-btn:hover  { border-color: #2563eb; color: #1d4ed8; background: #eff6ff; }\r\n.pth-ai-target-btn.ai-sel { border-color: #2563eb; background: #dbeafe; color: #1d4ed8; }\r\n.pth-ai-ticon { font-size: 1rem; flex-shrink: 0; }\r\n\r\n\/* \u2500\u2500 Template chips \u2500\u2500 *\/\r\n.pth-ai-tpl-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }\r\n.pth-ai-tpl-btn {\r\n  background: #f1f5f9; border: 1px solid #e2e8f0;\r\n  border-radius: 20px; padding: 4px 11px;\r\n  font-size: 0.76rem; font-weight: 700; color: #334155;\r\n  cursor: pointer; font-family: inherit; transition: all 0.12s;\r\n}\r\n.pth-ai-tpl-btn:hover    { background: #eff6ff; border-color: #bfdbfe; color: #1d4ed8; }\r\n.pth-ai-tpl-btn.tpl-sel  { background: #eff6ff; border-color: #bfdbfe; color: #1d4ed8; }\r\n\r\n\/* \u2500\u2500 Loading \u2500\u2500 *\/\r\n.pth-ai-loading-box {\r\n  display: flex; align-items: center; gap: 10px;\r\n  padding: 13px 16px; background: #eff6ff;\r\n  border: 1px solid #bfdbfe; border-radius: 8px;\r\n  color: #1d4ed8; font-size: 0.85rem; font-weight: 700;\r\n  font-family: inherit; margin-top: 10px;\r\n}\r\n.pth-ai-dots span {\r\n  display: inline-block; width: 7px; height: 7px;\r\n  background: #2563eb; border-radius: 50%; margin: 0 2px;\r\n  animation: pthDot 1.2s infinite;\r\n}\r\n.pth-ai-dots span:nth-child(2) { animation-delay: 0.2s; }\r\n.pth-ai-dots span:nth-child(3) { animation-delay: 0.4s; }\r\n@keyframes pthDot {\r\n  0%,80%,100%{ transform:scale(0.6); opacity:0.4; }\r\n  40%        { transform:scale(1);   opacity:1;   }\r\n}\r\n\r\n\/* \u2500\u2500 Output preview \u2500\u2500 *\/\r\n.pth-ai-preview-box {\r\n  background: #0f172a;\r\n  border-radius: 8px;\r\n  padding: 14px;\r\n  margin-top: 8px;\r\n  max-height: 280px;\r\n  overflow-y: auto;\r\n}\r\n.pth-ai-preview-box pre {\r\n  color: #7dd3fc;\r\n  font-family: 'Courier New', monospace;\r\n  font-size: 0.8rem;\r\n  margin: 0;\r\n  white-space: pre-wrap;\r\n  word-break: break-word;\r\n  line-height: 1.6;\r\n}\r\n\r\n\/* \u2500\u2500 History \u2500\u2500 *\/\r\n.pth-ai-hist-item {\r\n  display: flex; align-items: center; justify-content: space-between;\r\n  padding: 8px 12px; border: 1px solid #e2e8f0;\r\n  border-radius: 8px; margin-bottom: 6px;\r\n  font-size: 0.8rem; background: #fff; font-family: inherit;\r\n  gap: 10px;\r\n}\r\n.pth-ai-hist-topic { color: #0f172a; font-weight: 700; }\r\n.pth-ai-hist-meta  { color: #94a3b8; font-size: 0.72rem; }\r\n.pth-ai-hist-use {\r\n  background: #eff6ff; border: 1px solid #bfdbfe;\r\n  border-radius: 6px; padding: 3px 10px;\r\n  font-size: 0.72rem; font-weight: 700; color: #1d4ed8;\r\n  cursor: pointer; font-family: inherit; flex-shrink: 0;\r\n  white-space: nowrap;\r\n}\r\n.pth-ai-hist-use:hover { background: #dbeafe; }\r\n<\/style>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function () {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function () { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  \/* ============================================================\r\n     PROVIDERS DEFINITION\r\n     ============================================================ *\/\r\n  var AI_PROVS = [\r\n    {\r\n      id:      'gemini',\r\n      icon:    '&#x1F4A0;',\r\n      name:    'Gemini Flash',\r\n      tag:     'FREE',\r\n      tagCls:  'free',\r\n      info:    '<strong>Google Gemini 2.0 Flash<\/strong> \u2014 Free, no credit card needed.<br>Get free key &#x2192; <a href=\"https:\/\/aistudio.google.com\/app\/apikey\" target=\"_blank\" rel=\"noopener\">aistudio.google.com<\/a>',\r\n      ph:      'AIza...',\r\n      models:  ['gemini-2.5-flash','gemini-2.0-flash','gemini-1.5-flash','gemini-1.5-flash-latest','gemini-1.5-flash-8b']\r\n    },\r\n    {\r\n      id:      'groq',\r\n      icon:    '&#x26A1;',\r\n      name:    'Groq \/ Llama',\r\n      tag:     'FREE',\r\n      tagCls:  'free',\r\n      info:    '<strong>Groq \u2014 Llama 3.3 70B<\/strong> \u2014 Extremely fast, free tier available.<br>Get free key &#x2192; <a href=\"https:\/\/console.groq.com\/keys\" target=\"_blank\" rel=\"noopener\">console.groq.com<\/a>',\r\n      ph:      'gsk_...',\r\n      models:  ['llama-3.3-70b-versatile','llama-3.1-70b-versatile','llama3-70b-8192','mixtral-8x7b-32768','llama3-8b-8192']\r\n    },\r\n    {\r\n      id:      'claude',\r\n      icon:    '&#x1F9E0;',\r\n      name:    'Claude',\r\n      tag:     'PAID',\r\n      tagCls:  'paid',\r\n      info:    '<strong>Anthropic Claude Sonnet 4.6<\/strong> \u2014 Most intelligent, best quality output.<br>Get key &#x2192; <a href=\"https:\/\/console.anthropic.com\/\" target=\"_blank\" rel=\"noopener\">console.anthropic.com<\/a>',\r\n      ph:      'sk-ant-...',\r\n      models:  ['claude-sonnet-4-6']\r\n    }\r\n  ];\r\n\r\n  \/* Target activity tabs *\/\r\n  var AI_TARGETS = [\r\n    { id:'crossword',  icon:'&#x1F9E9;', label:'Crossword',      desc:'WORD:Clue pairs' },\r\n    { id:'wordsearch', icon:'&#x1F50D;', label:'Word Search',    desc:'Word list' },\r\n    { id:'sort',       icon:'&#x1F501;', label:'Drag &amp; Sort',    desc:'Ordered steps' },\r\n    { id:'match',      icon:'&#x1F517;', label:'Match Pairs',    desc:'Term:Definition' },\r\n    { id:'memory',     icon:'&#x1F3B4;', label:'Memory Match',   desc:'Term:Match pairs' },\r\n    { id:'hotspots',   icon:'&#x1F5BC;', label:'Image Hotspots', desc:'Pin title:description' },\r\n    { id:'blanks',     icon:'&#x1F4DD;', label:'Fill in Blanks', desc:'Paragraph with [blanks]' },\r\n    { id:'bingo',      icon:'&#x1F522;', label:'Bingo Maker',    desc:'Word list (1-3 words)' },\r\n    { id:'flashcards', icon:'&#x1F4C7;', label:'Flashcards',     desc:'Term:Definition' },\r\n    { id:'cryptogram', icon:'&#x1F575;', label:'Cryptogram',     desc:'Short quote + author' }\r\n  ];\r\n\r\n  \/* Quick topics per target *\/\r\n  var AI_TPLS = {\r\n    crossword:  ['Solar System','World War 2','Human Body','Programming','Shakespeare','Climate Change','Ancient Egypt','Mathematics'],\r\n    wordsearch: ['Animals','Countries','Sports','Food & Cooking','Science Lab','Music Genres','Ocean Life','Geography'],\r\n    sort:       ['Baking a Cake','Scientific Method','Writing an Essay','Plant Life Cycle','Water Cycle','Making Tea','Building a Website','Solving an Equation'],\r\n    match:      ['Capital Cities','Chemical Elements','Famous Scientists','Literary Works','Historical Events','Tech Terms','Musical Instruments','Art Movements'],\r\n    memory:     ['Animals & Sounds','Flags & Countries','Words & Emojis','Scientists & Inventions','Countries & Capitals','Fruits & Colors','Planets & Features','Jobs & Tools'],\r\n    hotspots:   ['Human Anatomy','World Map','Solar System Diagram','Cell Structure','Water Cycle','Computer Parts','Volcano Diagram','Ecosystem'],\r\n    blanks:     ['Photosynthesis','Water Cycle','Solar System','Human Digestion','Electricity','Climate Change','DNA & Genetics','Ecosystem'],\r\n    bingo:      ['Space Exploration','Animals','World Countries','Science Terms','Music Instruments','Food & Cooking','Sports','Ocean Life'],\r\n    flashcards: ['Programming Terms','Biology Vocabulary','Historical Events','Chemistry Elements','Geography Facts','Literature','Math Concepts','Physics Laws'],\r\n    cryptogram: ['Success & Motivation','Science & Discovery','Literature & Poetry','Wisdom & Philosophy','Education','Courage','Creativity','Leadership']\r\n  };\r\n\r\n  \/* App state *\/\r\n  var AI = {\r\n    prov:       'gemini',\r\n    target:     'crossword',\r\n    history:    [],\r\n    loading:    false,\r\n    lastResult: ''\r\n  };\r\n\r\n  \/* ============================================================\r\n     KEY STORAGE \u2014 sessionStorage per provider (like Tool 67)\r\n     ============================================================ *\/\r\n  function getKey(prov) {\r\n    try { return sessionStorage.getItem('pthils_k_' + (prov||AI.prov)) || ''; } catch(e) { return ''; }\r\n  }\r\n  function saveKey(prov, key) {\r\n    try { sessionStorage.setItem('pthils_k_' + (prov||AI.prov), key); } catch(e) {}\r\n  }\r\n  function clearKey(prov) {\r\n    try { sessionStorage.removeItem('pthils_k_' + (prov||AI.prov)); } catch(e) {}\r\n  }\r\n\r\n  \/* ============================================================\r\n     BUILD TAB HTML\r\n     ============================================================ *\/\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-ai');\r\n    if (!panel || panel.getAttribute('data-ai-built')) return;\r\n    panel.setAttribute('data-ai-built','1');\r\n\r\n    \/* Provider tabs *\/\r\n    var provHTML = '';\r\n    AI_PROVS.forEach(function(p) {\r\n      var hasSaved = getKey(p.id) ? ' &#x2705;' : '';\r\n      provHTML +=\r\n        '<div class=\"pth-ai-pvtab' + (p.id===AI.prov?' pv-sel':'') + '\" data-pv=\"' + p.id + '\" role=\"button\" tabindex=\"0\" aria-label=\"' + p.name + '\">' +\r\n          '<span class=\"pth-ai-pvicon\">' + p.icon + '<\/span>' +\r\n          '<span class=\"pth-ai-pvname\" id=\"pth-ai-pvn-' + p.id + '\">' + p.name + hasSaved + '<\/span>' +\r\n          '<span class=\"pth-ai-pvtag ' + p.tagCls + '\">' + p.tag + '<\/span>' +\r\n        '<\/div>';\r\n    });\r\n\r\n    \/* Target buttons *\/\r\n    var targetHTML = '';\r\n    AI_TARGETS.forEach(function(t) {\r\n      targetHTML +=\r\n        '<button class=\"pth-ai-target-btn' + (t.id==='crossword'?' ai-sel':'') + '\" data-target=\"' + t.id + '\">' +\r\n          '<span class=\"pth-ai-ticon\">' + t.icon + '<\/span>' +\r\n          '<span><div>' + t.label + '<\/div><div style=\"font-size:0.68rem;color:#94a3b8;font-weight:500;\">' + t.desc + '<\/div><\/span>' +\r\n        '<\/button>';\r\n    });\r\n\r\n    panel.innerHTML =\r\n      '<div class=\"pth-ils-layout\" id=\"pth-ai-layout\">' +\r\n      '<div class=\"pth-ils-main\">' +\r\n\r\n      \/* \u2500\u2500 CARD 1: AI Provider \u2500\u2500 *\/\r\n      '<div class=\"pth-ils-card\">' +\r\n        '<h3>&#x1F916; AI Provider<\/h3>' +\r\n        '<p style=\"font-size:0.8rem;color:#334155;margin:0 0 12px;\">Choose your AI platform. <strong>Gemini &amp; Groq are FREE!<\/strong><\/p>' +\r\n        '<div class=\"pth-ai-pvtabs\" id=\"pth-ai-pvtabs\">' + provHTML + '<\/div>' +\r\n        \/* Provider info box *\/\r\n        '<div class=\"pth-ai-pvinfo\" id=\"pth-ai-pvinfo\"><\/div>' +\r\n        \/* Key input *\/\r\n        '<div class=\"pth-ai-key-wrap\">' +\r\n          '<input type=\"password\" class=\"pth-ai-kinput\" id=\"pth-ai-kinput\" placeholder=\"\" aria-label=\"API Key\">' +\r\n          '<button class=\"pth-ai-eyebtn\" id=\"pth-ai-eyebtn\" aria-label=\"Show\/hide key\">&#x1F441;<\/button>' +\r\n        '<\/div>' +\r\n        '<div class=\"pth-ai-save-row\">' +\r\n          '<button class=\"pth-ai-save-btn\" id=\"pth-ai-save-btn\">&#x1F4BE; Save Key<\/button>' +\r\n          '<span class=\"pth-ai-key-status\" id=\"pth-ai-key-status\"><\/span>' +\r\n          '<button class=\"pth-ils-btn pth-ils-btn-outline pth-ils-btn-sm\" id=\"pth-ai-clear-btn\" style=\"margin-left:auto;\">&#x1F5D1; Clear Key<\/button>' +\r\n        '<\/div>' +\r\n        '<p style=\"font-size:0.74rem;color:#94a3b8;margin:0;line-height:1.5;\">' +\r\n          '&#x1F512; Keys stored in <code style=\"background:#f1f5f9;padding:1px 5px;border-radius:3px;\">sessionStorage<\/code> only &#x2014; clears when tab closes, never sent to PTH servers.' +\r\n        '<\/p>' +\r\n      '<\/div>' +\r\n\r\n      \/* \u2500\u2500 CARD 2: Target Tab \u2500\u2500 *\/\r\n      '<div class=\"pth-ils-card\">' +\r\n        '<h3>&#x1F3AF; Fill Which Activity?<\/h3>' +\r\n        '<div class=\"pth-ai-target-grid\" id=\"pth-ai-target-grid\">' + targetHTML + '<\/div>' +\r\n      '<\/div>' +\r\n\r\n      \/* \u2500\u2500 CARD 3: Topic & Generate \u2500\u2500 *\/\r\n      '<div class=\"pth-ils-card\">' +\r\n        '<h3>&#x1F4DA; Topic &amp; Generate<\/h3>' +\r\n\r\n        \/* Quick template chips *\/\r\n        '<label class=\"pth-ils-label\" style=\"margin-bottom:6px;\">Quick topics:<\/label>' +\r\n        '<div class=\"pth-ai-tpl-row\" id=\"pth-ai-tpl-row\"><\/div>' +\r\n\r\n        \/* Topic input *\/\r\n        '<label class=\"pth-ils-label\" for=\"pth-ai-topic\">Topic (any language)<\/label>' +\r\n        '<input type=\"text\" class=\"pth-ils-input\" id=\"pth-ai-topic\" ' +\r\n          'placeholder=\"Solar System \/ &#x0DC3;&#x0DDC;&#x0DBD;&#x0DA4; &#x0DB8;&#x0DAB;&#x0DA9;&#x0DBD; \/ &#x592A;&#x967D;&#x7CFB;...\" ' +\r\n          'aria-label=\"Topic\">' +\r\n\r\n        \/* Count + Language *\/\r\n        '<div style=\"display:flex;gap:10px;flex-wrap:wrap;\">' +\r\n          '<div style=\"flex:1;min-width:110px;\">' +\r\n            '<label class=\"pth-ils-label\" for=\"pth-ai-count\">Items<\/label>' +\r\n            '<select class=\"pth-ils-select\" id=\"pth-ai-count\" aria-label=\"Item count\">' +\r\n              '<option value=\"6\">6 items<\/option>' +\r\n              '<option value=\"8\" selected>8 items<\/option>' +\r\n              '<option value=\"10\">10 items<\/option>' +\r\n              '<option value=\"12\">12 items<\/option>' +\r\n              '<option value=\"15\">15 items<\/option>' +\r\n            '<\/select>' +\r\n          '<\/div>' +\r\n          '<div style=\"flex:2;min-width:150px;\">' +\r\n            '<label class=\"pth-ils-label\" for=\"pth-ai-lang\">Clue \/ Definition Language<\/label>' +\r\n            '<select class=\"pth-ils-select\" id=\"pth-ai-lang\" aria-label=\"Output language\">' +\r\n              '<option value=\"English\">English<\/option>' +\r\n              '<option value=\"Sinhala\">&#x0DC3;&#x0DD2;&#x0D82;&#x0DC4;&#x0DBD; (Sinhala)<\/option>' +\r\n              '<option value=\"Tamil\">&#xBBA4;&#xBAE4;&#xBBBF;&#xBBB4;&#xBBCD; (Tamil)<\/option>' +\r\n              '<option value=\"Arabic\">&#x627;&#x644;&#x639;&#x631;&#x628;&#x64A;&#x629; (Arabic)<\/option>' +\r\n              '<option value=\"Chinese\">&#x4E2D;&#x6587; (Chinese)<\/option>' +\r\n              '<option value=\"Japanese\">&#x65E5;&#x672C;&#x8A9E; (Japanese)<\/option>' +\r\n              '<option value=\"Korean\">&#xD55C;&#xAD6D;&#xC5B4; (Korean)<\/option>' +\r\n              '<option value=\"Hindi\">&#x939;&#x93F;&#x928;&#x94D;&#x926;&#x940; (Hindi)<\/option>' +\r\n              '<option value=\"French\">Fran&#xE7;ais<\/option>' +\r\n              '<option value=\"German\">Deutsch<\/option>' +\r\n              '<option value=\"Spanish\">Espa&#xF1;ol<\/option>' +\r\n              '<option value=\"Portuguese\">Portugu&#xEA;s<\/option>' +\r\n              '<option value=\"Russian\">&#x420;&#x443;&#x441;&#x441;&#x43A;&#x438;&#x439;<\/option>' +\r\n              '<option value=\"Indonesian\">Bahasa Indonesia<\/option>' +\r\n              '<option value=\"Malay\">Bahasa Melayu<\/option>' +\r\n              '<option value=\"Italian\">Italiano<\/option>' +\r\n              '<option value=\"Turkish\">T&#xFC;rk&#xE7;e<\/option>' +\r\n              '<option value=\"Vietnamese\">Ti&#x1EBF;ng Vi&#x1EC7;t<\/option>' +\r\n              '<option value=\"Thai\">&#x0E44;&#x0E17;&#x0E22; (Thai)<\/option>' +\r\n              '<option value=\"Dutch\">Nederlands<\/option>' +\r\n              '<option value=\"Swedish\">Svenska<\/option>' +\r\n              '<option value=\"Polish\">Polski<\/option>' +\r\n            '<\/select>' +\r\n          '<\/div>' +\r\n          '<div style=\"flex:1;min-width:110px;\">' +\r\n            '<label class=\"pth-ils-label\" for=\"pth-ai-level\">Difficulty<\/label>' +\r\n            '<select class=\"pth-ils-select\" id=\"pth-ai-level\" aria-label=\"Difficulty\">' +\r\n              '<option value=\"easy\">Easy<\/option>' +\r\n              '<option value=\"medium\" selected>Medium<\/option>' +\r\n              '<option value=\"hard\">Hard<\/option>' +\r\n            '<\/select>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n        '<div class=\"pth-ils-btn-row\">' +\r\n          '<button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-ai-gen-btn\" style=\"min-width:160px;\">&#x2728; Generate with AI<\/button>' +\r\n          '<button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-ai-regen-btn\">&#x1F504; Regenerate<\/button>' +\r\n        '<\/div>' +\r\n\r\n        \/* Loading *\/\r\n        '<div id=\"pth-ai-loading\" style=\"display:none;\">' +\r\n          '<div class=\"pth-ai-loading-box\">' +\r\n            '<div class=\"pth-ai-dots\"><span><\/span><span><\/span><span><\/span><\/div>' +\r\n            '<span id=\"pth-ai-load-txt\">Generating...<\/span>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n        \/* Result *\/\r\n        '<div id=\"pth-ai-result-wrap\" style=\"display:none;\">' +\r\n          '<div style=\"display:flex;align-items:center;justify-content:space-between;margin-top:12px;margin-bottom:6px;\">' +\r\n            '<span style=\"font-size:0.82rem;font-weight:700;color:#047857;\">&#x2705; Ready! <span id=\"pth-ai-count-label\"><\/span><\/span>' +\r\n            '<div style=\"display:flex;gap:6px;\">' +\r\n              '<button class=\"pth-ils-btn pth-ils-btn-success pth-ils-btn-sm\" id=\"pth-ai-use-btn\">&#x27A1; Use in Tab<\/button>' +\r\n              '<button class=\"pth-ils-btn pth-ils-btn-outline pth-ils-btn-sm\" id=\"pth-ai-copy-btn\">&#x1F4CB; Copy<\/button>' +\r\n            '<\/div>' +\r\n          '<\/div>' +\r\n          '<div class=\"pth-ai-preview-box\"><pre id=\"pth-ai-preview\"><\/pre><\/div>' +\r\n        '<\/div>' +\r\n\r\n      '<\/div>' + \/* end topic card *\/\r\n\r\n      \/* \u2500\u2500 CARD 4: History \u2500\u2500 *\/\r\n      '<div class=\"pth-ils-card\" id=\"pth-ai-hist-card\" style=\"display:none;\">' +\r\n        '<h3>&#x1F4DC; Recent (last 10)<\/h3>' +\r\n        '<div id=\"pth-ai-hist-list\"><\/div>' +\r\n        '<button class=\"pth-ils-btn pth-ils-btn-outline pth-ils-btn-sm\" id=\"pth-ai-hist-clear\">&#x1F5D1; Clear History<\/button>' +\r\n      '<\/div>' +\r\n\r\n      '<\/div>' + \/* end main *\/\r\n\r\n      \/* \u2500\u2500 SIDEBAR \u2500\u2500 *\/\r\n      '<div class=\"pth-ils-sidebar\">' +\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4A1; How it Works<\/h3>' +\r\n          '<p style=\"font-size:0.82rem;color:#334155;line-height:1.6;margin:0;\">' +\r\n            '1. Choose <strong>AI provider<\/strong> &amp; paste key.<br>' +\r\n            '2. Click <strong>&#x1F4BE; Save Key<\/strong>.<br>' +\r\n            '3. Choose <strong>activity tab<\/strong> to fill.<br>' +\r\n            '4. Enter <strong>topic<\/strong> (any language).<br>' +\r\n            '5. Click <strong>&#x2728; Generate<\/strong>.<br>' +\r\n            '6. Click <strong>&#x27A1; Use in Tab<\/strong>.<br>' +\r\n            '7. Switch to tab &amp; click Generate!' +\r\n          '<\/p>' +\r\n        '<\/div>' +\r\n\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4B0; Free vs Paid<\/h3>' +\r\n          '<div style=\"font-size:0.8rem;color:#334155;line-height:1.8;\">' +\r\n            '<span style=\"background:#f0fdf4;color:#047857;padding:2px 8px;border-radius:20px;font-weight:700;font-size:0.72rem;\">FREE<\/span> ' +\r\n            '<strong>Gemini Flash<\/strong> &#x2014; Google<br>' +\r\n            '<span style=\"background:#f0fdf4;color:#047857;padding:2px 8px;border-radius:20px;font-weight:700;font-size:0.72rem;\">FREE<\/span> ' +\r\n            '<strong>Groq \/ Llama 3<\/strong> &#x2014; Meta<br>' +\r\n            '<span style=\"background:#fefce8;color:#92400e;padding:2px 8px;border-radius:20px;font-weight:700;font-size:0.72rem;\">PAID<\/span> ' +\r\n            '<strong>Claude Sonnet<\/strong> &#x2014; Anthropic<br><br>' +\r\n            '<em style=\"font-size:0.74rem;color:#94a3b8;\">Start with Gemini &#x2014; it\\'s free &amp; very capable!<\/em>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n\r\n        '<div class=\"pth-ils-card\">' +\r\n          '<h3>&#x1F4DD; Output Formats<\/h3>' +\r\n          '<div id=\"pth-ai-fmt-info\" style=\"font-size:0.78rem;color:#334155;line-height:1.7;\"><\/div>' +\r\n        '<\/div>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n  }\r\n\r\n  \/* ============================================================\r\n     UPDATE UI ON PROVIDER CHANGE\r\n     ============================================================ *\/\r\n  var PROV_INFO = {\r\n    crossword:  '<strong>Crossword:<\/strong> WORD:Clue line format',\r\n    wordsearch: '<strong>Word Search:<\/strong> One uppercase word per line',\r\n    sort:       '<strong>Drag &amp; Sort:<\/strong> Steps in correct order, one per line',\r\n    match:      '<strong>Match Pairs:<\/strong> Term:Definition pairs',\r\n    memory:     '<strong>Memory Match:<\/strong> Term:Match pairs (emoji encouraged!)'\r\n  };\r\n\r\n  function updateProviderUI(pvId) {\r\n    AI.prov = pvId;\r\n    var prov = null;\r\n    AI_PROVS.forEach(function(p){ if(p.id===pvId) prov=p; });\r\n    if (!prov) return;\r\n\r\n    \/* Info box *\/\r\n    var infoEl = document.getElementById('pth-ai-pvinfo');\r\n    if (infoEl) infoEl.innerHTML = prov.info;\r\n\r\n    \/* Key input placeholder *\/\r\n    var ki = document.getElementById('pth-ai-kinput');\r\n    if (ki) ki.placeholder = prov.ph + ' \u2014 paste your API key here';\r\n\r\n    \/* Show saved key status *\/\r\n    var saved = getKey(pvId);\r\n    if (ki) ki.value = saved;\r\n    updateKeyStatus(!!saved);\r\n  }\r\n\r\n  function updateKeyStatus(hasSaved) {\r\n    var st = document.getElementById('pth-ai-key-status');\r\n    if (!st) return;\r\n    if (hasSaved) {\r\n      st.className = 'pth-ai-key-status ks-ok';\r\n      st.innerHTML = '&#x2705; Key saved';\r\n    } else {\r\n      st.className = 'pth-ai-key-status ks-no';\r\n      st.innerHTML = '&#x26A0; No key';\r\n    }\r\n  }\r\n\r\n  \/* ============================================================\r\n     PROVIDER NAMES (with saved tick)\r\n     ============================================================ *\/\r\n  function refreshProvNames() {\r\n    AI_PROVS.forEach(function(p) {\r\n      var el = document.getElementById('pth-ai-pvn-' + p.id);\r\n      if (el) el.innerHTML = p.name + (getKey(p.id) ? ' &#x2705;' : '');\r\n    });\r\n  }\r\n\r\n  \/* ============================================================\r\n     FORMAT INFO per target\r\n     ============================================================ *\/\r\n  function updateFormatInfo() {\r\n    var el = document.getElementById('pth-ai-fmt-info');\r\n    if (!el) return;\r\n    var html = '';\r\n    AI_TARGETS.forEach(function(t) {\r\n      html += '<div style=\"margin-bottom:6px;\">' + t.icon + ' ' + PROV_INFO[t.id] + '<\/div>';\r\n    });\r\n    el.innerHTML = html;\r\n  }\r\n\r\n  \/* ============================================================\r\n     TEMPLATE TOPICS\r\n     ============================================================ *\/\r\n  function updateTemplates() {\r\n    var row = document.getElementById('pth-ai-tpl-row');\r\n    if (!row) return;\r\n    var tpls = AI_TPLS[AI.target] || AI_TPLS.crossword;\r\n    row.innerHTML = '';\r\n    tpls.forEach(function(tpl) {\r\n      var btn = document.createElement('button');\r\n      btn.className = 'pth-ai-tpl-btn';\r\n      btn.textContent = tpl;\r\n      btn.addEventListener('click', function() {\r\n        var ti = document.getElementById('pth-ai-topic');\r\n        if (ti) ti.value = tpl;\r\n        row.querySelectorAll('.pth-ai-tpl-btn').forEach(function(b){ b.classList.remove('tpl-sel'); });\r\n        btn.classList.add('tpl-sel');\r\n      });\r\n      row.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  \/* ============================================================\r\n     BUILD PROMPT\r\n     ============================================================ *\/\r\n  function buildPrompt(target, topic, count, lang, level) {\r\n    var diff = { easy:'Use simple, beginner-friendly language.', medium:'Use moderate, general-audience complexity.', hard:'Use advanced, academic-level content.' }[level] || '';\r\n    var p = {\r\n      crossword:\r\n        'Generate exactly ' + count + ' crossword word-clue pairs about \"' + topic + '\".\\n' +\r\n        'RULES:\\n1. WORD: single English\/Latin A-Z word, 3-12 chars, no spaces.\\n' +\r\n        '2. CLUE: write in ' + lang + '. ' + diff + '\\n' +\r\n        '3. Output ONLY: WORD:Clue\\nNo numbering, no extra text.',\r\n      wordsearch:\r\n        'Generate exactly ' + count + ' words related to \"' + topic + '\".\\n' +\r\n        'RULES:\\n1. Single English word, A-Z, 3-15 chars.\\n2. ' + diff + '\\n' +\r\n        '3. Output ONLY one uppercase word per line. No numbering.',\r\n      sort:\r\n        'Generate exactly ' + count + ' sequential steps\/sentences about \"' + topic + '\" in ' + lang + '.\\n' +\r\n        'RULES:\\n1. Write in CORRECT logical order.\\n2. One clear sentence per line.\\n3. ' + diff + '\\n' +\r\n        'No numbering, no bullets.',\r\n      match:\r\n        'Generate exactly ' + count + ' term-definition pairs about \"' + topic + '\".\\n' +\r\n        'RULES:\\n1. TERM: short (1-4 words). 2. DEFINITION: brief, in ' + lang + ', 5-12 words.\\n3. ' + diff + '\\n' +\r\n        'Output ONLY: Term:Definition. No numbering.',\r\n      memory:\r\n        'Generate exactly ' + count + ' matching pairs about \"' + topic + '\".\\n' +\r\n        'RULES:\\n1. TERM: word\/phrase in ' + lang + '. 2. MATCH: emoji, translation, or related word.\\n' +\r\n        '3. Use emoji where fun\/relevant. ' + diff + '\\nOutput ONLY: Term:Match. No numbering.',\r\n      hotspots:\r\n        'Generate exactly ' + count + ' hotspot annotations for an educational image about \"' + topic + '\".\\n' +\r\n        'RULES:\\n1. Each hotspot has a short TITLE (2-5 words) and a DESCRIPTION (1-2 sentences) in ' + lang + '.\\n' +\r\n        '2. ' + diff + '\\n3. Output ONLY: Title:Description. No numbering.',\r\n      blanks:\r\n        'Write an educational paragraph (80-120 words) about \"' + topic + '\" in ' + lang + '.\\n' +\r\n        'Select exactly ' + count + ' key vocabulary words and wrap them in square brackets like [this].\\n' +\r\n        'RULES:\\n1. Text must flow naturally as a coherent paragraph.\\n2. ' + diff + '\\n' +\r\n        '3. Output ONLY the paragraph text with [bracketed] words. No extra text.',\r\n      bingo:\r\n        'Generate exactly 30 vocabulary words or short phrases about \"' + topic + '\" in ' + lang + '.\\n' +\r\n        'RULES:\\n1. Each word\/phrase should be 1-3 words maximum (short for Bingo cards).\\n' +\r\n        '2. One word\/phrase per line. No numbering, no bullets.\\n3. ' + diff + '\\n' +\r\n        'Output ONLY the list.',\r\n      flashcards:\r\n        'Generate exactly ' + count + ' flashcard pairs about \"' + topic + '\".\\n' +\r\n        'RULES:\\n1. TERM: short (1-4 words). 2. DEFINITION: clear explanation in ' + lang + ', 5-15 words.\\n' +\r\n        '3. ' + diff + '\\nOutput ONLY: Term:Definition. No numbering.',\r\n      cryptogram:\r\n        'Give me one short, famous quote about \"' + topic + '\" in English.\\n' +\r\n        'RULES:\\n1. Quote must be 10-20 words maximum.\\n2. English letters A-Z only (no accents).\\n' +\r\n        '3. Format EXACTLY: Quote text - Author Name\\n4. No quotation marks. Output ONLY the quote line.'\r\n    };\r\n    return p[target] || p.crossword;\r\n  }\r\n\r\n  \/* ============================================================\r\n     CLEAN OUTPUT\r\n     ============================================================ *\/\r\n  function cleanOutput(raw, target) {\r\n    var lines = raw.split('\\n').map(function(l){ return l.trim(); }).filter(function(l){ return l.length > 0; });\r\n    \/* Remove markdown bullets and numbering *\/\r\n    lines = lines.map(function(l){ return l.replace(\/^[\\*\\-\\d\\.\\)]+\\s*\/,''); });\r\n\r\n    if (target === 'crossword') {\r\n      return lines.filter(function(l){\r\n        var idx = l.indexOf(':'); if (idx < 2) return false;\r\n        return \/^[A-Za-z]{3,12}$\/.test(l.substring(0, idx).trim());\r\n      });\r\n    }\r\n    if (target === 'wordsearch') {\r\n      return lines.map(function(l){ return l.replace(\/[^A-Za-z]\/g,'').toUpperCase(); }).filter(function(l){ return l.length >= 2 && l.length <= 15; });\r\n    }\r\n    if (target === 'sort') { return lines.filter(function(l){ return l.length > 5; }); }\r\n    if (target === 'match' || target === 'memory' || target === 'hotspots' || target === 'flashcards') { return lines.filter(function(l){ return l.indexOf(':') > 0; }); }\r\n    if (target === 'blanks') {\r\n      \/* Return the full text as a single joined block \u2014 keep [brackets] intact *\/\r\n      var fullText = lines.join(' ');\r\n      return fullText.indexOf('[') > -1 ? [fullText] : lines;\r\n    }\r\n    if (target === 'bingo') {\r\n      return lines.map(function(l){ return l.replace(\/^[\\d\\.\\-\\*\\)]+\\s*\/,'').trim(); }).filter(function(l){ return l.length >= 2; });\r\n    }\r\n    if (target === 'cryptogram') {\r\n      \/* Return single line: Quote text - Author *\/\r\n      var joined = lines.join(' ').trim();\r\n      return joined ? [joined] : lines;\r\n    }\r\n    return lines;\r\n  }\r\n\r\n  \/* ============================================================\r\n     CALL AI \u2014 Gemini \/ Groq \/ Claude (like Tool 67)\r\n     ============================================================ *\/\r\n  function callAI(prompt, pvId, onSuccess, onError) {\r\n    var key = getKey(pvId);\r\n    if (!key) { onError('No API key saved for this provider. Click Save Key first.'); return; }\r\n\r\n    if (pvId === 'gemini') {\r\n      var GBASE   = 'https:\/\/generativelanguage.googleapis.com\/v1beta\/models\/';\r\n      var GMODELS = ['gemini-2.5-flash','gemini-2.0-flash','gemini-1.5-flash','gemini-1.5-flash-latest'];\r\n      var gi = 0;\r\n      function tryGemini() {\r\n        if (gi >= GMODELS.length) { onError('Gemini: All models failed. Check key at aistudio.google.com'); return; }\r\n        var model = GMODELS[gi]; gi++;\r\n        fetch(GBASE + model + ':generateContent?key=' + key, {\r\n          method: 'POST',\r\n          headers: { 'Content-Type':'application\/json' },\r\n          body: JSON.stringify({\r\n            contents: [{ parts: [{ text: prompt }] }],\r\n            generationConfig: { maxOutputTokens: 1500, temperature: 0.7 }\r\n          })\r\n        })\r\n        .then(function(r){ return r.json(); })\r\n        .then(function(d){\r\n          if (d.candidates && d.candidates[0] && d.candidates[0].content) {\r\n            onSuccess(d.candidates[0].content.parts[0].text);\r\n          } else if (d.error) {\r\n            \/* Try next model on quota\/model errors *\/\r\n            tryGemini();\r\n          } else { tryGemini(); }\r\n        })\r\n        .catch(function(){ tryGemini(); });\r\n      }\r\n      tryGemini();\r\n\r\n    } else if (pvId === 'groq') {\r\n      var QMODELS = ['llama-3.3-70b-versatile','llama-3.1-70b-versatile','llama3-70b-8192','mixtral-8x7b-32768'];\r\n      var qi = 0;\r\n      function tryGroq() {\r\n        if (qi >= QMODELS.length) { onError('Groq: All models failed. Check key at console.groq.com'); return; }\r\n        var model = QMODELS[qi]; qi++;\r\n        fetch('https:\/\/api.groq.com\/openai\/v1\/chat\/completions', {\r\n          method: 'POST',\r\n          headers: { 'Content-Type':'application\/json', 'Authorization':'Bearer '+key },\r\n          body: JSON.stringify({\r\n            model: model,\r\n            messages: [{ role:'user', content: prompt }],\r\n            max_tokens: 1500\r\n          })\r\n        })\r\n        .then(function(r){ return r.json(); })\r\n        .then(function(d){\r\n          if (d.choices && d.choices[0]) { onSuccess(d.choices[0].message.content); }\r\n          else if (d.error && d.error.code === 'model_not_active') { tryGroq(); }\r\n          else { onError('Groq: ' + (d.error ? d.error.message : 'Unknown error')); }\r\n        })\r\n        .catch(function(){ tryGroq(); });\r\n      }\r\n      tryGroq();\r\n\r\n    } else {\r\n      \/* Claude *\/\r\n      fetch('https:\/\/api.anthropic.com\/v1\/messages', {\r\n        method: 'POST',\r\n        headers: {\r\n          'Content-Type': 'application\/json',\r\n          'x-api-key': key,\r\n          'anthropic-version': '2023-06-01',\r\n          'anthropic-dangerous-direct-browser-calls': 'true'\r\n        },\r\n        body: JSON.stringify({\r\n          model: 'claude-sonnet-4-6',\r\n          max_tokens: 1500,\r\n          messages: [{ role:'user', content: prompt }]\r\n        })\r\n      })\r\n      .then(function(r){ return r.json(); })\r\n      .then(function(d){\r\n        if (d.error) { onError('Claude: ' + d.error.message); return; }\r\n        onSuccess(d.content[0].text);\r\n      })\r\n      .catch(function(err){ onError('Claude: ' + err.message); });\r\n    }\r\n  }\r\n\r\n  \/* ============================================================\r\n     GENERATE\r\n     ============================================================ *\/\r\n  function runGenerate() {\r\n    if (AI.loading) return;\r\n    var topic  = (document.getElementById('pth-ai-topic')||{}).value || '';\r\n    var count  = parseInt((document.getElementById('pth-ai-count')||{}).value || '8');\r\n    var lang   = (document.getElementById('pth-ai-lang')||{}).value || 'English';\r\n    var level  = (document.getElementById('pth-ai-level')||{}).value || 'medium';\r\n\r\n    if (!topic.trim()) { window.pthILS.toast('Enter a topic first.','error'); return; }\r\n    if (!getKey(AI.prov)) {\r\n      window.pthILS.toast('No API key saved! Paste your key and click Save Key.','error');\r\n      var ki = document.getElementById('pth-ai-kinput');\r\n      if (ki) ki.focus();\r\n      return;\r\n    }\r\n\r\n    AI.loading = true;\r\n    var genBtn  = document.getElementById('pth-ai-gen-btn');\r\n    var loading = document.getElementById('pth-ai-loading');\r\n    var result  = document.getElementById('pth-ai-result-wrap');\r\n    var loadTxt = document.getElementById('pth-ai-load-txt');\r\n\r\n    if (genBtn)  { genBtn.disabled = true; genBtn.innerHTML = '&#x23F3; Generating...'; }\r\n    if (loading) loading.style.display = 'block';\r\n    if (result)  result.style.display  = 'none';\r\n\r\n    var pvName = ''; AI_PROVS.forEach(function(p){ if(p.id===AI.prov) pvName=p.name; });\r\n    var tLabel = ''; AI_TARGETS.forEach(function(t){ if(t.id===AI.target) tLabel=t.label; });\r\n    if (loadTxt) loadTxt.textContent = pvName + ' is generating ' + count + ' items for ' + tLabel + '...';\r\n\r\n    var prompt = buildPrompt(AI.target, topic, count, lang, level);\r\n\r\n    callAI(prompt, AI.prov,\r\n      function(text) {\r\n        \/* Success *\/\r\n        AI.loading = false;\r\n        if (genBtn)  { genBtn.disabled=false; genBtn.innerHTML='&#x2728; Generate with AI'; }\r\n        if (loading) loading.style.display='none';\r\n\r\n        var cleaned = cleanOutput(text, AI.target);\r\n        if (!cleaned.length) {\r\n          window.pthILS.toast('Unexpected AI output. Try rephrasing topic or switching provider.','error');\r\n          return;\r\n        }\r\n        var output = cleaned.join('\\n');\r\n        AI.lastResult = output;\r\n\r\n        \/* Show preview *\/\r\n        var preview = document.getElementById('pth-ai-preview');\r\n        if (preview) preview.textContent = output;\r\n        var cLabel  = document.getElementById('pth-ai-count-label');\r\n        if (cLabel) cLabel.textContent = cleaned.length + ' ' + tLabel + ' items generated via ' + pvName;\r\n        if (result) result.style.display = 'block';\r\n\r\n        \/* History *\/\r\n        addHistory(topic, tLabel, pvName, lang, output, cleaned.length);\r\n        window.pthILS.toast(pvName + ': ' + cleaned.length + ' items ready!', 'success');\r\n      },\r\n      function(errMsg) {\r\n        \/* Error *\/\r\n        AI.loading = false;\r\n        if (genBtn)  { genBtn.disabled=false; genBtn.innerHTML='&#x2728; Generate with AI'; }\r\n        if (loading) loading.style.display='none';\r\n        window.pthILS.toast('Error: ' + errMsg, 'error');\r\n      }\r\n    );\r\n  }\r\n\r\n  \/* ============================================================\r\n     USE IN TAB\r\n     ============================================================ *\/\r\n  function useInTab() {\r\n    if (!AI.lastResult) { window.pthILS.toast('Generate content first!','error'); return; }\r\n    document.dispatchEvent(new CustomEvent('pthILSAIFill', { detail: { target:AI.target, content:AI.lastResult } }));\r\n    \/* Map AI target IDs to shell tab button data-tab values *\/\r\n    var tabMap = {\r\n      crossword:'crossword', wordsearch:'wordsearch', sort:'sort', match:'match', memory:'memory',\r\n      hotspots:'hotspots', blanks:'blanks', bingo:'bingo', flashcards:'flashcards', cryptogram:'cryptogram'\r\n    };\r\n    var tabId = tabMap[AI.target] || AI.target;\r\n    var tabBtn = document.querySelector('.pth-ils-tab-btn[data-tab=\"' + tabId + '\"]');\r\n    if (tabBtn) setTimeout(function(){ tabBtn.click(); }, 100);\r\n    window.pthILS.toast('Content sent to ' + AI.target + ' tab!', 'success');\r\n  }\r\n\r\n  \/* ============================================================\r\n     HISTORY\r\n     ============================================================ *\/\r\n  function addHistory(topic, tLabel, pvName, lang, content, count) {\r\n    AI.history.unshift({ topic:topic, tLabel:tLabel, pvName:pvName, lang:lang, count:count, content:content, time:new Date().toLocaleTimeString() });\r\n    if (AI.history.length > 10) AI.history = AI.history.slice(0,10);\r\n    renderHistory();\r\n  }\r\n\r\n  function renderHistory() {\r\n    var card = document.getElementById('pth-ai-hist-card');\r\n    var list = document.getElementById('pth-ai-hist-list');\r\n    if (!list) return;\r\n    if (!AI.history.length) { if(card) card.style.display='none'; return; }\r\n    if (card) card.style.display='block';\r\n    list.innerHTML='';\r\n    AI.history.forEach(function(h, idx) {\r\n      var div = document.createElement('div');\r\n      div.className = 'pth-ai-hist-item';\r\n      div.innerHTML =\r\n        '<div style=\"min-width:0;flex:1;\">' +\r\n          '<div class=\"pth-ai-hist-topic\">' + window.pthILS.esc(h.topic) + '<\/div>' +\r\n          '<div class=\"pth-ai-hist-meta\">' + h.tLabel + ' &bull; ' + h.count + ' items &bull; ' + h.pvName + ' &bull; ' + h.lang + ' &bull; ' + h.time + '<\/div>' +\r\n        '<\/div>' +\r\n        '<button class=\"pth-ai-hist-use\" data-idx=\"' + idx + '\">Use<\/button>';\r\n      list.appendChild(div);\r\n    });\r\n    list.querySelectorAll('.pth-ai-hist-use').forEach(function(btn) {\r\n      btn.addEventListener('click', function() {\r\n        var item = AI.history[parseInt(btn.getAttribute('data-idx'))];\r\n        if (!item) return;\r\n        AI.lastResult = item.content;\r\n        var preview = document.getElementById('pth-ai-preview');\r\n        if (preview) preview.textContent = item.content;\r\n        var result = document.getElementById('pth-ai-result-wrap');\r\n        if (result) result.style.display='block';\r\n        window.pthILS.toast('Loaded from history!','info');\r\n      });\r\n    });\r\n  }\r\n\r\n  \/* ============================================================\r\n     WIRE EVENTS\r\n     ============================================================ *\/\r\n  function wireEvents() {\r\n    \/* Provider tabs *\/\r\n    var pvTabs = document.querySelectorAll('#pth-ai-pvtabs .pth-ai-pvtab');\r\n    pvTabs.forEach(function(tab) {\r\n      tab.addEventListener('click', function() {\r\n        pvTabs.forEach(function(t){ t.classList.remove('pv-sel'); });\r\n        tab.classList.add('pv-sel');\r\n        updateProviderUI(tab.getAttribute('data-pv'));\r\n      });\r\n      tab.addEventListener('keydown', function(e){ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); tab.click(); } });\r\n    });\r\n\r\n    \/* Key show\/hide *\/\r\n    var eyeBtn  = document.getElementById('pth-ai-eyebtn');\r\n    var kinput  = document.getElementById('pth-ai-kinput');\r\n    if (eyeBtn && kinput) {\r\n      eyeBtn.addEventListener('click', function() {\r\n        var isPass = kinput.type === 'password';\r\n        kinput.type = isPass ? 'text' : 'password';\r\n        eyeBtn.innerHTML = isPass ? '&#x1F648;' : '&#x1F441;';\r\n      });\r\n    }\r\n\r\n    \/* Save key *\/\r\n    var saveBtn = document.getElementById('pth-ai-save-btn');\r\n    if (saveBtn) {\r\n      saveBtn.addEventListener('click', function() {\r\n        var k = (kinput ? kinput.value : '').trim();\r\n        if (!k) { window.pthILS.toast('Paste your API key first.','error'); return; }\r\n        saveKey(AI.prov, k);\r\n        updateKeyStatus(true);\r\n        refreshProvNames();\r\n        window.pthILS.toast('API key saved for ' + AI.prov + '!','success');\r\n      });\r\n    }\r\n\r\n    \/* Clear key *\/\r\n    var clearKeyBtn = document.getElementById('pth-ai-clear-btn');\r\n    if (clearKeyBtn) {\r\n      clearKeyBtn.addEventListener('click', function() {\r\n        clearKey(AI.prov);\r\n        if (kinput) kinput.value = '';\r\n        updateKeyStatus(false);\r\n        refreshProvNames();\r\n        window.pthILS.toast('Key cleared.','info');\r\n      });\r\n    }\r\n\r\n    \/* Save on Enter in key input *\/\r\n    if (kinput) {\r\n      kinput.addEventListener('keydown', function(e) {\r\n        if (e.key === 'Enter') { e.preventDefault(); if (saveBtn) saveBtn.click(); }\r\n      });\r\n    }\r\n\r\n    \/* Target buttons *\/\r\n    var targetBtns = document.querySelectorAll('#pth-ai-target-grid .pth-ai-target-btn');\r\n    targetBtns.forEach(function(btn) {\r\n      btn.addEventListener('click', function() {\r\n        targetBtns.forEach(function(b){ b.classList.remove('ai-sel'); });\r\n        btn.classList.add('ai-sel');\r\n        AI.target = btn.getAttribute('data-target');\r\n        updateTemplates();\r\n        var result = document.getElementById('pth-ai-result-wrap');\r\n        if (result) result.style.display='none';\r\n        AI.lastResult = '';\r\n      });\r\n    });\r\n\r\n    \/* Generate *\/\r\n    var genBtn = document.getElementById('pth-ai-gen-btn');\r\n    var rgnBtn = document.getElementById('pth-ai-regen-btn');\r\n    if (genBtn) genBtn.addEventListener('click', runGenerate);\r\n    if (rgnBtn) rgnBtn.addEventListener('click', runGenerate);\r\n\r\n    \/* Enter on topic *\/\r\n    var topicInput = document.getElementById('pth-ai-topic');\r\n    if (topicInput) topicInput.addEventListener('keydown', function(e){ if(e.key==='Enter'){ e.preventDefault(); runGenerate(); } });\r\n\r\n    \/* Use in tab *\/\r\n    var useBtn = document.getElementById('pth-ai-use-btn');\r\n    if (useBtn) useBtn.addEventListener('click', useInTab);\r\n\r\n    \/* Copy *\/\r\n    var copyBtn = document.getElementById('pth-ai-copy-btn');\r\n    if (copyBtn) copyBtn.addEventListener('click', function() {\r\n      if (!AI.lastResult) { window.pthILS.toast('Nothing to copy.','error'); return; }\r\n      window.pthILS.copy(AI.lastResult, 'Content');\r\n    });\r\n\r\n    \/* History clear *\/\r\n    var hclr = document.getElementById('pth-ai-hist-clear');\r\n    if (hclr) hclr.addEventListener('click', function(){ AI.history=[]; renderHistory(); window.pthILS.toast('History cleared.','info'); });\r\n\r\n    \/* Global events *\/\r\n    document.addEventListener('pthILSSample', function(e) {\r\n      if (e.detail.tab !== 'ai') return;\r\n      var ti = document.getElementById('pth-ai-topic');\r\n      if (ti) { ti.value='Solar System'; window.pthILS.toast('Try \"Solar System\"!','info'); }\r\n    });\r\n    document.addEventListener('pthILSClear', function(e) {\r\n      if (e.detail.tab !== 'ai') return;\r\n      var ti = document.getElementById('pth-ai-topic'); if(ti)ti.value='';\r\n      AI.lastResult='';\r\n      var rw = document.getElementById('pth-ai-result-wrap'); if(rw)rw.style.display='none';\r\n    });\r\n    document.addEventListener('pthILSTabActive', function(e) {\r\n      if (e.detail.tab !== 'ai') return;\r\n      var prev = window.pthILS.activeTab;\r\n      if (prev && prev !== 'ai') {\r\n        var mb = document.querySelector('#pth-ai-target-grid .pth-ai-target-btn[data-target=\"'+prev+'\"]');\r\n        if (mb) { document.querySelectorAll('#pth-ai-target-grid .pth-ai-target-btn').forEach(function(b){b.classList.remove('ai-sel');}); mb.classList.add('ai-sel'); AI.target=prev; updateTemplates(); }\r\n      }\r\n    });\r\n\r\n    \/* Initialize *\/\r\n    updateProviderUI(AI.prov);\r\n    updateTemplates();\r\n    updateFormatInfo();\r\n  }\r\n\r\n  function init() {\r\n    buildTabHTML();\r\n    setTimeout(function(){ wireEvents(); }, 100);\r\n  }\r\n\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<style data-no-optimize=\"1\">\r\n#pth-tab-hotspots {\r\n  --hs-pin-color: #ef4444;\r\n  --hs-pin-hover: #dc2626;\r\n  --hs-pin-size: 28px;\r\n}\r\n.pth-hs-workspace {\r\n  position: relative; display: inline-block; max-width: 100%;\r\n  border: 2px dashed #cbd5e1; border-radius: 8px; overflow: hidden;\r\n  background: #f1f5f9; min-height: 200px; text-align: center;\r\n}\r\n.pth-hs-workspace img {\r\n  display: block; max-width: 100%; height: auto; width: auto; pointer-events: none;\r\n}\r\n.pth-hs-pins-layer {\r\n  position: absolute; top: 0; left: 0; width: 100%; height: 100%; cursor: crosshair;\r\n}\r\n.pth-hs-pin {\r\n  position: absolute; width: var(--hs-pin-size); height: var(--hs-pin-size);\r\n  background: var(--hs-pin-color); color: #fff; border-radius: 50%;\r\n  display: flex; align-items: center; justify-content: center;\r\n  transform: translate(-50%, -50%); cursor: pointer;\r\n  box-shadow: 0 4px 6px rgba(0,0,0,0.3); border: 2px solid #fff;\r\n  font-size: 0.8rem; font-weight: 800; font-family: 'Inter', sans-serif;\r\n  transition: transform 0.15s, background 0.15s; z-index: 10;\r\n}\r\n.pth-hs-pin:hover { transform: translate(-50%, -50%) scale(1.15); background: var(--hs-pin-hover); z-index: 20; }\r\n.pth-hs-pin.active { outline: 4px solid rgba(59, 130, 246, 0.5); background: #2563eb; }\r\n\r\n.pth-hs-empty-state {\r\n  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);\r\n  color: #64748b; font-weight: 700; font-size: 1.1rem; pointer-events: none;\r\n}\r\n\r\n\/* Edit Panel *\/\r\n.pth-hs-edit-panel {\r\n  background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 16px;\r\n  margin-top: 15px; display: none;\r\n}\r\n.pth-hs-edit-panel.active { display: block; animation: pthHsFadeIn 0.2s ease; }\r\n@keyframes pthHsFadeIn { from{opacity:0; transform:translateY(-5px);} to{opacity:1; transform:translateY(0);} }\r\n\r\n.pth-hs-pin-list { max-height: 250px; overflow-y: auto; margin-top: 15px; }\r\n.pth-hs-list-item {\r\n  display: flex; align-items: center; justify-content: space-between;\r\n  background: #fff; border: 1px solid #e2e8f0; padding: 8px 12px;\r\n  border-radius: 6px; margin-bottom: 6px; cursor: pointer; transition: 0.15s;\r\n}\r\n.pth-hs-list-item:hover { border-color: #94a3b8; }\r\n.pth-hs-list-item.active { border-color: #2563eb; background: #eff6ff; }\r\n.pth-hs-list-num { background: #334155; color: #fff; width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.7rem; font-weight: 800; margin-right: 10px; }\r\n.pth-hs-list-title { flex: 1; font-size: 0.85rem; font-weight: 700; color: #1e293b; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\r\n\r\n\/* Media Preview *\/\r\n\/* Live-tool preview modal (draggable) *\/\r\n.pth-hs-pmodal-overlay { display:none; position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(15,23,42,0.55); z-index:99999; }\r\n.pth-hs-pmodal-overlay.open { display:block; }\r\n.pth-hs-pmodal {\r\n  position:fixed; top:50%; left:50%; transform:translate(-50%,-50%);\r\n  background:#fff; border-radius:14px; width:92%; max-width:460px;\r\n  box-shadow:0 24px 60px rgba(0,0,0,0.3); z-index:100000; overflow:hidden;\r\n  cursor:default; user-select:none;\r\n}\r\n.pth-hs-pmodal-head {\r\n  padding:14px 16px; background:#1d4ed8; color:#fff;\r\n  display:flex; align-items:center; justify-content:space-between;\r\n  cursor:move; border-radius:14px 14px 0 0;\r\n}\r\n.pth-hs-pmodal-title { font-size:0.95rem; font-weight:800; margin:0; color:#fff; flex:1; }\r\n.pth-hs-pmodal-drag-hint { font-size:0.68rem; color:rgba(255,255,255,0.7); margin-right:10px; }\r\n.pth-hs-pmodal-close {\r\n  background:rgba(255,255,255,0.2); border:none; color:#fff;\r\n  width:28px; height:28px; border-radius:50%; cursor:pointer;\r\n  font-weight:800; font-size:0.9rem; display:flex; align-items:center; justify-content:center;\r\n}\r\n.pth-hs-pmodal-close:hover { background:rgba(255,255,255,0.35); }\r\n.pth-hs-pmodal-body { padding:16px; max-height:70vh; overflow-y:auto; }\r\n.pth-hs-pmodal-desc { font-size:0.9rem; line-height:1.6; color:#334155; margin:0 0 12px; white-space:pre-wrap; }\r\n.pth-hs-pmodal-yt { border-radius:8px; overflow:hidden; background:#0f172a; margin-bottom:12px; }\r\n.pth-hs-pmodal-yt iframe { width:100%; aspect-ratio:16\/9; border:none; display:block; }\r\n.pth-hs-pmodal-yt-thumb { position:relative; cursor:pointer; border-radius:8px; overflow:hidden; background:#000; margin-bottom:12px; }\r\n.pth-hs-pmodal-yt-thumb img { width:100%; display:block; opacity:0.85; }\r\n.pth-hs-pmodal-play {\r\n  position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);\r\n  width:52px; height:52px; background:rgba(255,0,0,0.9); border-radius:50%;\r\n  display:flex; align-items:center; justify-content:center;\r\n}\r\n.pth-hs-pmodal-play-tri { width:0;height:0;border-left:18px solid #fff;border-top:11px solid transparent;border-bottom:11px solid transparent;margin-left:4px; }\r\n.pth-hs-pmodal-lbl { position:absolute;bottom:8px;left:0;right:0;text-align:center;color:#fff;font-size:0.78rem;font-weight:700; }\r\n.pth-hs-pmodal-link { display:inline-block;padding:8px 16px;background:#2563eb;color:#fff;text-decoration:none;border-radius:6px;font-weight:700;font-size:0.82rem; }\r\n.pth-hs-pmodal-audio { width:100%;margin-bottom:10px; }\r\n.pth-hs-pmodal-pin-num { display:inline-flex;align-items:center;justify-content:center;background:#ef4444;color:#fff;border-radius:50%;width:22px;height:22px;font-size:0.7rem;font-weight:800;margin-right:6px;flex-shrink:0; }\r\n.pth-hs-pmodal-media-swap { font-size:0.72rem;color:#2563eb;cursor:pointer;text-decoration:underline;display:block;margin-bottom:8px; }\r\n<\/style>\r\n\r\n<div id=\"pth-hs-ui-source\" style=\"display:none;\" aria-hidden=\"true\">\r\n  <div class=\"pth-ils-layout\" id=\"pth-hs-layout\">\r\n    \r\n    <div class=\"pth-ils-main\">\r\n      <div class=\"pth-ils-card\">\r\n        <h3>\ud83d\uddbc\ufe0f Interactive Image Annotator<\/h3>\r\n        <p style=\"font-size:0.8rem; color:#475569; margin:0 0 15px;\">Upload an image and click anywhere on it to add interactive hotspots. No canvas used, 100% mobile responsive!<\/p>\r\n        \r\n        <div style=\"display:flex; gap:10px; align-items:center; margin-bottom:15px; flex-wrap:wrap;\">\r\n          <input type=\"file\" id=\"pth-hs-file\" accept=\"image\/*\" style=\"display:none;\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-hs-upload-btn\" style=\"flex:1;\">\ud83d\udcc1 Upload Image<\/button>\r\n          <span style=\"font-size:0.8rem; color:#94a3b8; font-weight:700;\">OR<\/span>\r\n          <input type=\"text\" class=\"pth-ils-input\" id=\"pth-hs-url\" placeholder=\"Paste Image URL...\" style=\"margin-bottom:0; flex:2;\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-hs-load-url-btn\">Load URL<\/button>\r\n        <\/div>\r\n\r\n        <div class=\"pth-hs-workspace\" id=\"pth-hs-workspace\">\r\n          <div class=\"pth-hs-empty-state\" id=\"pth-hs-empty\">Image will appear here...<\/div>\r\n          <img id=\"pth-hs-img\" alt=\"Workspace\">\r\n          <div class=\"pth-hs-pins-layer\" id=\"pth-hs-pins-layer\"><\/div>\r\n        <\/div>\r\n        \r\n        <div style=\"font-size:0.75rem; color:#64748b; margin-top:8px; text-align:center;\">\r\n          \ud83d\udc46 Click anywhere on the image above to add a new pin.\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"pth-ils-card\" id=\"pth-hs-export-card\" style=\"display:none;\">\r\n        <h3>\ud83d\udce4 Export Interactive Image<\/h3>\r\n        <p style=\"font-size:0.8rem; color:#475569; margin:0 0 12px;\">Export as a standalone HTML file. It will contain the image and a built-in popup viewer for all your pins!<\/p>\r\n        <div class=\"pth-ils-btn-row\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-hs-html-btn\">\ud83d\udcc4 Download Interactive HTML<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-hs-copy-btn\">\ud83d\udccb Copy HTML Code<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-hs-print-btn\">\ud83d\udda8\ufe0f Print Map<\/button>\r\n        <\/div>\r\n        <div class=\"pth-ils-code-box\" id=\"pth-hs-code-box\" style=\"display:none;\">\r\n          <textarea id=\"pth-hs-code-ta\" readonly aria-label=\"HTML code\" style=\"min-height:120px;\"><\/textarea>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"pth-ils-sidebar\">\r\n      \r\n      <div class=\"pth-ils-card\">\r\n        <h3>\ud83d\udccd Hotspots List<\/h3>\r\n        <div id=\"pth-hs-list-empty\" style=\"font-size:0.8rem; color:#94a3b8; text-align:center; padding:20px 0;\">No pins added yet.<\/div>\r\n        <div class=\"pth-hs-pin-list\" id=\"pth-hs-pin-list\"><\/div>\r\n      <\/div>\r\n\r\n      <div class=\"pth-hs-edit-panel\" id=\"pth-hs-edit-panel\">\r\n        <h3 style=\"margin-top:0; color:#1d4ed8; font-size:0.9rem;\">\u270f\ufe0f Edit Pin Details<\/h3>\r\n        \r\n        <label class=\"pth-ils-label\">Title<\/label>\r\n        <input type=\"text\" class=\"pth-ils-input\" id=\"pth-hs-edit-title\" placeholder=\"E.g., Mitochondria\">\r\n        \r\n        <label class=\"pth-ils-label\">Description (Optional)<\/label>\r\n        <textarea class=\"pth-ils-textarea\" id=\"pth-hs-edit-desc\" placeholder=\"Enter detailed information here...\" style=\"min-height:80px;\"><\/textarea>\r\n        \r\n        <label class=\"pth-ils-label\">External Link (Optional)<\/label>\r\n        <input type=\"url\" class=\"pth-ils-input\" id=\"pth-hs-edit-link\" placeholder=\"https:\/\/wikipedia.org\/...\">\r\n        \r\n        <label class=\"pth-ils-label\">Video \/ Audio URL (Optional)<\/label>\r\n        <input type=\"url\" class=\"pth-ils-input\" id=\"pth-hs-edit-media\" placeholder=\"YouTube URL, Video ID (e.g. RBhC2svq5pc), or .mp3 link\">\r\n        <span class=\"pth-hs-media-hint\">&#x1F4FA; Paste a YouTube URL, plain Video ID, or an .mp3\/.wav link for audio.<\/span>\r\n        \r\n        <div style=\"display:flex; gap:8px; margin-top:15px;\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-hs-save-btn\" style=\"flex:1; justify-content:center;\">\ud83d\udcbe Save<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-danger\" id=\"pth-hs-del-btn\" style=\"padding:8px 12px;\" aria-label=\"Delete\">\ud83d\uddd1\ufe0f<\/button>\r\n        <\/div>\r\n      <\/div>\r\n      \r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n\r\n\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function() {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function() { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-hotspots');\r\n    if (!panel || panel.getAttribute('data-hs-built')) return;\r\n    \r\n    var source = document.getElementById('pth-hs-ui-source');\r\n    if(source) {\r\n        panel.appendChild(source.firstElementChild);\r\n        source.parentNode.removeChild(source);\r\n        panel.setAttribute('data-hs-built','1');\r\n    }\r\n  }\r\n\r\n  \/* Core State *\/\r\n  var HS = {\r\n    imageSrc: '',\r\n    pins: [],\r\n    activeIndex: -1,\r\n    counter: 1\r\n  };\r\n\r\n  \/* Helper to escape HTML safely *\/\r\n  function escHTML(s) {\r\n    return String(s==null?'':s).replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;');\r\n  }\r\n\r\n  function updateActivePinUI() {\r\n    var pins = document.querySelectorAll('.pth-hs-pin');\r\n    for(var i = 0; i < pins.length; i++) {\r\n        if(i === HS.activeIndex) pins[i].classList.add('active');\r\n        else pins[i].classList.remove('active');\r\n    }\r\n    \r\n    var items = document.querySelectorAll('.pth-hs-list-item');\r\n    for(var j = 0; j < items.length; j++) {\r\n        if(j === HS.activeIndex) items[j].classList.add('active');\r\n        else items[j].classList.remove('active');\r\n    }\r\n  }\r\n\r\n  function hsRenderPins() {\r\n    var layer = document.getElementById('pth-hs-pins-layer');\r\n    if(!layer) return;\r\n    layer.innerHTML = '';\r\n    \r\n    HS.pins.forEach(function(pin, index) {\r\n      var btn = document.createElement('div');\r\n      btn.className = 'pth-hs-pin' + (index === HS.activeIndex ? ' active' : '');\r\n      btn.style.left = pin.x + '%';\r\n      btn.style.top = pin.y + '%';\r\n      btn.textContent = index + 1;\r\n      \r\n      btn.addEventListener('click', function(e) {\r\n        e.stopPropagation();\r\n        hsSelectPin(index);\r\n        hsOpenPreview(index);\r\n      });\r\n      \r\n      layer.appendChild(btn);\r\n    });\r\n\r\n    hsRenderList();\r\n  }\r\n\r\n  \/* \u2500\u2500 Extract YouTube video ID from URL or plain ID \u2500\u2500 *\/\r\n  function getYtId(media) {\r\n    if (!media) return null;\r\n    var plain = media.trim();\r\n    if (\/^[a-zA-Z0-9_-]{11}$\/.test(plain)) return plain;\r\n    var r = \/^.*(youtu\\.be\\\/|v\\\/|u\\\/\\w\\\/|embed\\\/|watch\\?v=|&v=)([^#&?]*).*\/;\r\n    var m = plain.match(r);\r\n    return (m && m[2] && m[2].length === 11) ? m[2] : null;\r\n  }\r\n\r\n  \/* \u2500\u2500 Build and open a dynamically-created draggable preview modal \u2500\u2500 *\/\r\n  function hsOpenPreview(index) {\r\n    var pin = HS.pins[index];\r\n    if (!pin) return;\r\n\r\n    \/* Remove any existing preview *\/\r\n    var old = document.getElementById('pth-hs-live-modal');\r\n    if (old) old.parentNode.removeChild(old);\r\n\r\n    var ytId = getYtId(pin.media || '');\r\n    var hasAudio = pin.media && !ytId && (pin.media.indexOf('.mp3') > -1 || pin.media.indexOf('.wav') > -1);\r\n\r\n    \/* Build media HTML *\/\r\n    var mediaHTML = '';\r\n    if (ytId) {\r\n      var onHttps = (window.location.protocol === 'https:' || window.location.protocol === 'http:');\r\n      if (onHttps) {\r\n        mediaHTML =\r\n          '<div style=\"border-radius:8px;overflow:hidden;background:#0f172a;margin-bottom:10px;\">' +\r\n          '<iframe src=\"https:\/\/www.youtube-nocookie.com\/embed\/' + ytId + '?rel=0&modestbranding=1\" ' +\r\n          'style=\"width:100%;aspect-ratio:16\/9;border:none;display:block;\" allowfullscreen ' +\r\n          'allow=\"accelerometer;autoplay;clipboard-write;encrypted-media;gyroscope;picture-in-picture\" ' +\r\n          'loading=\"lazy\" title=\"' + escHTML(pin.title || 'Video') + '\"><\/iframe>' +\r\n          '<\/div>';\r\n      } else {\r\n        \/* file:\/\/ \u2014 thumbnail click-to-open *\/\r\n        mediaHTML =\r\n          '<div id=\"pth-hs-yt-tw\" style=\"position:relative;cursor:pointer;border-radius:8px;overflow:hidden;background:#000;margin-bottom:10px;\">' +\r\n          '<img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/' + ytId + '\/hqdefault.jpg\" alt=\"Watch on YouTube\" style=\"width:100%;display:block;opacity:0.85;\">' +\r\n          '<div style=\"position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:52px;height:52px;background:rgba(255,0,0,0.9);border-radius:50%;display:flex;align-items:center;justify-content:center;\">' +\r\n          '<div style=\"width:0;height:0;border-left:18px solid #fff;border-top:11px solid transparent;border-bottom:11px solid transparent;margin-left:4px;\"><\/div>' +\r\n          '<\/div>' +\r\n          '<div style=\"position:absolute;bottom:8px;left:0;right:0;text-align:center;color:#fff;font-size:0.78rem;font-weight:700;\">\\u25B6 Watch on YouTube<\/div>' +\r\n          '<\/div>';\r\n      }\r\n    } else if (hasAudio) {\r\n      mediaHTML = '<audio controls src=\"' + escHTML(pin.media) + '\" style=\"width:100%;margin-bottom:10px;\"><\/audio>';\r\n    }\r\n\r\n    var linkHTML = pin.link\r\n      ? '<a href=\"' + escHTML(pin.link) + '\" target=\"_blank\" rel=\"noopener\" style=\"display:inline-block;padding:8px 16px;background:#2563eb;color:#fff;text-decoration:none;border-radius:6px;font-weight:700;font-size:0.82rem;\">Learn More \\u2192<\/a>'\r\n      : '';\r\n\r\n    \/* Outer overlay *\/\r\n    var overlay = document.createElement('div');\r\n    overlay.id = 'pth-hs-live-modal';\r\n    overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(15,23,42,0.55);z-index:2147483647;';\r\n\r\n    \/* Modal box *\/\r\n    var modal = document.createElement('div');\r\n    modal.id = 'pth-hs-live-modal-box';\r\n    modal.style.cssText =\r\n      'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);' +\r\n      'background:#fff;border-radius:14px;width:92%;max-width:460px;' +\r\n      'box-shadow:0 24px 60px rgba(0,0,0,0.35);z-index:2147483647;overflow:hidden;';\r\n\r\n    modal.innerHTML =\r\n      '<div id=\"pth-hs-lm-head\" style=\"padding:12px 16px;background:#1d4ed8;color:#fff;display:flex;align-items:center;gap:8px;cursor:move;border-radius:14px 14px 0 0;\">' +\r\n        '<span style=\"background:rgba(255,255,255,0.25);color:#fff;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:0.7rem;font-weight:800;flex-shrink:0;\">' + (index + 1) + '<\/span>' +\r\n        '<span style=\"flex:1;font-size:0.95rem;font-weight:800;color:#fff;\">' + escHTML(pin.title || 'Pin ' + (index + 1)) + '<\/span>' +\r\n        '<span style=\"font-size:0.68rem;color:rgba(255,255,255,0.7);margin-right:8px;\">\\u2195\\u2194 drag<\/span>' +\r\n        '<button id=\"pth-hs-lm-close\" style=\"background:rgba(255,255,255,0.2);border:none;color:#fff;width:28px;height:28px;border-radius:50%;cursor:pointer;font-weight:800;font-size:0.9rem;display:flex;align-items:center;justify-content:center;\" aria-label=\"Close\">\\u00D7<\/button>' +\r\n      '<\/div>' +\r\n      '<div style=\"padding:16px;max-height:65vh;overflow-y:auto;\">' +\r\n        (pin.desc ? '<p style=\"font-size:0.9rem;line-height:1.6;color:#334155;margin:0 0 12px;white-space:pre-wrap;\">' + escHTML(pin.desc) + '<\/p>' : '') +\r\n        mediaHTML +\r\n        linkHTML +\r\n      '<\/div>';\r\n\r\n    overlay.appendChild(modal);\r\n    document.body.appendChild(overlay);\r\n\r\n    \/* Wire YouTube thumbnail click *\/\r\n    if (ytId && (window.location.protocol !== 'https:' && window.location.protocol !== 'http:')) {\r\n      var tw = document.getElementById('pth-hs-yt-tw');\r\n      if (tw) tw.addEventListener('click', function(){ window.open('https:\/\/www.youtube.com\/watch?v=' + ytId, '_blank'); });\r\n    }\r\n\r\n    \/* Close button *\/\r\n    var closeBtn = document.getElementById('pth-hs-lm-close');\r\n    if (closeBtn) closeBtn.addEventListener('click', hsClosePreview);\r\n\r\n    \/* Click outside to close *\/\r\n    overlay.addEventListener('click', function(e){ if(e.target===overlay) hsClosePreview(); });\r\n\r\n    \/* Escape key *\/\r\n    document.addEventListener('keydown', hsEscapeHandler);\r\n\r\n    \/* Drag *\/\r\n    var head = document.getElementById('pth-hs-lm-head');\r\n    if (head) {\r\n      var dragging=false, startX=0, startY=0;\r\n      head.addEventListener('pointerdown', function(e){\r\n        if(e.target.id==='pth-hs-lm-close') return;\r\n        dragging=true;\r\n        var r=modal.getBoundingClientRect();\r\n        modal.style.transform='none';\r\n        modal.style.top=r.top+'px';\r\n        modal.style.left=r.left+'px';\r\n        startX=e.clientX; startY=e.clientY;\r\n        head.setPointerCapture(e.pointerId);\r\n        e.preventDefault();\r\n      });\r\n      head.addEventListener('pointermove', function(e){\r\n        if(!dragging) return;\r\n        modal.style.top=(parseInt(modal.style.top)+(e.clientY-startY))+'px';\r\n        modal.style.left=(parseInt(modal.style.left)+(e.clientX-startX))+'px';\r\n        startX=e.clientX; startY=e.clientY;\r\n      });\r\n      head.addEventListener('pointerup',function(){ dragging=false; });\r\n      head.addEventListener('pointercancel',function(){ dragging=false; });\r\n    }\r\n  }\r\n\r\n  function hsEscapeHandler(e){ if(e.key==='Escape') hsClosePreview(); }\r\n\r\n  function hsClosePreview() {\r\n    var el = document.getElementById('pth-hs-live-modal');\r\n    if (el) el.parentNode.removeChild(el);\r\n    document.removeEventListener('keydown', hsEscapeHandler);\r\n  }\r\n\r\n  \/* \u2500\u2500 (kept empty \u2014 drag now handled inline above) \u2500\u2500 *\/\r\n  function initModalDrag() {}\r\n\r\n  function hsRenderList() {\r\n    var list = document.getElementById('pth-hs-pin-list');\r\n    var empty = document.getElementById('pth-hs-list-empty');\r\n    var editPanel = document.getElementById('pth-hs-edit-panel');\r\n    if(!list || !empty) return;\r\n    \r\n    if(HS.pins.length === 0) {\r\n      list.innerHTML = '';\r\n      empty.style.display = 'block';\r\n      if(editPanel) editPanel.classList.remove('active');\r\n      return;\r\n    }\r\n    \r\n    empty.style.display = 'none';\r\n    list.innerHTML = '';\r\n    \r\n    HS.pins.forEach(function(pin, index) {\r\n      var item = document.createElement('div');\r\n      item.className = 'pth-hs-list-item' + (index === HS.activeIndex ? ' active' : '');\r\n      \r\n      var title = pin.title || 'Pin ' + (index + 1);\r\n      item.innerHTML = '<div class=\"pth-hs-list-num\">' + (index + 1) + '<\/div><div class=\"pth-hs-list-title\">' + escHTML(title) + '<\/div>';\r\n      \r\n      item.addEventListener('click', function() { hsSelectPin(index); });\r\n      list.appendChild(item);\r\n    });\r\n  }\r\n\r\n  function hsSelectPin(index) {\r\n    HS.activeIndex = index;\r\n    updateActivePinUI();\r\n    \r\n    var panel = document.getElementById('pth-hs-edit-panel');\r\n    var pin = HS.pins[index];\r\n    if(!pin || !panel) return;\r\n    \r\n    var tEl = document.getElementById('pth-hs-edit-title');\r\n    var dEl = document.getElementById('pth-hs-edit-desc');\r\n    var lEl = document.getElementById('pth-hs-edit-link');\r\n    var mEl = document.getElementById('pth-hs-edit-media');\r\n\r\n    if(tEl) tEl.value = pin.title || '';\r\n    if(dEl) dEl.value = pin.desc || '';\r\n    if(lEl) lEl.value = pin.link || '';\r\n    if(mEl) mEl.value = pin.media || '';\r\n    \r\n    panel.classList.add('active');\r\n  }\r\n\r\n  function hsSavePin() {\r\n    if(HS.activeIndex === -1) return;\r\n    var pin = HS.pins[HS.activeIndex];\r\n    \r\n    var tEl = document.getElementById('pth-hs-edit-title');\r\n    var dEl = document.getElementById('pth-hs-edit-desc');\r\n    var lEl = document.getElementById('pth-hs-edit-link');\r\n    var mEl = document.getElementById('pth-hs-edit-media');\r\n\r\n    if(pin) {\r\n        pin.title = tEl ? tEl.value.trim() : '';\r\n        pin.desc = dEl ? dEl.value.trim() : '';\r\n        pin.link = lEl ? lEl.value.trim() : '';\r\n        pin.media = mEl ? mEl.value.trim() : '';\r\n    }\r\n    \r\n    window.pthILS.toast('Pin saved!', 'success');\r\n    hsRenderList();\r\n  }\r\n\r\n  function hsDeletePin() {\r\n    if(HS.activeIndex === -1) return;\r\n    HS.pins.splice(HS.activeIndex, 1);\r\n    HS.activeIndex = -1;\r\n    var panel = document.getElementById('pth-hs-edit-panel');\r\n    if(panel) panel.classList.remove('active');\r\n    hsRenderPins();\r\n    window.pthILS.toast('Pin deleted.', 'info');\r\n  }\r\n\r\n  function handleImageClick(e) {\r\n    if(!HS.imageSrc) {\r\n        window.pthILS.toast('Load an image first!', 'warn');\r\n        return;\r\n    }\r\n    \r\n    var rect = e.target.getBoundingClientRect();\r\n    var x = ((e.clientX - rect.left) \/ rect.width) * 100;\r\n    var y = ((e.clientY - rect.top) \/ rect.height) * 100;\r\n    \r\n    x = Math.max(0, Math.min(100, x));\r\n    y = Math.max(0, Math.min(100, y));\r\n\r\n    var newPin = {\r\n      x: x.toFixed(2),\r\n      y: y.toFixed(2),\r\n      title: '',\r\n      desc: '',\r\n      link: '',\r\n      media: ''\r\n    };\r\n    \r\n    HS.pins.push(newPin);\r\n    hsRenderPins();\r\n    hsSelectPin(HS.pins.length - 1);\r\n    \r\n    var titleInp = document.getElementById('pth-hs-edit-title');\r\n    if(titleInp) setTimeout(function(){ titleInp.focus(); }, 100);\r\n  }\r\n\r\n  function handleFileUpload(e) {\r\n    var file = e.target.files[0];\r\n    if(!file) return;\r\n    var reader = new FileReader();\r\n    reader.onload = function(evt) {\r\n      setImage(evt.target.result);\r\n    };\r\n    reader.readAsDataURL(file);\r\n  }\r\n\r\n  function handleUrlLoad() {\r\n    var urlInp = document.getElementById('pth-hs-url');\r\n    var url = urlInp ? urlInp.value.trim() : '';\r\n    if(!url) { window.pthILS.toast('Enter a valid URL', 'error'); return; }\r\n    setImage(url);\r\n  }\r\n\r\n  function setImage(src) {\r\n    HS.imageSrc = src;\r\n    HS.pins = [];\r\n    HS.activeIndex = -1;\r\n    \r\n    var imgEl = document.getElementById('pth-hs-img');\r\n    var emptyEl = document.getElementById('pth-hs-empty');\r\n    \r\n    if(!imgEl || !emptyEl) return;\r\n\r\n    imgEl.src = src;\r\n    imgEl.onload = function() {\r\n        emptyEl.style.display = 'none';\r\n        var expCard = document.getElementById('pth-hs-export-card');\r\n        if(expCard) expCard.style.display = 'block';\r\n        window.pthILS.toast('Image loaded! Click to add pins.', 'success');\r\n        hsRenderPins();\r\n    };\r\n    imgEl.onerror = function() {\r\n        window.pthILS.toast('Failed to load image.', 'error');\r\n        HS.imageSrc = '';\r\n        imgEl.src = '';\r\n        emptyEl.style.display = 'block';\r\n    };\r\n  }\r\n\r\n  \/* ============================================================\r\n     EXPORT HTML BUILDER (100% BULLETPROOF ONCLICK EVENTS)\r\n     ============================================================ *\/\r\n  function hsBuildExportHTML() {\r\n    if(!HS.imageSrc || !HS.pins.length) return '';\r\n\r\n    function escH(s){ return String(s||'').replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;'); }\r\n\r\n    \/* Pre-render all pins as static positioned divs \u2014 no onclick (forbidden), EventListeners wired in the inline script instead *\/\r\n    var pinsHTML = '';\r\n    HS.pins.forEach(function(pin, i) {\r\n      pinsHTML += '<'+'div class=\"hs-pin\" style=\"left:'+pin.x+'%;top:'+pin.y+'%;\" data-idx=\"'+i+'\">'+(i+1)+'<'+'\/div>';\r\n    });\r\n\r\n    \/* Page CSS \u2014 fully split structural tags *\/\r\n    var css =\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;}' +\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;padding:24px;background:#eef2f9;color:#1e293b;display:flex;justify-content:center;min-height:100vh;}' +\r\n      '.hs-page{width:100%;max-width:1000px;background:#fff;padding:24px;border-radius:16px;box-shadow:0 10px 30px -10px rgba(15,23,42,0.18);}' +\r\n      '.hs-head{text-align:center;margin:0 0 18px;}' +\r\n      'h1{color:#1d4ed8;font-size:1.5rem;font-weight:800;margin:0 0 4px;}' +\r\n      '.hs-sub{color:#334155;font-size:0.85rem;margin:0;}' +\r\n      '.hs-img-wrap{position:relative;display:inline-block;width:100%;border-radius:8px;overflow:hidden;}' +\r\n      '.hs-img-wrap img{display:block;width:100%;height:auto;}' +\r\n      '.hs-pin{position:absolute;width:28px;height:28px;background:#ef4444;color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;transform:translate(-50%,-50%);cursor:pointer;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:2px solid #fff;font-size:0.8rem;font-weight:800;z-index:10;transition:transform 0.2s,background 0.2s;}' +\r\n      '.hs-pin:hover{transform:translate(-50%,-50%) scale(1.15);background:#dc2626;z-index:20;}' +\r\n      '.hs-modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(15,23,42,0.7);z-index:9998;display:none;align-items:center;justify-content:center;padding:16px;}' +\r\n      '.hs-modal-overlay.open{display:flex;}' +\r\n      '.hs-modal{background:#fff;border-radius:12px;width:100%;max-width:500px;max-height:90vh;overflow-y:auto;box-shadow:0 24px 60px rgba(0,0,0,0.3);position:relative;}' +\r\n      '.hs-modal-header{padding:16px 20px;border-bottom:1px solid #e2e8f0;display:flex;justify-content:space-between;align-items:center;cursor:move;background:#1d4ed8;border-radius:12px 12px 0 0;}' +\r\n      '.hs-modal-title{margin:0;font-size:1.05rem;font-weight:800;color:#fff;}' +\r\n      '.hs-modal-drag-hint{font-size:0.68rem;color:rgba(255,255,255,0.7);margin-right:8px;}' +\r\n      '.hs-modal-close{background:rgba(255,255,255,0.2);border:none;width:28px;height:28px;border-radius:50%;cursor:pointer;font-weight:700;color:#fff;display:flex;align-items:center;justify-content:center;}' +\r\n      '.hs-modal-close:hover{background:rgba(255,255,255,0.35);}' +\r\n      '.hs-modal-body{padding:20px;}' +\r\n      '.hs-modal-desc{font-size:0.95rem;line-height:1.6;color:#334155;margin:0 0 16px;white-space:pre-wrap;}' +\r\n      '.hs-modal-link{display:inline-block;padding:8px 16px;background:#2563eb;color:#fff;text-decoration:none;border-radius:6px;font-weight:700;font-size:0.85rem;}' +\r\n      '.hs-modal-link:hover{background:#1d4ed8;}' +\r\n      '.hs-modal-media{margin-top:16px;border-radius:8px;overflow:hidden;background:#0f172a;}' +\r\n      '.hs-modal-media iframe{width:100%;aspect-ratio:16\/9;border:none;display:block;}' +\r\n      '.hs-modal-media audio{width:100%;display:block;}' +\r\n      '.hs-footer-btns{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:20px 0 0;padding-top:16px;border-top:2px solid #e2e8f0;}' +\r\n      '.hs-btn{padding:9px 18px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;}' +\r\n      '.hs-btn-b{background:#fff;border:2px solid #e2e8f0;color:#334155;}' +\r\n      '.hs-btn-c{background:#7c3aed;color:#fff;}' +\r\n      '@media print{body{background:#fff;}.hs-page{box-shadow:none;padding:0;}.hs-modal-overlay,.hs-footer-btns{display:none!important;}}';\r\n\r\n    \/* Safe JSON for pin data \u2014 no < or > needed since we use textContent in the script *\/\r\n    var safeJSON = JSON.stringify(HS.pins);\r\n\r\n    \/* Inline interactivity script \u2014 addEventListener only (no onclick attrs) *\/\r\n    var sc = [\r\n      '(function(){',\r\n        'var hsData=' + safeJSON + ';',\r\n        'function hsOpenModal(i){',\r\n          'var p=hsData[i];if(!p)return;',\r\n          'document.getElementById(\"hs-m-title\").textContent=p.title||\"Pin \"+(i+1);',\r\n          'document.getElementById(\"hs-m-desc\").textContent=p.desc||\"\";',\r\n          'var lw=document.getElementById(\"hs-m-link-wrap\");lw.innerHTML=\"\";',\r\n          'if(p.link){var a=document.createElement(\"a\");a.href=p.link;a.target=\"_blank\";a.className=\"hs-modal-link\";a.textContent=\"Learn More \\u2192\";lw.appendChild(a);}',\r\n          'var md=document.getElementById(\"hs-m-media\");md.innerHTML=\"\";',\r\n          'if(p.media){',\r\n            'var plain=p.media.trim();',\r\n            'var id=null;',\r\n            'if(\/^[a-zA-Z0-9_-]{11}$\/.test(plain)){id=plain;}',\r\n            'else{var r=\/^.*(youtu\\\\.be\\\\\/|v\\\\\/|u\\\\\/\\\\w\\\\\/|embed\\\\\/|watch\\\\?v=|\\\\&v=)([^#\\\\&\\\\?]*).*\/;var m=plain.match(r);if(m&&m[2]&&m[2].length===11)id=m[2];}',\r\n            'if(id){',\r\n              \/* Thumbnail link \u2014 works on file:\/\/ AND https:\/\/ (iframe blocked by YouTube on file:\/\/) *\/\r\n              'var wrap=document.createElement(\"div\");wrap.style.cssText=\"position:relative;cursor:pointer;border-radius:8px;overflow:hidden;background:#000;\";',\r\n              'var thumb=document.createElement(\"img\");thumb.src=\"https:\/\/img.youtube.com\/vi\/\"+id+\"\/hqdefault.jpg\";thumb.style.cssText=\"width:100%;display:block;opacity:0.85;\";thumb.alt=\"Watch on YouTube\";',\r\n              'var play=document.createElement(\"div\");play.style.cssText=\"position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:60px;height:60px;background:rgba(255,0,0,0.9);border-radius:50%;display:flex;align-items:center;justify-content:center;\";',\r\n              'var tri=document.createElement(\"div\");tri.style.cssText=\"width:0;height:0;border-left:20px solid #fff;border-top:12px solid transparent;border-bottom:12px solid transparent;margin-left:5px;\";',\r\n              'var lbl=document.createElement(\"div\");lbl.style.cssText=\"position:absolute;bottom:10px;left:0;right:0;text-align:center;color:#fff;font-size:0.8rem;font-weight:700;text-shadow:0 1px 3px rgba(0,0,0,0.8);\";\\nlbl.textContent=\"\u25b6 Watch on YouTube\";',\r\n              'play.appendChild(tri);wrap.appendChild(thumb);wrap.appendChild(play);wrap.appendChild(lbl);',\r\n              'wrap.addEventListener(\"click\",function(){window.open(\"https:\/\/www.youtube.com\/watch?v=\"+id,\"_blank\");});',\r\n              'md.appendChild(wrap);}',\r\n            'else if(p.media.indexOf(\".mp3\")>-1||p.media.indexOf(\".wav\")>-1){var aud=document.createElement(\"audio\");aud.controls=true;aud.src=p.media;md.appendChild(aud);}}',\r\n          'document.getElementById(\"hs-modal\").classList.add(\"open\");',\r\n        '}',\r\n        'function hsCloseModal(){document.getElementById(\"hs-modal\").classList.remove(\"open\");document.getElementById(\"hs-m-media\").innerHTML=\"\";}',\r\n        'document.querySelectorAll(\".hs-pin\").forEach(function(pin){',\r\n          'pin.addEventListener(\"click\",function(){hsOpenModal(parseInt(pin.getAttribute(\"data-idx\")));});',\r\n        '});',\r\n        'document.getElementById(\"hs-m-close\").addEventListener(\"click\",hsCloseModal);',\r\n        'document.getElementById(\"hs-modal\").addEventListener(\"click\",function(e){if(e.target===this)hsCloseModal();});',\r\n        \/* Drag on modal header *\/\r\n        'var dhead=document.getElementById(\"hs-modal-head\"),dbox=document.getElementById(\"hs-modal-box\");',\r\n        'var dg=false,sx=0,sy=0;',\r\n        'if(dhead&&dbox){',\r\n          'dhead.addEventListener(\"pointerdown\",function(e){if(e.target.id===\"hs-m-close\")return;dg=true;var r=dbox.getBoundingClientRect();dbox.style.position=\"fixed\";dbox.style.margin=\"0\";dbox.style.top=r.top+\"px\";dbox.style.left=r.left+\"px\";dbox.style.transform=\"none\";sx=e.clientX;sy=e.clientY;dhead.setPointerCapture(e.pointerId);e.preventDefault();});',\r\n          'dhead.addEventListener(\"pointermove\",function(e){if(!dg)return;dbox.style.top=(parseInt(dbox.style.top)+(e.clientY-sy))+\"px\";dbox.style.left=(parseInt(dbox.style.left)+(e.clientX-sx))+\"px\";sx=e.clientX;sy=e.clientY;});',\r\n          'dhead.addEventListener(\"pointerup\",function(){dg=false;});',\r\n          'dhead.addEventListener(\"pointercancel\",function(){dg=false;});',\r\n        '}',\r\n        'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n\r\n    var so = '<'+'script'+'>';\r\n    var sc2 = '<'+'\/'+'script'+'>';\r\n    var docOpen =\r\n      '<'+'!DOCTYPE html>' +\r\n      '<'+'html lang=\"en\">' +\r\n      '<'+'head>' +\r\n      '<'+'meta charset=\"UTF-8\">' +\r\n      '<'+'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">' +\r\n      '<'+'title>Interactive Image Map<'+'\/title>' +\r\n      '<'+'style>'+css+'<'+'\/style>' +\r\n      '<'+'\/head>' +\r\n      '<'+'body>';\r\n    var docClose = '<'+'\/'+'body>'+'<'+'\/'+'html>';\r\n\r\n    var body =\r\n      '<div class=\"hs-page\">' +\r\n      '<div class=\"hs-head\"><h2>&#x1F5FA; Interactive Image Map<\/h2><p class=\"hs-sub\">Click a hotspot to learn more.<\/p><\/div>' +\r\n      '<div class=\"hs-img-wrap\" id=\"hs-wrap\">' +\r\n        '<img decoding=\"async\" src=\"'+escH(HS.imageSrc)+'\" alt=\"Interactive Map\" style=\"display:block;width:100%;height:auto;\" data-no-lazy=\"1\">' +\r\n        pinsHTML +\r\n      '<\/div>' +\r\n      '<div class=\"hs-footer-btns\">' +\r\n        '<button class=\"hs-btn hs-btn-c\" id=\"btn-print\">&#x1F5A8; Print Map<\/button>' +\r\n      '<\/div>' +\r\n      '<\/div>' +\r\n      '<div class=\"hs-modal-overlay\" id=\"hs-modal\">' +\r\n        '<div class=\"hs-modal\" id=\"hs-modal-box\">' +\r\n          '<div class=\"hs-modal-header\" id=\"hs-modal-head\">' +\r\n            '<h3 class=\"hs-modal-title\" id=\"hs-m-title\">Title<\/h3>' +\r\n            '<span class=\"hs-modal-drag-hint\">\\u2195\\u2194 drag<\/span>' +\r\n            '<button class=\"hs-modal-close\" id=\"hs-m-close\" aria-label=\"Close\">\\u00D7<\/button>' +\r\n          '<\/div>' +\r\n          '<div class=\"hs-modal-body\">' +\r\n            '<div class=\"hs-modal-desc\" id=\"hs-m-desc\"><\/div>' +\r\n            '<div class=\"hs-modal-media\" id=\"hs-m-media\"><\/div>' +\r\n            '<div id=\"hs-m-link-wrap\" style=\"margin-top:16px;\"><\/div>' +\r\n          '<\/div>' +\r\n        '<\/div>' +\r\n      '<\/div>';\r\n\r\n    return docOpen + body + so + sc + sc2 + docClose;\r\n  }\r\n\r\n  \/* ============================================================\r\n     WIRE EVENTS\r\n     ============================================================ *\/\r\n  function wireEvents() {\r\n    var b = function(id,fn){var el=document.getElementById(id);if(el)el.addEventListener('click',fn);};\r\n    \r\n    b('pth-hs-upload-btn', function(){ \r\n        var fileInp = document.getElementById('pth-hs-file');\r\n        if(fileInp) fileInp.click(); \r\n    });\r\n    var fileInp = document.getElementById('pth-hs-file');\r\n    if(fileInp) fileInp.addEventListener('change', handleFileUpload);\r\n    \r\n    b('pth-hs-load-btn', handleUrlLoad);\r\n    b('pth-hs-load-url-btn', handleUrlLoad);\r\n\r\n    var layer = document.getElementById('pth-hs-pins-layer');\r\n    if(layer) layer.addEventListener('click', handleImageClick);\r\n\r\n    b('pth-hs-save-btn', hsSavePin);\r\n    b('pth-hs-del-btn', hsDeletePin);\r\n\r\n    b('pth-hs-html-btn', function(){\r\n      if(!HS.imageSrc || HS.pins.length === 0){ window.pthILS.toast('Add image and pins first!','error'); return; }\r\n      var c = hsBuildExportHTML(); if(!c) return;\r\n      try {\r\n        var blob=new Blob([c],{type:'text\/html'});\r\n        var url=URL.createObjectURL(blob);\r\n        var a=document.createElement('a');\r\n        a.href=url;a.download='interactive-image.html';\r\n        document.body.appendChild(a);a.click();document.body.removeChild(a);\r\n        setTimeout(function(){URL.revokeObjectURL(url);},2000);\r\n        window.pthILS.toast('HTML file downloaded!','success');\r\n      } catch(err){ window.pthILS.toast('Download failed: '+err.message,'error'); }\r\n    });\r\n    b('pth-hs-print-btn', function(){\r\n      if(!HS.imageSrc || HS.pins.length === 0){ window.pthILS.toast('Add image and pins first!','error'); return; }\r\n      var c = hsBuildExportHTML(); if(!c) return;\r\n      var w = window.open('','_blank');\r\n      if(!w){ window.pthILS.toast('Popup blocked! Allow popups for this site to print.','error'); return; }\r\n      w.document.open();w.document.write(c);w.document.close();\r\n      var printed=false;\r\n      function doPrint(){ if(printed)return; printed=true; w.focus(); w.print(); }\r\n      w.addEventListener('load',function(){ setTimeout(doPrint,150); });\r\n      setTimeout(doPrint,1200);\r\n    });\r\n    b('pth-hs-copy-btn', function(){\r\n      if(!HS.imageSrc || HS.pins.length === 0){ window.pthILS.toast('Add image and pins first!','error'); return; }\r\n      window.pthILS.showCopyHTML(hsBuildExportHTML(), 'pth-hs-code-box');\r\n    });\r\n\r\n    document.addEventListener('pthILSSample', function(e){\r\n      if(e.detail.tab !== 'hotspots') return;\r\n      loadHotspotSample();\r\n    });\r\n\r\n    document.addEventListener('pthILSClear', function(e){\r\n      if(e.detail.tab !== 'hotspots') return;\r\n      HS.imageSrc = '';\r\n      HS.pins = [];\r\n      HS.activeIndex = -1;\r\n      \r\n      var imgEl = document.getElementById('pth-hs-img');\r\n      var emptyEl = document.getElementById('pth-hs-empty');\r\n      var urlEl = document.getElementById('pth-hs-url');\r\n      var exportCard = document.getElementById('pth-hs-export-card');\r\n      var editPanel = document.getElementById('pth-hs-edit-panel');\r\n      \r\n      if(imgEl) imgEl.src = '';\r\n      if(emptyEl) emptyEl.style.display = 'block';\r\n      if(urlEl) urlEl.value = '';\r\n      if(exportCard) exportCard.style.display = 'none';\r\n      if(editPanel) editPanel.classList.remove('active');\r\n      \r\n      hsRenderPins();\r\n      window.pthILS.toast('Workspace cleared!', 'info');\r\n    });\r\n  }\r\n\r\n  \/* Sample Data Loader *\/\r\n  function loadHotspotSample() {\r\n      var sampleImgUrl = 'https:\/\/schoolict.net\/tools\/sampledata\/hosport.jpeg'; \r\n      var urlInp = document.getElementById('pth-hs-url');\r\n      if(urlInp) urlInp.value = sampleImgUrl;\r\n      \r\n      var samplePins = [\r\n          {\r\n              x: \"33.50\", y: \"14.50\", \r\n              title: \"Speaking Pace Analysis\", \r\n              desc: \"This chart monitors the speaker's words per minute (WPM). The green bar indicates an optimal, steady pace, while red warns of speaking too quickly.\", \r\n              link: \"https:\/\/wikipedia.org\/wiki\/Words_per_minute\", \r\n              media: \"\"\r\n          },\r\n          {\r\n              x: \"68.50\", y: \"17.00\", \r\n              title: \"Total Word Count\", \r\n              desc: \"A quick metric showing the total number of words analyzed in this session (1,247 words).\", \r\n              link: \"\", \r\n              media: \"\"\r\n          },\r\n          {\r\n              x: \"30.00\", y: \"70.00\", \r\n              title: \"Sentiment Word Cloud\", \r\n              desc: \"Visual representation of the most frequently used words. Larger green words like 'Excellent' and 'Helpful' indicate a highly positive sentiment overall.\", \r\n              link: \"\", \r\n              media: \"https:\/\/www.youtube.com\/watch?v=DEhV_Y5p2Xo\" \r\n          },\r\n          {\r\n              x: \"75.00\", y: \"65.00\", \r\n              title: \"Silence Gap Tracker\", \r\n              desc: \"Identifies long pauses in speech. For example, a 20-minute gap was detected at timestamp 02:56. This is crucial for evaluating engagement.\", \r\n              link: \"\", \r\n              media: \"\"\r\n          }\r\n      ];\r\n\r\n      HS.imageSrc = sampleImgUrl;\r\n      HS.pins = samplePins;\r\n      HS.activeIndex = -1;\r\n      \r\n      var imgEl = document.getElementById('pth-hs-img');\r\n      var emptyEl = document.getElementById('pth-hs-empty');\r\n      var expCard = document.getElementById('pth-hs-export-card');\r\n      \r\n      if(!imgEl || !emptyEl) return;\r\n\r\n      imgEl.src = sampleImgUrl;\r\n      imgEl.onload = function() {\r\n          emptyEl.style.display = 'none';\r\n          if(expCard) expCard.style.display = 'block';\r\n          window.pthILS.toast('Analytics Dashboard Sample Loaded!', 'success');\r\n          hsRenderPins();\r\n      };\r\n      imgEl.onerror = function() {\r\n          window.pthILS.toast('Failed to load sample image. Please check the URL.', 'error');\r\n          HS.imageSrc = '';\r\n          imgEl.src = '';\r\n          emptyEl.style.display = 'block';\r\n      };\r\n  }\r\n\r\n  function init() {\r\n    buildTabHTML();\r\n    setTimeout(function(){ wireEvents(); }, 150);\r\n  }\r\n\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v2.0 \u2014 Fill in the Blanks Maker \u2014 100% BULLETPROOF FIX -->\r\n\r\n<style data-no-optimize=\"1\">\r\n\/* ============================================================\r\n   FILL IN THE BLANKS STYLES\r\n   ============================================================ *\/\r\n#pth-tab-blanks {\r\n  --fb-text-color: #1e293b;\r\n  --fb-inp-bg: #f8fafc;\r\n  --fb-inp-border: #94a3b8;\r\n  --fb-correct-bg: #dcfce7;\r\n  --fb-correct-text: #047857;\r\n  --fb-correct-border: #10b981;\r\n  --fb-wrong-bg: #fef2f2;\r\n  --fb-wrong-text: #991b1b;\r\n  --fb-wrong-border: #ef4444;\r\n}\r\n\r\n.pth-fb-textarea-wrap { position: relative; margin-bottom: 10px; }\r\n.pth-fb-highlighter-btn {\r\n  background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe;\r\n  padding: 6px 12px; border-radius: 6px; font-size: 0.75rem; font-weight: 700;\r\n  cursor: pointer; display: inline-flex; align-items: center; gap: 5px;\r\n  margin-bottom: 8px; transition: 0.2s;\r\n}\r\n.pth-fb-highlighter-btn:hover { background: #dbeafe; }\r\n\r\n.pth-fb-preview-content {\r\n  font-size: 1.05rem; line-height: 2; color: var(--fb-text-color);\r\n  background: #fff; padding: 20px; border-radius: 8px; border: 1px solid #e2e8f0;\r\n}\r\n.pth-fb-input {\r\n  border: none; border-bottom: 2px solid var(--fb-inp-border);\r\n  background: var(--fb-inp-bg); font-family: inherit; font-size: inherit;\r\n  font-weight: 700; color: #2563eb; text-align: center; outline: none;\r\n  padding: 0 5px; margin: 0 4px; border-radius: 4px 4px 0 0;\r\n  transition: all 0.2s;\r\n}\r\n.pth-fb-input:focus { border-bottom-color: #2563eb; background: #eff6ff; }\r\n.pth-fb-input.correct {\r\n  background: var(--fb-correct-bg); color: var(--fb-correct-text);\r\n  border-bottom-color: var(--fb-correct-border);\r\n}\r\n.pth-fb-input.wrong {\r\n  background: var(--fb-wrong-bg); color: var(--fb-wrong-text);\r\n  border-bottom-color: var(--fb-wrong-border);\r\n}\r\n\r\n.pth-fb-word-bank {\r\n  background: #f8fafc; border: 2px dashed #cbd5e1; padding: 15px;\r\n  border-radius: 8px; margin-bottom: 20px; display: none;\r\n}\r\n.pth-fb-word-bank-title { font-size: 0.8rem; font-weight: 800; color: #475569; text-transform: uppercase; margin-bottom: 10px; }\r\n.pth-fb-wb-words { display: flex; flex-wrap: wrap; gap: 8px; }\r\n.pth-fb-wb-word {\r\n  background: #fff; border: 1px solid #e2e8f0; padding: 4px 10px;\r\n  border-radius: 15px; font-size: 0.85rem; font-weight: 700; color: #1e293b;\r\n  box-shadow: 0 1px 2px rgba(0,0,0,0.05);\r\n}\r\n.pth-fb-wb-word.used { text-decoration: line-through; opacity: 0.5; }\r\n\r\n.pth-fb-meta { display: flex; justify-content: center; gap: 15px; margin-bottom: 15px; }\r\n.pth-fb-score { color: #1d4ed8; font-weight: 800; background: #eff6ff; padding: 6px 14px; border-radius: 20px; font-size: 0.85rem; }\r\n\r\n.pth-fb-options { display: flex; gap: 15px; margin-bottom: 15px; flex-wrap: wrap; }\r\n.pth-fb-opt-lbl { display: flex; align-items: center; gap: 5px; font-size: 0.8rem; font-weight: 700; color: #334155; cursor: pointer; }\r\n\r\n\/* Print Specific Overrides *\/\r\n@media print {\r\n  body * { visibility: hidden; }\r\n  #pth-tab-blanks .pth-ils-main > .pth-ils-card:not(#pth-fb-preview-card) { display: none !important; }\r\n  #pth-fb-preview-card, #pth-fb-preview-card * { visibility: visible; }\r\n  #pth-fb-preview-card { position: absolute; left: 0; top: 0; width: 100%; border: none; box-shadow: none; padding: 0; margin: 0; }\r\n  .pth-fb-input { border-bottom: 1px solid #000 !important; background: transparent !important; color: #000 !important; }\r\n  .pth-fb-preview-content { border: none !important; padding: 0 !important; }\r\n  #pth-fb-action-btns, .pth-fb-meta { display: none !important; }\r\n}\r\n<\/style>\r\n\r\n<!-- UI SOURCE (Hidden Div - Safe from WP Stripping) -->\r\n<div id=\"pth-fb-ui-source\" style=\"display:none;\" aria-hidden=\"true\">\r\n  <div class=\"pth-ils-layout\" id=\"pth-fb-layout\">\r\n    \r\n    <!-- Main Col -->\r\n    <div class=\"pth-ils-main\">\r\n      \r\n      <!-- Creator Card -->\r\n      <div class=\"pth-ils-card\">\r\n        <h3>\ud83d\udcdd Fill in the Blanks Creator<\/h3>\r\n        <p style=\"font-size:0.8rem; color:#475569; margin:0 0 12px;\">Paste your text below. Select a word and click the button to turn it into a blank space.<\/p>\r\n        \r\n        <button class=\"pth-cw-lang-pick-btn\" id=\"pth-fib-lang-pick-btn\" aria-label=\"Choose text language\" style=\"display:inline-flex;align-items:center;gap:8px;padding:9px 16px;background:#fff;border:2px solid #e2e8f0;border-radius:8px;cursor:pointer;font-family:Inter,system-ui,sans-serif;font-size:0.85rem;font-weight:700;color:#334155;width:100%;margin-bottom:10px;\">\r\n          <span id=\"pth-fib-pick-flag\" style=\"font-size:0.68rem;font-weight:800;background:#2563eb;color:#fff;border-radius:5px;padding:3px 6px;min-width:26px;text-align:center;\">EN<\/span>\r\n          <span id=\"pth-fib-pick-text\" style=\"flex:1;text-align:left;\">English \u2014 Text Language<\/span>\r\n          <span style=\"color:#94a3b8;font-size:0.8rem;\">&#x25BC;<\/span>\r\n        <\/button>\r\n\r\n        <div class=\"pth-fb-textarea-wrap\">\r\n          <button class=\"pth-fb-highlighter-btn\" id=\"pth-fb-make-blank-btn\" aria-label=\"Make Blank\">\r\n            <span style=\"font-size:1rem;\">\ud83d\udd8d\ufe0f<\/span> Make Selected Word Blank <strong>[ ]<\/strong>\r\n          <\/button>\r\n          <p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 6px;font-style:italic;\">&#x2139;&#xFE0F; The text below is just an example placeholder (not real data) &#x2014; type your own text with [blanks], or click &#x1F4A1; <strong>Load Sample<\/strong> above to fill in working examples.<\/p>\r\n          <textarea class=\"pth-ils-textarea\" id=\"pth-fb-input\" aria-label=\"Paragraph text\" style=\"min-height:180px; font-size:0.95rem;\" placeholder=\"Type your paragraph here. Wrap words in square brackets to make them blanks. For example: The capital of France is [Paris].\"><\/textarea>\r\n        <\/div>\r\n        \r\n        <div class=\"pth-fb-options\">\r\n          <label class=\"pth-fb-opt-lbl\"><input type=\"checkbox\" id=\"pth-fb-opt-wordbank\" checked> Show Word Bank<\/label>\r\n          <label class=\"pth-fb-opt-lbl\"><input type=\"checkbox\" id=\"pth-fb-opt-casesens\"> Case Sensitive Check<\/label>\r\n        <\/div>\r\n\r\n        <div class=\"pth-ils-btn-row\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-fb-gen-btn\">\u26a1 Generate Worksheet<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Preview Card -->\r\n      <div class=\"pth-ils-card\" id=\"pth-fb-preview-card\" style=\"display:none;\">\r\n        <h3 id=\"pth-fb-preview-title\">\ud83d\udcdd Complete the Paragraph<\/h3>\r\n        \r\n        <div class=\"pth-fb-meta\">\r\n          <span class=\"pth-fb-score\" id=\"pth-fb-score\">Score: 0 \/ 0<\/span>\r\n        <\/div>\r\n\r\n        <div class=\"pth-fb-word-bank\" id=\"pth-fb-word-bank\">\r\n          <div class=\"pth-fb-word-bank-title\">Word Bank<\/div>\r\n          <div class=\"pth-fb-wb-words\" id=\"pth-fb-wb-words\"><\/div>\r\n        <\/div>\r\n\r\n        <div class=\"pth-fb-preview-content\" id=\"pth-fb-preview-content\"><\/div>\r\n\r\n        <div class=\"pth-ils-btn-row\" style=\"margin-top:20px;\" id=\"pth-fb-action-btns\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-fb-check-btn\">\u2705 Check Answers<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fb-reveal-btn\">\ud83d\udc41 Reveal All<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fb-reset-btn\">\ud83d\udd04 Reset<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Export Card -->\r\n      <div class=\"pth-ils-card\" id=\"pth-fb-export-card\" style=\"display:none;\">\r\n        <h3>\ud83d\udce4 Export & Print<\/h3>\r\n        <div class=\"pth-ils-btn-row\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-fb-html-btn\">\ud83d\udcc4 Download Interactive HTML<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-fb-copy-btn\">\ud83d\udccb Copy HTML Code<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fb-print-btn\">\ud83d\udda8\ufe0f Print Worksheet<\/button>\r\n        <\/div>\r\n        <div class=\"pth-ils-code-box\" id=\"pth-fb-code-box\" style=\"display:none;\">\r\n          <textarea id=\"pth-fb-code-ta\" readonly aria-label=\"HTML code\"><\/textarea>\r\n        <\/div>\r\n      <\/div>\r\n      \r\n    <\/div>\r\n\r\n    <!-- Sidebar Col -->\r\n    <div class=\"pth-ils-sidebar\">\r\n      <div class=\"pth-ils-card\">\r\n        <h3>\ud83d\udca1 How to Use<\/h3>\r\n        <ul style=\"font-size:0.82rem;color:#334155;line-height:1.6;margin:0;padding-left:18px;\">\r\n          <li>Paste any article or text.<\/li>\r\n          <li>Highlight a word and click <strong>Make Blank<\/strong>.<\/li>\r\n          <li>Or manually wrap words like <code>[this]<\/code>.<\/li>\r\n          <li>Enable <strong>Word Bank<\/strong> to show a list of shuffled answers to the student.<\/li>\r\n          <li>Click <strong>Print Worksheet<\/strong> to generate a clean, paper-ready copy!<\/li>\r\n        <\/ul>\r\n      <\/div>\r\n      \r\n      <div class=\"pth-ils-card\">\r\n        <h3>\ud83d\udcca Stats<\/h3>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Total Blanks<\/span><span class=\"pth-ils-stat-val\" id=\"pth-fb-s-blanks\">\u2014<\/span><\/div>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Word Bank<\/span><span class=\"pth-ils-stat-val\" id=\"pth-fb-s-wb\">\u2014<\/span><\/div>\r\n      <\/div>\r\n      \r\n      <!-- AI Generator -->\r\n      <div class=\"pth-ils-card\" id=\"pth-fb-ai-card\" style=\"background:#f5f3ff;border-color:#ddd6fe;\">\r\n        <h3 style=\"color:#6d28d9;\">\ud83e\udd16 AI Cloze Generator<\/h3>\r\n        <p style=\"font-size:0.8rem;color:#334155;margin:0 0 10px;\">Let AI write a paragraph with pre-made blanks based on any topic!<\/p>\r\n        <label class=\"pth-ils-label\">\ud83d\udd11 Anthropic API Key<\/label>\r\n        <input type=\"password\" class=\"pth-ils-input\" id=\"pth-fb-ai-key\" placeholder=\"sk-ant-...\" style=\"font-family:monospace;font-size:0.8rem;\">\r\n        <label class=\"pth-ils-label\">\ud83d\udcda Topic<\/label>\r\n        <input type=\"text\" class=\"pth-ils-input\" id=\"pth-fb-ai-topic\" placeholder=\"Photosynthesis\">\r\n        <label class=\"pth-ils-label\">\ud83d\udd22 Number of Blanks<\/label>\r\n        <select class=\"pth-ils-select\" id=\"pth-fb-ai-count\">\r\n          <option value=\"5\">5 Blanks<\/option>\r\n          <option value=\"8\" selected>8 Blanks<\/option>\r\n          <option value=\"10\">10 Blanks<\/option>\r\n        <\/select>\r\n        <button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-fb-ai-gen-btn\" style=\"width:100%;justify-content:center;\">\u2728 Generate with AI<\/button>\r\n        <div id=\"pth-fb-ai-status\" style=\"display:none;margin-top:10px;border-radius:8px;padding:10px;font-size:0.8rem;font-weight:700;\"><\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function() {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function() { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  \/* ============================================================\r\n     MULTILINGUAL METHODS \u2014 self-contained\r\n     ============================================================ *\/\r\n  if (!window.pthILS) window.pthILS = {};\r\n  if (!window.pthILS.detectScript) {\r\n    window.pthILS.detectScript = function(t) {\r\n      if (!t||!t.trim()) return 'latin';\r\n      if (\/[\\u0D80-\\u0DFF]\/.test(t)) return 'sinhala';\r\n      if (\/[\\u0B80-\\u0BFF]\/.test(t)) return 'tamil';\r\n      if (\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(t)) return 'rtl';\r\n      if (\/[\\u3000-\\u9FFF\\uAC00-\\uD7AF]\/.test(t)) return 'cjk';\r\n      if (\/[\\u0900-\\u097F]\/.test(t)) return 'devanagari';\r\n      if (\/[\\u0E00-\\u0E7F]\/.test(t)) return 'thai';\r\n      if (\/[\\u0980-\\u09FF]\/.test(t)) return 'bengali';\r\n      return 'latin';\r\n    };\r\n  }\r\n  if (!window.pthILS.isRTL) {\r\n    window.pthILS.isRTL = function(t) { return \/[\\u0591-\\u07FF\\u200F\\u202B\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(t); };\r\n  }\r\n  if (!window.pthILS.getFontStack) {\r\n    window.pthILS.getFontStack = function(s) {\r\n      return ({sinhala:\"'Noto Sans Sinhala',system-ui,sans-serif\",tamil:\"'Noto Sans Tamil',system-ui,sans-serif\",\r\n               rtl:\"'Noto Sans Arabic','Noto Sans Hebrew',system-ui,sans-serif\",\r\n               cjk:\"'Noto Sans CJK SC',system-ui,sans-serif\",\r\n               devanagari:\"'Noto Sans Devanagari',system-ui,sans-serif\",\r\n               thai:\"'Noto Sans Thai',system-ui,sans-serif\",\r\n               bengali:\"'Noto Sans Bengali',system-ui,sans-serif\"})[s] || \"'Inter',system-ui,sans-serif\";\r\n    };\r\n  }\r\n  if (!window.pthILS.loadedFonts) window.pthILS.loadedFonts = {};\r\n  if (!window.pthILS.loadFont) {\r\n    window.pthILS.loadFont = function(s) {\r\n      if (window.pthILS.loadedFonts[s]) return;\r\n      window.pthILS.loadedFonts[s]=true;\r\n      var m={sinhala:'Noto+Sans+Sinhala:wght@400;700',tamil:'Noto+Sans+Tamil:wght@400;700',\r\n             rtl:'Noto+Sans+Arabic:wght@400;700',devanagari:'Noto+Sans+Devanagari:wght@400;700',\r\n             thai:'Noto+Sans+Thai:wght@400;700',bengali:'Noto+Sans+Bengali:wght@400;700',\r\n             cjk:'Noto+Sans+SC:wght@400;700'};\r\n      if (!m[s]) return;\r\n      var l=document.createElement('link');l.rel='stylesheet';\r\n      l.href='https:\/\/fonts.googleapis.com\/css2?family='+m[s]+'&display=swap';\r\n      document.head.appendChild(l);\r\n    };\r\n  }\r\n\r\n  var FIB_LANGS = [\r\n    {code:'en', native:'English', en:'English'},\r\n    {code:'si', native:'\\u0DC3\\u0DD2\\u0982\\u0DC4\\u0DBD', en:'Sinhala'},\r\n    {code:'ta', native:'\\u0BA4\\u0BAE\\u0BBF\\u0BB4\\u0BCD', en:'Tamil'},\r\n    {code:'zh', native:'\\u4E2D\\u6587', en:'Chinese'},\r\n    {code:'ar', native:'\\u0627\\u0644\\u0639\\u0631\\u0628\\u064A\\u0629', en:'Arabic'},\r\n    {code:'hi', native:'\\u0939\\u093F\\u0928\\u094D\\u0926\\u0940', en:'Hindi'},\r\n    {code:'es', native:'Espa\\u00F1ol', en:'Spanish'},\r\n    {code:'fr', native:'Fran\\u00E7ais', en:'French'},\r\n    {code:'pt', native:'Portugu\\u00EAs', en:'Portuguese'},\r\n    {code:'de', native:'Deutsch', en:'German'},\r\n    {code:'ja', native:'\\u65E5\\u672C\\u8A9E', en:'Japanese'},\r\n    {code:'ko', native:'\\uD55C\\uAD6D\\uC5B4', en:'Korean'},\r\n    {code:'ru', native:'\\u0420\\u0443\\u0441\\u0441\\u043A\\u0438\\u0439', en:'Russian'},\r\n    {code:'it', native:'Italiano', en:'Italian'},\r\n    {code:'tr', native:\"T\\u00FCrk\\u00E7e\", en:'Turkish'},\r\n    {code:'id', native:'Bahasa Indonesia', en:'Indonesian'},\r\n    {code:'ms', native:'Bahasa Melayu', en:'Malay'},\r\n    {code:'bn', native:'\\u09AC\\u09BE\\u0982\\u09B2\\u09BE', en:'Bengali'},\r\n    {code:'vi', native:\"Ti\\u1EBFng Vi\\u1EC7t\", en:'Vietnamese'},\r\n    {code:'th', native:'\\u0E44\\u0E17\\u0E22', en:'Thai'},\r\n    {code:'sw', native:'Kiswahili', en:'Swahili'},\r\n    {code:'nl', native:'Nederlands', en:'Dutch'},\r\n    {code:'pl', native:'Polski', en:'Polish'},\r\n    {code:'uk', native:'\\u0423\\u043A\\u0440\\u0430\\u0457\\u043D\\u0441\\u044C\\u043A\\u0430', en:'Ukrainian'},\r\n    {code:'el', native:'\\u0395\\u03BB\\u03BB\\u03B7\\u03BD\\u03B9\\u03BA\\u03AC', en:'Greek'},\r\n    {code:'he', native:'\\u05E2\\u05D1\\u05E8\\u05D9\\u05EA', en:'Hebrew'},\r\n    {code:'fa', native:'\\u0641\\u0627\\u0631\\u0633\\u06CC', en:'Persian'},\r\n    {code:'ur', native:'\\u0627\\u0631\\u062F\\u0648', en:'Urdu'},\r\n    {code:'ne', native:'\\u0928\\u0947\\u092A\\u093E\\u0932\\u0940', en:'Nepali'},\r\n    {code:'sv', native:'Svenska', en:'Swedish'},\r\n    {code:'ro', native:\"Rom\\u00E2n\\u0103\", en:'Romanian'},\r\n    {code:'fil', native:'Filipino', en:'Filipino'},\r\n    {code:'af', native:'Afrikaans', en:'Afrikaans'}\r\n  ];\r\n\r\n  var FIB_SAMPLES = {\r\n    en:'The [sun] is the star at the center of the [Solar System]. It is a nearly perfect sphere of hot [plasma], heated to incandescence by nuclear [fusion] reactions in its core. It radiates this energy mainly as visible [light], ultraviolet light, and [infrared] radiation, and is the most important source of [energy] for life on Earth.',\r\n    si:'The [sun] is the star at the center of the [Solar System]. It radiates [energy] as visible [light] for life on [Earth].',\r\n    es:'El [sol] es la estrella en el centro del [sistema solar]. Irradia [energ\u00eda] como [luz] visible.',\r\n    fr:'Le [soleil] est l\\'\u00e9toile au centre du [syst\u00e8me solaire]. Il irradie de l\\'[\u00e9nergie] sous forme de [lumi\u00e8re] visible.',\r\n    de:'Die [Sonne] ist der Stern im Zentrum des [Sonnensystems]. Sie strahlt [Energie] als sichtbares [Licht] aus.',\r\n    zh:'[\\u592A\\u9633]\\u662F[\\u592A\\u9633\\u7CFB][\\u4E2D\\u5FC3]\\u7684[\\u6052\\u661F]\\u3002\\u5B83\\u8F90\\u5C04[\\u80FD\\u91CF]\\u4E3B\\u8981\\u662F[\\u53EF\\u89C1\\u5149].',\r\n    ar:'[\\u0627\\u0644\\u0634\\u0645\\u0633] \\u0647\\u064A [\\u0646\\u062C\\u0645] \\u0641\\u064A \\u0645\\u0631\\u043A\\u0632 [\\u0627\\u0644\\u0646\\u0638\\u0627\\u0645 \\u0627\\u0644\\u0634\\u0645\\u0633\\u064A]. \\u062A\\u0634\\u0639 [\\u0637\\u0627\\u0642\\u0629] \\u0628\\u0634\\u0643\\u0644 \\u0636\\u0648\\u0621 [\\u0645\\u0631\\u0626\\u064A].',\r\n    hi:'[\\u0938\\u0942\\u0930\\u094D\\u0079] [\\u0938\\u094C\\u0930 \\u092E\\u0902\\u0921\\u0932] \\u0915\\u0947 \\u0915\\u0947\\u0902\\u0926\\u094D\\u0930 \\u092E\\u0947\\u0902 [\\u0924\\u093E\\u0930\\u093E] \\u0939\\u0948\\u0964 \\u092F\\u0939 [\\u0909\\u0930\\u094D\\u091C\\u093E] [\\u0926\\u0943\\u0936\\u094D\\u092F \\u092A\\u094D\\u0930\\u0915\\u093E\\u0936] \\u0915\\u0947 \\u0930\\u0942\\u092A \\u092E\\u0947\\u0902 \\u0935\\u093F\\u0915\\u093F\\u0930\\u0923 \\u0915\\u0930\\u0924\\u093E \\u0939\\u0948\\u0964'\r\n  };\r\n\r\n  var FIB_CURRENT_LANG = {code:'en', native:'English', en:'English'};\r\n\r\n  function fibApplyLangToInput(ta, text) {\r\n    if (!ta || !text) return;\r\n    var first = (text.split('\\n')[0] || '').replace(\/\\[.*?\\]\/g,'').trim();\r\n    var script = window.pthILS.detectScript(first);\r\n    window.pthILS.loadFont(script);\r\n    ta.style.fontFamily = window.pthILS.getFontStack(script);\r\n    ta.style.direction = window.pthILS.isRTL(first) ? 'rtl' : 'ltr';\r\n  }\r\n\r\n  function buildLangPopup() {\r\n    if (document.getElementById('pth-fib-lang-overlay')) return;\r\n    var style = document.createElement('style');\r\n    style.textContent = '#pth-fib-lang-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(15,23,42,0.55);z-index:9999998;align-items:center;justify-content:center;padding:16px;}#pth-fib-lang-overlay.pth-lo-open{display:flex;}#pth-fib-lang-modal{background:#fff;border-radius:16px;width:100%;max-width:660px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}.pth-lm-head{padding:20px 20px 0;flex-shrink:0;}.pth-lm-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;font-family:Inter,system-ui,sans-serif;}.pth-lm-sub{font-size:0.78rem;color:#334155;margin:0 0 12px;font-family:Inter,system-ui,sans-serif;}.pth-lm-close{position:absolute;top:14px;right:14px;background:#f1f5f9;border:none;width:32px;height:32px;border-radius:50%;font-size:0.9rem;cursor:pointer;color:#334155;display:flex;align-items:center;justify-content:center;font-family:inherit;font-weight:700;}.pth-lm-close:hover{background:#e2e8f0;}.pth-lm-search-wrap{padding:0 16px 10px;flex-shrink:0;}.pth-lm-search{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-family:Inter,system-ui,sans-serif;font-size:0.85rem;color:#1e293b;outline:none;background:#f8fafc;}.pth-lm-search::placeholder{color:#94a3b8;}.pth-lm-search:focus{border-color:#2563eb;background-color:#fff;}.pth-lm-grid-wrap{overflow-y:auto;flex:1;padding:0 8px 8px;}.pth-lm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}.pth-lm-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:8px;cursor:pointer;border:2px solid transparent;font-family:Inter,system-ui,sans-serif;background:transparent;text-align:left;width:100%;transition:background 0.1s;}.pth-lm-item:hover{background:#f1f5f9;}.pth-lm-item.pth-lm-sel{background:#eff6ff;border-color:#bfdbfe;}.pth-lm-flag{font-size:0.62rem;font-weight:800;line-height:1;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;text-align:center;background:#eff6ff;color:#1d4ed8;border-radius:5px;letter-spacing:0.3px;}.pth-lm-names{display:flex;flex-direction:column;min-width:0;}.pth-lm-native{font-size:0.82rem;font-weight:700;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.pth-lm-en{font-size:0.7rem;color:#334155;font-weight:500;}.pth-lm-footer{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;background:#f8fafc;}.pth-lm-footer-cur{font-size:0.8rem;color:#334155;font-family:Inter,system-ui,sans-serif;}.pth-lm-footer-cur strong{color:#1d4ed8;}.pth-lm-no-res{text-align:center;padding:24px;color:#334155;font-size:0.85rem;font-family:Inter,system-ui,sans-serif;display:none;}@media(max-width:520px){.pth-lm-grid{grid-template-columns:repeat(2,1fr);}#pth-fib-lang-modal{border-radius:12px;max-height:92vh;}}@media(max-width:360px){.pth-lm-grid{grid-template-columns:1fr;}}';\r\n    document.head.appendChild(style);\r\n    var overlay = document.createElement('div');\r\n    overlay.id = 'pth-fib-lang-overlay';\r\n    overlay.setAttribute('role','dialog');overlay.setAttribute('aria-modal','true');\r\n    overlay.innerHTML =\r\n      '<div id=\"pth-fib-lang-modal\">' +\r\n        '<div class=\"pth-lm-head\"><p class=\"pth-lm-title\">&#x1F30D; Choose Text Language<\/p><p class=\"pth-lm-sub\">Select language for sample paragraph<\/p><\/div>' +\r\n        '<button class=\"pth-lm-close\" id=\"pth-fib-lm-close\" aria-label=\"Close\">&#x2715;<\/button>' +\r\n        '<div class=\"pth-lm-search-wrap\"><input type=\"text\" class=\"pth-lm-search\" id=\"pth-fib-lm-search\" placeholder=\"Search language...\" aria-label=\"Search language\" autocomplete=\"off\"><\/div>' +\r\n        '<div class=\"pth-lm-grid-wrap\"><div class=\"pth-lm-grid\" id=\"pth-fib-lm-grid\"><\/div><div class=\"pth-lm-no-res\" id=\"pth-fib-lm-nores\">No languages found.<\/div><\/div>' +\r\n        '<div class=\"pth-lm-footer\"><span class=\"pth-lm-footer-cur\">Selected: <strong id=\"pth-fib-lm-cur\">English<\/strong><\/span><span style=\"font-size:0.72rem;color:#475569;\">&#x1F512; Browser only<\/span><\/div>' +\r\n      '<\/div>';\r\n    document.body.appendChild(overlay);\r\n    fibRenderLangGrid('');\r\n    var searchEl=document.getElementById('pth-fib-lm-search');\r\n    if(searchEl) searchEl.addEventListener('input',function(){ fibRenderLangGrid(searchEl.value.toLowerCase().trim()); });\r\n    var closeBtn=document.getElementById('pth-fib-lm-close');\r\n    if(closeBtn) closeBtn.addEventListener('click',fibCloseLangPopup);\r\n    overlay.addEventListener('click',function(e){ if(e.target===overlay) fibCloseLangPopup(); });\r\n    document.addEventListener('keydown',function(e){ if(e.key==='Escape') fibCloseLangPopup(); });\r\n  }\r\n\r\n  function fibRenderLangGrid(query) {\r\n    var grid=document.getElementById('pth-fib-lm-grid');\r\n    var nores=document.getElementById('pth-fib-lm-nores');\r\n    if(!grid) return;\r\n    grid.innerHTML='';\r\n    var filtered=FIB_LANGS.filter(function(l){ if(!query)return true; return l.en.toLowerCase().indexOf(query)!==-1||l.native.toLowerCase().indexOf(query)!==-1||l.code.indexOf(query)!==-1; });\r\n    if(!filtered.length){ if(nores)nores.style.display='block'; return; }\r\n    if(nores)nores.style.display='none';\r\n    filtered.forEach(function(l){\r\n      var btn=document.createElement('button');\r\n      btn.className='pth-lm-item'+(l.code===FIB_CURRENT_LANG.code?' pth-lm-sel':'');\r\n      btn.innerHTML='<span class=\"pth-lm-flag\">'+l.code.toUpperCase()+'<\/span><span class=\"pth-lm-names\"><span class=\"pth-lm-native\">'+l.native+'<\/span><span class=\"pth-lm-en\">'+l.en+'<\/span><\/span>';\r\n      btn.addEventListener('click',function(){ fibSelectLang(l); });\r\n      grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function fibSelectLang(l) {\r\n    FIB_CURRENT_LANG=l;\r\n    var cur=document.getElementById('pth-fib-lm-cur');\r\n    if(cur) cur.innerHTML=l.code.toUpperCase()+' '+l.native+' ('+l.en+')';\r\n    var flag=document.getElementById('pth-fib-pick-flag');\r\n    var text=document.getElementById('pth-fib-pick-text');\r\n    if(flag) flag.innerHTML=l.code.toUpperCase();\r\n    if(text) text.innerHTML=l.native+' \\u2014 '+l.en;\r\n    if(FIB_SAMPLES[l.code]) {\r\n      var ta=document.getElementById('pth-fb-input');\r\n      if(ta){ ta.value=FIB_SAMPLES[l.code]; fibApplyLangToInput(ta,FIB_SAMPLES[l.code]); }\r\n      window.pthILS.toast('Loaded: '+l.native+' ('+l.en+')', 'success');\r\n    } else {\r\n      window.pthILS.toast(l.en+' selected! Type your own text.','info');\r\n    }\r\n    fibRenderLangGrid('');\r\n    fibCloseLangPopup();\r\n  }\r\n\r\n  function fibOpenLangPopup() {\r\n    buildLangPopup();\r\n    var overlay=document.getElementById('pth-fib-lang-overlay');\r\n    if(overlay){ overlay.classList.add('pth-lo-open'); var s=document.getElementById('pth-fib-lm-search'); if(s){s.value='';fibRenderLangGrid('');setTimeout(function(){s.focus();},100);} }\r\n  }\r\n\r\n  function fibCloseLangPopup() {\r\n    var overlay=document.getElementById('pth-fib-lang-overlay');\r\n    if(overlay) overlay.classList.remove('pth-lo-open');\r\n  }\r\n\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-blanks');\r\n    if (!panel || panel.getAttribute('data-fb-built')) return;\r\n    \r\n    var source = document.getElementById('pth-fb-ui-source');\r\n    if(source) {\r\n        panel.appendChild(source.firstElementChild);\r\n        source.parentNode.removeChild(source);\r\n        panel.setAttribute('data-fb-built','1');\r\n    }\r\n  }\r\n\r\n  \/* Core State *\/\r\n  var FB = {\r\n    rawHtml: '',\r\n    answers: [],\r\n    showWordBank: true,\r\n    caseSensitive: false\r\n  };\r\n\r\n  \/* Helper to escape HTML safely *\/\r\n  function escHTML(s) {\r\n    return String(s==null?'':s).replace(\/&\/g,'&').replace(\/<\/g,'<').replace(\/>\/g,'>').replace(\/\"\/g,'\"');\r\n  }\r\n\r\n  \/* Text Highlighter Logic *\/\r\n  function makeSelectedBlank() {\r\n    var ta = document.getElementById('pth-fb-input');\r\n    if(!ta) return;\r\n    \r\n    var start = ta.selectionStart;\r\n    var end = ta.selectionEnd;\r\n    var text = ta.value;\r\n    \r\n    if (start === end) {\r\n        window.pthILS.toast('Select a word first!', 'warn');\r\n        ta.focus();\r\n        return;\r\n    }\r\n    \r\n    var selected = text.substring(start, end).trim();\r\n    if (!selected) return;\r\n    \r\n    \/* Avoid double wrapping *\/\r\n    if (selected.charAt(0) === '[' && selected.charAt(selected.length-1) === ']') {\r\n        window.pthILS.toast('Already a blank!', 'info');\r\n        return;\r\n    }\r\n\r\n    var before = text.substring(0, start);\r\n    var after = text.substring(end);\r\n    \r\n    ta.value = before + '[' + selected + ']' + after;\r\n    \r\n    \/* Restore selection but move cursor past bracket *\/\r\n    ta.focus();\r\n    ta.setSelectionRange(start, start + selected.length + 2);\r\n    window.pthILS.toast('Marked as blank!', 'success');\r\n  }\r\n\r\n  \/* Generate Logic *\/\r\n  function fbGenerate() {\r\n    var rawText = (document.getElementById('pth-fb-input') || {}).value || '';\r\n    if (!rawText.trim()) { window.pthILS.toast('Enter some text first!', 'error'); return; }\r\n\r\n    var optWB = document.getElementById('pth-fb-opt-wordbank');\r\n    var optCS = document.getElementById('pth-fb-opt-casesens');\r\n    FB.showWordBank = optWB ? optWB.checked : true;\r\n    FB.caseSensitive = optCS ? optCS.checked : false;\r\n\r\n    FB.answers = [];\r\n    \r\n    \/* Regex to find [word] patterns. Supports multiple words in brackets. *\/\r\n    var regex = \/\\[(.*?)\\]\/g;\r\n    var counter = 0;\r\n    \r\n    \/* Escape base text to prevent XSS, but preserve newlines as <br> *\/\r\n    var safeText = escHTML(rawText).replace(\/\\n\/g, '<br>');\r\n    \r\n    \/* The regex runs on the escaped text, so we need to match escaped brackets *\/\r\n    var safeRegex = \/\\[(.*?)\\]\/g; \r\n    \r\n    var parsedHtml = safeText.replace(safeRegex, function(match, group1) {\r\n        var ans = group1.trim();\r\n        if(!ans) return '[]'; \/* Empty bracket fallback *\/\r\n        \r\n        FB.answers.push(ans); \/\/ Unescape logic if needed, but safe HTML is fine here\r\n        \r\n        \/\/ Calculate input width based on answer length\r\n        var w = Math.max(3, ans.length) * 14 + 10; \r\n        \r\n        var inp = '<input type=\"text\" class=\"pth-fb-input\" data-idx=\"'+counter+'\" data-ans=\"'+ans+'\" style=\"width:'+w+'px;\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\">';\r\n        counter++;\r\n        return inp;\r\n    });\r\n\r\n    if (FB.answers.length === 0) {\r\n        window.pthILS.toast('No blanks found. Wrap words in [brackets].', 'warn');\r\n        return;\r\n    }\r\n\r\n    FB.rawHtml = parsedHtml;\r\n    fbRenderPreview();\r\n\r\n    var e = function(id){ return document.getElementById(id); };\r\n    if(e('pth-fb-s-blanks')) e('pth-fb-s-blanks').textContent = FB.answers.length;\r\n    if(e('pth-fb-s-wb')) e('pth-fb-s-wb').textContent = FB.showWordBank ? 'Yes' : 'No';\r\n\r\n    e('pth-fb-preview-card').style.display = 'block';\r\n    e('pth-fb-export-card').style.display = 'block';\r\n    window.pthILS.toast('Worksheet Generated!', 'success');\r\n  }\r\n\r\n  function fbRenderPreview() {\r\n    var contentEl = document.getElementById('pth-fb-preview-content');\r\n    if(contentEl) contentEl.innerHTML = FB.rawHtml;\r\n\r\n    var wbEl = document.getElementById('pth-fb-word-bank');\r\n    var wbWords = document.getElementById('pth-fb-wb-words');\r\n    \r\n    if (FB.showWordBank && wbEl && wbWords) {\r\n        wbEl.style.display = 'block';\r\n        wbWords.innerHTML = '';\r\n        var shuffled = window.pthILS.shuffle(FB.answers.slice());\r\n        shuffled.forEach(function(word) {\r\n            var wDiv = document.createElement('div');\r\n            wDiv.className = 'pth-fb-wb-word';\r\n            wDiv.textContent = word; \/\/ Word is already safe string\r\n            wbWords.appendChild(wDiv);\r\n        });\r\n    } else if (wbEl) {\r\n        wbEl.style.display = 'none';\r\n    }\r\n\r\n    document.getElementById('pth-fb-score').textContent = 'Score: 0 \/ ' + FB.answers.length;\r\n    \r\n    \/\/ Add input listeners to update word bank 'used' status\r\n    if (FB.showWordBank) {\r\n        var inputs = document.querySelectorAll('#pth-fb-preview-content .pth-fb-input');\r\n        inputs.forEach(function(inp) {\r\n            inp.addEventListener('input', updateWordBankStatus);\r\n        });\r\n    }\r\n  }\r\n\r\n  function updateWordBankStatus() {\r\n    var inputs = document.querySelectorAll('#pth-fb-preview-content .pth-fb-input');\r\n    var usedWords = [];\r\n    inputs.forEach(function(i){ \r\n        if(i.value.trim()) usedWords.push(FB.caseSensitive ? i.value.trim() : i.value.trim().toLowerCase()); \r\n    });\r\n\r\n    var wbWords = document.querySelectorAll('#pth-fb-wb-words .pth-fb-wb-word');\r\n    wbWords.forEach(function(wEl) {\r\n        var wordText = FB.caseSensitive ? wEl.textContent : wEl.textContent.toLowerCase();\r\n        var idx = usedWords.indexOf(wordText);\r\n        if (idx !== -1) {\r\n            wEl.classList.add('used');\r\n            usedWords.splice(idx, 1); \/\/ remove one instance to handle duplicates correctly\r\n        } else {\r\n            wEl.classList.remove('used');\r\n        }\r\n    });\r\n  }\r\n\r\n  function fbCheck() {\r\n    var inputs = document.querySelectorAll('#pth-fb-preview-content .pth-fb-input');\r\n    if (!inputs.length) return;\r\n\r\n    var correctCount = 0;\r\n    inputs.forEach(function(inp) {\r\n        var ans = inp.getAttribute('data-ans');\r\n        var val = inp.value.trim();\r\n        inp.classList.remove('correct', 'wrong');\r\n        \r\n        if (val) {\r\n            var isCorrect = FB.caseSensitive ? (val === ans) : (val.toLowerCase() === ans.toLowerCase());\r\n            if (isCorrect) {\r\n                inp.classList.add('correct');\r\n                correctCount++;\r\n            } else {\r\n                inp.classList.add('wrong');\r\n            }\r\n        }\r\n    });\r\n\r\n    document.getElementById('pth-fb-score').textContent = 'Score: ' + correctCount + ' \/ ' + FB.answers.length;\r\n    \r\n    if (correctCount === FB.answers.length) {\r\n        window.pthILS.toast('Perfect Score!', 'success');\r\n    } else {\r\n        window.pthILS.toast(correctCount + ' out of ' + FB.answers.length + ' correct.', 'info');\r\n    }\r\n  }\r\n\r\n  function fbReveal() {\r\n    var inputs = document.querySelectorAll('#pth-fb-preview-content .pth-fb-input');\r\n    inputs.forEach(function(inp) {\r\n        inp.value = inp.getAttribute('data-ans');\r\n        inp.classList.remove('correct', 'wrong');\r\n        inp.classList.add('correct');\r\n    });\r\n    updateWordBankStatus();\r\n    window.pthILS.toast('Answers Revealed!', 'warn');\r\n  }\r\n\r\n  function fbReset() {\r\n    var inputs = document.querySelectorAll('#pth-fb-preview-content .pth-fb-input');\r\n    inputs.forEach(function(inp) {\r\n        inp.value = '';\r\n        inp.classList.remove('correct', 'wrong');\r\n    });\r\n    updateWordBankStatus();\r\n    document.getElementById('pth-fb-score').textContent = 'Score: 0 \/ ' + FB.answers.length;\r\n  }\r\n\r\n  \/* ============================================================\r\n     EXPORT HTML BUILDER \u2014 v3.6 compliant\r\n     ============================================================ *\/\r\n  function fbBuildExportHTML() {\r\n    if (!FB.answers.length) return '';\r\n\r\n    \/* Pre-build the HTML of the worksheet with inputs already in place *\/\r\n    var worksheetHTML = FB.rawHtml;\r\n    var answers = FB.answers;\r\n    var showWB  = FB.showWordBank;\r\n    var caseSens= FB.caseSensitive;\r\n    var answersJSON = JSON.stringify(answers);\r\n\r\n    \/* Word bank HTML *\/\r\n    var wbHTML = '';\r\n    if (showWB) {\r\n      var shuffled = answers.slice().sort(function(){ return Math.random()-0.5; });\r\n      var wbWords = shuffled.map(function(w){ return '<span class=\"fb-wb-word\">'+w+'<\/span>'; }).join('');\r\n      wbHTML = '<div class=\"fb-word-bank\" id=\"fb-wb\"><div class=\"fb-wb-title\">Word Bank<\/div><div class=\"fb-wb-words\" id=\"fb-wb-words\">'+wbWords+'<\/div><\/div>';\r\n    }\r\n\r\n    var css =\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;color-adjust:exact;}' +\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;background:#eef2f9;color:#1e293b;display:flex;justify-content:center;padding:32px 16px;min-height:100vh;}' +\r\n      '.fb-page{width:100%;max-width:800px;background:#fff;border-radius:18px;box-shadow:0 10px 30px -10px rgba(15,23,42,0.18);padding:30px 34px 34px;}' +\r\n      '.fb-head{text-align:center;margin:0 0 18px;}' +\r\n      'h1{color:#1d4ed8;font-size:1.5rem;font-weight:800;margin:0 0 6px;}' +\r\n      '.fb-sub{color:#334155;font-size:0.85rem;margin:0;}' +\r\n      '.fb-meta{display:flex;align-items:center;justify-content:center;gap:14px;margin:14px 0 18px;flex-wrap:wrap;}' +\r\n      '.fb-score{color:#1d4ed8;font-weight:800;background:#eff6ff;padding:5px 14px;border-radius:20px;font-size:0.88rem;}' +\r\n      '.fb-timer{font-size:0.88rem;font-weight:700;color:#334155;background:#f1f5f9;padding:5px 12px;border-radius:7px;}' +\r\n      '.fb-word-bank{background:#f8fafc;border:2px dashed #cbd5e1;padding:18px;border-radius:10px;margin-bottom:22px;}' +\r\n      '.fb-wb-title{font-size:0.82rem;font-weight:800;color:#334155;text-transform:uppercase;margin-bottom:10px;}' +\r\n      '.fb-wb-words{display:flex;flex-wrap:wrap;gap:8px;}' +\r\n      '.fb-wb-word{background:#fff;border:1px solid #e2e8f0;padding:4px 12px;border-radius:20px;font-size:0.88rem;font-weight:700;color:#1e293b;}' +\r\n      '.fb-wb-word.used{text-decoration:line-through;opacity:0.4;}' +\r\n      '.fb-content{font-size:1.1rem;line-height:2.2;color:#1e293b;}' +\r\n      '.fb-input,.pth-fb-input{border:none;border-bottom:2px solid #94a3b8;background:#f8fafc;font-family:inherit;font-size:inherit;font-weight:700;color:#2563eb;text-align:center;outline:none;padding:2px 5px;margin:0 4px;border-radius:4px 4px 0 0;transition:all 0.2s;}' +\r\n      '.fb-input:focus,.pth-fb-input:focus{border-bottom-color:#2563eb;background:#eff6ff;}' +\r\n      '.fb-input.correct,.pth-fb-input.correct{background:#dcfce7;color:#047857;border-bottom-color:#10b981;}' +\r\n      '.fb-input.wrong,.pth-fb-input.wrong{background:#fef2f2;color:#991b1b;border-bottom-color:#ef4444;}' +\r\n      '.fb-input.revealed,.pth-fb-input.revealed{background:#fefce8;color:#92400e;border-bottom-color:#f59e0b;}' +\r\n      '.fb-btns{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin-top:28px;padding-top:20px;border-top:2px solid #e2e8f0;}' +\r\n      '.fb-btn{padding:9px 18px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.06);}' +\r\n      '.fb-btn-p{background:#2563eb;color:#fff;}' +\r\n      '.fb-btn-a{background:#fff;border:2px solid #e2e8f0;color:#334155;}' +\r\n      '.fb-btn-c{background:#7c3aed;color:#fff;}' +\r\n      '.fb-btn.active{outline:3px solid #fde68a;}' +\r\n      '@media(max-width:480px){.fb-page{padding:20px 16px 26px;border-radius:12px;}}' +\r\n      '@media print{body{background:#fff;padding:0;display:block;}.fb-page{box-shadow:none;padding:10px;max-width:100%;border-radius:0;}.fb-btns,.fb-timer{display:none!important;}.fb-input,.pth-fb-input{border-bottom:1px solid #000!important;background:transparent!important;color:#000!important;}}';\r\n\r\n    var sc = [\r\n      '(function(){',\r\n        'var answers='+answersJSON+';',\r\n        'var caseSens='+JSON.stringify(caseSens)+';',\r\n        'var showWB='+JSON.stringify(showWB)+';',\r\n        'var tStart=Date.now();var tEl=document.getElementById(\"fb-timer\");',\r\n        'if(tEl){setInterval(function(){var s=Math.floor((Date.now()-tStart)\/1000),m=Math.floor(s\/60),ss=s%60;tEl.textContent=\"\\u23F1 \"+(m<10?\"0\":\"\")+m+\":\"+(ss<10?\"0\":\"\")+ss;},1000);}',\r\n        'function upWb(){',\r\n          'if(!showWB)return;',\r\n          'var inps=document.querySelectorAll(\".pth-fb-input\");var used=[];',\r\n          'inps.forEach(function(i){if(i.value.trim())used.push(caseSens?i.value.trim():i.value.trim().toLowerCase());});',\r\n          'document.querySelectorAll(\".fb-wb-word\").forEach(function(we){',\r\n            'var wt=caseSens?we.textContent:we.textContent.toLowerCase();',\r\n            'var ix=used.indexOf(wt);',\r\n            'if(ix!==-1){we.classList.add(\"used\");used.splice(ix,1);}else{we.classList.remove(\"used\");}',\r\n          '});',\r\n        '}',\r\n        'document.querySelectorAll(\".pth-fb-input\").forEach(function(inp){inp.addEventListener(\"input\",upWb);});',\r\n        'document.getElementById(\"btn-check\").addEventListener(\"click\",function(){',\r\n          'var cor=0;document.querySelectorAll(\".pth-fb-input\").forEach(function(inp){',\r\n            'var a=inp.getAttribute(\"data-ans\"),v=inp.value.trim();',\r\n            'inp.classList.remove(\"correct\",\"wrong\",\"revealed\");',\r\n            'if(v){var ok=caseSens?(v===a):(v.toLowerCase()===a.toLowerCase());',\r\n            'if(ok){inp.classList.add(\"correct\");cor++;}else{inp.classList.add(\"wrong\");}}',\r\n          '});',\r\n          'document.getElementById(\"fb-score\").textContent=\"Score: \"+cor+\" \/ \"+answers.length;',\r\n        '});',\r\n        'var akOn=false;',\r\n        'document.getElementById(\"btn-answerkey\").addEventListener(\"click\",function(e){akOn=!akOn;e.target.classList.toggle(\"active\",akOn);',\r\n          'if(akOn){document.querySelectorAll(\".pth-fb-input\").forEach(function(inp){inp.value=inp.getAttribute(\"data-ans\");inp.classList.add(\"revealed\");inp.classList.remove(\"correct\",\"wrong\");});upWb();e.target.textContent=\"Hide Answer Key\";}',\r\n          'else{document.querySelectorAll(\".pth-fb-input\").forEach(function(inp){inp.value=\"\";inp.classList.remove(\"correct\",\"wrong\",\"revealed\");});upWb();document.getElementById(\"fb-score\").textContent=\"Score: 0 \/ \"+answers.length;e.target.textContent=\"Answer Key Mode\";}',\r\n        '});',\r\n        'document.getElementById(\"btn-reveal\").addEventListener(\"click\",function(){',\r\n          'document.querySelectorAll(\".pth-fb-input\").forEach(function(inp){inp.value=inp.getAttribute(\"data-ans\");inp.classList.add(\"revealed\");inp.classList.remove(\"correct\",\"wrong\");});',\r\n          'document.getElementById(\"fb-score\").textContent=\"Score: \"+answers.length+\" \/ \"+answers.length;',\r\n          'upWb();',\r\n        '});',\r\n        'document.getElementById(\"btn-reset\").addEventListener(\"click\",function(){',\r\n          'document.querySelectorAll(\".pth-fb-input\").forEach(function(inp){inp.value=\"\";inp.classList.remove(\"correct\",\"wrong\",\"revealed\");});',\r\n          'upWb();document.getElementById(\"fb-score\").textContent=\"Score: 0 \/ \"+answers.length;',\r\n        '});',\r\n        'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n\r\n    var so='<'+'script'+'>';\r\n    var sc2='<'+'\/'+'script'+'>';\r\n    var docOpen='<'+'!DOCTYPE html>'+'<'+'html lang=\"en\">'+'<'+'head>'+\r\n      '<'+'meta charset=\"UTF-8\">'+\r\n      '<'+'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">'+\r\n      '<'+'title>Fill in the Blanks Worksheet<'+'\/title>'+\r\n      '<'+'style>'+css+'<'+'\/style>'+\r\n      '<'+'\/head>'+'<'+'body>';\r\n    var docClose='<'+'\/'+'body>'+'<'+'\/'+'html>';\r\n\r\n    var body =\r\n      '<div class=\"fb-page\">' +\r\n      '<div class=\"fb-head\"><h2>&#x1F4DD; Complete the Paragraph<\/h2><p class=\"fb-sub\">Fill in the missing words below.<\/p><\/div>' +\r\n      '<div class=\"fb-meta\"><span class=\"fb-score\" id=\"fb-score\">Score: 0 \/ '+answers.length+'<\/span><span class=\"fb-timer\" id=\"fb-timer\">\\u23F1 00:00<\/span><\/div>' +\r\n      wbHTML +\r\n      '<div class=\"fb-content\">'+worksheetHTML+'<\/div>' +\r\n      '<div class=\"fb-btns\">' +\r\n        '<button class=\"fb-btn fb-btn-p\" id=\"btn-check\">\\u2705 Check Answers<\/button>' +\r\n        '<button class=\"fb-btn fb-btn-a\" id=\"btn-reveal\">\\uD83D\\uDC41 Reveal All<\/button>' +\r\n        '<button class=\"fb-btn fb-btn-a\" id=\"btn-reset\">\\uD83D\\uDD04 Reset<\/button>' +\r\n        '<button class=\"fb-btn fb-btn-a\" id=\"btn-answerkey\">\\uD83D\\uDDDD Answer Key Mode<\/button>' +\r\n        '<button class=\"fb-btn fb-btn-c\" id=\"btn-print\">\\uD83D\\uDDA8 Print Worksheet<\/button>' +\r\n      '<\/div>' +\r\n      '<\/div>';\r\n\r\n    return docOpen + body + so + sc + sc2 + docClose;\r\n  }\r\n\r\n  \/* ============================================================\r\n     WIRE EVENTS\r\n     ============================================================ *\/\r\n  function wireEvents() {\r\n    var b = function(id,fn){var el=document.getElementById(id);if(el)el.addEventListener('click',fn);};\r\n    \r\n    b('pth-fb-make-blank-btn', makeSelectedBlank);\r\n    b('pth-fb-gen-btn', fbGenerate);\r\n    b('pth-fb-check-btn', fbCheck);\r\n    b('pth-fb-reveal-btn', fbReveal);\r\n    b('pth-fb-reset-btn', fbReset);\r\n    b('pth-fib-lang-pick-btn', fibOpenLangPopup);\r\n\r\n    \/* Export Actions *\/\r\n    b('pth-fb-html-btn', function(){\r\n      if(!FB.answers.length){ window.pthILS.toast('Generate a worksheet first!','error'); return; }\r\n      var c=fbBuildExportHTML(); if(!c) return;\r\n      try {\r\n        var blob=new Blob([c],{type:'text\/html'});\r\n        var url=URL.createObjectURL(blob);\r\n        var a=document.createElement('a');\r\n        a.href=url;a.download='fill-in-blanks.html';\r\n        document.body.appendChild(a);a.click();document.body.removeChild(a);\r\n        setTimeout(function(){URL.revokeObjectURL(url);},2000);\r\n        window.pthILS.toast('HTML file downloaded!','success');\r\n      } catch(err){ window.pthILS.toast('Download failed: '+err.message,'error'); }\r\n    });\r\n    \r\n    b('pth-fb-copy-btn', function(){\r\n      if(!FB.answers.length){ window.pthILS.toast('Generate a worksheet first!','error'); return; }\r\n      window.pthILS.showCopyHTML(fbBuildExportHTML(), 'pth-fb-code-box');\r\n    });\r\n\r\n    b('pth-fb-print-btn', function(){\r\n      if(!FB.answers.length){ window.pthILS.toast('Generate a worksheet first!','error'); return; }\r\n      var c=fbBuildExportHTML(); if(!c) return;\r\n      var w=window.open('','_blank');\r\n      if(!w){ window.pthILS.toast('Popup blocked! Allow popups for this site to print.','error'); return; }\r\n      w.document.open();w.document.write(c);w.document.close();\r\n      var printed=false;\r\n      function doPrint(){ if(printed)return; printed=true; w.focus(); w.print(); }\r\n      w.addEventListener('load',function(){ setTimeout(doPrint,150); });\r\n      setTimeout(doPrint,1200);\r\n    });\r\n\r\n    \/* Sample Logic *\/\r\n    document.addEventListener('pthILSSample', function(e){\r\n      if(e.detail.tab !== 'blanks') return;\r\n      var ta = document.getElementById('pth-fb-input');\r\n      if(ta) {\r\n        ta.value = FIB_SAMPLES[FIB_CURRENT_LANG.code] || FIB_SAMPLES.en;\r\n        fibApplyLangToInput(ta, ta.value);\r\n        window.pthILS.toast('Sample Loaded! Click Generate.', 'success');\r\n      }\r\n    });\r\n\r\n    \/* Clear Logic *\/\r\n    document.addEventListener('pthILSClear', function(e){\r\n      if(e.detail.tab !== 'blanks') return;\r\n      var ta = document.getElementById('pth-fb-input');\r\n      if(ta) ta.value = '';\r\n      document.getElementById('pth-fb-preview-card').style.display = 'none';\r\n      document.getElementById('pth-fb-export-card').style.display = 'none';\r\n      FB.answers = [];\r\n      window.pthILS.toast('Worksheet Cleared.', 'info');\r\n    });\r\n\r\n    \/* AI Cloze Generator *\/\r\n    b('pth-fb-ai-gen-btn', function() {\r\n      var key=(document.getElementById('pth-fb-ai-key')||{}).value||'';\r\n      var topic=(document.getElementById('pth-fb-ai-topic')||{}).value||'';\r\n      var count=(document.getElementById('pth-fb-ai-count')||{}).value||'8';\r\n      var btn=document.getElementById('pth-fb-ai-gen-btn');\r\n      \r\n      if(key.indexOf('sk-ant-')!==0){ window.pthILS.toast('Enter valid Anthropic API key','error'); return; }\r\n      if(!topic.trim()){ window.pthILS.toast('Enter a topic','error'); return; }\r\n      \r\n      btn.textContent='Generating...'; btn.disabled=true;\r\n      \r\n      var prompt = 'Write a short educational paragraph (about 80-120 words) about \"'+topic+'\". Then, select exactly '+count+' key vocabulary words in the text and wrap them in square brackets like [this]. Ensure the text flows naturally. Return ONLY the text, nothing else.';\r\n      \r\n      fetch('https:\/\/api.anthropic.com\/v1\/messages',{\r\n        method:'POST',\r\n        headers:{'Content-Type':'application\/json','x-api-key':key,'anthropic-version':'2023-06-01','anthropic-dangerous-direct-browser-calls':'true'},\r\n        body:JSON.stringify({model:'claude-sonnet-4-6',max_tokens:800,messages:[{role:'user',content:prompt}]})\r\n      }).then(function(r){return r.json();}).then(function(data){\r\n        btn.innerHTML='\\u2728 Generate with AI'; btn.disabled=false;\r\n        if(data.error){ window.pthILS.toast(data.error.message,'error'); return; }\r\n        var text=(data.content&&data.content[0]&&data.content[0].text)||'';\r\n        if(text.indexOf('[') === -1) { window.pthILS.toast('AI failed to format correctly. Try again.','error'); return; }\r\n        var ta = document.getElementById('pth-fb-input');\r\n        if(ta) { ta.value = text.trim(); fibApplyLangToInput(ta, ta.value); }\r\n        window.pthILS.toast('AI generated content! Click Generate Worksheet.', 'success');\r\n        document.getElementById('pth-fb-gen-btn').scrollIntoView({behavior:'smooth',block:'center'});\r\n      }).catch(function(e){ \r\n        btn.innerHTML='\\u2728 Generate with AI'; btn.disabled=false; \r\n        window.pthILS.toast('Network Error: '+e.message,'error'); \r\n      });\r\n    });\r\n  }\r\n\r\n  function init() {\r\n    buildTabHTML();\r\n    setTimeout(function(){ wireEvents(); }, 150);\r\n  }\r\n\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v3.6 \u2014 Bingo Maker -->\r\n\r\n<style data-no-optimize=\"1\">\r\n#pth-tab-bingo {\r\n  --bg-color: #ffffff;\r\n  --bg-header: #1d4ed8;\r\n  --bg-header-text: #ffffff;\r\n  --bg-cell-alt: #eff6ff;\r\n  --text-color: #0f172a;\r\n  --grid-border: #0f172a;\r\n}\r\n\r\n.pth-bg-options-wrap {\r\n  display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));\r\n  gap: 12px; margin-bottom: 15px;\r\n}\r\n\r\n\/* Colour theme selector *\/\r\n.pth-bg-theme-row {\r\n  display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; align-items: center;\r\n}\r\n.pth-bg-theme-btn {\r\n  width: 34px; height: 34px; border-radius: 50%; border: 3px solid transparent;\r\n  cursor: pointer; display: flex; align-items: center; justify-content: center;\r\n  transition: transform 0.15s;\r\n}\r\n.pth-bg-theme-btn:hover { transform: scale(1.15); }\r\n.pth-bg-theme-btn.active { border-color: #0f172a; }\r\n\r\n.pth-bg-preview-wrap {\r\n  display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;\r\n  background: #f1f5f9; padding: 20px; border-radius: 8px; border: 1px solid #e2e8f0;\r\n  max-height: 620px; overflow-y: auto;\r\n}\r\n\r\n\/* Individual Bingo Card *\/\r\n.pth-bg-card {\r\n  background: var(--bg-color); width: 100%; max-width: 300px;\r\n  border: 3px solid var(--grid-border); padding: 8px;\r\n  box-shadow: 0 4px 12px rgba(0,0,0,0.08); page-break-inside: avoid;\r\n  border-radius: 4px;\r\n}\r\n.pth-bg-card-title {\r\n  text-align: center; font-size: 1.6rem; font-weight: 900;\r\n  letter-spacing: 8px; margin: 0 0 6px; color: var(--bg-header-text);\r\n  text-transform: uppercase; background: var(--bg-header);\r\n  padding: 6px 4px; border-radius: 3px; letter-spacing: 10px;\r\n}\r\n.pth-bg-grid {\r\n  display: grid; grid-template-columns: repeat(5, 1fr);\r\n  border-top: 2px solid var(--grid-border); border-left: 2px solid var(--grid-border);\r\n}\r\n.pth-bg-cell {\r\n  border-right: 2px solid var(--grid-border); border-bottom: 2px solid var(--grid-border);\r\n  aspect-ratio: 1 \/ 1; display: flex; align-items: center; justify-content: center;\r\n  text-align: center; padding: 3px; font-size: 0.72rem; font-weight: 700;\r\n  color: var(--text-color); word-break: break-word; line-height: 1.2;\r\n  background: var(--bg-color);\r\n}\r\n.pth-bg-cell:nth-child(even) { background: var(--bg-cell-alt); }\r\n.pth-bg-cell-free {\r\n  background: var(--bg-header) !important; color: var(--bg-header-text) !important;\r\n  font-size: 0.85rem; font-weight: 900;\r\n}\r\n.pth-bg-card-num {\r\n  text-align: center; font-size: 0.68rem; color: #64748b;\r\n  margin-top: 4px; font-weight: 600;\r\n}\r\n\r\n\/* How to Play card *\/\r\n.pth-bg-how-step {\r\n  display: flex; gap: 10px; align-items: flex-start; margin-bottom: 10px;\r\n}\r\n.pth-bg-how-num {\r\n  background: #2563eb; color: #fff; border-radius: 50%;\r\n  width: 22px; height: 22px; min-width: 22px; display: flex;\r\n  align-items: center; justify-content: center; font-size: 0.72rem;\r\n  font-weight: 800; margin-top: 1px;\r\n}\r\n.pth-bg-how-text { font-size: 0.8rem; color: #334155; line-height: 1.5; }\r\n\r\n\/* Print *\/\r\n@media print {\r\n  * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; color-adjust: exact !important; }\r\n  #pth-tab-bingo .pth-ils-main > .pth-ils-card:not(#pth-bg-preview-card) { display: none !important; }\r\n  #pth-bg-layout { display: block !important; }\r\n  .pth-ils-main { display: block !important; }\r\n  #pth-bg-preview-card { display: block !important; border: none !important; box-shadow: none !important; padding: 0 !important; margin: 0 !important; }\r\n  .pth-bg-preview-wrap { background: transparent !important; padding: 0 !important; border: none !important; max-height: none !important; overflow: visible !important; display: grid !important; grid-template-columns: 1fr 1fr !important; gap: 15px !important; }\r\n  .pth-bg-card { max-width: 100% !important; box-shadow: none !important; page-break-inside: avoid; }\r\n  .pth-ils-btn-row { display: none !important; }\r\n}\r\n<\/style>\r\n\r\n<!-- UI SOURCE (Hidden Div - Safe from WP Stripping) -->\r\n<div id=\"pth-bg-ui-source\" style=\"display:none;\" aria-hidden=\"true\">\r\n  <div class=\"pth-ils-layout\" id=\"pth-bg-layout\">\r\n    \r\n    <!-- Main Col -->\r\n    <div class=\"pth-ils-main\">\r\n      \r\n      <!-- Creator Card -->\r\n      <div class=\"pth-ils-card\">\r\n        <h3>\ud83d\udd22 Bingo Card Maker<\/h3>\r\n        <p style=\"font-size:0.8rem; color:#475569; margin:0 0 12px;\">Enter a list of words below, choose your colour theme, and generate randomized 5\u00d75 Bingo cards for your class.<\/p>\r\n        \r\n        <label class=\"pth-ils-label\" for=\"pth-bg-input\">Enter Words \u2014 one per line (minimum 24 recommended)<\/label>\r\n        <p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 4px;font-style:italic;\">&#x2139;&#xFE0F; The text below is just an example placeholder (not real data) &#x2014; type your own words, or click &#x1F4A1; <strong>Load Sample<\/strong> above to fill in working examples.<\/p>\r\n        <button id=\"pth-bg-lang-pick-btn\" aria-label=\"Choose word language\" style=\"display:inline-flex;align-items:center;gap:8px;padding:9px 16px;background:#fff;border:2px solid #e2e8f0;border-radius:8px;cursor:pointer;font-family:Inter,system-ui,sans-serif;font-size:0.85rem;font-weight:700;color:#334155;width:100%;margin-bottom:8px;transition:all 0.15s;\">\r\n          <span id=\"pth-bg-pick-flag\" style=\"font-size:0.68rem;font-weight:800;background:#2563eb;color:#fff;border-radius:5px;padding:3px 6px;min-width:26px;text-align:center;\">EN<\/span>\r\n          <span id=\"pth-bg-pick-text\" style=\"flex:1;text-align:left;\">English &#x2014; Word Language<\/span>\r\n          <span style=\"color:#94a3b8;font-size:0.8rem;\">&#x25BC;<\/span>\r\n        <\/button>\r\n        <textarea class=\"pth-ils-textarea\" id=\"pth-bg-input\" aria-label=\"Bingo words\" style=\"min-height:160px; font-size:0.95rem;\" placeholder=\"Apple&#10;Banana&#10;Orange&#10;Grapes&#10;Mango&#10;... (Add at least 24 words)\"><\/textarea>\r\n\r\n        <!-- Colour Theme Picker -->\r\n        <label class=\"pth-ils-label\" style=\"margin-bottom:8px;\">\ud83c\udfa8 Colour Theme<\/label>\r\n        <div class=\"pth-bg-theme-row\" id=\"pth-bg-theme-row\">\r\n          <button class=\"pth-bg-theme-btn active\" data-theme=\"classic\"   style=\"background:linear-gradient(135deg,#1d4ed8,#ffffff);\" title=\"Classic Blue\" aria-label=\"Classic Blue\"><\/button>\r\n          <button class=\"pth-bg-theme-btn\" data-theme=\"forest\"    style=\"background:linear-gradient(135deg,#047857,#d1fae5);\" title=\"Forest Green\" aria-label=\"Forest Green\"><\/button>\r\n          <button class=\"pth-bg-theme-btn\" data-theme=\"sunset\"    style=\"background:linear-gradient(135deg,#dc2626,#fef9c3);\" title=\"Sunset Red\" aria-label=\"Sunset Red\"><\/button>\r\n          <button class=\"pth-bg-theme-btn\" data-theme=\"purple\"    style=\"background:linear-gradient(135deg,#7c3aed,#ede9fe);\" title=\"Purple\" aria-label=\"Purple\"><\/button>\r\n          <button class=\"pth-bg-theme-btn\" data-theme=\"ocean\"     style=\"background:linear-gradient(135deg,#0891b2,#e0f2fe);\" title=\"Ocean Teal\" aria-label=\"Ocean Teal\"><\/button>\r\n          <button class=\"pth-bg-theme-btn\" data-theme=\"gold\"      style=\"background:linear-gradient(135deg,#b45309,#fef3c7);\" title=\"Gold\" aria-label=\"Gold\"><\/button>\r\n          <button class=\"pth-bg-theme-btn\" data-theme=\"rose\"      style=\"background:linear-gradient(135deg,#be185d,#fce7f3);\" title=\"Rose Pink\" aria-label=\"Rose Pink\"><\/button>\r\n          <button class=\"pth-bg-theme-btn\" data-theme=\"mono\"      style=\"background:linear-gradient(135deg,#0f172a,#f8fafc);\" title=\"Monochrome\" aria-label=\"Monochrome\"><\/button>\r\n          <span style=\"font-size:0.75rem;color:#64748b;font-weight:600;align-self:center;\">Colours print exactly as shown<\/span>\r\n        <\/div>\r\n        \r\n        <div class=\"pth-bg-options-wrap\">\r\n          <div>\r\n            <label class=\"pth-ils-label\" for=\"pth-bg-opt-count\">Number of Cards<\/label>\r\n            <select class=\"pth-ils-select\" id=\"pth-bg-opt-count\">\r\n              <option value=\"1\">1 Card<\/option>\r\n              <option value=\"5\">5 Cards<\/option>\r\n              <option value=\"10\" selected>10 Cards<\/option>\r\n              <option value=\"20\">20 Cards<\/option>\r\n              <option value=\"30\">30 Cards<\/option>\r\n            <\/select>\r\n          <\/div>\r\n          <div>\r\n            <label class=\"pth-ils-label\" for=\"pth-bg-opt-title\">Card Title<\/label>\r\n            <input type=\"text\" class=\"pth-ils-input\" id=\"pth-bg-opt-title\" value=\"BINGO\" aria-label=\"Card title\">\r\n          <\/div>\r\n          <div>\r\n            <label class=\"pth-ils-label\" for=\"pth-bg-opt-free\">Free Space Text<\/label>\r\n            <input type=\"text\" class=\"pth-ils-input\" id=\"pth-bg-opt-free\" value=\"FREE\" aria-label=\"Free space text\">\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"pth-ils-btn-row\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-bg-gen-btn\">\u26a1 Generate Bingo Cards<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Preview Card -->\r\n      <div class=\"pth-ils-card\" id=\"pth-bg-preview-card\" style=\"display:none;\">\r\n        <h3 id=\"pth-bg-preview-title\">\ud83d\udc40 Preview Generated Cards<\/h3>\r\n        \r\n        <div class=\"pth-bg-preview-wrap\" id=\"pth-bg-preview-wrap\">\r\n          <!-- Cards injected here via JS -->\r\n        <\/div>\r\n\r\n        <div class=\"pth-ils-btn-row\" style=\"margin-top:20px; padding-top:15px; border-top:1px solid #e2e8f0;\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-bg-html-btn\">\ud83d\udcc4 Download HTML<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-bg-copy-btn\">\ud83d\udccb Copy HTML Code<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-bg-print-btn\">\ud83d\udda8\ufe0f Print All Cards<\/button>\r\n        <\/div>\r\n\r\n        <div class=\"pth-ils-code-box\" id=\"pth-bg-code-box\" style=\"display:none;\">\r\n          <textarea id=\"pth-bg-code-ta\" readonly aria-label=\"HTML code\"><\/textarea>\r\n        <\/div>\r\n      <\/div>\r\n      \r\n    <\/div>\r\n\r\n    <!-- Sidebar Col -->\r\n    <div class=\"pth-ils-sidebar\">\r\n\r\n      <!-- How to Play -->\r\n      <div class=\"pth-ils-card\" style=\"background:#f0fdf4;border-color:#bbf7d0;\">\r\n        <h3 style=\"color:#047857;\">\ud83c\udfae How to Play Bingo<\/h3>\r\n        <div class=\"pth-bg-how-step\"><div class=\"pth-bg-how-num\">1<\/div><div class=\"pth-bg-how-text\"><strong>Print &amp; Distribute<\/strong> \u2014 Print and give each student a unique card. Every card is shuffled differently!<\/div><\/div>\r\n        <div class=\"pth-bg-how-step\"><div class=\"pth-bg-how-num\">2<\/div><div class=\"pth-bg-how-text\"><strong>Teacher Calls<\/strong> \u2014 The teacher reads out or shows words one at a time from the word list.<\/div><\/div>\r\n        <div class=\"pth-bg-how-step\"><div class=\"pth-bg-how-num\">3<\/div><div class=\"pth-bg-how-text\"><strong>Students Mark<\/strong> \u2014 Students find and cross off or cover matching words on their card using counters or pens.<\/div><\/div>\r\n        <div class=\"pth-bg-how-step\"><div class=\"pth-bg-how-num\">4<\/div><div class=\"pth-bg-how-text\"><strong>Win a Line or Full Card<\/strong> \u2014 First to complete a row, column, diagonal, or full card shouts <strong>\"BINGO!\"<\/strong> and wins!<\/div><\/div>\r\n        <div class=\"pth-bg-how-step\"><div class=\"pth-bg-how-num\">&#x2605;<\/div><div class=\"pth-bg-how-text\"><strong>FREE space<\/strong> \u2014 The centre cell is free for everyone and counts toward any line.<\/div><\/div>\r\n        <p style=\"font-size:0.75rem;color:#334155;margin:8px 0 0;line-height:1.5;\">\ud83d\udca1 <em>Tip: print the word list separately so students can verify their win.<\/em><\/p>\r\n      <\/div>\r\n\r\n      <div class=\"pth-ils-card\">\r\n        <h3>\ud83d\udcca Stats<\/h3>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Words Provided<\/span><span class=\"pth-ils-stat-val\" id=\"pth-bg-s-words\">\u2014<\/span><\/div>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Cards Generated<\/span><span class=\"pth-ils-stat-val\" id=\"pth-bg-s-cards\">\u2014<\/span><\/div>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Active Theme<\/span><span class=\"pth-ils-stat-val\" id=\"pth-bg-s-theme\">Classic Blue<\/span><\/div>\r\n      <\/div>\r\n      \r\n      <!-- AI Generator -->\r\n      <div class=\"pth-ils-card\" id=\"pth-bg-ai-card\" style=\"background:#f5f3ff;border-color:#ddd6fe;\">\r\n        <h3 style=\"color:#6d28d9;\">\ud83e\udd16 AI Words Generator<\/h3>\r\n        <p style=\"font-size:0.8rem;color:#334155;margin:0 0 10px;\">Generate 30 vocabulary words instantly based on any topic!<\/p>\r\n        <label class=\"pth-ils-label\">\ud83d\udd11 Anthropic API Key<\/label>\r\n        <input type=\"password\" class=\"pth-ils-input\" id=\"pth-bg-ai-key\" placeholder=\"sk-ant-...\" style=\"font-family:monospace;font-size:0.8rem;\" aria-label=\"API Key\">\r\n        <label class=\"pth-ils-label\">\ud83d\udcda Topic \/ Theme<\/label>\r\n        <input type=\"text\" class=\"pth-ils-input\" id=\"pth-bg-ai-topic\" placeholder=\"e.g. Space Exploration\" aria-label=\"Topic\">\r\n        <label class=\"pth-ils-label\">\ud83c\udf0d Language<\/label>\r\n        <select class=\"pth-ils-select\" id=\"pth-bg-ai-lang\" aria-label=\"Output language\">\r\n          <option value=\"English\">English<\/option>\r\n          <option value=\"Sinhala\">Sinhala<\/option>\r\n          <option value=\"Tamil\">Tamil<\/option>\r\n          <option value=\"Arabic\">Arabic<\/option>\r\n          <option value=\"Chinese\">Chinese<\/option>\r\n          <option value=\"Hindi\">Hindi<\/option>\r\n          <option value=\"Spanish\">Spanish<\/option>\r\n          <option value=\"French\">French<\/option>\r\n          <option value=\"German\">German<\/option>\r\n          <option value=\"Japanese\">Japanese<\/option>\r\n          <option value=\"Korean\">Korean<\/option>\r\n          <option value=\"Portuguese\">Portuguese<\/option>\r\n          <option value=\"Russian\">Russian<\/option>\r\n          <option value=\"Indonesian\">Indonesian<\/option>\r\n          <option value=\"Thai\">Thai<\/option>\r\n        <\/select>\r\n        <button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-bg-ai-gen-btn\" style=\"width:100%;justify-content:center;\">\u2728 Generate Words<\/button>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<!-- EXPORT HTML TEMPLATE (Safe from Browser Stripping) -->\r\n\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function() {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function() { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  var BG_LANGS = [\r\n    {code:'en',native:'English',en:'English'},{code:'si',native:'\\u0DC3\\u0DD2\\u0982\\u0DC4\\u0DBD',en:'Sinhala'},\r\n    {code:'ta',native:'\\u0BA4\\u0BAE\\u0BBF\\u0BB4\\u0BCD',en:'Tamil'},{code:'zh',native:'\\u4E2D\\u6587',en:'Chinese'},\r\n    {code:'ar',native:'\\u0627\\u0644\\u0639\\u0631\\u0628\\u064A\\u0629',en:'Arabic'},{code:'hi',native:'\\u0939\\u093F\\u0928\\u094D\\u0926\\u0940',en:'Hindi'},\r\n    {code:'es',native:'Espa\\u00F1ol',en:'Spanish'},{code:'fr',native:'Fran\\u00E7ais',en:'French'},\r\n    {code:'pt',native:'Portugu\\u00EAs',en:'Portuguese'},{code:'de',native:'Deutsch',en:'German'},\r\n    {code:'ja',native:'\\u65E5\\u672C\\u8A9E',en:'Japanese'},{code:'ko',native:'\\uD55C\\uAD6D\\uC5B4',en:'Korean'},\r\n    {code:'ru',native:'\\u0420\\u0443\\u0441\\u0441\\u043A\\u0438\\u0439',en:'Russian'},{code:'it',native:'Italiano',en:'Italian'},\r\n    {code:'tr',native:'T\\u00FCrk\\u00E7e',en:'Turkish'},{code:'id',native:'Bahasa Indonesia',en:'Indonesian'},\r\n    {code:'ms',native:'Bahasa Melayu',en:'Malay'},{code:'bn',native:'\\u09AC\\u09BE\\u0982\\u09B2\\u09BE',en:'Bengali'},\r\n    {code:'vi',native:'Ti\\u1EBFng Vi\\u1EC7t',en:'Vietnamese'},{code:'th',native:'\\u0E44\\u0E17\\u0E22',en:'Thai'},\r\n    {code:'sw',native:'Kiswahili',en:'Swahili'},{code:'nl',native:'Nederlands',en:'Dutch'},\r\n    {code:'pl',native:'Polski',en:'Polish'},{code:'uk',native:'\\u0423\\u043A\\u0440\\u0430\\u0457\\u043D\\u0441\\u044C\\u043A\\u0430',en:'Ukrainian'},\r\n    {code:'el',native:'\\u0395\\u03BB\\u03BB\\u03B7\\u03BD\\u03B9\\u03BA\\u03AC',en:'Greek'},{code:'he',native:'\\u05E2\\u05D1\\u05E8\\u05D9\\u05EA',en:'Hebrew'},\r\n    {code:'fa',native:'\\u0641\\u0627\\u0631\\u0633\\u06CC',en:'Persian'},{code:'ur',native:'\\u0627\\u0631\\u062F\\u0648',en:'Urdu'},\r\n    {code:'ne',native:'\\u0928\\u0947\\u092A\\u093E\\u0932\\u0940',en:'Nepali'},{code:'sv',native:'Svenska',en:'Swedish'},\r\n    {code:'ro',native:'Rom\\u00E2n\\u0103',en:'Romanian'},{code:'fil',native:'Filipino',en:'Filipino'},\r\n    {code:'af',native:'Afrikaans',en:'Afrikaans'}\r\n  ];\r\n\r\n  var BG_WORD_SAMPLES = {\r\n    en:'Sun\\nMoon\\nStar\\nVenus\\nMars\\nEarth\\nOrbit\\nComet\\nPluto\\nSaturn\\nJupiter\\nNeptune\\nUranus\\nMercury\\nGalaxy\\nNebula\\nRocket\\nMeteor\\nAsteroid\\nGravity\\nEclipse\\nTelescope\\nSatellite\\nSpaceship\\nAstronaut\\nBlack Hole\\nConstellation',\r\n    es:'Sol\\nLuna\\nEstrella\\nVenus\\nMarte\\nTierra\\nOrbita\\nCometa\\nPlut\\u00F3n\\nSaturno\\nJ\\u00FApiter\\nNeptuno\\nUrano\\nMercurio\\nGalaxia\\nNebulosa\\nCohete\\nMeteoro\\nAsteroide\\nGravedad\\nEclipse\\nTelescopi\\nSat\\u00E9lite\\nCohete\\nAstronauta\\nAgujero Negro\\nConstelaci\\u00F3n',\r\n    fr:'Soleil\\nLune\\n\\u00C9toile\\nV\\u00E9nus\\nMars\\nTerre\\nOrbite\\nCom\\u00E8te\\nPluton\\nSaturne\\nJupiter\\nNeptune\\nUranus\\nMercure\\nGalaxie\\nN\\u00E9buleuse\\nFus\\u00E9e\\nM\\u00E9t\\u00E9ore\\nAst\\u00E9ro\\u00EFde\\nGravit\\u00E9\\n\\u00C9clipse\\nT\\u00E9lescope\\nSatellite\\nVaisseau\\nAstronaute\\nTrou Noir\\nConstellation',\r\n    de:'Sonne\\nMond\\nStern\\nVenus\\nMars\\nErde\\nOrbit\\nKomet\\nPluto\\nSaturn\\nJupiter\\nNeptun\\nUranus\\nMerkur\\nGalaxie\\nNebel\\nRakete\\nMeteor\\nAsteroid\\nSchwerkraft\\nEklipse\\nTeleskop\\nSatellit\\nRaumschiff\\nAstronaut\\nSchwarzes Loch\\nKonstellation',\r\n    zh:'\\u592A\\u9633\\n\\u6708\\u4EAE\\n\\u661F\\u661F\\n\\u91D1\\u661F\\n\\u706B\\u661F\\n\\u5730\\u7403\\n\\u8F68\\u9053\\n\\u5F57\\u661F\\n\\u51A5\\u738B\\u661F\\n\\u571F\\u661F\\n\\u6728\\u661F\\n\\u6D77\\u738B\\u661F\\n\\u5929\\u738B\\u661F\\n\\u6C34\\u661F\\n\\u661F\\u7CFB\\n\\u661F\\u4E91\\n\\u706B\\u7BAD\\n\\u9668\\u77F3\\n\\u5C0F\\u884C\\u661F\\n\\u5F15\\u529B\\n\\u65E5\\u98DF\\n\\u671B\\u8FDC\\u955C\\n\\u536B\\u661F\\n\\u5B87\\u5B99\\u98DE\\u8239\\n\\u5B87\\u5B99\\u98DE\\u884C\\u5458\\n\\u9ED1\\u6D1E\\n\\u661F\\u5EA7'\r\n  };\r\n\r\n  var BG_CURRENT_LANG = {code:'en',native:'English',en:'English'};\r\n\r\n  function bgOpenLangPopup() {\r\n    if (!document.getElementById('pth-bg-lang-overlay')) {\r\n      var style = document.createElement('style');\r\n      style.textContent = '#pth-bg-lang-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(15,23,42,0.55);z-index:9999998;align-items:center;justify-content:center;padding:16px;}#pth-bg-lang-overlay.pth-lo-open{display:flex;}#pth-bg-lang-modal{background:#fff;border-radius:16px;width:100%;max-width:660px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}.pth-lm-head{padding:20px 20px 0;flex-shrink:0;}.pth-lm-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;}.pth-lm-sub{font-size:0.78rem;color:#334155;margin:0 0 12px;}.pth-lm-close{position:absolute;top:14px;right:14px;background:#f1f5f9;border:none;width:32px;height:32px;border-radius:50%;font-size:0.9rem;cursor:pointer;color:#334155;font-weight:700;}.pth-lm-close:hover{background:#e2e8f0;}.pth-lm-search-wrap{padding:0 16px 10px;flex-shrink:0;}.pth-lm-search{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-size:0.85rem;color:#1e293b;outline:none;background:#f8fafc;}.pth-lm-search:focus{border-color:#2563eb;}.pth-lm-grid-wrap{overflow-y:auto;flex:1;padding:0 8px 8px;}.pth-lm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}.pth-lm-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:8px;cursor:pointer;border:2px solid transparent;background:transparent;text-align:left;width:100%;}.pth-lm-item:hover{background:#f1f5f9;}.pth-lm-item.pth-lm-sel{background:#eff6ff;border-color:#bfdbfe;}.pth-lm-flag{font-size:0.62rem;font-weight:800;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;background:#eff6ff;color:#1d4ed8;border-radius:5px;}.pth-lm-names{display:flex;flex-direction:column;min-width:0;}.pth-lm-native{font-size:0.82rem;font-weight:700;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.pth-lm-en{font-size:0.7rem;color:#334155;}.pth-lm-footer{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;background:#f8fafc;}.pth-lm-footer-cur{font-size:0.8rem;color:#334155;}.pth-lm-footer-cur strong{color:#1d4ed8;}.pth-lm-no-res{text-align:center;padding:24px;color:#334155;font-size:0.85rem;display:none;}@media(max-width:520px){.pth-lm-grid{grid-template-columns:repeat(2,1fr);}}';\r\n      document.head.appendChild(style);\r\n      var ov=document.createElement('div');ov.id='pth-bg-lang-overlay';\r\n      ov.innerHTML='<div id=\"pth-bg-lang-modal\"><div class=\"pth-lm-head\"><p class=\"pth-lm-title\">&#x1F30D; Choose Word Language<\/p><p class=\"pth-lm-sub\">Select language for sample words<\/p><\/div><button class=\"pth-lm-close\" id=\"pth-bg-lm-close\">&#x2715;<\/button><div class=\"pth-lm-search-wrap\"><input type=\"text\" class=\"pth-lm-search\" id=\"pth-bg-lm-search\" placeholder=\"Search language...\" autocomplete=\"off\" aria-label=\"Search language\"><\/div><div class=\"pth-lm-grid-wrap\"><div class=\"pth-lm-grid\" id=\"pth-bg-lm-grid\"><\/div><div class=\"pth-lm-no-res\" id=\"pth-bg-lm-nores\">No languages found.<\/div><\/div><div class=\"pth-lm-footer\"><span class=\"pth-lm-footer-cur\">Selected: <strong id=\"pth-bg-lm-cur\">English<\/strong><\/span><span style=\"font-size:0.72rem;color:#475569;\">&#x1F512; Browser only<\/span><\/div><\/div>';\r\n      document.body.appendChild(ov);\r\n      var se=document.getElementById('pth-bg-lm-search');\r\n      if(se) se.addEventListener('input',function(){bgRenderLangGrid(se.value.toLowerCase().trim());});\r\n      var cl=document.getElementById('pth-bg-lm-close');\r\n      if(cl) cl.addEventListener('click',bgCloseLangPopup);\r\n      ov.addEventListener('click',function(e){if(e.target===ov)bgCloseLangPopup();});\r\n      document.addEventListener('keydown',function(e){if(e.key==='Escape')bgCloseLangPopup();});\r\n    }\r\n    bgRenderLangGrid('');\r\n    var ov=document.getElementById('pth-bg-lang-overlay');\r\n    if(ov){ov.classList.add('pth-lo-open');var s=document.getElementById('pth-bg-lm-search');if(s){s.value='';setTimeout(function(){s.focus();},100);}}\r\n  }\r\n\r\n  function bgCloseLangPopup() {\r\n    var ov=document.getElementById('pth-bg-lang-overlay');\r\n    if(ov) ov.classList.remove('pth-lo-open');\r\n  }\r\n\r\n  function bgRenderLangGrid(query) {\r\n    var grid=document.getElementById('pth-bg-lm-grid');\r\n    var nores=document.getElementById('pth-bg-lm-nores');\r\n    if(!grid) return;\r\n    grid.innerHTML='';\r\n    var filtered=BG_LANGS.filter(function(l){if(!query)return true;return l.en.toLowerCase().indexOf(query)!==-1||l.native.toLowerCase().indexOf(query)!==-1||l.code.indexOf(query)!==-1;});\r\n    if(!filtered.length){if(nores)nores.style.display='block';return;}\r\n    if(nores) nores.style.display='none';\r\n    filtered.forEach(function(l){\r\n      var btn=document.createElement('button');\r\n      btn.className='pth-lm-item'+(l.code===BG_CURRENT_LANG.code?' pth-lm-sel':'');\r\n      btn.innerHTML='<span class=\"pth-lm-flag\">'+l.code.toUpperCase()+'<\/span><span class=\"pth-lm-names\"><span class=\"pth-lm-native\">'+l.native+'<\/span><span class=\"pth-lm-en\">'+l.en+'<\/span><\/span>';\r\n      btn.addEventListener('click',function(){bgSelectLang(l);});\r\n      grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function bgSelectLang(l) {\r\n    BG_CURRENT_LANG=l;\r\n    var cur=document.getElementById('pth-bg-lm-cur');\r\n    if(cur) cur.innerHTML=l.code.toUpperCase()+' '+l.native+' ('+l.en+')';\r\n    var flag=document.getElementById('pth-bg-pick-flag');\r\n    var text=document.getElementById('pth-bg-pick-text');\r\n    if(flag) flag.innerHTML=l.code.toUpperCase();\r\n    if(text) text.innerHTML=l.native+' -- '+l.en;\r\n    if(BG_WORD_SAMPLES[l.code]){\r\n      var ta=document.getElementById('pth-bg-input');\r\n      if(ta){ta.value=BG_WORD_SAMPLES[l.code];}\r\n      window.pthILS.toast('Loaded: '+l.native+' ('+l.en+')','success');\r\n    } else {\r\n      window.pthILS.toast(l.en+' selected! Type your own words.','info');\r\n    }\r\n    bgCloseLangPopup();\r\n  }\r\n\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-bingo');\r\n    if (!panel || panel.getAttribute('data-bg-built')) return;\r\n    var source = document.getElementById('pth-bg-ui-source');\r\n    if(source) {\r\n      panel.appendChild(source.firstElementChild);\r\n      source.parentNode.removeChild(source);\r\n      panel.setAttribute('data-bg-built','1');\r\n    }\r\n  }\r\n\r\n  \/* Colour themes *\/\r\n  var BG_THEMES = {\r\n    classic: { name:'Classic Blue',  header:'#1d4ed8', headerText:'#ffffff', cellAlt:'#eff6ff', bg:'#ffffff', border:'#0f172a' },\r\n    forest:  { name:'Forest Green',  header:'#047857', headerText:'#ffffff', cellAlt:'#d1fae5', bg:'#ffffff', border:'#065f46' },\r\n    sunset:  { name:'Sunset Red',    header:'#dc2626', headerText:'#ffffff', cellAlt:'#fef9c3', bg:'#ffffff', border:'#991b1b' },\r\n    purple:  { name:'Purple',        header:'#7c3aed', headerText:'#ffffff', cellAlt:'#ede9fe', bg:'#ffffff', border:'#4c1d95' },\r\n    ocean:   { name:'Ocean Teal',    header:'#0891b2', headerText:'#ffffff', cellAlt:'#e0f2fe', bg:'#ffffff', border:'#164e63' },\r\n    gold:    { name:'Gold',          header:'#b45309', headerText:'#ffffff', cellAlt:'#fef3c7', bg:'#ffffff', border:'#78350f' },\r\n    rose:    { name:'Rose Pink',     header:'#be185d', headerText:'#ffffff', cellAlt:'#fce7f3', bg:'#ffffff', border:'#9d174d' },\r\n    mono:    { name:'Monochrome',    header:'#0f172a', headerText:'#ffffff', cellAlt:'#f1f5f9', bg:'#ffffff', border:'#0f172a' }\r\n  };\r\n\r\n  var BG = {\r\n    words: [],\r\n    cardsHtml: '',\r\n    cardCount: 10,\r\n    title: 'BINGO',\r\n    freeText: 'FREE',\r\n    font: \"'Inter', sans-serif\",\r\n    theme: 'classic'\r\n  };\r\n\r\n  function escHTML(s) {\r\n    return String(s==null?'':s).replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;');\r\n  }\r\n\r\n  \/* Build one bingo card's HTML *\/\r\n  function buildCard(words, title, freeText, font, theme, cardNum) {\r\n    var t = BG_THEMES[theme] || BG_THEMES.classic;\r\n    var shuffled = window.pthILS.shuffle(words.slice());\r\n    while (shuffled.length < 24) { shuffled = shuffled.concat(window.pthILS.shuffle(words.slice())); }\r\n    var gridHTML = '';\r\n    var wi = 0;\r\n    for (var r = 0; r < 5; r++) {\r\n      for (var c = 0; c < 5; c++) {\r\n        if (r === 2 && c === 2) {\r\n          gridHTML += '<div class=\"pth-bg-cell pth-bg-cell-free\" style=\"font-family:'+font+';background:'+t.header+'!important;color:'+t.headerText+'!important;\">' + escHTML(freeText) + '<\/div>';\r\n        } else {\r\n          var altBg = (r + c) % 2 === 0 ? t.bg : t.cellAlt;\r\n          gridHTML += '<div class=\"pth-bg-cell\" style=\"font-family:'+font+';background:'+altBg+';\">' + escHTML(shuffled[wi]) + '<\/div>';\r\n          wi++;\r\n        }\r\n      }\r\n    }\r\n    return '<div class=\"pth-bg-card\" style=\"border-color:'+t.border+';\">' +\r\n      '<div class=\"pth-bg-card-title\" style=\"background:'+t.header+';color:'+t.headerText+';\">' + escHTML(title) + '<\/div>' +\r\n      '<div class=\"pth-bg-grid\" style=\"border-color:'+t.border+';\">' + gridHTML + '<\/div>' +\r\n      '<div class=\"pth-bg-card-num\">Card #' + cardNum + '<\/div>' +\r\n      '<\/div>';\r\n  }\r\n\r\n  function bgGenerate() {\r\n    var rawText = (document.getElementById('pth-bg-input') || {}).value || '';\r\n    var lines = window.pthILS.parseLines(rawText);\r\n    if (lines.length < 10) { window.pthILS.toast('Please enter at least 10 words (24+ recommended).', 'error'); return; }\r\n    BG.cardCount = parseInt((document.getElementById('pth-bg-opt-count')||{}).value||'10') || 10;\r\n    BG.title    = ((document.getElementById('pth-bg-opt-title')||{}).value||'BINGO').trim() || 'BINGO';\r\n    BG.freeText = ((document.getElementById('pth-bg-opt-free')||{}).value||'FREE').trim()   || 'FREE';\r\n    BG.words = lines;\r\n    var script = window.pthILS.detectScript(rawText);\r\n    window.pthILS.loadFont(script);\r\n    BG.font = window.pthILS.getFontStack(script);\r\n    var wrapHTML = '';\r\n    for (var i = 0; i < BG.cardCount; i++) {\r\n      wrapHTML += buildCard(BG.words, BG.title, BG.freeText, BG.font, BG.theme, i + 1);\r\n    }\r\n    BG.cardsHtml = wrapHTML;\r\n    var previewWrap = document.getElementById('pth-bg-preview-wrap');\r\n    if (previewWrap) previewWrap.innerHTML = BG.cardsHtml;\r\n    var e = function(id){ return document.getElementById(id); };\r\n    if (e('pth-bg-s-words')) e('pth-bg-s-words').textContent = BG.words.length;\r\n    if (e('pth-bg-s-cards')) e('pth-bg-s-cards').textContent = BG.cardCount;\r\n    var th = BG_THEMES[BG.theme];\r\n    if (e('pth-bg-s-theme')) e('pth-bg-s-theme').textContent = th ? th.name : BG.theme;\r\n    e('pth-bg-preview-card').style.display = 'block';\r\n    window.pthILS.toast(BG.cardCount + ' Bingo cards generated!', 'success');\r\n  }\r\n\r\n  \/* ============================================================\r\n     EXPORT HTML BUILDER -- v3.6 string-concat, no template, print-color-adjust\r\n     ============================================================ *\/\r\n  function bgBuildExportHTML() {\r\n    if (!BG.cardsHtml || !BG.words.length) return '';\r\n    var t = BG_THEMES[BG.theme] || BG_THEMES.classic;\r\n\r\n    \/* Rebuild cards fresh with inline-all-styles for max print compat *\/\r\n    var cardsHTML = '';\r\n    for (var i = 0; i < BG.cardCount; i++) {\r\n      cardsHTML += buildCard(BG.words, BG.title, BG.freeText, BG.font, BG.theme, i + 1);\r\n    }\r\n\r\n    var css =\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;color-adjust:exact;}' +\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;background:#eef2f9;padding:24px;text-align:center;}' +\r\n      '.bg-toolbar{background:#fff;padding:12px;border-radius:10px;box-shadow:0 2px 8px rgba(0,0,0,0.08);margin-bottom:20px;display:flex;justify-content:center;gap:10px;flex-wrap:wrap;}' +\r\n      '.bg-btn{padding:10px 22px;border-radius:8px;border:none;background:'+t.header+';color:'+t.headerText+';font-size:0.9rem;font-weight:700;cursor:pointer;font-family:inherit;}' +\r\n      '.bg-wrap{display:flex;flex-wrap:wrap;gap:24px;justify-content:center;margin:0 auto;max-width:1200px;}' +\r\n      '.pth-bg-card{background:#fff;width:300px;border:3px solid '+t.border+';padding:8px;box-shadow:0 4px 12px rgba(0,0,0,0.1);page-break-inside:avoid;border-radius:4px;}' +\r\n      '.pth-bg-card-title{text-align:center;font-size:1.6rem;font-weight:900;letter-spacing:10px;margin:0 0 6px;color:'+t.headerText+';text-transform:uppercase;background:'+t.header+';padding:6px 4px;border-radius:3px;}' +\r\n      '.pth-bg-grid{display:grid;grid-template-columns:repeat(5,1fr);border-top:2px solid '+t.border+';border-left:2px solid '+t.border+';}' +\r\n      '.pth-bg-cell{border-right:2px solid '+t.border+';border-bottom:2px solid '+t.border+';aspect-ratio:1\/1;display:flex;align-items:center;justify-content:center;text-align:center;padding:3px;font-size:0.72rem;font-weight:700;word-break:break-word;line-height:1.2;}' +\r\n      '.pth-bg-cell-free{background:'+t.header+'!important;color:'+t.headerText+'!important;font-weight:900;font-size:0.85rem;}' +\r\n      '.pth-bg-card-num{text-align:center;font-size:0.65rem;color:#64748b;margin-top:4px;font-weight:600;}' +\r\n      '.how-box{background:#f0fdf4;border:1px solid #bbf7d0;border-radius:10px;padding:16px;margin:0 auto 20px;max-width:700px;text-align:left;}' +\r\n      '.how-box h2{color:#047857;font-size:1.1rem;margin:0 0 10px;}' +\r\n      '.how-step{display:flex;gap:10px;align-items:flex-start;margin-bottom:8px;font-size:0.85rem;color:#334155;line-height:1.5;}' +\r\n      '.how-num{background:#047857;color:#fff;border-radius:50%;width:20px;height:20px;min-width:20px;display:flex;align-items:center;justify-content:center;font-size:0.7rem;font-weight:800;margin-top:1px;}' +\r\n      '@media print{' +\r\n        'body{background:#fff;padding:10px;}' +\r\n        '.bg-toolbar,.how-box{display:none!important;}' +\r\n        '.bg-wrap{display:grid;grid-template-columns:1fr 1fr;gap:15px;max-width:100%;}' +\r\n        '.pth-bg-card{width:100%;box-shadow:none;}' +\r\n      '}';\r\n\r\n    var sc = [\r\n      '(function(){',\r\n        'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n\r\n    var so='<'+'script'+'>';\r\n    var sc2='<'+'\/'+'script'+'>';\r\n    var docOpen='<'+'!DOCTYPE html>'+'<'+'html lang=\"en\">'+'<'+'head>'+\r\n      '<'+'meta charset=\"UTF-8\">'+\r\n      '<'+'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">'+\r\n      '<'+'title>Bingo Cards -- '+escHTML(BG.title)+'<'+'\/title>'+\r\n      '<'+'style>'+css+'<'+'\/style>'+\r\n      '<'+'\/head>'+'<'+'body>';\r\n    var docClose='<'+'\/'+'body>'+'<'+'\/'+'html>';\r\n\r\n    var body =\r\n      '<div class=\"bg-toolbar\">' +\r\n        '<button class=\"bg-btn\" id=\"btn-print\">\\uD83D\\uDDA8 Print Bingo Cards<\/button>' +\r\n      '<\/div>' +\r\n      '<div class=\"how-box\">' +\r\n        '<h2>\\uD83C\\uDFAE How to Play<\/h2>' +\r\n        '<div class=\"how-step\"><div class=\"how-num\">1<\/div><div>Print and give each student a unique card -- every card is shuffled differently!<\/div><\/div>' +\r\n        '<div class=\"how-step\"><div class=\"how-num\">2<\/div><div>Teacher reads out words from the list one at a time.<\/div><\/div>' +\r\n        '<div class=\"how-step\"><div class=\"how-num\">3<\/div><div>Students cross off or cover matching words on their card.<\/div><\/div>' +\r\n        '<div class=\"how-step\"><div class=\"how-num\">4<\/div><div>First to complete a row, column, or diagonal shouts <strong>BINGO!<\/strong><\/div><\/div>' +\r\n        '<div class=\"how-step\"><div class=\"how-num\">\\u2605<\/div><div>The FREE space in the centre counts toward any line for everyone.<\/div><\/div>' +\r\n      '<\/div>' +\r\n      '<div class=\"bg-wrap\">' + cardsHTML + '<\/div>';\r\n\r\n    return docOpen + body + so + sc + sc2 + docClose;\r\n  }\r\n\r\n  \/* ============================================================\r\n     WIRE EVENTS\r\n     ============================================================ *\/\r\n  function wireEvents() {\r\n    var b = function(id,fn){var el=document.getElementById(id);if(el)el.addEventListener('click',fn);};\r\n    \r\n    b('pth-bg-gen-btn', bgGenerate);\r\n    b('pth-bg-lang-pick-btn', bgOpenLangPopup);\r\n\r\n    \/* Colour theme buttons *\/\r\n    var themeRow = document.getElementById('pth-bg-theme-row');\r\n    if (themeRow) {\r\n      themeRow.querySelectorAll('.pth-bg-theme-btn').forEach(function(btn) {\r\n        btn.addEventListener('click', function() {\r\n          themeRow.querySelectorAll('.pth-bg-theme-btn').forEach(function(b){ b.classList.remove('active'); });\r\n          btn.classList.add('active');\r\n          BG.theme = btn.getAttribute('data-theme') || 'classic';\r\n          var th = BG_THEMES[BG.theme];\r\n          var tEl = document.getElementById('pth-bg-s-theme');\r\n          if (tEl) tEl.textContent = th ? th.name : BG.theme;\r\n          if (BG.cardsHtml) bgGenerate(); \/* Regenerate with new theme *\/\r\n        });\r\n      });\r\n    }\r\n\r\n    \/* Export Actions *\/\r\n    b('pth-bg-html-btn', function(){\r\n      if(!BG.cardsHtml){ window.pthILS.toast('Generate cards first!','error'); return; }\r\n      var c=bgBuildExportHTML(); if(!c) return;\r\n      try {\r\n        var blob=new Blob([c],{type:'text\/html'});\r\n        var url=URL.createObjectURL(blob);\r\n        var a=document.createElement('a');\r\n        a.href=url;a.download='bingo-cards.html';\r\n        document.body.appendChild(a);a.click();document.body.removeChild(a);\r\n        setTimeout(function(){URL.revokeObjectURL(url);},2000);\r\n        window.pthILS.toast('HTML file downloaded!','success');\r\n      } catch(err){ window.pthILS.toast('Download failed: '+err.message,'error'); }\r\n    });\r\n\r\n    b('pth-bg-copy-btn', function(){\r\n      if(!BG.cardsHtml){ window.pthILS.toast('Generate cards first!','error'); return; }\r\n      window.pthILS.showCopyHTML(bgBuildExportHTML(), 'pth-bg-code-box');\r\n    });\r\n\r\n    b('pth-bg-print-btn', function(){\r\n      if(!BG.cardsHtml){ window.pthILS.toast('Generate cards first!','error'); return; }\r\n      var c=bgBuildExportHTML(); if(!c) return;\r\n      var w=window.open('','_blank');\r\n      if(!w){ window.pthILS.toast('Popup blocked! Allow popups for this site to print.','error'); return; }\r\n      w.document.open();w.document.write(c);w.document.close();\r\n      var printed=false;\r\n      function doPrint(){ if(printed)return; printed=true; w.focus(); w.print(); }\r\n      w.addEventListener('load',function(){ setTimeout(doPrint,150); });\r\n      setTimeout(doPrint,1200);\r\n    });\r\n\r\n    \/* Sample Logic *\/\r\n    var sampleWords = \"Sun\\nMercury\\nVenus\\nEarth\\nMars\\nJupiter\\nSaturn\\nUranus\\nNeptune\\nPluto\\nMoon\\nAsteroid\\nComet\\nMeteor\\nGalaxy\\nNebula\\nBlack Hole\\nStar\\nConstellation\\nOrbit\\nGravity\\nTelescope\\nAstronaut\\nSpaceship\\nRocket\\nSatellite\\nEclipse\";\r\n    document.addEventListener('pthILSSample', function(e){\r\n      if(e.detail.tab !== 'bingo') return;\r\n      var ta = document.getElementById('pth-bg-input');\r\n      if(ta) { ta.value = sampleWords; window.pthILS.toast('Sample Loaded! Click Generate.', 'success'); }\r\n    });\r\n\r\n    \/* Clear Logic *\/\r\n    document.addEventListener('pthILSClear', function(e){\r\n      if(e.detail.tab !== 'bingo') return;\r\n      var ta = document.getElementById('pth-bg-input');\r\n      if(ta) ta.value = '';\r\n      document.getElementById('pth-bg-preview-card').style.display = 'none';\r\n      BG.cardsHtml = '';\r\n      window.pthILS.toast('Workspace Cleared.', 'info');\r\n    });\r\n\r\n    \/* AI Word Generator *\/\r\n    b('pth-bg-ai-gen-btn', function() {\r\n      var key=(document.getElementById('pth-bg-ai-key')||{}).value||'';\r\n      var topic=(document.getElementById('pth-bg-ai-topic')||{}).value||'';\r\n      var lang=(document.getElementById('pth-bg-ai-lang')||{}).value||'English';\r\n      var btn=document.getElementById('pth-bg-ai-gen-btn');\r\n      if(key.indexOf('sk-ant-')!==0){ window.pthILS.toast('Enter valid Anthropic API key','error'); return; }\r\n      if(!topic.trim()){ window.pthILS.toast('Enter a topic','error'); return; }\r\n      btn.textContent='Generating...'; btn.disabled=true;\r\n      var prompt = 'Generate exactly 30 unique vocabulary words or short phrases about \"'+topic+'\" in '+lang+'. RULES: one word\/phrase per line, NO numbering, NO bullets, NO extra text. Short words are better for Bingo cards (1-3 words max each).';\r\n      fetch('https:\/\/api.anthropic.com\/v1\/messages',{\r\n        method:'POST',\r\n        headers:{'Content-Type':'application\/json','x-api-key':key,'anthropic-version':'2023-06-01','anthropic-dangerous-direct-browser-calls':'true'},\r\n        body:JSON.stringify({model:'claude-sonnet-4-6',max_tokens:600,messages:[{role:'user',content:prompt}]})\r\n      }).then(function(r){return r.json();}).then(function(data){\r\n        btn.innerHTML='\\u2728 Generate Words'; btn.disabled=false;\r\n        if(data.error){ window.pthILS.toast(data.error.message,'error'); return; }\r\n        var text=(data.content&&data.content[0]&&data.content[0].text)||'';\r\n        var lines=text.split('\\n').map(function(l){return l.replace(\/^[\\d\\.\\-\\*]+\/g,'').trim();}).filter(function(l){return l.length>1;});\r\n        if(lines.length < 10) { window.pthILS.toast('AI failed to format correctly. Try again.','error'); return; }\r\n        var ta = document.getElementById('pth-bg-input');\r\n        if(ta) ta.value = lines.join('\\n');\r\n        window.pthILS.toast('AI loaded '+lines.length+' words! Click Generate.', 'success');\r\n        document.getElementById('pth-bg-gen-btn').scrollIntoView({behavior:'smooth',block:'center'});\r\n      }).catch(function(e){ \r\n        btn.innerHTML='\\u2728 Generate Words'; btn.disabled=false; \r\n        window.pthILS.toast('Network Error: '+e.message,'error'); \r\n      });\r\n    });\r\n  }\r\n\r\n  \/* Core State *\/\r\n  var BG = {\r\n    words: [],\r\n    cardsHtml: '',\r\n    cardCount: 10,\r\n    title: 'BINGO',\r\n    freeText: 'FREE',\r\n    font: \"'Inter', sans-serif\"\r\n  };\r\n\r\n  \/* Helper to escape HTML safely *\/\r\n  function escHTML(s) {\r\n    return String(s==null?'':s).replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;');\r\n  }\r\n\r\n  function init() {\r\n    buildTabHTML();\r\n    setTimeout(function(){ wireEvents(); }, 150);\r\n  }\r\n\r\n  waitForShell(init);\r\n})();\r\n<\/script>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v3.6 \u2014 Flashcard Maker (Tab 10) -->\r\n\r\n<style data-no-optimize=\"1\">\r\n\/* \u2500\u2500 Language picker button (shared) \u2500\u2500 *\/\r\n.pth-cw-lang-pick-btn{display:inline-flex;align-items:center;gap:8px;padding:9px 16px;background:#fff;border:2px solid #e2e8f0;border-radius:8px;cursor:pointer;font-family:'Inter',system-ui,sans-serif;font-size:0.85rem;font-weight:700;color:#334155;transition:all 0.15s;width:100%;margin-bottom:10px;}\r\n.pth-cw-lang-pick-btn:hover{border-color:#2563eb;color:#1d4ed8;background:#eff6ff;}\r\n.pth-cw-lang-pick-flag{font-size:0.68rem;font-weight:800;background:#2563eb;color:#fff;border-radius:5px;padding:3px 6px;min-width:26px;text-align:center;letter-spacing:0.3px;}\r\n.pth-cw-lang-pick-text{flex:1;text-align:left;}\r\n.pth-cw-lang-pick-arrow{color:#94a3b8;font-size:0.8rem;}\r\n\r\n\/* \u2500\u2500 Flashcard workspace \u2500\u2500 *\/\r\n.pth-fc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;padding:16px;background:#f1f5f9;border-radius:10px;border:1px solid #e2e8f0;max-height:560px;overflow-y:auto;margin-top:16px;}\r\n.pth-fc-card{background:transparent;width:100%;height:160px;perspective:1000px;cursor:pointer;position:relative;}\r\n.pth-fc-inner{position:relative;width:100%;height:100%;text-align:center;transition:transform 0.5s cubic-bezier(0.4,0.2,0.2,1);transform-style:preserve-3d;}\r\n.pth-fc-card.fc-flipped .pth-fc-inner{transform:rotateY(180deg);}\r\n.pth-fc-front,.pth-fc-back{position:absolute;width:100%;height:100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;display:flex;align-items:center;justify-content:center;padding:14px;border-radius:12px;box-shadow:0 4px 8px -2px rgba(0,0,0,0.1);border:2px solid #e2e8f0;line-height:1.4;word-break:break-word;}\r\n.pth-fc-front{background:#fff;color:#1e293b;font-size:1.1rem;font-weight:800;}\r\n.pth-fc-back{background:#eff6ff;color:#1d4ed8;font-size:0.9rem;font-weight:700;transform:rotateY(180deg);border-color:#bfdbfe;}\r\n.pth-fc-card.fc-known .pth-fc-front,.pth-fc-card.fc-known .pth-fc-back{border-color:#10b981;box-shadow:0 0 0 2px #10b981;}\r\n.pth-fc-card.fc-unknown .pth-fc-front,.pth-fc-card.fc-unknown .pth-fc-back{border-color:#ef4444;box-shadow:0 0 0 2px #ef4444;}\r\n.pth-fc-badge{position:absolute;top:6px;right:8px;font-size:0.62rem;font-weight:800;background:#64748b;color:#fff;border-radius:10px;padding:2px 7px;z-index:2;}\r\n.pth-fc-card.fc-known .pth-fc-badge{background:#10b981;}\r\n.pth-fc-card.fc-unknown .pth-fc-badge{background:#ef4444;}\r\n\r\n\/* \u2500\u2500 Study \/ Quiz Mode \u2500\u2500 *\/\r\n.pth-fc-study-box{background:#fff;border:2px solid #e2e8f0;border-radius:16px;padding:32px;text-align:center;min-height:260px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;box-shadow:0 8px 24px -4px rgba(0,0,0,0.08);}\r\n.pth-fc-study-term{font-size:1.6rem;font-weight:900;color:#1e293b;line-height:1.3;}\r\n.pth-fc-study-def{font-size:1.1rem;font-weight:600;color:#1d4ed8;display:none;background:#eff6ff;padding:14px 20px;border-radius:10px;border:2px solid #bfdbfe;width:100%;}\r\n.pth-fc-study-progress{font-size:0.8rem;color:#64748b;font-weight:600;}\r\n.pth-fc-study-btns{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;}\r\n.pth-fc-study-bar{height:6px;background:#e2e8f0;border-radius:3px;overflow:hidden;width:100%;}\r\n.pth-fc-study-fill{height:100%;background:linear-gradient(90deg,#10b981,#2563eb);border-radius:3px;transition:width 0.4s;}\r\n\r\n@media print{\r\n  *{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important;color-adjust:exact!important;}\r\n  #pth-fc-input-card,#pth-fc-study-card,.pth-ils-btn-row,.pth-ils-stat-row{display:none!important;}\r\n  #pth-fc-grid-card{display:block!important;}\r\n  .pth-fc-grid{display:grid!important;grid-template-columns:repeat(3,1fr)!important;background:transparent!important;border:none!important;max-height:none!important;overflow:visible!important;padding:0!important;}\r\n  .pth-fc-card{height:auto!important;perspective:none!important;margin-bottom:10px;break-inside:avoid;}\r\n  .pth-fc-inner{transform:none!important;transition:none!important;transform-style:flat!important;}\r\n  .pth-fc-front,.pth-fc-back{position:relative!important;transform:none!important;backface-visibility:visible!important;box-shadow:none!important;border:1px solid #cbd5e1!important;height:auto!important;padding:8px!important;}\r\n  .pth-fc-front{border-bottom:none!important;border-radius:8px 8px 0 0!important;}\r\n  .pth-fc-back{border-top:1px dashed #cbd5e1!important;border-radius:0 0 8px 8px!important;}\r\n}\r\n<\/style>\r\n\r\n<div id=\"pth-fc-ui-source\" style=\"display:none;\" aria-hidden=\"true\">\r\n  <div class=\"pth-ils-layout\" id=\"pth-fc-layout\">\r\n\r\n    <!-- MAIN COL -->\r\n    <div class=\"pth-ils-main\">\r\n\r\n      <!-- Input Card -->\r\n      <div class=\"pth-ils-card\" id=\"pth-fc-input-card\">\r\n        <h3>\ud83d\udcc7 Flashcard Maker<\/h3>\r\n\r\n        <button class=\"pth-cw-lang-pick-btn\" id=\"pth-fc-lang-btn\" aria-label=\"Choose language\">\r\n          <span class=\"pth-cw-lang-pick-flag\" id=\"pth-fc-pick-flag\">EN<\/span>\r\n          <span class=\"pth-cw-lang-pick-text\" id=\"pth-fc-pick-text\">English \u2014 Card Language<\/span>\r\n          <span class=\"pth-cw-lang-pick-arrow\">&#x25BC;<\/span>\r\n        <\/button>\r\n\r\n        <label class=\"pth-ils-label\" for=\"pth-fc-input\">Enter Term : Definition \u2014 one pair per line<\/label>\r\n        <p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 6px;font-style:italic;\">&#x2139;&#xFE0F; The text below is just an example placeholder \u2014 type your own pairs, or click &#x1F4A1; <strong>Load Sample<\/strong> above.<\/p>\r\n        <textarea class=\"pth-ils-textarea\" id=\"pth-fc-input\" aria-label=\"Term and definition pairs\" style=\"min-height:150px;\" placeholder=\"Photosynthesis : Process by which plants make food using sunlight&#10;Mitochondria : Powerhouse of the cell&#10;Gravity : Force that attracts objects toward each other&#10;DNA : Molecule carrying genetic instructions\"><\/textarea>\r\n\r\n        <div class=\"pth-ils-btn-row\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-fc-gen-btn\">&#x26A1; Generate Flashcards<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Grid Card -->\r\n      <div class=\"pth-ils-card\" id=\"pth-fc-grid-card\" style=\"display:none;\">\r\n        <h3>&#x1F501; Browse Cards <span id=\"pth-fc-grid-label\" style=\"font-size:0.8rem;color:#64748b;font-weight:600;\"><\/span><\/h3>\r\n        <p style=\"font-size:0.82rem;color:#64748b;margin:0 0 10px;\">Click any card to flip it. Use keyboard: &#x25C4;&#x25BA; to navigate, Space to flip.<\/p>\r\n\r\n        <div class=\"pth-ils-btn-row\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fc-flip-all-btn\">&#x1F504; Flip All<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fc-shuffle-btn\">&#x1F500; Shuffle<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fc-reset-known-btn\">&#x1F9F9; Clear Marks<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-primary\" id=\"pth-fc-study-mode-btn\">&#x1F393; Study Mode<\/button>\r\n        <\/div>\r\n\r\n        <div class=\"pth-fc-grid\" id=\"pth-fc-grid\"><!-- cards injected --><\/div>\r\n\r\n        <div class=\"pth-ils-btn-row\" style=\"margin-top:18px;padding-top:14px;border-top:1px solid #e2e8f0;\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-success\" id=\"pth-fc-html-btn\">&#x1F4C4; Download HTML<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-purple\" id=\"pth-fc-copy-btn\">&#x1F4CB; Copy HTML<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fc-print-btn\">&#x1F5A8; Print Cards<\/button>\r\n        <\/div>\r\n        <div class=\"pth-ils-code-box\" id=\"pth-fc-code-box\" style=\"display:none;\">\r\n          <textarea id=\"pth-fc-code-ta\" readonly aria-label=\"HTML code\"><\/textarea>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fc-code-copy-btn\">&#x1F4CB; Copy<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Study Mode Card -->\r\n      <div class=\"pth-ils-card\" id=\"pth-fc-study-card\" style=\"display:none;\">\r\n        <h3>&#x1F393; Study Mode <span id=\"pth-fc-study-label\" style=\"font-size:0.8rem;color:#64748b;font-weight:600;\"><\/span><\/h3>\r\n        <div class=\"pth-fc-study-box\" id=\"pth-fc-study-box\">\r\n          <div class=\"pth-fc-study-progress\" id=\"pth-fc-study-prog\">Card 1 \/ 1<\/div>\r\n          <div class=\"pth-fc-study-bar\"><div class=\"pth-fc-study-fill\" id=\"pth-fc-study-fill\" style=\"width:0%;\"><\/div><\/div>\r\n          <div class=\"pth-fc-study-term\" id=\"pth-fc-study-term\">Term<\/div>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fc-reveal-btn\">&#x1F441; Reveal Answer<\/button>\r\n          <div class=\"pth-fc-study-def\" id=\"pth-fc-study-def\">Definition<\/div>\r\n          <div class=\"pth-fc-study-btns\" id=\"pth-fc-study-btns\" style=\"display:none;\">\r\n            <button class=\"pth-ils-btn\" id=\"pth-fc-known-btn\" style=\"background:#10b981;color:#fff;\">&#x2705; Know It<\/button>\r\n            <button class=\"pth-ils-btn\" id=\"pth-fc-unknown-btn\" style=\"background:#ef4444;color:#fff;\">&#x274C; Still Learning<\/button>\r\n          <\/div>\r\n        <\/div>\r\n        <div class=\"pth-ils-btn-row\" style=\"margin-top:12px;\">\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fc-study-back-btn\">&#x2190; Back to Cards<\/button>\r\n          <button class=\"pth-ils-btn pth-ils-btn-outline\" id=\"pth-fc-study-restart-btn\">&#x1F504; Restart<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n    <\/div>\r\n\r\n    <!-- SIDEBAR -->\r\n    <div class=\"pth-ils-sidebar\">\r\n      <div class=\"pth-ils-card\">\r\n        <h3>&#x1F4CA; Progress<\/h3>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Total Cards<\/span><span class=\"pth-ils-stat-val\" id=\"pth-fc-s-total\">\u2014<\/span><\/div>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">&#x2705; Know It<\/span><span class=\"pth-ils-stat-val\" id=\"pth-fc-s-known\" style=\"color:#10b981;\">0<\/span><\/div>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">&#x274C; Learning<\/span><span class=\"pth-ils-stat-val\" id=\"pth-fc-s-unknown\" style=\"color:#ef4444;\">0<\/span><\/div>\r\n        <div class=\"pth-ils-stat-row\"><span class=\"pth-ils-stat-label\">Language<\/span><span class=\"pth-ils-stat-val\" id=\"pth-fc-s-lang\">English<\/span><\/div>\r\n      <\/div>\r\n\r\n      <div class=\"pth-ils-card\" style=\"background:#f0fdf4;border-color:#bbf7d0;\">\r\n        <h3 style=\"color:#047857;\">&#x1F4D6; How to Use<\/h3>\r\n        <ul style=\"font-size:0.82rem;line-height:1.7;padding-left:18px;margin:0;color:#334155;\">\r\n          <li>Enter pairs as <strong>Term : Definition<\/strong>, one per line.<\/li>\r\n          <li>Click any card to flip between term and definition.<\/li>\r\n          <li>Use <strong>&#x25C4;&#x25BA;<\/strong> arrow keys to navigate, <strong>Space<\/strong> to flip.<\/li>\r\n          <li>Mark cards &#x2705; <em>Know It<\/em> \/ &#x274C; <em>Learning<\/em> in Study Mode.<\/li>\r\n          <li>Download the HTML file to share with students offline.<\/li>\r\n        <\/ul>\r\n      <\/div>\r\n    <\/div>\r\n\r\n  <\/div>\r\n<\/div>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function() {\r\n  'use strict';\r\n\r\n  function waitForShell(cb) {\r\n    if (window.pthILS && window.pthILS.shellReady) { cb(); return; }\r\n    var iv = setInterval(function() {\r\n      if (window.pthILS && window.pthILS.shellReady) { clearInterval(iv); cb(); }\r\n    }, 50);\r\n    setTimeout(function() { clearInterval(iv); }, 10000);\r\n  }\r\n\r\n  \/* \u2500\u2500 multilingual helpers \u2500\u2500 *\/\r\n  if (!window.pthILS) window.pthILS = {};\r\n  if (!window.pthILS.detectScript) {\r\n    window.pthILS.detectScript = function(t) {\r\n      if (!t) return 'latin';\r\n      if (\/[\\u0D80-\\u0DFF]\/.test(t)) return 'sinhala';\r\n      if (\/[\\u0B80-\\u0BFF]\/.test(t)) return 'tamil';\r\n      if (\/[\\u0591-\\u07FF\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(t)) return 'rtl';\r\n      if (\/[\\u3000-\\u9FFF\\uAC00-\\uD7AF]\/.test(t)) return 'cjk';\r\n      if (\/[\\u0900-\\u097F]\/.test(t)) return 'devanagari';\r\n      if (\/[\\u0E00-\\u0E7F]\/.test(t)) return 'thai';\r\n      return 'latin';\r\n    };\r\n  }\r\n  if (!window.pthILS.isRTL) { window.pthILS.isRTL = function(t) { return \/[\\u0591-\\u07FF\\u200F\\uFB1D-\\uFDFD\\uFE70-\\uFEFC]\/.test(t); }; }\r\n  if (!window.pthILS.getFontStack) {\r\n    window.pthILS.getFontStack = function(s) {\r\n      return ({sinhala:\"'Noto Sans Sinhala',system-ui\",tamil:\"'Noto Sans Tamil',system-ui\",rtl:\"'Noto Sans Arabic',system-ui\",cjk:\"'Noto Sans CJK SC',system-ui\",devanagari:\"'Noto Sans Devanagari',system-ui\",thai:\"'Noto Sans Thai',system-ui\"})[s] || \"'Inter',system-ui,sans-serif\";\r\n    };\r\n  }\r\n  if (!window.pthILS.loadedFonts) window.pthILS.loadedFonts = {};\r\n  if (!window.pthILS.loadFont) {\r\n    window.pthILS.loadFont = function(s) {\r\n      if (window.pthILS.loadedFonts[s]) return; window.pthILS.loadedFonts[s] = true;\r\n      var m = {sinhala:'Noto+Sans+Sinhala:wght@400;700',tamil:'Noto+Sans+Tamil:wght@400;700',rtl:'Noto+Sans+Arabic:wght@400;700',devanagari:'Noto+Sans+Devanagari:wght@400;700',thai:'Noto+Sans+Thai:wght@400;700',cjk:'Noto+Sans+SC:wght@400;700'};\r\n      if (!m[s]) return;\r\n      var l = document.createElement('link'); l.rel = 'stylesheet';\r\n      l.href = 'https:\/\/fonts.googleapis.com\/css2?family=' + m[s] + '&display=swap';\r\n      document.head.appendChild(l);\r\n    };\r\n  }\r\n\r\n  var FC_LANGS = [\r\n    {code:'en',native:'English',en:'English'},{code:'si',native:'\\u0DC3\\u0DD2\\u0982\\u0DC4\\u0DBD',en:'Sinhala'},\r\n    {code:'ta',native:'\\u0BA4\\u0BAE\\u0BBF\\u0BB4\\u0BCD',en:'Tamil'},{code:'zh',native:'\\u4E2D\\u6587',en:'Chinese'},\r\n    {code:'ar',native:'\\u0627\\u0644\\u0639\\u0631\\u0628\\u064A\\u0629',en:'Arabic'},{code:'hi',native:'\\u0939\\u093F\\u0928\\u094D\\u0926\\u0940',en:'Hindi'},\r\n    {code:'es',native:'Espa\\u00F1ol',en:'Spanish'},{code:'fr',native:'Fran\\u00E7ais',en:'French'},\r\n    {code:'pt',native:'Portugu\\u00EAs',en:'Portuguese'},{code:'de',native:'Deutsch',en:'German'},\r\n    {code:'ja',native:'\\u65E5\\u672C\\u8A9E',en:'Japanese'},{code:'ko',native:'\\uD55C\\uAD6D\\uC5B4',en:'Korean'},\r\n    {code:'ru',native:'\\u0420\\u0443\\u0441\\u0441\\u043A\\u0438\\u0439',en:'Russian'},{code:'it',native:'Italiano',en:'Italian'},\r\n    {code:'tr',native:'T\\u00FCrk\\u00E7e',en:'Turkish'},{code:'id',native:'Bahasa Indonesia',en:'Indonesian'},\r\n    {code:'ms',native:'Bahasa Melayu',en:'Malay'},{code:'bn',native:'\\u09AC\\u09BE\\u0982\\u09B2\\u09BE',en:'Bengali'},\r\n    {code:'vi',native:'Ti\\u1EBFng Vi\\u1EC7t',en:'Vietnamese'},{code:'th',native:'\\u0E44\\u0E17\\u0E22',en:'Thai'},\r\n    {code:'sw',native:'Kiswahili',en:'Swahili'},{code:'nl',native:'Nederlands',en:'Dutch'},\r\n    {code:'pl',native:'Polski',en:'Polish'},{code:'uk',native:'\\u0423\\u043A\\u0440\\u0430\\u0457\\u043D\\u0441\\u044C\\u043A\\u0430',en:'Ukrainian'},\r\n    {code:'el',native:'\\u0395\\u03BB\\u03BB\\u03B7\\u03BD\\u03B9\\u03BA\\u03AC',en:'Greek'},{code:'he',native:'\\u05E2\\u05D1\\u05E8\\u05D9\\u05EA',en:'Hebrew'},\r\n    {code:'fa',native:'\\u0641\\u0627\\u0631\\u0633\\u06CC',en:'Persian'},{code:'ur',native:'\\u0627\\u0631\\u062F\\u0648',en:'Urdu'},\r\n    {code:'ne',native:'\\u0928\\u0947\\u092A\\u093E\\u0932\\u0940',en:'Nepali'},{code:'sv',native:'Svenska',en:'Swedish'},\r\n    {code:'ro',native:'Rom\\u00E2n\\u0103',en:'Romanian'},{code:'fil',native:'Filipino',en:'Filipino'},\r\n    {code:'af',native:'Afrikaans',en:'Afrikaans'}\r\n  ];\r\n\r\n  var FC_SAMPLES = {\r\n    en:'HTML : Hypertext Markup Language\\nCSS : Cascading Style Sheets\\nJavaScript : Programming language for the web\\nPhotosynthesis : Plants make food using sunlight\\nMitochondria : Powerhouse of the cell\\nGravity : Force attracting objects together\\nDNA : Molecule carrying genetic instructions\\nAtom : Smallest unit of matter',\r\n    es:'HTML : Lenguaje de marcado\\nCSS : Hojas de estilo\\nJavaScript : Lenguaje de programacion\\nFotosintesis : Las plantas hacen comida con luz solar',\r\n    fr:'HTML : Langage de balisage\\nCSS : Feuilles de style\\nJavaScript : Langage de programmation\\nPhotosynthese : Les plantes font de la nourriture avec la lumiere',\r\n    de:'HTML : Auszeichnungssprache\\nCSS : Stilvorlagen\\nJavaScript : Programmiersprache\\nPhotosynthese : Pflanzen stellen Nahrung mit Sonnenlicht her',\r\n    zh:'HTML : \\u8D85\\u6587\\u672C\\u6807\\u8BB0\\u8BED\\u8A00\\nCSS : \\u5C42\\u53E0\\u6837\\u5F0F\\u8868\\nJavaScript : \\u7F16\\u7A0B\\u8BED\\u8A00\\n\\u5149\\u5408\\u4F5C\\u7528 : \\u690D\\u7269\\u5229\\u7528\\u9633\\u5149\\u5236\\u9020\\u98DF\\u7269',\r\n    ja:'HTML : \\u30CF\\u30A4\\u30D1\\u30FC\\u30C6\\u30AD\\u30B9\\u30C8\\nCSS : \\u30B9\\u30BF\\u30A4\\u30EB\\u30B7\\u30FC\\u30C8\\nJavaScript : \\u30D7\\u30ED\\u30B0\\u30E9\\u30DF\\u30F3\\u30B0\\u8A00\\u8A9E'\r\n  };\r\n\r\n  var FC_CURRENT_LANG = {code:'en',native:'English',en:'English'};\r\n  var FC = { pairs: [], known: {}, studyIdx: 0, studyQueue: [], font: \"'Inter',system-ui,sans-serif\" };\r\n\r\n  function escH(s) { return String(s==null?'':s).replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;'); }\r\n\r\n  \/* \u2500\u2500 Language popup \u2500\u2500 *\/\r\n  function fcOpenLangPopup() {\r\n    if (!document.getElementById('pth-fc-lang-overlay')) {\r\n      var sty = document.createElement('style');\r\n      sty.textContent = '#pth-fc-lang-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(15,23,42,0.55);z-index:9999998;align-items:center;justify-content:center;padding:16px;}#pth-fc-lang-overlay.pth-lo-open{display:flex;}#pth-fc-lang-modal{background:#fff;border-radius:16px;width:100%;max-width:660px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}.pth-lm-head{padding:20px 20px 0;flex-shrink:0;}.pth-lm-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;}.pth-lm-sub{font-size:0.78rem;color:#334155;margin:0 0 12px;}.pth-lm-close{position:absolute;top:14px;right:14px;background:#f1f5f9;border:none;width:32px;height:32px;border-radius:50%;cursor:pointer;color:#334155;font-weight:700;font-size:0.9rem;}.pth-lm-close:hover{background:#e2e8f0;}.pth-lm-search-wrap{padding:0 16px 10px;flex-shrink:0;}.pth-lm-search{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-size:0.85rem;color:#1e293b;outline:none;}.pth-lm-search:focus{border-color:#2563eb;}.pth-lm-grid-wrap{overflow-y:auto;flex:1;padding:0 8px 8px;}.pth-lm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}.pth-lm-item{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:8px;cursor:pointer;border:2px solid transparent;background:transparent;text-align:left;width:100%;}.pth-lm-item:hover{background:#f1f5f9;}.pth-lm-item.pth-lm-sel{background:#eff6ff;border-color:#bfdbfe;}.pth-lm-flag{font-size:0.62rem;font-weight:800;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;background:#eff6ff;color:#1d4ed8;border-radius:5px;}.pth-lm-names{display:flex;flex-direction:column;min-width:0;}.pth-lm-native{font-size:0.82rem;font-weight:700;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.pth-lm-en{font-size:0.7rem;color:#334155;}.pth-lm-footer{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;justify-content:space-between;flex-shrink:0;background:#f8fafc;font-size:0.8rem;color:#334155;}.pth-lm-footer strong{color:#1d4ed8;}.pth-lm-no-res{text-align:center;padding:24px;color:#334155;font-size:0.85rem;display:none;}@media(max-width:520px){.pth-lm-grid{grid-template-columns:repeat(2,1fr);}}';\r\n      document.head.appendChild(sty);\r\n      var ov = document.createElement('div'); ov.id = 'pth-fc-lang-overlay';\r\n      ov.innerHTML = '<div id=\"pth-fc-lang-modal\"><div class=\"pth-lm-head\"><p class=\"pth-lm-title\">&#x1F30D; Choose Card Language<\/p><p class=\"pth-lm-sub\">Select language for sample pairs<\/p><\/div><button class=\"pth-lm-close\" id=\"pth-fc-lm-close\">&#x2715;<\/button><div class=\"pth-lm-search-wrap\"><input type=\"text\" class=\"pth-lm-search\" id=\"pth-fc-lm-search\" placeholder=\"Search...\" aria-label=\"Search language\" autocomplete=\"off\"><\/div><div class=\"pth-lm-grid-wrap\"><div class=\"pth-lm-grid\" id=\"pth-fc-lm-grid\"><\/div><div class=\"pth-lm-no-res\" id=\"pth-fc-lm-nores\">No languages found.<\/div><\/div><div class=\"pth-lm-footer\"><span>Selected: <strong id=\"pth-fc-lm-cur\">English<\/strong><\/span><span>&#x1F512; Browser only<\/span><\/div><\/div>';\r\n      document.body.appendChild(ov);\r\n      var se = document.getElementById('pth-fc-lm-search');\r\n      if (se) se.addEventListener('input', function() { fcRenderLangGrid(se.value.toLowerCase().trim()); });\r\n      document.getElementById('pth-fc-lm-close').addEventListener('click', fcCloseLangPopup);\r\n      ov.addEventListener('click', function(e) { if (e.target === ov) fcCloseLangPopup(); });\r\n      document.addEventListener('keydown', function(e) { if (e.key === 'Escape') fcCloseLangPopup(); });\r\n    }\r\n    fcRenderLangGrid('');\r\n    var ov = document.getElementById('pth-fc-lang-overlay');\r\n    if (ov) { ov.classList.add('pth-lo-open'); var s = document.getElementById('pth-fc-lm-search'); if (s) { s.value = ''; setTimeout(function() { s.focus(); }, 100); } }\r\n  }\r\n\r\n  function fcCloseLangPopup() { var ov = document.getElementById('pth-fc-lang-overlay'); if (ov) ov.classList.remove('pth-lo-open'); }\r\n\r\n  function fcRenderLangGrid(q) {\r\n    var grid = document.getElementById('pth-fc-lm-grid'), nores = document.getElementById('pth-fc-lm-nores');\r\n    if (!grid) return; grid.innerHTML = '';\r\n    var f = FC_LANGS.filter(function(l) { return !q || l.en.toLowerCase().indexOf(q) !== -1 || l.native.toLowerCase().indexOf(q) !== -1 || l.code.indexOf(q) !== -1; });\r\n    if (!f.length) { if (nores) nores.style.display = 'block'; return; }\r\n    if (nores) nores.style.display = 'none';\r\n    f.forEach(function(l) {\r\n      var btn = document.createElement('button');\r\n      btn.className = 'pth-lm-item' + (l.code === FC_CURRENT_LANG.code ? ' pth-lm-sel' : '');\r\n      btn.innerHTML = '<span class=\"pth-lm-flag\">' + l.code.toUpperCase() + '<\/span><span class=\"pth-lm-names\"><span class=\"pth-lm-native\">' + l.native + '<\/span><span class=\"pth-lm-en\">' + l.en + '<\/span><\/span>';\r\n      btn.addEventListener('click', function() { fcSelectLang(l); });\r\n      grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function fcSelectLang(l) {\r\n    FC_CURRENT_LANG = l;\r\n    var cur = document.getElementById('pth-fc-lm-cur'); if (cur) cur.innerHTML = l.code.toUpperCase() + ' ' + l.native;\r\n    var flag = document.getElementById('pth-fc-pick-flag'); if (flag) flag.innerHTML = l.code.toUpperCase();\r\n    var text = document.getElementById('pth-fc-pick-text'); if (text) text.innerHTML = l.native + ' -- ' + l.en;\r\n    var sl = document.getElementById('pth-fc-s-lang'); if (sl) sl.textContent = l.native;\r\n    if (FC_SAMPLES[l.code]) {\r\n      var ta = document.getElementById('pth-fc-input');\r\n      if (ta) {\r\n        ta.value = FC_SAMPLES[l.code];\r\n        var script = window.pthILS.detectScript(FC_SAMPLES[l.code]);\r\n        window.pthILS.loadFont(script);\r\n        ta.style.fontFamily = window.pthILS.getFontStack(script);\r\n        ta.style.direction = window.pthILS.isRTL(FC_SAMPLES[l.code]) ? 'rtl' : 'ltr';\r\n      }\r\n      window.pthILS.toast('Loaded: ' + l.native + ' (' + l.en + ')', 'success');\r\n    } else {\r\n      window.pthILS.toast(l.en + ' selected! Type your own pairs.', 'info');\r\n    }\r\n    fcRenderLangGrid(''); fcCloseLangPopup();\r\n  }\r\n\r\n  \/* \u2500\u2500 Card rendering \u2500\u2500 *\/\r\n  function fcRenderGrid() {\r\n    var wrap = document.getElementById('pth-fc-grid'); if (!wrap) return;\r\n    wrap.innerHTML = '';\r\n    FC.pairs.forEach(function(p, i) {\r\n      var card = document.createElement('div'); card.className = 'pth-fc-card'; card.setAttribute('data-idx', i);\r\n      if (FC.known[i] === true)  { card.classList.add('fc-known'); }\r\n      if (FC.known[i] === false) { card.classList.add('fc-unknown'); }\r\n      var inner = document.createElement('div'); inner.className = 'pth-fc-inner';\r\n      var front = document.createElement('div'); front.className = 'pth-fc-front'; front.style.fontFamily = FC.font; front.textContent = p.a;\r\n      var back  = document.createElement('div'); back.className  = 'pth-fc-back';  back.style.fontFamily  = FC.font; back.textContent  = p.b;\r\n      var badge = document.createElement('span'); badge.className = 'pth-fc-badge';\r\n      badge.textContent = FC.known[i] === true ? '\\u2705' : (FC.known[i] === false ? '\\u274C' : '#' + (i+1));\r\n      inner.appendChild(front); inner.appendChild(back); card.appendChild(inner); card.appendChild(badge);\r\n      card.addEventListener('click', function() { card.classList.toggle('fc-flipped'); });\r\n      wrap.appendChild(card);\r\n    });\r\n    fcUpdateProgress();\r\n    var lbl = document.getElementById('pth-fc-grid-label'); if (lbl) lbl.textContent = '(' + FC.pairs.length + ' cards)';\r\n  }\r\n\r\n  function fcUpdateProgress() {\r\n    var known = 0, unknown = 0;\r\n    Object.keys(FC.known).forEach(function(k) { if (FC.known[k] === true) known++; else if (FC.known[k] === false) unknown++; });\r\n    var sk = document.getElementById('pth-fc-s-known');   if (sk) sk.textContent = known;\r\n    var su = document.getElementById('pth-fc-s-unknown'); if (su) su.textContent = unknown;\r\n  }\r\n\r\n  \/* \u2500\u2500 Study Mode \u2500\u2500 *\/\r\n  function fcStartStudy() {\r\n    FC.studyQueue = FC.pairs.map(function(_,i){return i;});\r\n    \/\/ prioritise unknowns\r\n    FC.studyQueue.sort(function(a,b) {\r\n      var wa = FC.known[a] === false ? 0 : FC.known[a] === true ? 2 : 1;\r\n      var wb = FC.known[b] === false ? 0 : FC.known[b] === true ? 2 : 1;\r\n      return wa - wb;\r\n    });\r\n    FC.studyIdx = 0;\r\n    fcShowStudyCard();\r\n    var gc = document.getElementById('pth-fc-grid-card');   if (gc) gc.style.display = 'none';\r\n    var sc = document.getElementById('pth-fc-study-card');  if (sc) sc.style.display = 'block';\r\n  }\r\n\r\n  function fcShowStudyCard() {\r\n    var idx = FC.studyQueue[FC.studyIdx];\r\n    if (idx === undefined) { fcStudyFinish(); return; }\r\n    var p = FC.pairs[idx];\r\n    var termEl = document.getElementById('pth-fc-study-term');   if (termEl) { termEl.textContent = p.a; termEl.style.fontFamily = FC.font; }\r\n    var defEl  = document.getElementById('pth-fc-study-def');    if (defEl)  { defEl.textContent  = p.b; defEl.style.fontFamily  = FC.font; defEl.style.display = 'none'; }\r\n    var rb = document.getElementById('pth-fc-reveal-btn'); if (rb) rb.style.display = 'inline-flex';\r\n    var sb = document.getElementById('pth-fc-study-btns'); if (sb) sb.style.display = 'none';\r\n    var total = FC.studyQueue.length;\r\n    var prog  = document.getElementById('pth-fc-study-prog');  if (prog)  prog.textContent  = 'Card ' + (FC.studyIdx + 1) + ' \/ ' + total;\r\n    var fill  = document.getElementById('pth-fc-study-fill');  if (fill)  fill.style.width  = Math.round((FC.studyIdx \/ total) * 100) + '%';\r\n    var lbl   = document.getElementById('pth-fc-study-label'); if (lbl)   lbl.textContent   = '(' + (FC.studyIdx + 1) + '\/' + total + ')';\r\n  }\r\n\r\n  function fcStudyFinish() {\r\n    var termEl = document.getElementById('pth-fc-study-term'); if (termEl) termEl.textContent = '\\uD83C\\uDF89 All done!';\r\n    var defEl  = document.getElementById('pth-fc-study-def');  if (defEl)  { defEl.textContent = 'Great work! Check your progress in the sidebar.'; defEl.style.display = 'block'; }\r\n    var rb = document.getElementById('pth-fc-reveal-btn'); if (rb) rb.style.display = 'none';\r\n    var sb = document.getElementById('pth-fc-study-btns'); if (sb) sb.style.display = 'none';\r\n    var fill = document.getElementById('pth-fc-study-fill'); if (fill) fill.style.width = '100%';\r\n    window.pthILS.toast('Session complete!', 'success');\r\n  }\r\n\r\n  \/* \u2500\u2500 Export HTML builder \u2500\u2500 *\/\r\n  function fcBuildExportHTML() {\r\n    if (!FC.pairs.length) return '';\r\n    var pairsJSON = JSON.stringify(FC.pairs);\r\n\r\n    var css =\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact;print-color-adjust:exact;color-adjust:exact;}' +\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;background:#eef2f9;padding:32px 16px;min-height:100vh;}' +\r\n      '.fc-page{max-width:1100px;margin:0 auto;}' +\r\n      '.fc-head{text-align:center;margin:0 0 20px;}' +\r\n      'h1{color:#1d4ed8;font-size:1.5rem;font-weight:800;margin:0 0 6px;}' +\r\n      '.fc-sub{color:#334155;font-size:0.85rem;margin:0;}' +\r\n      '.fc-meta{display:flex;align-items:center;justify-content:center;gap:14px;margin:14px 0 18px;flex-wrap:wrap;}' +\r\n      '.fc-stat{font-size:0.88rem;font-weight:700;color:#1d4ed8;background:#eff6ff;padding:5px 14px;border-radius:20px;}' +\r\n      '.fc-timer{font-size:0.88rem;font-weight:700;color:#334155;background:#f1f5f9;padding:5px 12px;border-radius:7px;}' +\r\n      '.fc-toolbar{background:#fff;padding:14px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,0.06);margin-bottom:20px;display:flex;justify-content:center;gap:10px;flex-wrap:wrap;}' +\r\n      '.fc-btn{padding:9px 20px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;}' +\r\n      '.fc-btn-p{background:#2563eb;color:#fff;}.fc-btn-g{background:#10b981;color:#fff;}.fc-btn-o{background:#f59e0b;color:#fff;}.fc-btn-b{background:#fff;border:2px solid #e2e8f0;color:#334155;}' +\r\n      '.fc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:18px;max-width:1100px;margin:0 auto;}' +\r\n      '.fc-card{background:transparent;width:100%;height:170px;perspective:1000px;cursor:pointer;}' +\r\n      '.fc-inner{position:relative;width:100%;height:100%;text-align:center;transition:transform 0.5s;transform-style:preserve-3d;}' +\r\n      '.fc-card.flipped .fc-inner{transform:rotateY(180deg);}' +\r\n      '.fc-front,.fc-back{position:absolute;width:100%;height:100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;display:flex;align-items:center;justify-content:center;padding:16px;border-radius:14px;box-shadow:0 4px 12px rgba(0,0,0,0.08);border:2px solid #e2e8f0;line-height:1.4;word-break:break-word;}' +\r\n      '.fc-front{background:#fff;color:#1e293b;font-size:1.1rem;font-weight:800;}' +\r\n      '.fc-back{background:#eff6ff;color:#1d4ed8;font-size:0.9rem;font-weight:700;transform:rotateY(180deg);border-color:#bfdbfe;}' +\r\n      '.fc-num{position:absolute;top:6px;right:8px;font-size:0.6rem;font-weight:800;background:#94a3b8;color:#fff;border-radius:10px;padding:2px 6px;}' +\r\n      '@media print{body{background:#fff;padding:10px;}.fc-toolbar,.fc-meta,.fc-timer{display:none!important;}.fc-grid{display:grid!important;grid-template-columns:repeat(3,1fr)!important;gap:10px!important;}.fc-card{height:auto!important;perspective:none!important;break-inside:avoid;}.fc-inner{transform:none!important;transition:none!important;transform-style:flat!important;}.fc-front,.fc-back{position:relative!important;transform:none!important;backface-visibility:visible!important;box-shadow:none!important;height:auto!important;padding:8px!important;border:1px solid #cbd5e1!important;}.fc-back{transform:none!important;border-top:1px dashed #bfdbfe!important;border-radius:0 0 8px 8px!important;}.fc-front{border-radius:8px 8px 0 0!important;}}';\r\n\r\n    var sc = [\r\n      '(function(){',\r\n        'var data=' + pairsJSON + ';',\r\n        'var grid=document.getElementById(\"fc-grid\");',\r\n        'var secs=0,ti=setInterval(function(){secs++;var t=document.getElementById(\"fc-timer\");if(t)t.textContent=\"\\u23F1 \"+(Math.floor(secs\/60)<10?\"0\":\"\")+Math.floor(secs\/60)+\":\"+(secs%60<10?\"0\":\"\")+secs%60;},1000);',\r\n        'data.forEach(function(p,i){',\r\n          'var card=document.createElement(\"div\");card.className=\"fc-card\";',\r\n          'var inner=document.createElement(\"div\");inner.className=\"fc-inner\";',\r\n          'var front=document.createElement(\"div\");front.className=\"fc-front\";front.textContent=p.a;',\r\n          'var back=document.createElement(\"div\");back.className=\"fc-back\";back.textContent=p.b;',\r\n          'var num=document.createElement(\"span\");num.className=\"fc-num\";num.textContent=\"#\"+(i+1);',\r\n          'inner.appendChild(front);inner.appendChild(back);card.appendChild(inner);card.appendChild(num);',\r\n          'card.addEventListener(\"click\",function(){this.classList.toggle(\"flipped\");});',\r\n          'grid.appendChild(card);',\r\n        '});',\r\n        'document.getElementById(\"fc-score\").textContent=data.length+\" cards\";',\r\n        'document.getElementById(\"btn-flip\").addEventListener(\"click\",function(){document.querySelectorAll(\".fc-card\").forEach(function(c){c.classList.toggle(\"flipped\");});});',\r\n        'document.getElementById(\"btn-reveal\").addEventListener(\"click\",function(){document.querySelectorAll(\".fc-card\").forEach(function(c){c.classList.add(\"flipped\");});});',\r\n        'document.getElementById(\"btn-shuffle\").addEventListener(\"click\",function(){var cards=Array.from(grid.querySelectorAll(\".fc-card\"));cards.sort(function(){return Math.random()-0.5;});cards.forEach(function(c){grid.appendChild(c);});});',\r\n        'document.getElementById(\"btn-print\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n\r\n    var so='<'+'script'+'>', sc2='<'+'\/'+'script'+'>';\r\n    var docOpen='<'+'!DOCTYPE html>'+'<'+'html lang=\"en\">'+'<'+'head>'+'<'+'meta charset=\"UTF-8\">'+\r\n      '<'+'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">'+\r\n      '<'+'title>Interactive Flashcards<'+'\/title>'+'<'+'style>'+css+'<'+'\/style>'+'<'+'\/head>'+'<'+'body>';\r\n    var docClose='<'+'\/'+'body>'+'<'+'\/'+'html>';\r\n\r\n    var body =\r\n      '<div class=\"fc-page\">' +\r\n      '<div class=\"fc-head\"><h2>\\uD83D\\uDCC7 Interactive Flashcards<\/h2><p class=\"fc-sub\">Click any card to flip it and reveal the definition.<\/p><\/div>' +\r\n      '<div class=\"fc-meta\"><span class=\"fc-stat\" id=\"fc-score\">...<\/span><span class=\"fc-timer\" id=\"fc-timer\">\\u23F1 00:00<\/span><\/div>' +\r\n      '<div class=\"fc-toolbar\">' +\r\n        '<button class=\"fc-btn fc-btn-p\" id=\"btn-flip\">\\uD83D\\uDD04 Flip All<\/button>' +\r\n        '<button class=\"fc-btn fc-btn-g\" id=\"btn-reveal\">\\uD83D\\uDC41 Reveal All<\/button>' +\r\n        '<button class=\"fc-btn fc-btn-o\" id=\"btn-shuffle\">\\uD83D\\uDD00 Shuffle<\/button>' +\r\n        '<button class=\"fc-btn fc-btn-b\" id=\"btn-print\">\\uD83D\\uDDA8 Print<\/button>' +\r\n      '<\/div>' +\r\n      '<div class=\"fc-grid\" id=\"fc-grid\"><\/div>' +\r\n      '<\/div>';\r\n\r\n    return docOpen + body + so + sc + sc2 + docClose;\r\n  }\r\n\r\n  \/* \u2500\u2500 buildTabHTML \u2500\u2500 *\/\r\n  function buildTabHTML() {\r\n    var panel = document.getElementById('pth-tab-flashcards');\r\n    if (!panel || panel.getAttribute('data-fc-built')) return;\r\n    var source = document.getElementById('pth-fc-ui-source');\r\n    if (source) {\r\n      panel.appendChild(source.firstElementChild);\r\n      source.parentNode.removeChild(source);\r\n      panel.setAttribute('data-fc-built', '1');\r\n    }\r\n  }\r\n\r\n  \/* \u2500\u2500 Wire events \u2500\u2500 *\/\r\n  function wireEvents() {\r\n    var b = function(id, fn) { var el = document.getElementById(id); if (el) el.addEventListener('click', fn); };\r\n\r\n    b('pth-fc-lang-btn', fcOpenLangPopup);\r\n    b('pth-fc-gen-btn', function() {\r\n      var ta = document.getElementById('pth-fc-input');\r\n      if (!ta || !ta.value.trim()) { window.pthILS.toast('Please enter some pairs first!', 'error'); return; }\r\n      var script = window.pthILS.detectScript(ta.value);\r\n      window.pthILS.loadFont(script);\r\n      FC.font = window.pthILS.getFontStack(script);\r\n      var lines = ta.value.split('\\n'); FC.pairs = [];\r\n      lines.forEach(function(line) {\r\n        line = line.trim(); if (!line) return;\r\n        var idx = line.indexOf(':'); if (idx < 1) return;\r\n        FC.pairs.push({ a: line.substring(0, idx).trim(), b: line.substring(idx + 1).trim() });\r\n      });\r\n      if (!FC.pairs.length) { window.pthILS.toast('Format: Term : Definition per line', 'error'); return; }\r\n      FC.known = {};\r\n      fcRenderGrid();\r\n      var gc = document.getElementById('pth-fc-grid-card'); if (gc) gc.style.display = 'block';\r\n      var sc = document.getElementById('pth-fc-study-card'); if (sc) sc.style.display = 'none';\r\n      var st = document.getElementById('pth-fc-s-total'); if (st) st.textContent = FC.pairs.length;\r\n      window.pthILS.toast('Generated ' + FC.pairs.length + ' cards!', 'success');\r\n    });\r\n\r\n    b('pth-fc-flip-all-btn', function() {\r\n      document.querySelectorAll('#pth-fc-grid .pth-fc-card').forEach(function(c) { c.classList.toggle('fc-flipped'); });\r\n    });\r\n\r\n    b('pth-fc-shuffle-btn', function() {\r\n      for (var i = FC.pairs.length - 1; i > 0; i--) {\r\n        var j = Math.floor(Math.random() * (i + 1));\r\n        var tmp = FC.pairs[i]; FC.pairs[i] = FC.pairs[j]; FC.pairs[j] = tmp;\r\n        var tk = FC.known[i]; FC.known[i] = FC.known[j]; FC.known[j] = tk;\r\n      }\r\n      fcRenderGrid(); window.pthILS.toast('Cards shuffled!', 'info');\r\n    });\r\n\r\n    b('pth-fc-reset-known-btn', function() {\r\n      FC.known = {}; fcRenderGrid(); window.pthILS.toast('Marks cleared!', 'info');\r\n    });\r\n\r\n    b('pth-fc-study-mode-btn', function() {\r\n      if (!FC.pairs.length) { window.pthILS.toast('Generate cards first!', 'error'); return; }\r\n      fcStartStudy();\r\n    });\r\n\r\n    b('pth-fc-reveal-btn', function() {\r\n      var def = document.getElementById('pth-fc-study-def'); if (def) def.style.display = 'block';\r\n      var rb  = document.getElementById('pth-fc-reveal-btn'); if (rb) rb.style.display = 'none';\r\n      var sb  = document.getElementById('pth-fc-study-btns'); if (sb) sb.style.display = 'flex';\r\n    });\r\n\r\n    b('pth-fc-known-btn', function() {\r\n      FC.known[FC.studyQueue[FC.studyIdx]] = true;\r\n      FC.studyIdx++; fcShowStudyCard(); fcUpdateProgress();\r\n    });\r\n\r\n    b('pth-fc-unknown-btn', function() {\r\n      FC.known[FC.studyQueue[FC.studyIdx]] = false;\r\n      FC.studyIdx++; fcShowStudyCard(); fcUpdateProgress();\r\n    });\r\n\r\n    b('pth-fc-study-back-btn', function() {\r\n      var gc = document.getElementById('pth-fc-grid-card');  if (gc) gc.style.display = 'block';\r\n      var sc = document.getElementById('pth-fc-study-card'); if (sc) sc.style.display = 'none';\r\n      fcRenderGrid();\r\n    });\r\n\r\n    b('pth-fc-study-restart-btn', function() { fcStartStudy(); window.pthILS.toast('Session restarted!', 'info'); });\r\n\r\n    b('pth-fc-html-btn', function() {\r\n      if (!FC.pairs.length) { window.pthILS.toast('Generate cards first!', 'error'); return; }\r\n      var c = fcBuildExportHTML(); if (!c) return;\r\n      try {\r\n        var blob = new Blob([c], {type:'text\/html'});\r\n        var url = URL.createObjectURL(blob);\r\n        var a = document.createElement('a'); a.href = url; a.download = 'flashcards.html';\r\n        document.body.appendChild(a); a.click(); document.body.removeChild(a);\r\n        setTimeout(function() { URL.revokeObjectURL(url); }, 2000);\r\n        window.pthILS.toast('HTML file downloaded!', 'success');\r\n      } catch(err) { window.pthILS.toast('Download failed: ' + err.message, 'error'); }\r\n    });\r\n\r\n    b('pth-fc-copy-btn', function() {\r\n      if (!FC.pairs.length) { window.pthILS.toast('Generate cards first!', 'error'); return; }\r\n      window.pthILS.showCopyHTML(fcBuildExportHTML(), 'pth-fc-code-box');\r\n    });\r\n\r\n    b('pth-fc-print-btn', function() {\r\n      if (!FC.pairs.length) { window.pthILS.toast('Generate cards first!', 'error'); return; }\r\n      var c = fcBuildExportHTML(); if (!c) return;\r\n      var w = window.open('', '_blank');\r\n      if (!w) { window.pthILS.toast('Popup blocked! Allow popups to print.', 'error'); return; }\r\n      w.document.open(); w.document.write(c); w.document.close();\r\n      var printed = false;\r\n      function doPrint() { if (printed) return; printed = true; w.focus(); w.print(); }\r\n      w.addEventListener('load', function() { setTimeout(doPrint, 150); });\r\n      setTimeout(doPrint, 1200);\r\n    });\r\n\r\n    b('pth-fc-code-copy-btn', function() {\r\n      var ta = document.getElementById('pth-fc-code-ta');\r\n      if (ta) { ta.select(); try { document.execCommand('copy'); window.pthILS.toast('Copied!', 'success'); } catch(e) {} }\r\n    });\r\n\r\n    \/* Keyboard navigation *\/\r\n    document.addEventListener('keydown', function(e) {\r\n      var gc = document.getElementById('pth-fc-grid-card');\r\n      var sc = document.getElementById('pth-fc-study-card');\r\n      var gridVisible = gc && gc.style.display !== 'none';\r\n      var studyVisible = sc && sc.style.display !== 'none';\r\n      if (!gridVisible && !studyVisible) return;\r\n      if (e.key === ' ' && studyVisible) {\r\n        e.preventDefault();\r\n        var rb = document.getElementById('pth-fc-reveal-btn');\r\n        if (rb && rb.style.display !== 'none') rb.click();\r\n      }\r\n    });\r\n\r\n    \/* pthILS events *\/\r\n    document.addEventListener('pthILSSample', function(e) {\r\n      if (e.detail.tab !== 'flashcards') return;\r\n      var ta = document.getElementById('pth-fc-input');\r\n      if (ta) { ta.value = FC_SAMPLES.en; window.pthILS.toast('Sample Loaded! Click Generate.', 'success'); }\r\n    });\r\n    document.addEventListener('pthILSClear', function(e) {\r\n      if (e.detail.tab !== 'flashcards') return;\r\n      var ta = document.getElementById('pth-fc-input'); if (ta) ta.value = '';\r\n      var gc = document.getElementById('pth-fc-grid-card');  if (gc) gc.style.display = 'none';\r\n      var sc = document.getElementById('pth-fc-study-card'); if (sc) sc.style.display = 'none';\r\n      FC.pairs = []; FC.known = {};\r\n      var st = document.getElementById('pth-fc-s-total');   if (st) st.textContent = '--';\r\n      var sk = document.getElementById('pth-fc-s-known');   if (sk) sk.textContent = '0';\r\n      var su = document.getElementById('pth-fc-s-unknown'); if (su) su.textContent = '0';\r\n    });\r\n  }\r\n\r\n  function init() { buildTabHTML(); setTimeout(function() { wireEvents(); }, 100); }\r\n  waitForShell(init);\r\n})();\r\n<\/script>\r\n\n\n\n<!-- LSCACHE_DISABLE -->\r\n<!-- PTH ILS v3.6 \u2014 Cryptogram Maker (Tab 11) -->\r\n\r\n<style data-no-optimize=\"1\">\r\n#pth-cg-wrap { font-family: 'Inter', system-ui, sans-serif; max-width: 1400px; margin: 0 auto; box-sizing: border-box; }\r\n#pth-cg-wrap * { box-sizing: border-box; min-width: 0; }\r\n\r\n\/* Language picker *\/\r\n#pth-cg-wrap .cg-lang-btn { display:inline-flex;align-items:center;gap:8px;padding:9px 16px;background:#fff;border:2px solid #e2e8f0;border-radius:8px;cursor:pointer;font-family:'Inter',system-ui,sans-serif;font-size:0.85rem;font-weight:700;color:#334155;transition:all 0.15s;width:100%;margin-bottom:10px; }\r\n#pth-cg-wrap .cg-lang-btn:hover { border-color:#7c3aed;color:#6d28d9;background:#f5f3ff; }\r\n#pth-cg-wrap .cg-lang-flag { font-size:0.68rem;font-weight:800;background:#7c3aed;color:#fff;border-radius:5px;padding:3px 6px;min-width:26px;text-align:center; }\r\n#pth-cg-wrap .cg-lang-text { flex:1;text-align:left; }\r\n#pth-cg-wrap .cg-lang-arr { color:#94a3b8;font-size:0.8rem; }\r\n\r\n\/* Layout *\/\r\n#pth-cg-wrap .cg-layout { display:grid;grid-template-columns:1.8fr 1fr;gap:28px;align-items:start; }\r\n#pth-cg-wrap .cg-layout.cg-fw { grid-template-columns:1fr; }\r\n#pth-cg-wrap .cg-card { background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:22px;margin-bottom:22px;box-shadow:0 4px 6px -1px rgba(0,0,0,0.04); }\r\n\r\n\/* Form *\/\r\n#pth-cg-wrap .cg-label { display:block;font-size:0.85rem;font-weight:700;margin-bottom:7px;color:#475569; }\r\n#pth-cg-wrap .cg-textarea { width:100%;min-height:110px;padding:12px;border:2px solid #e2e8f0;border-radius:8px;font-family:inherit;font-size:0.95rem;resize:vertical;margin-bottom:14px;outline:none;line-height:1.5;color:#0f172a; }\r\n#pth-cg-wrap .cg-textarea:focus { border-color:#7c3aed; }\r\n#pth-cg-wrap .cg-input { width:100%;padding:9px 12px;border:2px solid #e2e8f0;border-radius:8px;font-family:inherit;font-size:0.88rem;outline:none;margin-bottom:12px;color:#0f172a; }\r\n#pth-cg-wrap .cg-input:focus { border-color:#7c3aed; }\r\n#pth-cg-wrap .cg-select { width:100%;padding:9px 12px;border:2px solid #e2e8f0;border-radius:8px;font-family:inherit;font-size:0.88rem;outline:none;background:#fff;cursor:pointer;margin-bottom:12px; }\r\n\r\n\/* Buttons *\/\r\n#pth-cg-wrap .cg-btn { padding:10px 20px;border-radius:8px;font-weight:700;cursor:pointer;border:none;font-family:'Inter',sans-serif;font-size:0.88rem;display:inline-flex;align-items:center;justify-content:center;gap:6px;transition:0.2s; }\r\n#pth-cg-wrap .cg-btn-p { background:#7c3aed;color:#fff; }\r\n#pth-cg-wrap .cg-btn-p:hover { background:#6d28d9; }\r\n#pth-cg-wrap .cg-btn-g { background:#10b981;color:#fff; }\r\n#pth-cg-wrap .cg-btn-g:hover { background:#059669; }\r\n#pth-cg-wrap .cg-btn-o { background:#f59e0b;color:#fff; }\r\n#pth-cg-wrap .cg-btn-s { background:#e2e8f0;color:#0f172a; }\r\n#pth-cg-wrap .cg-btn-s:hover { background:#cbd5e1; }\r\n#pth-cg-wrap .cg-btn-row { display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px; }\r\n\r\n\/* Progress *\/\r\n#pth-cg-wrap .cg-prog-wrap { height:6px;background:#e2e8f0;border-radius:3px;overflow:hidden;margin-bottom:16px; }\r\n#pth-cg-wrap .cg-prog-fill { height:100%;background:linear-gradient(90deg,#7c3aed,#10b981);border-radius:3px;transition:width 0.4s; }\r\n\r\n\/* Cryptogram Grid *\/\r\n#pth-cg-wrap .cg-workspace { background:#f8fafc;padding:20px;border-radius:10px;border:1px solid #e2e8f0;text-align:center; }\r\n#pth-cg-wrap .cg-word { display:inline-flex;gap:3px;margin-right:20px;margin-bottom:16px;vertical-align:top; }\r\n#pth-cg-wrap .cg-cell { display:flex;flex-direction:column;align-items:center;width:28px; }\r\n#pth-cg-wrap .cg-cipher { font-size:0.95rem;font-weight:800;color:#1e293b;margin-bottom:5px;height:20px;display:flex;align-items:center;justify-content:center; }\r\n#pth-cg-wrap .cg-box { width:100%;text-align:center;border:none;border-bottom:2.5px solid #0f172a;background:transparent;font-size:0.95rem;font-weight:800;color:#7c3aed;outline:none;padding:2px 0;text-transform:uppercase;font-family:'Inter',monospace;border-radius:2px 2px 0 0;transition:background 0.15s; }\r\n#pth-cg-wrap .cg-box:focus { background:#ede9fe; }\r\n#pth-cg-wrap .cg-box.cg-ok { color:#065f46!important;background:#d1fae5!important;border-color:#059669!important;font-weight:900!important; }\r\n#pth-cg-wrap .cg-box.cg-no { color:#7f1d1d!important;background:#fee2e2!important;border-color:#dc2626!important;font-weight:900!important; }\r\n#pth-cg-wrap .cg-punc { font-size:1.3rem;font-weight:800;color:#475569;display:flex;align-items:flex-end;padding-bottom:2px; }\r\n\r\n\/* Cipher key *\/\r\n#pth-cg-wrap .cg-key-wrap { display:flex;flex-wrap:wrap;gap:5px;margin-top:10px; }\r\n#pth-cg-wrap .cg-key-pair { background:#f1f5f9;border:1px solid #e2e8f0;border-radius:5px;padding:3px 8px;font-size:0.75rem;font-weight:700;color:#334155;font-family:monospace;white-space:nowrap; }\r\n#pth-cg-wrap .cg-key-pair span { color:#7c3aed; }\r\n\r\n\/* Stats *\/\r\n#pth-cg-wrap .cg-stat-row { display:flex;justify-content:space-between;align-items:center;padding:6px 0;border-bottom:1px solid #f1f5f9;font-size:0.82rem; }\r\n#pth-cg-wrap .cg-stat-lbl { color:#64748b;font-weight:600; }\r\n#pth-cg-wrap .cg-stat-val { font-weight:800;color:#0f172a; }\r\n\r\n\/* Toast *\/\r\n#pth-cg-toasts { position:fixed;bottom:20px;right:20px;z-index:9999;display:flex;flex-direction:column;gap:8px; }\r\n.pth-cg-toast { padding:10px 18px;border-radius:8px;color:#fff;font-weight:700;font-family:'Inter',sans-serif;font-size:0.88rem;box-shadow:0 4px 12px rgba(0,0,0,0.15);animation:cgToastIn 0.3s ease; }\r\n.pth-cg-toast.cg-ts { background:#10b981; }\r\n.pth-cg-toast.cg-te { background:#ef4444; }\r\n.pth-cg-toast.cg-ti { background:#7c3aed; }\r\n@keyframes cgToastIn { from{transform:translateY(16px);opacity:0;} to{transform:translateY(0);opacity:1;} }\r\n\r\n@media (max-width:768px) { #pth-cg-wrap .cg-layout { grid-template-columns:1fr; } }\r\n@media print {\r\n  *{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important;}\r\n  #pth-cg-wrap .cg-sidebar,.cg-btn,.cg-lang-btn,.cg-label,.cg-textarea,.cg-input,.cg-select,.cg-prog-wrap { display:none!important; }\r\n  #pth-cg-wrap .cg-layout { display:block!important; }\r\n  #pth-cg-wrap .cg-card { border:none;box-shadow:none;padding:0; }\r\n  #pth-cg-wrap .cg-workspace { background:transparent!important;border:none!important; }\r\n  #pth-cg-wrap .cg-box { border-bottom:2px solid #000!important;color:#000!important;background:transparent!important; }\r\n  #pth-cg-wrap .cg-cipher { color:#000!important; }\r\n}\r\n<\/style>\r\n\r\n<div id=\"pth-cg-toasts\"><\/div>\r\n\r\n<div id=\"pth-cg-wrap\">\r\n  <div class=\"cg-layout\" id=\"pth-cg-layout\">\r\n\r\n    <!-- MAIN -->\r\n    <div class=\"cg-main\">\r\n\r\n      <!-- Input Card -->\r\n      <div class=\"cg-card\">\r\n        <h3 style=\"margin:0 0 12px;font-size:1.15rem;color:#7c3aed;\">&#x1F575;&#xFE0F; Cryptogram Maker<\/h3>\r\n\r\n        <button class=\"cg-lang-btn\" id=\"pth-cg-lang-btn\" aria-label=\"Choose language\">\r\n          <span class=\"cg-lang-flag\" id=\"pth-cg-flag\">EN<\/span>\r\n          <span class=\"cg-lang-text\" id=\"pth-cg-lang-text\">English &#x2014; Quote Language<\/span>\r\n          <span class=\"cg-lang-arr\">&#x25BC;<\/span>\r\n        <\/button>\r\n\r\n        <label class=\"cg-label\" for=\"pth-cg-msg\">Enter Secret Message \/ Quote (A&#x2013;Z letters)<\/label>\r\n        <p style=\"font-size:0.78rem;color:#94a3b8;margin:0 0 6px;font-style:italic;\">&#x2139;&#xFE0F; Example below is a placeholder &#x2014; type your own, or click &#x1F4A1; Load Sample above.<\/p>\r\n        <textarea class=\"cg-textarea\" id=\"pth-cg-msg\" placeholder=\"The only way to do great work is to love what you do.\" aria-label=\"Message to encode\"><\/textarea>\r\n\r\n        <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px;\">\r\n          <div>\r\n            <label class=\"cg-label\" for=\"pth-cg-auth\">Author \/ Hint (Optional)<\/label>\r\n            <input type=\"text\" class=\"cg-input\" id=\"pth-cg-auth\" placeholder=\"- Steve Jobs\" aria-label=\"Author\">\r\n          <\/div>\r\n          <div>\r\n            <label class=\"cg-label\" for=\"pth-cg-type\">Cipher Type<\/label>\r\n            <select class=\"cg-select\" id=\"pth-cg-type\" aria-label=\"Cipher type\">\r\n              <option value=\"letters\">Random Letters (A = X)<\/option>\r\n              <option value=\"numbers\">Numbers (A = 14)<\/option>\r\n              <option value=\"symbols\">Symbols (A = &#x2605;)<\/option>\r\n            <\/select>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"cg-btn-row\" style=\"margin-top:4px;\">\r\n          <button class=\"cg-btn cg-btn-p\" id=\"pth-cg-gen\">&#x26A1; Generate Cryptogram<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Puzzle Card -->\r\n      <div class=\"cg-card\" id=\"pth-cg-puzzle\" style=\"display:none;\">\r\n        <h3 style=\"margin:0 0 6px;font-size:1.1rem;color:#1e293b;\">&#x1F50D; Crack the Code<\/h3>\r\n        <p style=\"font-size:0.82rem;color:#64748b;margin:0 0 10px;\">Type in the boxes. Same cipher = same letter &#x2014; auto-fills everywhere.<\/p>\r\n        <div class=\"cg-prog-wrap\"><div class=\"cg-prog-fill\" id=\"pth-cg-fill\" style=\"width:0%;\"><\/div><\/div>\r\n\r\n        <div class=\"cg-workspace\" id=\"pth-cg-grid\"><!-- cipher grid injected --><\/div>\r\n        <div style=\"text-align:right;margin-top:10px;font-weight:700;color:#475569;font-size:0.9rem;\" id=\"pth-cg-auth-disp\"><\/div>\r\n\r\n        <div class=\"cg-btn-row\" style=\"margin-top:14px;\">\r\n          <button class=\"cg-btn cg-btn-p\" id=\"pth-cg-check\">&#x2705; Check Answers<\/button>\r\n          <button class=\"cg-btn cg-btn-s\" id=\"pth-cg-reveal\">&#x1F441; Reveal All<\/button>\r\n          <button class=\"cg-btn cg-btn-s\" id=\"pth-cg-reset\">&#x1F504; Reset<\/button>\r\n          <button class=\"cg-btn cg-btn-s\" id=\"pth-cg-regen\">&#x1F3B2; New Cipher<\/button>\r\n        <\/div>\r\n\r\n        <div class=\"cg-btn-row\" style=\"padding-top:12px;border-top:1px solid #e2e8f0;margin-top:4px;\">\r\n          <button class=\"cg-btn cg-btn-g\" id=\"pth-cg-dl\">&#x1F4C4; Download HTML<\/button>\r\n          <button class=\"cg-btn cg-btn-p\" id=\"pth-cg-copy\">&#x1F4CB; Copy HTML<\/button>\r\n          <button class=\"cg-btn cg-btn-s\" id=\"pth-cg-print\">&#x1F5A8; Print Worksheet<\/button>\r\n        <\/div>\r\n        <div id=\"pth-cg-codebox\" style=\"display:none;margin-top:10px;\">\r\n          <textarea id=\"pth-cg-codetxt\" readonly style=\"width:100%;min-height:80px;font-family:monospace;font-size:0.78rem;padding:10px;border:1px solid #e2e8f0;border-radius:6px;background:#f8fafc;\" aria-label=\"HTML code\"><\/textarea>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Key Card -->\r\n      <div class=\"cg-card\" id=\"pth-cg-keycard\" style=\"display:none;\">\r\n        <h3 style=\"margin:0 0 6px;font-size:1rem;color:#1e293b;\">&#x1F511; Cipher Key Reference<\/h3>\r\n        <p style=\"font-size:0.78rem;color:#64748b;margin:0 0 8px;\">(Teacher reference \u2014 shows the encoding used)<\/p>\r\n        <div class=\"cg-key-wrap\" id=\"pth-cg-keytbl\"><\/div>\r\n      <\/div>\r\n\r\n    <\/div>\r\n\r\n    <!-- SIDEBAR -->\r\n    <div class=\"cg-sidebar\">\r\n\r\n      <div class=\"cg-card\">\r\n        <h3 style=\"margin:0 0 12px;font-size:1rem;\">&#x1F4CA; Stats<\/h3>\r\n        <div class=\"cg-stat-row\"><span class=\"cg-stat-lbl\">Letters<\/span><span class=\"cg-stat-val\" id=\"pth-cg-s-letters\">&#x2014;<\/span><\/div>\r\n        <div class=\"cg-stat-row\"><span class=\"cg-stat-lbl\">Words<\/span><span class=\"cg-stat-val\" id=\"pth-cg-s-words\">&#x2014;<\/span><\/div>\r\n        <div class=\"cg-stat-row\"><span class=\"cg-stat-lbl\">Filled In<\/span><span class=\"cg-stat-val\" id=\"pth-cg-s-filled\">0<\/span><\/div>\r\n        <div class=\"cg-stat-row\" style=\"border:none;\"><span class=\"cg-stat-lbl\">Cipher<\/span><span class=\"cg-stat-val\" id=\"pth-cg-s-cipher\">&#x2014;<\/span><\/div>\r\n      <\/div>\r\n\r\n      <div class=\"cg-card\" style=\"background:#f5f3ff;border-color:#ddd6fe;\">\r\n        <h3 style=\"margin:0 0 10px;color:#6d28d9;font-size:1rem;\">&#x1F4D6; How to Use<\/h3>\r\n        <ul style=\"font-size:0.82rem;line-height:1.7;padding-left:18px;margin:0;color:#334155;\">\r\n          <li>Enter any English phrase or quote.<\/li>\r\n          <li>Choose cipher: Letters, Numbers, or Symbols.<\/li>\r\n          <li>Click <strong>Generate<\/strong> to encode it.<\/li>\r\n          <li>Same symbol = same letter &#x2014; auto-fills!<\/li>\r\n          <li>Use <strong>New Cipher<\/strong> for a different encoding.<\/li>\r\n          <li>Download \/ Print for a clean student worksheet.<\/li>\r\n        <\/ul>\r\n      <\/div>\r\n\r\n      <div class=\"cg-card\" style=\"background:#f5f3ff;border-color:#ddd6fe;\">\r\n        <h3 style=\"margin:0 0 10px;color:#6d28d9;font-size:1rem;\">&#x1F916; AI Quote Finder<\/h3>\r\n        <p style=\"font-size:0.8rem;color:#334155;margin:0 0 10px;\">Get a famous quote to encrypt instantly.<\/p>\r\n        <label class=\"cg-label\">&#x1F511; Anthropic API Key<\/label>\r\n        <input type=\"password\" class=\"cg-input\" id=\"pth-cg-ai-key\" placeholder=\"sk-ant-...\" style=\"font-family:monospace;font-size:0.8rem;\" aria-label=\"API Key\">\r\n        <label class=\"cg-label\">&#x1F4DA; Topic<\/label>\r\n        <input type=\"text\" class=\"cg-input\" id=\"pth-cg-ai-topic\" placeholder=\"e.g. Success, Science, Nature\" aria-label=\"Topic\">\r\n        <button class=\"cg-btn cg-btn-p\" id=\"pth-cg-ai\" style=\"width:100%;\">&#x2728; Get Quote<\/button>\r\n      <\/div>\r\n\r\n    <\/div>\r\n\r\n  <\/div>\r\n<\/div>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function() {\r\n  'use strict';\r\n\r\n  var SYMBOLS = ['\\u2605','\\u2602','\\u2660','\\u2663','\\u2665','\\u2666','\\u266B','\\u2600','\\u2601','\\u2603','\\u2702','\\u2708','\\u2709','\\u2712','\\u270F','\\u2718','\\u271A','\\u2731','\\u2726','\\u2727','\\u2729','\\u272A','\\u272B','\\u272C','\\u272D','\\u272E'];\r\n\r\n  var CG_LANGS = [\r\n    {code:'en',native:'English',en:'English'},{code:'si',native:'\\u0DC3\\u0DD2\\u0982\\u0DC4\\u0DBD',en:'Sinhala'},\r\n    {code:'ta',native:'\\u0BA4\\u0BAE\\u0BBF\\u0BB4\\u0BCD',en:'Tamil'},{code:'zh',native:'\\u4E2D\\u6587',en:'Chinese'},\r\n    {code:'ar',native:'\\u0627\\u0644\\u0639\\u0631\\u0628\\u064A\\u0629',en:'Arabic'},{code:'hi',native:'\\u0939\\u093F\\u0928\\u094D\\u0926\\u0940',en:'Hindi'},\r\n    {code:'es',native:'Espa\\u00F1ol',en:'Spanish'},{code:'fr',native:'Fran\\u00E7ais',en:'French'},\r\n    {code:'pt',native:'Portugu\\u00EAs',en:'Portuguese'},{code:'de',native:'Deutsch',en:'German'},\r\n    {code:'ja',native:'\\u65E5\\u672C\\u8A9E',en:'Japanese'},{code:'ko',native:'\\uD55C\\uAD6D\\uC5B4',en:'Korean'},\r\n    {code:'ru',native:'\\u0420\\u0443\\u0441\\u0441\\u043A\\u0438\\u0439',en:'Russian'},{code:'it',native:'Italiano',en:'Italian'},\r\n    {code:'tr',native:'T\\u00FCrk\\u00E7e',en:'Turkish'},{code:'id',native:'Bahasa Indonesia',en:'Indonesian'},\r\n    {code:'ms',native:'Bahasa Melayu',en:'Malay'},{code:'bn',native:'\\u09AC\\u09BE\\u0982\\u09B2\\u09BE',en:'Bengali'},\r\n    {code:'vi',native:'Ti\\u1EBFng Vi\\u1EC7t',en:'Vietnamese'},{code:'th',native:'\\u0E44\\u0E17\\u0E22',en:'Thai'},\r\n    {code:'sw',native:'Kiswahili',en:'Swahili'},{code:'nl',native:'Nederlands',en:'Dutch'},\r\n    {code:'pl',native:'Polski',en:'Polish'},{code:'uk',native:'\\u0423\\u043A\\u0440\\u0430\\u0457\\u043D\\u0441\\u044C\\u043A\\u0430',en:'Ukrainian'},\r\n    {code:'el',native:'\\u0395\\u03BB\\u03BB\\u03B7\\u03BD\\u03B9\\u03BA\\u03AC',en:'Greek'},{code:'he',native:'\\u05E2\\u05D1\\u05E8\\u05D9\\u05EA',en:'Hebrew'},\r\n    {code:'fa',native:'\\u0641\\u0627\\u0631\\u0633\\u06CC',en:'Persian'},{code:'ur',native:'\\u0627\\u0631\\u062F\\u0648',en:'Urdu'},\r\n    {code:'ne',native:'\\u0928\\u0947\\u092A\\u093E\\u0932\\u0940',en:'Nepali'},{code:'sv',native:'Svenska',en:'Swedish'},\r\n    {code:'ro',native:'Rom\\u00E2n\\u0103',en:'Romanian'},{code:'fil',native:'Filipino',en:'Filipino'},\r\n    {code:'af',native:'Afrikaans',en:'Afrikaans'}\r\n  ];\r\n\r\n  var CG_SAMPLES = {\r\n    en:'The only way to do great work is to love what you do.',\r\n    es:'La vida es lo que pasa mientras estas ocupado haciendo otros planes.',\r\n    fr:'La vie est belle pour ceux qui la regardent avec les yeux du coeur.',\r\n    de:'Das Leben ist was passiert waehrend wir andere Plaene machen.',\r\n    pt:'A vida e o que acontece enquanto voce esta ocupado fazendo outros planos.',\r\n    it:'La vita e bella per coloro che la guardano con gli occhi del cuore.',\r\n    nl:'Het leven is wat er gebeurt terwijl je bezig bent andere plannen te maken.',\r\n    sv:'Livet ar vad som hander medan du ar upptagen med att gora andra planer.',\r\n    af:'Die lewe is mooi vir diegene wat dit bekyk met die oe van die hart.'\r\n  };\r\n\r\n  var CG_LANG = {code:'en',native:'English',en:'English'};\r\n  var CG = { plain:'', author:'', type:'letters', map:{}, total:0, initialized:false };\r\n\r\n  function escH(s){ return String(s==null?'':s).replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;'); }\r\n\r\n  function toast(msg,type){\r\n    var c=document.getElementById('pth-cg-toasts');if(!c)return;\r\n    var t=document.createElement('div');t.className='pth-cg-toast cg-t'+(type||'i');t.textContent=msg;\r\n    c.appendChild(t);setTimeout(function(){t.style.opacity='0';setTimeout(function(){if(t.parentNode)t.parentNode.removeChild(t);},300);},3000);\r\n  }\r\n\r\n  function shuffle(arr){\r\n    var a=arr.slice();\r\n    for(var i=a.length-1;i>0;i--){var j=Math.floor(Math.random()*(i+1));var t=a[i];a[i]=a[j];a[j]=t;}\r\n    return a;\r\n  }\r\n\r\n  function buildMap(type){\r\n    var alpha='ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),map={},arr;\r\n    if(type==='letters'){\r\n      arr=shuffle(alpha);\r\n      var tries=0;\r\n      while(tries<200){var ok=true;for(var i=0;i<26;i++){if(alpha[i]===arr[i]){ok=false;break;}}if(ok)break;arr=shuffle(alpha);tries++;}\r\n    } else if(type==='numbers'){\r\n      var nums=[];for(var n=1;n<=26;n++)nums.push(n.toString());arr=shuffle(nums);\r\n    } else { arr=shuffle(SYMBOLS); }\r\n    for(var k=0;k<26;k++) map[alpha[k]]=arr[k];\r\n    return map;\r\n  }\r\n\r\n  function updateProgress(){\r\n    var boxes=document.querySelectorAll('#pth-cg-grid .cg-box');\r\n    var filled=0;boxes.forEach(function(b){if(b.value.trim())filled++;});\r\n    var sf=document.getElementById('pth-cg-s-filled');if(sf)sf.textContent=filled+' \/ '+CG.total;\r\n    var pct=CG.total>0?Math.round(filled\/CG.total*100):0;\r\n    var fill=document.getElementById('pth-cg-fill');if(fill)fill.style.width=pct+'%';\r\n  }\r\n\r\n  function renderGrid(){\r\n    var wrap=document.getElementById('pth-cg-grid');if(!wrap)return;\r\n    var authD=document.getElementById('pth-cg-auth-disp');if(authD)authD.textContent=CG.author;\r\n    wrap.innerHTML='';CG.total=0;\r\n    var words=CG.plain.split(\/\\s+\/);\r\n    words.forEach(function(word){\r\n      if(!word)return;\r\n      var wDiv=document.createElement('div');wDiv.className='cg-word';\r\n      for(var i=0;i<word.length;i++){\r\n        var ch=word[i];\r\n        if(\/[A-Z]\/.test(ch)){\r\n          CG.total++;\r\n          var cell=document.createElement('div');cell.className='cg-cell';\r\n          var cLbl=document.createElement('div');cLbl.className='cg-cipher';cLbl.textContent=String(CG.map[ch]||'?');\r\n          var inp=document.createElement('input');\r\n          inp.className='cg-box';inp.type='text';inp.maxLength=1;\r\n          inp.setAttribute('data-ans',ch);inp.setAttribute('data-cipher',String(CG.map[ch]||''));\r\n          inp.setAttribute('aria-label','Enter decoded letter');\r\n          inp.addEventListener('input',onInput);\r\n          inp.addEventListener('keydown',onKeydown);\r\n          cell.appendChild(cLbl);cell.appendChild(inp);wDiv.appendChild(cell);\r\n        } else {\r\n          var punc=document.createElement('div');punc.className='cg-punc';punc.textContent=ch;wDiv.appendChild(punc);\r\n        }\r\n      }\r\n      wrap.appendChild(wDiv);\r\n    });\r\n    updateProgress();renderKeyTable();\r\n    var sf=document.getElementById('pth-cg-s-letters');if(sf)sf.textContent=CG.total;\r\n    var sw=document.getElementById('pth-cg-s-words');if(sw)sw.textContent=words.filter(function(w){return w.length>0;}).length;\r\n    var sc=document.getElementById('pth-cg-s-cipher');if(sc)sc.textContent={letters:'Random Letters',numbers:'Numbers',symbols:'Symbols'}[CG.type]||CG.type;\r\n  }\r\n\r\n  function onInput(e){\r\n    var val=e.target.value.toUpperCase().replace(\/[^A-Z]\/g,'');\r\n    e.target.value=val;\r\n    var ciph=e.target.getAttribute('data-cipher');\r\n    document.querySelectorAll('#pth-cg-grid .cg-box').forEach(function(x){x.classList.remove('cg-ok','cg-no');});\r\n    document.querySelectorAll('#pth-cg-grid .cg-box[data-cipher=\"'+ciph+'\"]').forEach(function(x){x.value=val;});\r\n    if(val){\r\n      var all=Array.from(document.querySelectorAll('#pth-cg-grid .cg-box'));\r\n      var idx=all.indexOf(e.target);\r\n      if(idx>-1&&idx<all.length-1)all[idx+1].focus();\r\n    }\r\n    updateProgress();\r\n  }\r\n\r\n  function onKeydown(e){\r\n    if(e.key==='Backspace'&&!e.target.value){\r\n      var all=Array.from(document.querySelectorAll('#pth-cg-grid .cg-box'));\r\n      var idx=all.indexOf(e.target);\r\n      if(idx>0){\r\n        all[idx-1].focus();\r\n        var pc=all[idx-1].getAttribute('data-cipher');\r\n        document.querySelectorAll('#pth-cg-grid .cg-box[data-cipher=\"'+pc+'\"]').forEach(function(x){x.value='';x.classList.remove('cg-ok','cg-no');});\r\n      }\r\n    }\r\n  }\r\n\r\n  function renderKeyTable(){\r\n    var tbl=document.getElementById('pth-cg-keytbl');if(!tbl)return;tbl.innerHTML='';\r\n    var alpha='ABCDEFGHIJKLMNOPQRSTUVWXYZ';\r\n    for(var i=0;i<26;i++){\r\n      var ch=alpha[i];if(CG.map[ch]===undefined)continue;\r\n      var pair=document.createElement('div');pair.className='cg-key-pair';\r\n      pair.innerHTML=ch+' = <span>'+escH(String(CG.map[ch]))+'<\/span>';\r\n      tbl.appendChild(pair);\r\n    }\r\n  }\r\n\r\n  \/* \u2500\u2500 Export HTML \u2500\u2500 *\/\r\n  function buildExportHTML(){\r\n    if(!CG.plain||!Object.keys(CG.map).length)return'';\r\n    var wordsHTML='';\r\n    CG.plain.split(\/\\s+\/).forEach(function(word){\r\n      if(!word)return;\r\n      var wH='<'+'div class=\"cg-word\">';\r\n      for(var i=0;i<word.length;i++){\r\n        var ch=word[i];\r\n        if(\/[A-Z]\/.test(ch)){\r\n          var ciph=escH(String(CG.map[ch]||'?'));\r\n          wH+='<'+'div class=\"cg-cell\">'+\r\n              '<'+'div class=\"cg-cipher\">'+ciph+'<'+'\/div>'+\r\n              '<'+'input class=\"cg-box\" type=\"text\" maxlength=\"1\" data-ans=\"'+ch+'\" data-cipher=\"'+ciph+'\" aria-label=\"Enter letter\">'+\r\n              '<'+'\/div>';\r\n        } else { wH+='<'+'div class=\"cg-punc\">'+escH(ch)+'<'+'\/div>'; }\r\n      }\r\n      wH+='<'+'\/div>';wordsHTML+=wH;\r\n    });\r\n    var keyHTML='';\r\n    var alpha='ABCDEFGHIJKLMNOPQRSTUVWXYZ';\r\n    for(var k=0;k<26;k++){var ltr=alpha[k];if(CG.map[ltr]!==undefined)keyHTML+='<'+'span class=\"ck\">'+ltr+' = <b>'+escH(String(CG.map[ltr]))+'<\/b><'+'\/span>';}\r\n    var pairsJSON=JSON.stringify(CG.map);\r\n    var total=CG.total;\r\n    var css=\r\n      '*{box-sizing:border-box;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important;color-adjust:exact!important;}'+\r\n      'body{font-family:Inter,system-ui,sans-serif;margin:0;background:#eef2f9;padding:28px 16px;}'+\r\n      '.pg{max-width:860px;margin:0 auto;background:#fff;border-radius:16px;box-shadow:0 8px 24px -4px rgba(0,0,0,0.12);padding:28px 32px 32px;}'+\r\n      'h1{color:#7c3aed;font-size:1.45rem;font-weight:800;text-align:center;margin:0 0 4px;}'+\r\n      '.sub{text-align:center;color:#334155;font-size:0.85rem;margin:0 0 14px;}'+\r\n      '.meta{display:flex;align-items:center;justify-content:center;gap:14px;margin:14px 0 16px;flex-wrap:wrap;}'+\r\n      '.sc{font-size:0.88rem;font-weight:700;color:#7c3aed;background:#f5f3ff;padding:5px 14px;border-radius:20px;}'+\r\n      '.tm{font-size:0.88rem;font-weight:700;color:#334155;background:#f1f5f9;padding:5px 12px;border-radius:7px;}'+\r\n      '.pw{height:6px;background:#e2e8f0;border-radius:3px;overflow:hidden;margin-bottom:16px;}'+\r\n      '.pf{height:100%;background:linear-gradient(90deg,#7c3aed,#10b981);border-radius:3px;transition:width 0.4s;}'+\r\n      '.ws{background:#f8fafc;padding:20px;border-radius:10px;border:1px solid #e2e8f0;text-align:center;}'+\r\n      '.cg-word{display:inline-flex;gap:3px;margin-right:18px;margin-bottom:14px;vertical-align:top;}'+\r\n      '.cg-cell{display:flex;flex-direction:column;align-items:center;width:27px;}'+\r\n      '.cg-cipher{font-size:0.9rem;font-weight:800;color:#1e293b;margin-bottom:4px;height:20px;display:flex;align-items:center;justify-content:center;}'+\r\n      '.cg-box{width:100%;text-align:center;border:none;border-bottom:2.5px solid #0f172a;background:transparent;font-size:0.9rem;font-weight:800;color:#7c3aed;outline:none;padding:2px 0;text-transform:uppercase;font-family:monospace;}'+\r\n      '.cg-box:focus{background:#ede9fe;}'+\r\n      '.cg-box.ok{color:#065f46!important;background:#d1fae5!important;border-color:#059669!important;font-weight:900!important;}'+\r\n      '.cg-box.no{color:#7f1d1d!important;background:#fee2e2!important;border-color:#dc2626!important;font-weight:900!important;}'+\r\n      '.cg-punc{font-size:1.2rem;font-weight:800;color:#475569;display:flex;align-items:flex-end;padding-bottom:2px;}'+\r\n      '.au{text-align:right;font-weight:700;color:#475569;margin-top:10px;font-size:0.9rem;}'+\r\n      '.btns{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:20px 0 0;padding-top:16px;border-top:2px solid #e2e8f0;}'+\r\n      '.btn{padding:9px 18px;border-radius:8px;border:none;font-family:inherit;font-size:0.85rem;font-weight:700;cursor:pointer;}'+\r\n      '.btn-p{background:#7c3aed;color:#fff;}.btn-g{background:#10b981;color:#fff;}.btn-b{background:#fff;border:2px solid #e2e8f0;color:#334155;}'+\r\n      '.ckey{margin-top:14px;padding:12px;background:#f5f3ff;border-radius:8px;display:none;}'+\r\n      '.ckey-t{font-size:0.78rem;font-weight:700;color:#6d28d9;margin:0 0 6px;}.ck{display:inline-block;background:#fff;border:1px solid #ddd6fe;border-radius:4px;padding:2px 7px;font-size:0.72rem;font-weight:700;color:#334155;font-family:monospace;margin:2px;}'+\r\n      '@media print{body{background:#fff;padding:8px;}.pg{box-shadow:none;padding:8px;}.btns,.tm,.pw{display:none!important;}.ckey{display:block!important;}.cg-box{border-bottom:1.5px solid #000!important;color:#000!important;background:transparent!important;}}';\r\n    var sc=[\r\n      '(function(){',\r\n        'var map='+pairsJSON+';',\r\n        'var tot='+total+';',\r\n        'var boxes=document.querySelectorAll(\".cg-box\");',\r\n        'var secs=0,ti=setInterval(function(){secs++;var t=document.getElementById(\"tm\");if(t){var m=Math.floor(secs\/60),s=secs%60;t.textContent=\"\\u23F1 \"+(m<10?\"0\":\"\")+m+\":\"+(s<10?\"0\":\"\")+s;}},1000);',\r\n        'function upP(){var f=0;boxes.forEach(function(b){if(b.value)f++;});document.getElementById(\"sc\").textContent=f+\" \/ \"+tot;var pct=tot?Math.round(f\/tot*100):0;var pf=document.getElementById(\"pf\");if(pf)pf.style.width=pct+\"%\";}',\r\n        'boxes.forEach(function(b){',\r\n          'b.addEventListener(\"input\",function(e){',\r\n            'var v=e.target.value.toUpperCase().replace(\/[^A-Z]\/g,\"\");e.target.value=v;',\r\n            'var c=e.target.getAttribute(\"data-cipher\");',\r\n            'boxes.forEach(function(x){x.classList.remove(\"ok\",\"no\");if(x.getAttribute(\"data-cipher\")===c)x.value=v;});',\r\n            'if(v){var a=Array.from(boxes),i=a.indexOf(e.target);if(i>-1&&i<a.length-1)a[i+1].focus();}',\r\n            'upP();',\r\n          '});',\r\n          'b.addEventListener(\"keydown\",function(e){',\r\n            'if(e.key===\"Backspace\"&&!e.target.value){',\r\n              'var a=Array.from(boxes),i=a.indexOf(e.target);',\r\n              'if(i>0){a[i-1].focus();var pc=a[i-1].getAttribute(\"data-cipher\");boxes.forEach(function(x){if(x.getAttribute(\"data-cipher\")===pc){x.value=\"\";x.classList.remove(\"ok\",\"no\");}});}',\r\n            '}',\r\n          '});',\r\n        '});',\r\n        'document.getElementById(\"b-chk\").addEventListener(\"click\",function(){var cor=0;boxes.forEach(function(b){b.classList.remove(\"ok\",\"no\");var v=b.value,a=b.getAttribute(\"data-ans\");if(v){if(v===a){b.classList.add(\"ok\");cor++;}else b.classList.add(\"no\");}});document.getElementById(\"sc\").textContent=cor+\" \/ \"+tot;});',\r\n        'document.getElementById(\"b-rev\").addEventListener(\"click\",function(){boxes.forEach(function(b){b.value=b.getAttribute(\"data-ans\");b.classList.remove(\"no\");b.classList.add(\"ok\");});document.getElementById(\"sc\").textContent=tot+\" \/ \"+tot;var pf=document.getElementById(\"pf\");if(pf)pf.style.width=\"100%\";});',\r\n        'document.getElementById(\"b-rst\").addEventListener(\"click\",function(){boxes.forEach(function(b){b.value=\"\";b.classList.remove(\"ok\",\"no\");});document.getElementById(\"sc\").textContent=\"0 \/ \"+tot;var pf=document.getElementById(\"pf\");if(pf)pf.style.width=\"0%\";});',\r\n        'document.getElementById(\"b-key\").addEventListener(\"click\",function(){var k=document.querySelector(\".ckey\");if(k){k.style.display=k.style.display===\"none\"?\"block\":\"none\";this.textContent=k.style.display===\"block\"?\"\\uD83D\\uDD11 Hide Key\":\"\\uD83D\\uDD11 Show Key\";}});',\r\n        'document.getElementById(\"b-prt\").addEventListener(\"click\",function(){window.print();});',\r\n      '})();'\r\n    ].join('');\r\n    var so='<'+'script'+'>';var sc2='<'+'\/'+'script'+'>';\r\n    var dO='<'+'!DOCTYPE html>'+'<'+'html lang=\"en\">'+'<'+'head>'+'<'+'meta charset=\"UTF-8\">'+'<'+'meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">'+'<'+'title>Cryptogram Puzzle<'+'\/title>'+'<'+'style>'+css+'<'+'\/style>'+'<'+'\/head>'+'<'+'body>';\r\n    var dC='<'+'\/'+'body>'+'<'+'\/'+'html>';\r\n    var body=\r\n      '<div class=\"pg\">'+\r\n      '<h2>\\uD83D\\uDD75\\uFE0F Crack the Code<\/h2>'+\r\n      '<p class=\"sub\">Decode the secret message! Each cipher always represents the same letter.<\/p>'+\r\n      '<div class=\"meta\"><span class=\"sc\" id=\"sc\">0 \/ '+total+'<\/span><span class=\"tm\" id=\"tm\">\\u23F1 00:00<\/span><\/div>'+\r\n      '<div class=\"pw\"><div class=\"pf\" id=\"pf\" style=\"width:0%;\"><\/div><\/div>'+\r\n      '<div class=\"ws\">'+wordsHTML+'<\/div>'+\r\n      (CG.author?'<div class=\"au\">'+escH(CG.author)+'<\/div>':'')+\r\n      '<div class=\"ckey\"><p class=\"ckey-t\">\\uD83D\\uDD11 Cipher Key (Teacher Reference)<\/p>'+keyHTML+'<\/div>'+\r\n      '<div class=\"btns\">'+\r\n        '<button class=\"btn btn-p\" id=\"b-chk\">\\u2705 Check Answers<\/button>'+\r\n        '<button class=\"btn btn-g\" id=\"b-rev\">\\uD83D\\uDC41 Reveal All<\/button>'+\r\n        '<button class=\"btn btn-b\" id=\"b-rst\">\\uD83D\\uDD04 Reset<\/button>'+\r\n        '<button class=\"btn btn-b\" id=\"b-key\">\\uD83D\\uDD11 Show Key<\/button>'+\r\n        '<button class=\"btn btn-b\" id=\"b-prt\">\\uD83D\\uDDA8 Print<\/button>'+\r\n      '<\/div>'+\r\n      '<\/div>';\r\n    return dO+body+so+sc+sc2+dC;\r\n  }\r\n\r\n  \/* \u2500\u2500 Language Popup \u2500\u2500 *\/\r\n  function openLangPopup(){\r\n    if(!document.getElementById('pth-cg-lo')){\r\n      var sty=document.createElement('style');\r\n      sty.textContent='#pth-cg-lo{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(15,23,42,0.55);z-index:9999998;align-items:center;justify-content:center;padding:16px;}#pth-cg-lo.open{display:flex;}#pth-cg-lm{background:#fff;border-radius:16px;width:100%;max-width:660px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 24px 60px rgba(0,0,0,0.25);overflow:hidden;position:relative;}.lm-h{padding:20px 20px 0;flex-shrink:0;}.lm-t{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 3px;font-family:Inter,system-ui;}.lm-s{font-size:0.78rem;color:#334155;margin:0 0 12px;}.lm-x{position:absolute;top:14px;right:14px;background:#f1f5f9;border:none;width:32px;height:32px;border-radius:50%;cursor:pointer;color:#334155;font-weight:700;font-size:0.9rem;}.lm-x:hover{background:#e2e8f0;}.lm-sw{padding:0 16px 10px;flex-shrink:0;}.lm-si{width:100%;padding:8px 12px;border:2px solid #e2e8f0;border-radius:8px;font-size:0.85rem;outline:none;}.lm-si:focus{border-color:#7c3aed;}.lm-gw{overflow-y:auto;flex:1;padding:0 8px 8px;}.lm-g{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;}.lm-i{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:8px;cursor:pointer;border:2px solid transparent;background:transparent;text-align:left;width:100%;}.lm-i:hover{background:#f1f5f9;}.lm-i.sel{background:#f5f3ff;border-color:#ddd6fe;}.lm-f{font-size:0.62rem;font-weight:800;flex-shrink:0;width:28px;height:20px;display:flex;align-items:center;justify-content:center;background:#f5f3ff;color:#7c3aed;border-radius:5px;}.lm-n{display:flex;flex-direction:column;min-width:0;}.lm-na{font-size:0.82rem;font-weight:700;color:#0f172a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.lm-ne{font-size:0.7rem;color:#334155;}.lm-ft{padding:10px 16px;border-top:1px solid #e2e8f0;display:flex;justify-content:space-between;flex-shrink:0;background:#f8fafc;font-size:0.8rem;color:#334155;}.lm-ft b{color:#7c3aed;}@media(max-width:520px){.lm-g{grid-template-columns:repeat(2,1fr);}}';\r\n      document.head.appendChild(sty);\r\n      var ov=document.createElement('div');ov.id='pth-cg-lo';\r\n      ov.innerHTML='<div id=\"pth-cg-lm\"><div class=\"lm-h\"><p class=\"lm-t\">&#x1F30D; Choose Quote Language<\/p><p class=\"lm-s\">Sample messages for each language (cipher uses A-Z)<\/p><\/div><button class=\"lm-x\" id=\"pth-cg-lx\">&#x2715;<\/button><div class=\"lm-sw\"><input type=\"text\" class=\"lm-si\" id=\"pth-cg-ls\" placeholder=\"Search language...\" autocomplete=\"off\" aria-label=\"Search\"><\/div><div class=\"lm-gw\"><div class=\"lm-g\" id=\"pth-cg-lg\"><\/div><div style=\"text-align:center;padding:24px;color:#334155;font-size:0.85rem;display:none;\" id=\"pth-cg-ln\">No languages found.<\/div><\/div><div class=\"lm-ft\"><span>Selected: <b id=\"pth-cg-lc\">English<\/b><\/span><span style=\"font-size:0.72rem;color:#475569;\">&#x1F4DD; Accented chars stripped to A-Z<\/span><\/div><\/div>';\r\n      document.body.appendChild(ov);\r\n      var se=document.getElementById('pth-cg-ls');\r\n      if(se) se.addEventListener('input',function(){renderLangGrid(se.value.toLowerCase().trim());});\r\n      document.getElementById('pth-cg-lx').addEventListener('click',closeLangPopup);\r\n      ov.addEventListener('click',function(e){if(e.target===ov)closeLangPopup();});\r\n      document.addEventListener('keydown',function(e){if(e.key==='Escape')closeLangPopup();});\r\n    }\r\n    renderLangGrid('');\r\n    var ov=document.getElementById('pth-cg-lo');if(ov)ov.classList.add('open');\r\n    var s=document.getElementById('pth-cg-ls');if(s){s.value='';setTimeout(function(){s.focus();},100);}\r\n  }\r\n\r\n  function closeLangPopup(){var ov=document.getElementById('pth-cg-lo');if(ov)ov.classList.remove('open');}\r\n\r\n  function renderLangGrid(q){\r\n    var grid=document.getElementById('pth-cg-lg'),nores=document.getElementById('pth-cg-ln');\r\n    if(!grid)return;grid.innerHTML='';\r\n    var f=CG_LANGS.filter(function(l){return !q||l.en.toLowerCase().indexOf(q)!==-1||l.native.toLowerCase().indexOf(q)!==-1||l.code.indexOf(q)!==-1;});\r\n    if(!f.length){if(nores)nores.style.display='block';return;}if(nores)nores.style.display='none';\r\n    f.forEach(function(l){\r\n      var btn=document.createElement('button');btn.className='lm-i'+(l.code===CG_LANG.code?' sel':'');\r\n      btn.innerHTML='<span class=\"lm-f\">'+l.code.toUpperCase()+'<\/span><span class=\"lm-n\"><span class=\"lm-na\">'+l.native+'<\/span><span class=\"lm-ne\">'+l.en+'<\/span><\/span>';\r\n      btn.addEventListener('click',function(){selectLang(l);});grid.appendChild(btn);\r\n    });\r\n  }\r\n\r\n  function selectLang(l){\r\n    CG_LANG=l;\r\n    var cur=document.getElementById('pth-cg-lc');if(cur)cur.innerHTML=l.code.toUpperCase()+' '+l.native;\r\n    var fl=document.getElementById('pth-cg-flag');if(fl)fl.innerHTML=l.code.toUpperCase();\r\n    var tx=document.getElementById('pth-cg-lang-text');if(tx)tx.innerHTML=l.native+' \\u2014 '+l.en;\r\n    if(CG_SAMPLES[l.code]){\r\n      var ta=document.getElementById('pth-cg-msg');if(ta)ta.value=CG_SAMPLES[l.code];\r\n      toast('Loaded: '+l.native+' ('+l.en+')','s');\r\n    } else { toast(l.en+' selected! Type your own quote.','i'); }\r\n    renderLangGrid('');closeLangPopup();\r\n  }\r\n\r\n  \/* \u2500\u2500 Init \u2500\u2500 *\/\r\n  function init(){\r\n    if(CG.initialized||!document.getElementById('pth-cg-wrap'))return;\r\n    CG.initialized=true;\r\n\r\n    var b=function(id,fn){var el=document.getElementById(id);if(el)el.addEventListener('click',fn);};\r\n\r\n    b('pth-cg-lang-btn',openLangPopup);\r\n\r\n    b('pth-cg-gen',function(){\r\n      var ta=document.getElementById('pth-cg-msg');\r\n      if(!ta||!ta.value.trim()){toast('Please enter a message.','e');return;}\r\n      CG.plain=ta.value.trim().toUpperCase().replace(\/[^A-Z\\s\\.,!?'\";\\-]\/g,'');\r\n      CG.author=(document.getElementById('pth-cg-auth')||{}).value||'';\r\n      CG.type=(document.getElementById('pth-cg-type')||{}).value||'letters';\r\n      CG.map=buildMap(CG.type);CG.total=0;\r\n      renderGrid();\r\n      document.getElementById('pth-cg-puzzle').style.display='block';\r\n      document.getElementById('pth-cg-keycard').style.display='block';\r\n      toast('Cryptogram generated!','s');\r\n    });\r\n\r\n    b('pth-cg-check',function(){\r\n      var boxes=document.querySelectorAll('#pth-cg-grid .cg-box');\r\n      var cor=0,all=true;\r\n      boxes.forEach(function(b){b.classList.remove('cg-ok','cg-no');var v=b.value,a=b.getAttribute('data-ans');if(!v){all=false;}else if(v===a){b.classList.add('cg-ok');cor++;}else b.classList.add('cg-no');});\r\n      if(cor===boxes.length&&boxes.length>0)toast('Brilliant! Code Cracked!','s');\r\n      else if(!all)toast('Keep going! Some letters missing.','i');\r\n      else toast('Almost! Check the red letters.','e');\r\n    });\r\n\r\n    b('pth-cg-reveal',function(){\r\n      document.querySelectorAll('#pth-cg-grid .cg-box').forEach(function(b){b.value=b.getAttribute('data-ans');b.classList.remove('cg-no');b.classList.add('cg-ok');});\r\n      updateProgress();toast('Secret revealed!','i');\r\n    });\r\n\r\n    b('pth-cg-reset',function(){\r\n      document.querySelectorAll('#pth-cg-grid .cg-box').forEach(function(b){b.value='';b.classList.remove('cg-ok','cg-no');});\r\n      updateProgress();toast('Grid cleared.','i');\r\n    });\r\n\r\n    b('pth-cg-regen',function(){\r\n      if(!CG.plain){toast('Generate first!','e');return;}\r\n      CG.map=buildMap(CG.type);CG.total=0;renderGrid();toast('New cipher!','s');\r\n    });\r\n\r\n    b('pth-cg-dl',function(){\r\n      if(!CG.plain){toast('Generate first!','e');return;}\r\n      var c=buildExportHTML();if(!c)return;\r\n      try{var blob=new Blob([c],{type:'text\/html'});var url=URL.createObjectURL(blob);var a=document.createElement('a');a.href=url;a.download='cryptogram-puzzle.html';document.body.appendChild(a);a.click();document.body.removeChild(a);setTimeout(function(){URL.revokeObjectURL(url);},2000);toast('Downloaded!','s');}\r\n      catch(err){toast('Download failed: '+err.message,'e');}\r\n    });\r\n\r\n    b('pth-cg-copy',function(){\r\n      if(!CG.plain){toast('Generate first!','e');return;}\r\n      var c=buildExportHTML();if(!c)return;\r\n      var cb=document.getElementById('pth-cg-codebox');var ta=document.getElementById('pth-cg-codetxt');\r\n      if(cb&&ta){cb.style.display='block';ta.value=c;ta.select();try{document.execCommand('copy');toast('Copied!','s');}catch(e){toast('Copy failed','e');}}\r\n    });\r\n\r\n    b('pth-cg-print',function(){\r\n      if(!CG.plain){toast('Generate first!','e');return;}\r\n      var c=buildExportHTML();if(!c)return;\r\n      var w=window.open('','_blank');\r\n      if(!w){toast('Popup blocked!','e');return;}\r\n      w.document.open();w.document.write(c);w.document.close();\r\n      var printed=false;function doPrint(){if(printed)return;printed=true;w.focus();w.print();}\r\n      w.addEventListener('load',function(){setTimeout(doPrint,150);});setTimeout(doPrint,1200);\r\n    });\r\n\r\n    b('pth-cg-ai',function(){\r\n      var key=(document.getElementById('pth-cg-ai-key')||{}).value||'';\r\n      var topic=(document.getElementById('pth-cg-ai-topic')||{}).value||'Motivation';\r\n      var btn=document.getElementById('pth-cg-ai');\r\n      if(key.indexOf('sk-ant-')!==0){toast('Enter valid Anthropic API key','e');return;}\r\n      btn.textContent='Fetching...';btn.disabled=true;\r\n      var prompt='Give me one short famous English quote about \"'+topic+'\". Format: Quote text - Author Name. No quotation marks. Max 20 words.';\r\n      fetch('https:\/\/api.anthropic.com\/v1\/messages',{method:'POST',headers:{'Content-Type':'application\/json','x-api-key':key,'anthropic-version':'2023-06-01','anthropic-dangerous-direct-browser-calls':'true'},body:JSON.stringify({model:'claude-sonnet-4-6',max_tokens:100,messages:[{role:'user',content:prompt}]})})\r\n      .then(function(r){return r.json();}).then(function(data){\r\n        btn.innerHTML='\\u2728 Get Quote';btn.disabled=false;\r\n        if(data.error){toast(data.error.message,'e');return;}\r\n        var text=(data.content&&data.content[0]&&data.content[0].text)||'';\r\n        var parts=text.split(' - ');\r\n        var ta=document.getElementById('pth-cg-msg');if(ta)ta.value=parts[0].trim();\r\n        var au=document.getElementById('pth-cg-auth');if(au&&parts[1])au.value='- '+parts[1].trim();\r\n        toast('Quote loaded! Click Generate.','s');\r\n        document.getElementById('pth-cg-gen').scrollIntoView({behavior:'smooth',block:'center'});\r\n      }).catch(function(e){btn.innerHTML='\\u2728 Get Quote';btn.disabled=false;toast('Error: '+e.message,'e');});\r\n    });\r\n\r\n    \/* PTH ILS toolbar events *\/\r\n    document.addEventListener('pthILSSample',function(e){\r\n      if(e.detail&&e.detail.tab!=='cryptogram')return;\r\n      var ta=document.getElementById('pth-cg-msg');\r\n      var au=document.getElementById('pth-cg-auth');\r\n      if(ta)ta.value=CG_SAMPLES[CG_LANG.code]||CG_SAMPLES.en;\r\n      if(au)au.value='- Nelson Mandela';\r\n      toast('Sample Loaded! Click Generate.','s');\r\n    });\r\n    document.addEventListener('pthILSClear',function(e){\r\n      if(e.detail&&e.detail.tab!=='cryptogram')return;\r\n      var ta=document.getElementById('pth-cg-msg');if(ta)ta.value='';\r\n      var au=document.getElementById('pth-cg-auth');if(au)au.value='';\r\n      document.getElementById('pth-cg-puzzle').style.display='none';\r\n      document.getElementById('pth-cg-keycard').style.display='none';\r\n      CG.plain='';CG.map={};CG.total=0;\r\n    });\r\n  }\r\n\r\n  \/* Bulletproof initialiser \u2014 same pattern as original that worked *\/\r\n  function tryInit(){\r\n    if(!CG.initialized&&document.getElementById('pth-cg-wrap'))init();\r\n  }\r\n  if(document.readyState==='complete'||document.readyState==='interactive'){\r\n    setTimeout(tryInit,50);\r\n  } else {\r\n    document.addEventListener('DOMContentLoaded',tryInit);\r\n    window.addEventListener('load',tryInit);\r\n  }\r\n  setTimeout(tryInit,800);\/* Extra safety *\/\r\n\r\n})();\r\n<\/script>\r\n\n\n\n\n<style>\n.pth-feature-wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:30px}\n.pth-feat-box{border:1px solid #e2e8f0;background:#fff;padding:24px;border-radius:12px;box-shadow:0 4px 6px -1px rgba(0,0,0,0.02);transition:all .3s ease}\n.pth-feat-box:hover{border-color:#bfdbfe;transform:translateY(-3px);box-shadow:0 10px 15px -3px rgba(0,0,0,0.05)}\n.pth-feat-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin-bottom:10px;display:flex;align-items:center;gap:10px}\n.pth-feat-text{font-size:.9rem;color:#1e293b;line-height:1.6;margin:0;font-weight:500}\n.pth-steps-wrap{border:1px solid #e2e8f0;background:#fff;padding:40px 30px;border-radius:16px;text-align:center;box-shadow:0 4px 6px -1px rgba(0,0,0,0.02);margin-bottom:40px}\n.pth-steps-title{font-size:1.2rem;font-weight:800;color:#0f172a;text-transform:uppercase;margin-bottom:35px;letter-spacing:1px}\n.pth-steps-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:30px}\n.pth-step-item{display:flex;flex-direction:column;align-items:center}\n.pth-step-num{width:45px;height:45px;background:#2563eb;color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.2rem;margin-bottom:15px;box-shadow:0 4px 10px rgba(37,99,235,.3)}\n.pth-step-name{font-weight:800;color:#0f172a;margin-bottom:8px;font-size:1rem}\n.pth-step-desc{font-size:.9rem;color:#1e293b;line-height:1.5;margin:0;font-weight:500}\n<\/style>\n\n<div class=\"pth-feature-wrap\">\n  <div class=\"pth-feat-box\">\n    <div class=\"pth-feat-title\">\ud83d\udfe2 5 Activity Types in One Place<\/div>\n    <p class=\"pth-feat-text\">Build crossword puzzles, word search grids, drag-sort challenges, match-the-pairs games, and flip-card memory matches \u2014 all from a single browser tab. No switching between apps. No accounts. Just create, export, and share.<\/p>\n  <\/div>\n  <div class=\"pth-feat-box\">\n    <div class=\"pth-feat-title\">\ud83d\udd35 AI-Powered Content Generation<\/div>\n    <p class=\"pth-feat-text\">The built-in AI Assistant tab connects to Gemini (free), Groq Llama (free), or Claude Sonnet (paid) to generate activity content from any topic in any language. Type a subject, pick a target activity, click Generate \u2014 done in seconds.<\/p>\n  <\/div>\n  <div class=\"pth-feat-box\">\n    <div class=\"pth-feat-title\">\ud83d\udfe3 Multilingual Clues &#038; Export<\/div>\n    <p class=\"pth-feat-text\">Crossword clues work in Sinhala, Tamil, Arabic, Chinese, Hindi, and 29 more languages. Every completed activity exports as a fully interactive standalone HTML file or PNG image \u2014 ready for print, classroom distribution, or online sharing.<\/p>\n  <\/div>\n<\/div>\n\n<div class=\"pth-steps-wrap\">\n  <div class=\"pth-steps-title\">How to Use Interactive Learning Studio Pro<\/div>\n  <div class=\"pth-steps-grid\">\n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">1<\/div>\n      <div class=\"pth-step-name\">Choose a Tab<\/div>\n      <p class=\"pth-step-desc\">Click Crossword, Word Search, Drag &amp; Sort, Match Pairs, or Memory Match from the tab bar at the top of the tool.<\/p>\n    <\/div>\n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">2<\/div>\n      <div class=\"pth-step-name\">Load Sample or Type<\/div>\n      <p class=\"pth-step-desc\">Click \ud83d\udca1 Load Sample to auto-fill demo content, or type your own words and clues directly into the input area \u2014 one per line.<\/p>\n    <\/div>\n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">3<\/div>\n      <div class=\"pth-step-name\">Generate Activity<\/div>\n      <p class=\"pth-step-desc\">Click \u26a1 Generate (Crossword \/ Word Search), \u26a1 Create Activity (Drag &amp; Sort), or \u26a1 Create Game \/ Start Game for Match Pairs and Memory Match.<\/p>\n    <\/div>\n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">4<\/div>\n      <div class=\"pth-step-name\">Export &amp; Share<\/div>\n      <p class=\"pth-step-desc\">Click \ud83d\uddbc Export PNG for a printable image, or \ud83d\udcc4 Download HTML for a fully interactive file students can open in any browser \u2014 no internet needed.<\/p>\n    <\/div>\n  <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Last updated: June 2026<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-why-teachers-and-trainers-choose-this-interactive-learning-studio\" class=\"wp-block-heading\">\ud83d\udd34 <strong>Why Teachers and Trainers Choose This Interactive Learning Studio<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Making educational activities from scratch takes hours. Writing crossword clues, positioning a word search grid, sequencing drag-and-drop steps, pairing terms with definitions \u2014 each of these tasks demands careful preparation before a lesson even starts. Most tools that solve this problem require a subscription, an account, or an internet connection during the session itself. This interactive learning studio removes all three barriers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Everything runs inside the browser. No server processes your data. No login stores your content. The tool generates a complete activity the moment you click Generate \u2014 and that activity can be exported as a standalone HTML file that works offline on any device. A teacher in a school with unreliable internet can hand students a USB drive containing the exported file. It opens. It works. Students solve it, drag tiles, flip cards, and check answers \u2014 all without touching a network connection.<\/p>\n\n\n<figure class=\"pth-article-figure pth-img-left\" style=\"float:left; width:700px; max-width:100%; margin:4px 28px 16px 0; clear:left;\"><img decoding=\"async\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/06\/nteractive-learning-studio-Games-800x447.jpeg\" alt=\"Five Activity Types\" width=\"700\" height=\"394\" loading=\"lazy\" data-no-lazy=\"1\" class=\"pth-article-img\" style=\"width:100%;height:auto;display:block;border-radius:10px;border:1px solid #e2e8f0;\"><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The design choice to support five distinct activity types in a single tabbed interface reflects how lesson planning actually works. A vocabulary lesson might start with a word search to introduce terms, move to a match-pairs game to link concepts, and finish with a crossword that tests retention. Jumping between five different websites to create those three activities breaks workflow. Having them in one place \u2014 with a shared toolbar for Load Sample, Full Width, Clear, and Print \u2014 keeps momentum intact.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe1-five-activity-types-what-each-one-does-and-when-to-use-it\" class=\"wp-block-heading\">\ud83d\udfe1 <strong>Five Activity Types \u2014 What Each One Does and When to Use It<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Each tab in the tool serves a specific pedagogical function. Understanding which activity fits which learning goal prevents the common mistake of overusing one format for every lesson.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-crossword-creator-assessment-through-recall\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Crossword Creator \u2014 Assessment Through Recall<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Crossword tab accepts WORD:Clue pairs \u2014 one per line. The placement algorithm tries up to 300 times per word to find a valid intersecting position in a 21\u00d721 grid, then trims the bounding box to the smallest rectangle that fits all placed words. Clues support any script: Sinhala, Arabic, Chinese, Devanagari, Thai, and 29 other languages display correctly using lazy-loaded Google Noto fonts. The language popup \u2014 searchable, 33 languages, three-column grid \u2014 makes switching between sample datasets instant.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Customize panel applies eight CSS variables in real time: cell size (28\u201356px), letter size, cell background, black cell color, letter color, correct\/wrong cell highlight colors, and across\/down clue colors. A student solving the exported HTML file gets the same visual treatment \u2014 all variables are baked into the export&#8217;s inline CSS. According to <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/Guides\/Cascading_variables\/Using_custom_properties\" target=\"_blank\" rel=\"noreferrer noopener\">MDN&#8217;s documentation on CSS custom properties<\/a>, this approach keeps styling predictable and overridable without framework dependencies.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud83d\udd35 Enter up to 20 word-clue pairs; the algorithm places the longest words first to maximize grid density<\/li>\n\n\n\n<li>\ud83d\udfe0 Skipped words (those that cannot be placed after 300 attempts) are listed in the Stats panel alongside words placed and grid size<\/li>\n\n\n\n<li>\ud83d\udfe3 Check Answers highlights correct cells green, wrong cells red; Reveal All fills remaining cells in yellow<\/li>\n<\/ul>\n\n\n\n<h3 id=\"\ud83d\udfe2-word-search-generator-recognition-before-recall\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Word Search Generator \u2014 Recognition Before Recall<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Word Search is the right activity at the start of a unit, not the end. When students haven&#8217;t encountered terms yet, recognition \u2014 spotting PHOTOSYNTHESIS hidden diagonally in a grid \u2014 builds familiarity with spelling before deeper meaning is introduced. The generator supports grid sizes from 10\u00d710 to 18\u00d718 and three direction modes: Horizontal Only, Horizontal + Vertical, and All Eight Directions including diagonals and reverse.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Selection works through click-and-drag on desktop and touch-drag on mobile. The Pointer Events API captures both input methods through a single event path \u2014 no separate mouse and touch handlers. When a valid word is selected, the cells turn green and the word tag at the bottom gains a strikethrough style. The built-in timer tracks personal best times across sessions, giving students a self-directed challenge even without a teacher present.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-drag-sort-sequencing-and-process-thinking\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Drag &amp; Sort \u2014 Sequencing and Process Thinking<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Two modes serve two distinct purposes. Sentence Sorter scrambles individual sentences that belong in a logical order \u2014 useful for narrative comprehension and argument structure. Step Sequencer scrambles procedural steps \u2014 useful for science experiments, programming tutorials, cooking recipes, and historical event timelines. Both modes use the same drag-and-drop engine with HTML5 drag events on desktop and Pointer Events API capture on touch screens.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After dragging items into order, Check Order highlights each item green (correct position) or red (wrong position) and shows a percentage score. Reshuffle resets to a new random arrangement of the same items \u2014 useful for repeated practice without regenerating the activity from scratch.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-match-pairs-and-memory-match-associative-learning\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Match Pairs and Memory Match \u2014 Associative Learning<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Match the Pairs displays terms and definitions in two shuffled columns. Students click a term, then click its matching definition. Correct pairs lock green and become non-interactive. Wrong selections flash red for 700 milliseconds, then reset \u2014 the brief penalty reinforces attention without frustrating learners. A live timer and attempt counter track performance across the session.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Memory Match uses CSS 3D flip animation \u2014 <code>rotateY(180deg)<\/code> with <code>backface-visibility:hidden<\/code> \u2014 to create genuine card-flip behavior without JavaScript-driven position changes. Students flip two cards; matching pairs stay face-up with a green border; non-matching pairs flip back after 900 milliseconds. The two-flip lock mechanism prevents a third card from being flipped while a mismatch is resetting, which is a common bug in simpler implementations. Emoji support in the Match field makes animal-to-emoji or fruit-to-emoji memory games possible with a single colon separator: <code>Apple:\ud83c\udf4e<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a broader collection of free vocabulary and comprehension tools, see our <a href=\"https:\/\/schoolict.net\/tools\/free-web-tools-directory-prime-tool-hub\/\">free web tools directory<\/a> \u2014 or explore the <a href=\"https:\/\/schoolict.net\/tools\/ai-code-studio\/\">PTH AI Code Studio<\/a> for AI-assisted code generation using the same multi-provider AI approach.<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-the-ai-assistant-tab-three-providers-one-workflow\" class=\"wp-block-heading\">\ud83d\udd34 <strong>The AI Assistant Tab \u2014 Three Providers, One Workflow<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The AI Assistant tab connects to three platforms through direct browser-to-API calls. Keys are stored in <code>sessionStorage<\/code> \u2014 they disappear when the browser tab closes and are never sent to PrimeToolHub servers. This matches the security model used in PTH AI Code Studio and is consistent with <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Window\/sessionStorage\" target=\"_blank\" rel=\"noreferrer noopener\">MDN&#8217;s sessionStorage specification<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Google Gemini Flash<\/strong> is free \u2014 no credit card required, just a Google account at AI Studio. <strong>Groq with Llama 3.3 70B<\/strong> is also free on the developer tier and runs significantly faster than most alternatives. <strong>Anthropic Claude Sonnet 4.6<\/strong> requires a paid API key but produces the most precisely formatted output for complex multilingual clue sets. The generator tries multiple models per provider in sequence \u2014 if Gemini 2.5 Flash returns a quota error, it automatically retries with Gemini 2.0 Flash, then 1.5 Flash, before reporting failure.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud83d\udd35 Paste your key and click \ud83d\udcbe Save Key \u2014 the provider tab shows a \u2705 tick when a key is stored<\/li>\n\n\n\n<li>\ud83d\udfe0 Choose the target activity tab, enter a topic in any language, set item count (6\u201315), output language (15 options), and difficulty<\/li>\n\n\n\n<li>\ud83d\udfe3 Click \u2728 Generate \u2014 the preview shows the cleaned output; click \u27a1 Use in Tab to auto-fill the target activity&#8217;s input and switch tabs automatically<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The output cleaner validates each format. Crossword output checks that the word before the colon matches <code>\/^[A-Za-z]{3,12}$\/<\/code>. Word Search output strips non-alphabetic characters and enforces uppercase. Sort output filters lines shorter than five characters. Match and Memory output require at least one colon per line. Lines failing validation are silently dropped \u2014 the displayed count reflects only valid items.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe1-exporting-activities-for-classroom-use\" class=\"wp-block-heading\">\ud83d\udfe1 <strong>Exporting Activities for Classroom Use<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Every activity type offers three export paths. Export PNG captures the current grid or game board as a raster image using the Canvas API \u2014 useful for embedding in slide decks or printing directly. Download HTML produces a self-contained file with all CSS, JavaScript, and data embedded inline \u2014 students can open it in Chrome, Firefox, Edge, or Safari without an internet connection. Copy HTML Code places the same markup in a scrollable text area for pasting into a CMS, LMS, or email.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The exported Word Search HTML uses Pointer Events API for both mouse and touch selection \u2014 the same approach that fixed the drag-selection bug that affected <code>mousedown<\/code>\/<code>mouseover<\/code> combinations in Chromium-based browsers. The exported Crossword uses a <code>data-json<\/code> attribute on a hidden div to store all grid and clue data, then injects an interactive script at the end of the <code>&lt;body&gt;<\/code> using a string split-join technique that avoids literal script tag pairs in source \u2014 a requirement for WordPress and LiteSpeed compatibility.<\/p>\n\n\n\n<style>\n.pth-faq-section{margin-top:50px;margin-bottom:40px;font-family:inherit}\n.pth-faq-header{font-size:1.8rem;font-weight:800;color:#0f172a;margin-bottom:25px;border-bottom:2px solid #e2e8f0;padding-bottom:10px;display:flex;align-items:center;gap:10px}\n.pth-faq-grid{display:grid;grid-template-columns:100%;gap:20px}\n@media(min-width:768px){.pth-faq-grid{grid-template-columns:repeat(2,1fr)}}\n@media(min-width:1024px){.pth-faq-grid{grid-template-columns:repeat(3,1fr)}}\n.pth-faq-card{background:#f8fafc;padding:24px;border-radius:12px;border:1px solid #e2e8f0;transition:transform .2s ease;break-inside:avoid}\n.pth-faq-card:hover{transform:translateY(-3px);box-shadow:0 4px 12px rgba(0,0,0,.05)}\n.pth-faq-q{color:#0f172a;font-size:1rem;font-weight:700;margin:0 0 12px;line-height:1.4}\n.pth-faq-a{margin:0;font-size:.95rem;color:#1e293b;line-height:1.6;font-weight:500}\n<\/style>\n\n<div class=\"pth-faq-section\">\n  <h2 class=\"pth-faq-header\">\u2753 Frequently Asked Questions<\/h2>\n  <div class=\"pth-faq-grid\">\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Does the interactive learning studio work without an internet connection?<\/p>\n      <p class=\"pth-faq-a\">All five activity tabs \u2014 Crossword, Word Search, Drag &amp; Sort, Match Pairs, and Memory Match \u2014 run entirely in your browser with zero server calls. The AI Assistant tab requires internet only when generating content; once you click Use in Tab, the filled activity works offline. Exported HTML files are fully self-contained and open without a network connection.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Which AI provider should I start with?<\/p>\n      <p class=\"pth-faq-a\">Start with Google Gemini Flash \u2014 it is free, requires only a Google account to get a key from AI Studio, and handles most topics and languages well. Groq with Llama 3.3 70B is the fastest option and also free on the developer tier. Use Claude Sonnet only if you need the highest output quality for complex multilingual crossword clues.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Can I write crossword clues in Sinhala, Tamil, or Arabic?<\/p>\n      <p class=\"pth-faq-a\">Yes. The WORD before the colon must use Latin letters A\u2013Z for grid placement, but the CLUE after the colon supports any language and script. The tool detects the script automatically, loads the appropriate Google Noto font, and applies right-to-left text direction for Arabic, Hebrew, Persian, and Urdu clues.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">How many words can I add to each activity?<\/p>\n      <p class=\"pth-faq-a\">Crossword accepts up to 20 word-clue pairs. Word Search accepts up to 20 words. Drag &amp; Sort has no hard limit but works best with 4\u201312 items for classroom readability. Match Pairs and Memory Match each support up to 16 pairs \u2014 larger sets create a 4-column grid that remains playable on tablets and desktops.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Is my API key safe when I paste it into the tool?<\/p>\n      <p class=\"pth-faq-a\">Your key is stored in <code>sessionStorage<\/code> only \u2014 it exists in your browser&#8217;s memory for the current tab session and is deleted automatically when the tab closes. The key is sent directly from your browser to the AI provider&#8217;s API (Google, Groq, or Anthropic) and never passes through PrimeToolHub servers.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Can students play the exported HTML on a phone?<\/p>\n      <p class=\"pth-faq-a\">Yes. All exported activities are mobile-responsive. The Word Search and Crossword grids scroll horizontally on small screens, and cell sizes adapt at the 480px breakpoint. Drag &amp; Sort and Match Pairs use Pointer Events API so touch dragging works the same as mouse dragging. Memory Match flips correctly on iOS Safari and Android Chrome.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Why are some crossword words listed as Skipped in the Stats panel?<\/p>\n      <p class=\"pth-faq-a\">The placement algorithm tries up to 300 random positions per word. If no valid intersection with existing placed words is found after 300 attempts, the word is marked Skipped. This happens when words share no common letters with already-placed words. Try adding shorter words or words that share letters with your topic&#8217;s key terms to reduce skips.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What does the Full Width button do?<\/p>\n      <p class=\"pth-faq-a\">Clicking \u26f6 Full Width hides the sidebar and expands the main activity area to 100% of the page width. This is useful on smaller laptops where the two-column layout compresses the grid. Click the button again to restore the sidebar with its How to Use guide, Stats panel, and AI Word Generator card.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Can I use the AI Assistant to fill all five activity types?<\/p>\n      <p class=\"pth-faq-a\">Yes. The AI Assistant tab generates content formatted specifically for each target: WORD:Clue pairs for Crossword, uppercase word lists for Word Search, ordered steps for Drag &amp; Sort, Term:Definition pairs for Match Pairs, and Term:Match pairs with optional emoji for Memory Match. Select the target tab first, enter your topic, click Generate, then Use in Tab \u2014 the content fills automatically.<\/p>\n    <\/div>\n\n  <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Interactive Learning Studio Create crossword puzzles, word searches, drag-sort activities and memory match games free with Interactive Learning Studio Pro \u2014 offline, no login required. \ud83d\udfe2 5 Activity Types in One Place Build crossword puzzles, word search grids, drag-sort challenges, match-the-pairs games, and flip-card memory matches \u2014 all from a single browser tab. No switching &#8230; <a title=\"Interactive Learning Studio Pro\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/interactive-learning-studio-pro\/\" aria-label=\"Read more about Interactive Learning Studio Pro\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":5889,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-5832","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/5832","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=5832"}],"version-history":[{"count":4,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/5832\/revisions"}],"predecessor-version":[{"id":7093,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/5832\/revisions\/7093"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/5889"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=5832"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}