{"id":743,"date":"2026-03-04T12:15:18","date_gmt":"2026-03-04T12:15:18","guid":{"rendered":"https:\/\/i-cte.org\/robot\/?p=743"},"modified":"2026-03-05T04:19:30","modified_gmt":"2026-03-05T04:19:30","slug":"prompting-for-educators","status":"publish","type":"post","link":"https:\/\/i-cte.org\/robot\/prompting-for-educators\/","title":{"rendered":"Prompting for Educators"},"content":{"rendered":"\n<!-- \u2705 ICTE Teacher Micro-Lesson \u2014 Prompting for Educators (FULL, WP-safe single block, Multi-speaker Google Voices)\n     Includes in Prompt Framework section:\n     (1) Reading text\n     (2) Comprehension MCQs with options + scoring\n     (3) Examples (3 templates + bad\u2192better rewrite)\n-->\n<div id=\"icte-prompting\">\n\n  <!-- \u2705 TOP MENU -->\n  <nav class=\"icte-menu\" aria-label=\"Prompting lesson navigation\">\n    <a href=\"#\" class=\"is-current\" data-view=\"conversation\">Conversation<\/a>\n    <a href=\"#\" data-view=\"framework\">Prompt Framework<\/a>\n    <a href=\"#\" data-view=\"templates\">Prompt Templates<\/a>\n    <a href=\"#\" data-view=\"rubrics\">Rubrics &#038; Feedback<\/a>\n    <a href=\"#\" data-view=\"cefr\">CEFR Adapting<\/a>\n    <a href=\"#\" data-view=\"listening\">Listening<\/a>\n    <a href=\"#\" data-view=\"tasks\">Practice Lab<\/a>\n    <a href=\"#\" data-view=\"progress\">Progress<\/a>\n  <\/nav>\n\n  <section class=\"icte-shell\" aria-label=\"ICTE Prompting for Educators lesson\">\n\n    <!-- \u2705 Header -->\n    <header class=\"icte-hero\">\n      <div class=\"icte-hero__text\">\n        <h2>Prompting for Educators<\/h2>\n        <p class=\"muted\">\n          Learn to write <b>clear prompts<\/b> with <b>constraints<\/b>, <b>rubrics<\/b>, and <b>CEFR adaptation<\/b>.\n          Includes a <b>two-speaker Google Voices<\/b> listening dialogue.\n        <\/p>\n      <\/div>\n\n      <div class=\"icte-hero__controls\">\n        <div class=\"icte-pill\">\n          <span class=\"dot\" id=\"icteMicDot\" aria-hidden=\"true\"><\/span>\n          <span id=\"icteMicStatus\">Mic: Off<\/span>\n        <\/div>\n\n        <div class=\"icte-row\">\n          <button class=\"btn\" id=\"icteStartVoice\" type=\"button\">Start Voice<\/button>\n          <button class=\"btn ghost\" id=\"icteStopVoice\" type=\"button\">Stop<\/button>\n        <\/div>\n\n        <!-- \u2705 Multi-speaker Google Voices -->\n        <div class=\"grid2\" style=\"margin-top:10px;\">\n          <label class=\"icte-label\">\n            Speaker A (Google)\n            <select id=\"voiceA\" class=\"icte-select\" aria-label=\"Speaker A voice\"><\/select>\n          <\/label>\n\n          <label class=\"icte-label\">\n            Speaker B (Google)\n            <select id=\"voiceB\" class=\"icte-select\" aria-label=\"Speaker B voice\"><\/select>\n          <\/label>\n        <\/div>\n\n        <div class=\"icte-small muted\">\n          Tip: For best results, use Chrome\/Edge. \u201cGoogle \u2026\u201d voices usually appear there.\n        <\/div>\n      <\/div>\n    <\/header>\n\n    <!-- \u2705 Views -->\n    <main class=\"icte-main\">\n\n      <!-- ===================== -->\n      <!-- \u2705 1) CONVERSATION -->\n      <!-- ===================== -->\n      <section class=\"view is-active\" data-view=\"conversation\" aria-label=\"Conversation practice\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>1) Conversation (Prompt Coaching)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"conv-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"convReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Build a strong prompt step-by-step. Focus on:\n            <b>role<\/b> + <b>task<\/b> + <b>constraints<\/b> + <b>output format<\/b> + <b>quality checks<\/b>.\n          <\/p>\n\n          <div class=\"chat\" id=\"convChat\" aria-live=\"polite\" aria-label=\"Conversation chat log\"><\/div>\n\n          <div class=\"chatbar\">\n            <input id=\"convText\" class=\"input\" type=\"text\" placeholder=\"Type your answer (optional)...\" autocomplete=\"off\" \/>\n            <button class=\"btn\" id=\"convSend\" type=\"button\">Send<\/button>\n            <button class=\"btn ghost\" id=\"convHear\" type=\"button\">\ud83d\udd0a Read last question<\/button>\n          <\/div>\n\n          <div class=\"muted icte-small\">\n            Goal: produce a reusable prompt for (1) lesson plan, (2) question bank, or (3) feedback.\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 2) PROMPT FRAMEWORK -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"framework\" aria-label=\"Prompt framework\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>2) Prompt Framework (CLEAR)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"framework-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"frameworkReadBtn\">\ud83d\udd0a Read the text<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"frameworkCheck\">Check answers<\/button>\n            <\/div>\n          <\/div>\n\n          <div class=\"note\">\n            Use <b>CLEAR<\/b>: <b>C<\/b>ontext, <b>L<\/b>earner level, <b>E<\/b>xact task, <b>A<\/b>cceptable constraints, <b>R<\/b>esponse format.\n          <\/div>\n\n          <!-- \u2705 (1) Reading text -->\n          <article class=\"reading\" id=\"frameworkReading\" aria-label=\"Reading text about CLEAR prompting\">\n            <div class=\"reading-title\">Reading: Why clear prompts matter for teachers<\/div>\n\n            <div class=\"reading-p\">\n              <b>1<\/b> When teachers use AI tools, the quality of the output depends heavily on the prompt.\n              A vague prompt like <i>\u201cMake a good lesson\u201d<\/i> often produces a generic answer.\n              A strong prompt works like good classroom instructions: it tells the tool exactly what to do and what to avoid.\n            <\/div>\n\n            <div class=\"reading-p\">\n              <b>2<\/b> A simple framework is <b>CLEAR<\/b>.\n              <b>C<\/b> means <b>Context<\/b>: the course, topic, lesson time, and classroom situation.\n              <b>L<\/b> means <b>Learner level<\/b>: the CEFR level and learner needs.\n              If the tool doesn\u2019t know the level, it may produce language that is too hard or too easy.\n            <\/div>\n\n            <div class=\"reading-p\">\n              <b>3<\/b> <b>E<\/b> is <b>Exact task<\/b>: what you want the tool to create, such as a lesson plan, question bank, or feedback.\n              You should specify the number of items and the activity type (role-play, MCQ, discussion, etc.).\n              This reduces randomness and saves teacher time.\n            <\/div>\n\n            <div class=\"reading-p\">\n              <b>4<\/b> <b>A<\/b> is <b>Acceptable constraints<\/b>.\n              Constraints are \u201cmust\u201d and \u201cmust not\u201d rules.\n              For example: <i>must include pair work<\/i>, <i>must include 8 target phrases<\/i>, <i>must not use sensitive topics<\/i>, and\n              <i>must not invent citations<\/i>.\n              Good constraints make outputs safer and more consistent.\n            <\/div>\n\n            <div class=\"reading-p\">\n              <b>5<\/b> <b>R<\/b> is <b>Response format<\/b>.\n              A clear format makes the output usable.\n              Teachers often request a table, an answer key, a rubric, and short rationales.\n              Finally, add a quality check: <i>\u201cIf anything is missing, ask me questions before you write.\u201d<\/i>\n            <\/div>\n          <\/article>\n\n          <!-- \u2705 (2) Comprehension MCQs -->\n          <h4 class=\"h4\" style=\"margin-top:12px;\">Comprehension check (choose the best answer)<\/h4>\n          <div id=\"frameworkQuiz\" class=\"stack\"><\/div>\n          <div class=\"feedback\" id=\"frameworkFb\" aria-live=\"polite\"><\/div>\n\n          <!-- \u2705 (3) Examples -->\n          <h4 class=\"h4\" style=\"margin-top:14px;\">Examples (copy &#038; adapt)<\/h4>\n\n          <div class=\"grid2\">\n            <div class=\"qitem\">\n              <div class=\"qtext\">Example 1 \u2014 Lesson plan prompt (B1 speaking)<\/div>\n              <pre class=\"pre\" id=\"ex1\"><\/pre>\n            <\/div>\n\n            <div class=\"qitem\">\n              <div class=\"qtext\">Example 2 \u2014 Question bank prompt (Reading MCQ)<\/div>\n              <pre class=\"pre\" id=\"ex2\"><\/pre>\n            <\/div>\n          <\/div>\n\n          <div class=\"qitem\" style=\"margin-top:12px;\">\n            <div class=\"qtext\">Example 3 \u2014 Feedback prompt (rubric-aligned)<\/div>\n            <pre class=\"pre\" id=\"ex3\"><\/pre>\n          <\/div>\n\n          <div class=\"qitem\" style=\"margin-top:12px;\">\n            <div class=\"qtext\">Bad prompt \u2192 Better prompt (CLEAR rewrite)<\/div>\n            <pre class=\"pre\" id=\"badBetter\"><\/pre>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 3) TEMPLATES -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"templates\" aria-label=\"Prompt templates\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>3) Prompt Templates (Copy &#038; Use)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"templates-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"tplSpeakA\">\ud83d\udd0a Read Template A<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"tplSpeakB\">\ud83d\udd0a Read Template B<\/button>\n            <\/div>\n          <\/div>\n\n          <div class=\"grid2\">\n            <div class=\"qitem\">\n              <div class=\"qtext\">Template A \u2014 Lesson Plan Prompt<\/div>\n              <pre class=\"pre\" id=\"tplA\"><\/pre>\n            <\/div>\n            <div class=\"qitem\">\n              <div class=\"qtext\">Template B \u2014 Question Bank Prompt<\/div>\n              <pre class=\"pre\" id=\"tplB\"><\/pre>\n            <\/div>\n          <\/div>\n\n          <div class=\"qitem\" style=\"margin-top:12px;\">\n            <div class=\"qtext\">Template C \u2014 Feedback Prompt (Rubric-aligned)<\/div>\n            <pre class=\"pre\" id=\"tplC\"><\/pre>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 4) RUBRICS & FEEDBACK -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"rubrics\" aria-label=\"Rubrics and feedback\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>4) Rubrics &#038; Feedback (Constraints that improve quality)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"rubrics-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"rubricCheck\">Score<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Choose the best constraint blocks to add to a prompt when you want <b>consistent grading<\/b> or <b>high-quality feedback<\/b>.\n          <\/p>\n\n          <div id=\"rubricSet\" class=\"stack\"><\/div>\n          <div class=\"feedback\" id=\"rubricFb\" aria-live=\"polite\"><\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 5) CEFR ADAPTING -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"cefr\" aria-label=\"CEFR adapting\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>5) Adapting Tasks to CEFR (A2 \u2192 B1 \u2192 B2)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"cefr-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"cefrCheck\">Check<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Select the best version for each level. Focus on <b>grammar load<\/b>, <b>vocabulary<\/b>, and <b>task complexity<\/b>.\n          <\/p>\n\n          <div id=\"cefrSet\" class=\"stack\"><\/div>\n          <div class=\"feedback\" id=\"cefrFb\" aria-live=\"polite\"><\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 6) LISTENING (2 voices) -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"listening\" aria-label=\"Two-speaker listening\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>6) Listening (Two Google Voices) \u2014 \u201cWhy prompts fail\u201d<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"list-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini\" type=\"button\" id=\"listenPlay\">\u25b6\ufe0f Play dialogue<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"listenStop\">\u23f9 Stop<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Listen to two teachers. Identify what makes prompts succeed: constraints, format, and checking.\n          <\/p>\n\n          <div id=\"listenQ\" class=\"stack\"><\/div>\n          <button class=\"btn\" id=\"listenCheck\" type=\"button\">Check<\/button>\n          <div class=\"feedback\" id=\"listenFb\" aria-live=\"polite\"><\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 7) PRACTICE LAB -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"tasks\" aria-label=\"Practice lab\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>7) Practice Lab (Build your own prompt)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"tasks-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"labCheck\">Check<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"labCopy\">Copy final prompt<\/button>\n            <\/div>\n          <\/div>\n\n          <div class=\"note\">\n            Fill each field. The app will generate a clean final prompt at the bottom.\n          <\/div>\n\n          <div class=\"grid2\">\n            <div class=\"qitem\">\n              <div class=\"qtext\">A) Context (course, topic, time, class size)<\/div>\n              <textarea class=\"textarea\" id=\"labContext\" rows=\"3\" placeholder=\"Example: EFL Speaking B1, 45 minutes, 30 students, topic: city living.\"><\/textarea>\n            <\/div>\n\n            <div class=\"qitem\">\n              <div class=\"qtext\">B) Learner level (CEFR) + needs<\/div>\n              <textarea class=\"textarea\" id=\"labLearners\" rows=\"3\" placeholder=\"Example: B1, mixed ability, needs more speaking fluency and vocabulary scaffolds.\"><\/textarea>\n            <\/div>\n          <\/div>\n\n          <div class=\"grid2\" style=\"margin-top:10px;\">\n            <div class=\"qitem\">\n              <div class=\"qtext\">C) Exact task<\/div>\n              <textarea class=\"textarea\" id=\"labTask\" rows=\"3\" placeholder=\"Example: create a communicative speaking lesson with warm-up, guided practice, and role-play.\"><\/textarea>\n            <\/div>\n\n            <div class=\"qitem\">\n              <div class=\"qtext\">D) Constraints (must \/ must not)<\/div>\n              <textarea class=\"textarea\" id=\"labConstraints\" rows=\"3\" placeholder=\"Example: must include 8 target phrases; must avoid sensitive topics; must include pair work; output in a table.\"><\/textarea>\n            <\/div>\n          <\/div>\n\n          <div class=\"qitem\" style=\"margin-top:10px;\">\n            <div class=\"qtext\">E) Output format (structure)<\/div>\n            <textarea class=\"textarea\" id=\"labFormat\" rows=\"2\" placeholder=\"Example: Output as a table: Stage | Time | Procedure | Teacher role | Student role | Materials.\"><\/textarea>\n          <\/div>\n\n          <div class=\"qitem\" style=\"margin-top:10px;\">\n            <div class=\"qtext\">F) Quality checks<\/div>\n            <textarea class=\"textarea\" id=\"labChecks\" rows=\"2\" placeholder=\"Example: include CEFR-appropriate language; include answer key; no fabricated references; include differentiation tips.\"><\/textarea>\n          <\/div>\n\n          <div class=\"qitem\" style=\"margin-top:12px;\">\n            <div class=\"qtext\">Generated final prompt<\/div>\n            <pre class=\"pre\" id=\"finalPrompt\"><\/pre>\n          <\/div>\n\n          <div class=\"feedback\" id=\"labFb\" aria-live=\"polite\"><\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 8) PROGRESS -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"progress\" aria-label=\"Progress tracking\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>Progress<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini ghost\" type=\"button\" id=\"progressReset\">Clear progress<\/button>\n            <\/div>\n          <\/div>\n\n          <div class=\"progress-grid\">\n            <div class=\"pbox\">\n              <div class=\"pnum\" id=\"pDone\">0<\/div>\n              <div class=\"muted\">Activities completed<\/div>\n            <\/div>\n            <div class=\"pbox\">\n              <div class=\"pnum\" id=\"pScore\">0%<\/div>\n              <div class=\"muted\">Average score<\/div>\n            <\/div>\n            <div class=\"pbox\">\n              <div class=\"pnum\" id=\"pQuality\">0<\/div>\n              <div class=\"muted\">Quality elements used<\/div>\n            <\/div>\n          <\/div>\n\n          <div class=\"note\">\n            Saved in your browser (local storage).\n          <\/div>\n\n          <h4 class=\"h4\">Quality Elements Bank<\/h4>\n          <div class=\"bank\" id=\"qualityBank\"><\/div>\n        <\/div>\n      <\/section>\n\n    <\/main>\n  <\/section>\n\n  <style>\n    \/* ===== WP-SAFE STYLES (scoped) ===== *\/\n    #icte-prompting *{ box-sizing:border-box; }\n    #icte-prompting{\n      --green:#28a745;\n      --dark:#132018;\n      --card:#ffffff;\n      --muted:#6b7280;\n      --line:#e5e7eb;\n      --shadow:0 8px 24px rgba(17,24,39,.08);\n      --radius:16px;\n      font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;\n      color:#111827;\n    }\n    #icte-prompting .icte-menu{\n      width:100%;\n      background:var(--green);\n      padding:10px 12px;\n      text-align:center;\n      overflow-x:auto;\n      white-space:nowrap;\n      position:sticky;\n      top:0;\n      z-index:999;\n      box-shadow:0 2px 10px rgba(0,0,0,.12);\n      border-radius:12px;\n      margin-bottom:12px;\n    }\n    #icte-prompting .icte-menu a{\n      display:inline-block;\n      color:#fff;\n      text-decoration:none;\n      font-weight:900;\n      padding:8px 10px;\n      border-radius:999px;\n      margin:0 3px;\n      opacity:.92;\n      transition:.15s;\n    }\n    #icte-prompting .icte-menu a:hover{ opacity:1; background:rgba(255,255,255,.14); }\n    #icte-prompting .icte-menu a.is-current{ background:#fff; color:var(--dark); opacity:1; }\n\n    #icte-prompting .icte-shell{ max-width:1100px; margin:0 auto; }\n    #icte-prompting .icte-hero{\n      display:grid;\n      grid-template-columns: 1.15fr .85fr;\n      gap:14px;\n      background:linear-gradient(135deg,#e9fff0, #ffffff);\n      border:1px solid var(--line);\n      border-radius:var(--radius);\n      padding:16px;\n      box-shadow:var(--shadow);\n      margin-bottom:14px;\n    }\n    @media (max-width: 920px){ #icte-prompting .icte-hero{ grid-template-columns:1fr; } }\n    #icte-prompting h2{ margin:0 0 6px 0; font-size:22px; }\n    #icte-prompting .muted{ color:var(--muted); }\n\n    #icte-prompting .icte-hero__controls{\n      border-left:1px dashed var(--line);\n      padding-left:14px;\n    }\n    @media (max-width: 920px){\n      #icte-prompting .icte-hero__controls{ border-left:none; padding-left:0; border-top:1px dashed var(--line); padding-top:12px; }\n    }\n\n    #icte-prompting .icte-row{ display:flex; gap:8px; flex-wrap:wrap; }\n    #icte-prompting .icte-label{ display:block; font-size:12px; font-weight:900; margin-top:8px; }\n    #icte-prompting .icte-select{\n      width:100%;\n      padding:10px 10px;\n      border:1px solid var(--line);\n      border-radius:12px;\n      background:#fff;\n      outline:none;\n      margin-top:6px;\n    }\n\n    #icte-prompting .icte-pill{\n      display:flex; align-items:center; gap:8px;\n      padding:10px 12px;\n      border:1px solid var(--line);\n      border-radius:999px;\n      background:#fff;\n      margin-bottom:10px;\n      font-weight:900;\n    }\n    #icte-prompting .dot{\n      width:10px; height:10px; border-radius:50%;\n      background:#9ca3af;\n      box-shadow:0 0 0 4px rgba(156,163,175,.18);\n    }\n    #icte-prompting .dot.on{\n      background:#22c55e;\n      box-shadow:0 0 0 4px rgba(34,197,94,.18);\n    }\n\n    #icte-prompting .btn{\n      border:none;\n      padding:10px 12px;\n      border-radius:12px;\n      background:var(--green);\n      color:#fff;\n      font-weight:900;\n      cursor:pointer;\n      transition:.15s;\n    }\n    #icte-prompting .btn:hover{ filter:brightness(.95); transform:translateY(-1px); }\n    #icte-prompting .btn:active{ transform:translateY(0); }\n    #icte-prompting .btn.ghost{\n      background:#fff;\n      color:#111827;\n      border:1px solid var(--line);\n    }\n    #icte-prompting .btn.mini{ padding:8px 10px; border-radius:10px; font-size:13px; }\n    #icte-prompting .icte-small{ font-size:12px; }\n\n    #icte-prompting .card{\n      background:var(--card);\n      border:1px solid var(--line);\n      border-radius:var(--radius);\n      padding:14px;\n      box-shadow:var(--shadow);\n      margin-bottom:14px;\n    }\n    #icte-prompting .card-h{\n      display:flex; gap:10px; align-items:flex-start; justify-content:space-between;\n      border-bottom:1px solid var(--line);\n      padding-bottom:10px;\n      margin-bottom:10px;\n    }\n    #icte-prompting .card-h h3{ margin:0; font-size:18px; }\n    #icte-prompting .card-actions{ display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end; }\n\n    #icte-prompting .view{ display:none; }\n    #icte-prompting .view.is-active{ display:block; }\n\n    #icte-prompting .chat{\n      background:#0b1220;\n      color:#e5e7eb;\n      border-radius:14px;\n      padding:12px;\n      min-height:220px;\n      max-height:420px;\n      overflow:auto;\n      border:1px solid rgba(255,255,255,.08);\n    }\n    #icte-prompting .msg{ margin:10px 0; display:flex; gap:10px; align-items:flex-start; }\n    #icte-prompting .who{\n      min-width:92px;\n      font-weight:900;\n      font-size:12px;\n      color:#93c5fd;\n      text-transform:uppercase;\n      letter-spacing:.06em;\n    }\n    #icte-prompting .bubble{\n      flex:1;\n      background:rgba(255,255,255,.06);\n      padding:10px 10px;\n      border-radius:12px;\n      line-height:1.45;\n      border:1px solid rgba(255,255,255,.06);\n      white-space:pre-line;\n    }\n    #icte-prompting .msg.user .who{ color:#86efac; }\n    #icte-prompting .msg.user .bubble{ background:rgba(34,197,94,.10); border-color:rgba(34,197,94,.18); }\n\n    #icte-prompting .chatbar{\n      margin-top:10px;\n      display:flex;\n      gap:8px;\n      align-items:center;\n    }\n    #icte-prompting .input{\n      flex:1;\n      padding:12px 12px;\n      border:1px solid var(--line);\n      border-radius:12px;\n      outline:none;\n    }\n    #icte-prompting .textarea{\n      width:100%;\n      padding:12px;\n      border:1px solid var(--line);\n      border-radius:12px;\n      outline:none;\n      resize:vertical;\n    }\n\n    #icte-prompting .grid2{\n      display:grid;\n      grid-template-columns:1fr 1fr;\n      gap:14px;\n      margin-top:10px;\n    }\n    @media (max-width: 920px){ #icte-prompting .grid2{ grid-template-columns:1fr; } }\n\n    #icte-prompting .stack{ display:flex; flex-direction:column; gap:10px; }\n    #icte-prompting .h4{ margin:0 0 6px 0; font-size:15px; }\n    #icte-prompting .qitem{\n      padding:10px;\n      border:1px solid var(--line);\n      border-radius:14px;\n      background:#fafafa;\n    }\n    #icte-prompting .qtext{ font-weight:900; margin-bottom:8px; }\n    #icte-prompting .row{ display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }\n\n    #icte-prompting .feedback{\n      margin-top:10px;\n      padding:10px 12px;\n      border-radius:14px;\n      border:1px solid var(--line);\n      background:#f9fafb;\n      font-weight:800;\n      display:none;\n      white-space:pre-line;\n    }\n    #icte-prompting .feedback.ok{ display:block; border-color:rgba(34,197,94,.35); background:#ecfdf5; }\n    #icte-prompting .feedback.bad{ display:block; border-color:rgba(239,68,68,.35); background:#fef2f2; }\n\n    #icte-prompting .note{\n      background:#eff6ff;\n      border:1px solid rgba(59,130,246,.22);\n      padding:10px 12px;\n      border-radius:14px;\n      margin:10px 0;\n    }\n\n    #icte-prompting .reading{\n      border:1px solid var(--line);\n      border-radius:14px;\n      padding:12px;\n      background:#fff;\n      margin-top:10px;\n    }\n    #icte-prompting .reading-title{ font-weight:900; margin-bottom:8px; }\n    #icte-prompting .reading-p{ padding:8px 0; border-top:1px dashed var(--line); }\n    #icte-prompting .reading-p:first-of-type{ border-top:none; }\n\n    #icte-prompting .progress-grid{\n      display:grid;\n      grid-template-columns:repeat(3,1fr);\n      gap:12px;\n      margin-top:10px;\n      margin-bottom:10px;\n    }\n    @media (max-width: 920px){ #icte-prompting .progress-grid{ grid-template-columns:1fr; } }\n    #icte-prompting .pbox{\n      border:1px solid var(--line);\n      border-radius:16px;\n      background:#fff;\n      padding:12px;\n      text-align:center;\n      box-shadow:var(--shadow);\n    }\n    #icte-prompting .pnum{ font-size:28px; font-weight:1000; }\n\n    #icte-prompting .bank{\n      border:1px solid var(--line);\n      border-radius:14px;\n      padding:12px;\n      background:#fff;\n      display:flex;\n      flex-wrap:wrap;\n      gap:8px;\n    }\n    #icte-prompting .tag{\n      border:1px solid var(--line);\n      background:#f9fafb;\n      padding:6px 10px;\n      border-radius:999px;\n      font-weight:900;\n      font-size:13px;\n    }\n\n    #icte-prompting .pre{\n      white-space:pre-wrap;\n      background:#0b1220;\n      color:#e5e7eb;\n      border-radius:12px;\n      padding:12px;\n      border:1px solid rgba(255,255,255,.08);\n      overflow:auto;\n      font-size:13px;\n      line-height:1.45;\n    }\n  <\/style>\n\n  <script>\n    (function(){\n      const root = document.getElementById('icte-prompting');\n      if(!root) return;\n\n      \/* =========================\n         Helpers\n      ========================= *\/\n      const qs = (sel, el=root) => el.querySelector(sel);\n      const qsa = (sel, el=root) => Array.from(el.querySelectorAll(sel));\n      const clamp = (n,min,max)=>Math.max(min,Math.min(max,n));\n      const norm = (s)=> (s||\"\").toString().trim();\n      const lower = (s)=> norm(s).toLowerCase();\n      const esc = (s)=> (s||\"\").replace(\/[&<>\"']\/g, m=>({ \"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#039;\" }[m]));\n      const shuffle = (arr)=> arr.map(v=>({v, r:Math.random()})).sort((a,b)=>a.r-b.r).map(o=>o.v);\n\n      \/* =========================\n         Navigation\n      ========================= *\/\n      const navLinks = qsa('.icte-menu a');\n      const views = qsa('.view');\n      function showView(name){\n        views.forEach(v=> v.classList.toggle('is-active', v.getAttribute('data-view')===name));\n        navLinks.forEach(a=> a.classList.toggle('is-current', a.getAttribute('data-view')===name));\n        window.scrollTo({top: root.offsetTop - 10, behavior:'smooth'});\n      }\n      navLinks.forEach(a=>{\n        a.addEventListener('click', (e)=>{\n          e.preventDefault();\n          const v = a.getAttribute('data-view');\n          if(v) showView(v);\n        });\n      });\n\n      \/* =========================\n         Multi-speaker Google Voices (SpeechSynthesis)\n      ========================= *\/\n      const voiceASelect = qs('#voiceA');\n      const voiceBSelect = qs('#voiceB');\n\n      let allVoices = [];\n      let googleVoicesEN = [];\n      let voiceA = null;\n      let voiceB = null;\n\n      function isEnglish(v){\n        const l = (v.lang||\"\").toLowerCase();\n        return l.startsWith(\"en\");\n      }\n      function isGoogle(v){\n        const n = (v.name||\"\").toLowerCase();\n        return n.includes(\"google\");\n      }\n\n      function loadVoices(){\n        if(!window.speechSynthesis) return;\n        allVoices = speechSynthesis.getVoices() || [];\n        const google = allVoices.filter(v => isEnglish(v) && isGoogle(v));\n        const english = allVoices.filter(v => isEnglish(v));\n        googleVoicesEN = google.length ? google : english;\n\n        const buildSelect = (sel, list) => {\n          sel.innerHTML = \"\";\n          list.forEach((v,i)=>{\n            const opt = document.createElement('option');\n            opt.value = String(i);\n            opt.textContent = `${v.name} (${v.lang})`;\n            sel.appendChild(opt);\n          });\n        };\n\n        buildSelect(voiceASelect, googleVoicesEN);\n        buildSelect(voiceBSelect, googleVoicesEN);\n\n        voiceA = googleVoicesEN[0] || null;\n        voiceB = googleVoicesEN[1] || googleVoicesEN[0] || null;\n\n        voiceASelect.value = \"0\";\n        voiceBSelect.value = String(Math.max(0, googleVoicesEN.indexOf(voiceB)));\n\n        voiceASelect.onchange = ()=>{\n          const idx = parseInt(voiceASelect.value,10);\n          voiceA = googleVoicesEN[idx] || voiceA;\n        };\n        voiceBSelect.onchange = ()=>{\n          const idx = parseInt(voiceBSelect.value,10);\n          voiceB = googleVoicesEN[idx] || voiceB;\n        };\n      }\n\n      if(window.speechSynthesis){\n        loadVoices();\n        speechSynthesis.onvoiceschanged = loadVoices;\n      }\n\n      function stopSpeak(){ if(window.speechSynthesis) speechSynthesis.cancel(); }\n\n      function speakAs(role, text, opts){\n        const t = norm(text);\n        if(!t || !window.speechSynthesis) return Promise.resolve();\n        const o = opts || {};\n        const u = new SpeechSynthesisUtterance(t);\n        if(role === \"A\" && voiceA) u.voice = voiceA;\n        if(role === \"B\" && voiceB) u.voice = voiceB;\n        u.rate = o.rate ?? 1.02;\n        u.pitch = o.pitch ?? 1.0;\n        u.volume = o.volume ?? 1.0;\n        return new Promise(resolve=>{\n          u.onend = resolve;\n          u.onerror = resolve;\n          speechSynthesis.speak(u);\n        });\n      }\n\n      async function speakDialogue(lines){\n        stopSpeak();\n        for(const line of lines){\n          await speakAs(line.role, line.text);\n        }\n      }\n\n      \/* =========================\n         Mic Speech Recognition (ASR)\n      ========================= *\/\n      const micDot = qs('#icteMicDot');\n      const micStatus = qs('#icteMicStatus');\n      const btnStartVoice = qs('#icteStartVoice');\n      const btnStopVoice = qs('#icteStopVoice');\n\n      let recognition = null;\n      let listening = false;\n      let lastPromptSpoken = \"\";\n\n      function setMicUI(on){\n        listening = on;\n        micDot.classList.toggle('on', on);\n        micStatus.textContent = on ? \"Mic: Listening\u2026\" : \"Mic: Off\";\n      }\n\n      function initRecognition(){\n        const SR = window.SpeechRecognition || window.webkitSpeechRecognition;\n        if(!SR) return null;\n        const r = new SR();\n        r.lang = 'en-US';\n        r.continuous = true;\n        r.interimResults = false;\n        r.maxAlternatives = 1;\n        return r;\n      }\n\n      function startListening(){\n        if(listening) return;\n        recognition = recognition || initRecognition();\n        if(!recognition){\n          alert(\"Speech Recognition is not available in this browser. Use Chrome\/Edge, or type your answers.\");\n          return;\n        }\n        recognition.onresult = (e)=>{\n          const res = e.results[e.results.length - 1];\n          const transcript = res && res[0] ? res[0].transcript : \"\";\n          handleVoiceTranscript(transcript);\n        };\n        recognition.onerror = ()=> setMicUI(false);\n        recognition.onend = ()=>{ if(listening){ try{ recognition.start(); }catch(_){ } } };\n        setMicUI(true);\n        try{ recognition.start(); }catch(_){ }\n      }\n\n      function stopListening(){\n        setMicUI(false);\n        try{ recognition && recognition.stop(); }catch(_){ }\n      }\n      btnStartVoice.addEventListener('click', startListening);\n      btnStopVoice.addEventListener('click', stopListening);\n\n      \/* =========================\n         Progress\n      ========================= *\/\n      const LS_KEY = \"icte_prompting_progress_v1\";\n      const progress = JSON.parse(localStorage.getItem(LS_KEY) || \"{}\");\n      function saveProgress(){ localStorage.setItem(LS_KEY, JSON.stringify(progress)); renderProgress(); }\n      function markDone(key, scorePct){\n        progress[key] = { done:true, score: clamp(scorePct,0,100), ts: Date.now() };\n        saveProgress();\n      }\n      function resetProgress(){ localStorage.removeItem(LS_KEY); location.reload(); }\n      qs('#progressReset').addEventListener('click', resetProgress);\n\n      \/* =========================\n         Quality elements bank\n      ========================= *\/\n      const quality = [\n        {k:\"role\", label:\"Role \/ audience\"},\n        {k:\"level\", label:\"Learner level (CEFR)\"},\n        {k:\"constraints\", label:\"Constraints (must\/must not)\"},\n        {k:\"format\", label:\"Output format\"},\n        {k:\"rubric\", label:\"Rubric criteria\"},\n        {k:\"examples\", label:\"Examples \/ model answer\"},\n        {k:\"safety\", label:\"Safety & bias checks\"},\n        {k:\"verification\", label:\"No fabricated sources\"}\n      ];\n      qs('#qualityBank').innerHTML = quality.map(x=>`<span class=\"tag\">${esc(x.label)}<\/span>`).join(\"\");\n\n      function addQuality(k){\n        progress._q = progress._q || {};\n        progress._q[k] = true;\n        saveProgress();\n      }\n\n      function renderProgress(){\n        const items = Object.values(progress).filter(p=>p && p.done);\n        const done = items.length;\n        const avg = done ? Math.round(items.reduce((s,p)=>s+(p.score||0),0)\/done) : 0;\n        qs('#pDone').textContent = String(done);\n        qs('#pScore').textContent = String(avg) + \"%\";\n        qs('#pQuality').textContent = String(Object.keys(progress._q || {}).length);\n      }\n\n      \/* =========================\n         TTS Instruction map\n      ========================= *\/\n      const SAY = {\n        \"conv-instr\": \"Conversation. Build a strong prompt step by step: context, learner level, exact task, constraints, output format, and quality checks.\",\n        \"framework-instr\": \"Prompt Framework. Read the text, then answer the comprehension questions. Study the examples to copy and adapt.\",\n        \"templates-instr\": \"Templates. Copy the prompts and replace the brackets with your course details.\",\n        \"rubrics-instr\": \"Rubrics. Choose constraint blocks that force consistent scoring and actionable feedback.\",\n        \"cefr-instr\": \"CEFR. Choose the best version for A2, B1, and B2.\",\n        \"list-instr\": \"Listening. Two teachers talk about why prompts fail. Answer the questions.\",\n        \"tasks-instr\": \"Practice lab. Fill the fields. The app will generate a clean final prompt at the bottom.\"\n      };\n      qsa('[data-say]').forEach(btn=>{\n        btn.addEventListener('click', ()=> speakAs(\"A\", SAY[btn.getAttribute('data-say')] || \"\"));\n      });\n\n      \/* =========================\n         1) Conversation coach\n      ========================= *\/\n      const convChat = qs('#convChat');\n      const convText = qs('#convText');\n      const convSend = qs('#convSend');\n      const convHear = qs('#convHear');\n      const convReset = qs('#convReset');\n\n      let convStep = 0;\n      const convSteps = [\n        {\n          bot: \"Choose ONE output: (A) lesson plan, (B) question bank, or (C) feedback. Type A, B, or C.\",\n          check: (a)=> \/^[abc]$\/i.test(a),\n          tips: \"Type A, B, or C.\"\n        },\n        {\n          bot: \"Add CONTEXT: course + topic + time. (Example: B1 speaking, topic: city living, 45 minutes.)\",\n          check: (a)=> a.length >= 15,\n          tips: \"Include course, topic, and time.\"\n        },\n        {\n          bot: \"Add LEARNER LEVEL and needs (CEFR + 1 skill need).\",\n          check: (a)=> \/(A1|A2|B1|B2|C1|C2)\/i.test(a) && a.length >= 12,\n          tips: \"Include CEFR and one need (e.g., speaking fluency, vocabulary).\"\n        },\n        {\n          bot: \"Add CONSTRAINTS: 2 MUST and 1 MUST NOT.\",\n          check: (a)=> \/(must).*(must).*(must not|mustn't)\/i.test(a),\n          tips: \"Write: must\u2026, must\u2026, must not\u2026\"\n        },\n        {\n          bot: \"Add OUTPUT FORMAT: table or bullet structure. (Example: Stage | Time | Procedure | Materials.)\",\n          check: (a)=> \/(table|stage|time|procedure|bullet|steps|format)\/i.test(a),\n          tips: \"Specify the structure clearly.\"\n        },\n        {\n          bot: \"Add QUALITY CHECKS: CEFR fit + answer key OR rubric + no fabricated sources.\",\n          check: (a)=> \/(CEFR|level)\/i.test(a) && \/(answer key|rubric)\/i.test(a) && \/(no fabricated|verify|sources)\/i.test(a),\n          tips: \"Include CEFR fit, answer key or rubric, and source verification.\"\n        }\n      ];\n\n      function addMsg(who, text){\n        const div = document.createElement('div');\n        div.className = 'msg ' + (who==='You' ? 'user' : 'bot');\n        div.innerHTML = `<div class=\"who\">${esc(who)}<\/div><div class=\"bubble\">${esc(text)}<\/div>`;\n        convChat.appendChild(div);\n        convChat.scrollTop = convChat.scrollHeight;\n      }\n\n      async function botAsk(){\n        const step = convSteps[convStep];\n        if(!step){\n          addMsg(\"Coach\",\"Great. You built a strong prompt with CLEAR + constraints + checks.\");\n          addQuality(\"role\"); addQuality(\"level\"); addQuality(\"constraints\"); addQuality(\"format\"); addQuality(\"verification\");\n          markDone(\"conversation\", 100);\n          await speakAs(\"A\",\"Great. You built a strong prompt with clear context, constraints, and checks.\");\n          return;\n        }\n        addMsg(\"Coach\", step.bot);\n        lastPromptSpoken = step.bot;\n        await speakAs(\"A\", step.bot);\n      }\n\n      function scoreAnswer(a){\n        const step = convSteps[convStep];\n        if(!step) return {ok:true, msg:\"\"};\n        const ok = step.check(norm(a));\n        const msg = ok ? \"\u2705 Good. Keep going.\" : \"\u26a0\ufe0f Try again. \" + step.tips;\n        return {ok, msg};\n      }\n\n      async function handleConversationInput(text){\n        const a = norm(text);\n        if(!a) return;\n        addMsg(\"You\", a);\n\n        if(\/(teacher|educator|assistant|role)\/i.test(a)) addQuality(\"role\");\n        if(\/A1|A2|B1|B2|C1|C2\/i.test(a)) addQuality(\"level\");\n        if(\/must not|mustn't\/i.test(a) || \/must\/i.test(a)) addQuality(\"constraints\");\n        if(\/table|stage|time|procedure|bullet|format\/i.test(a)) addQuality(\"format\");\n        if(\/rubric\/i.test(a)) addQuality(\"rubric\");\n        if(\/answer key|model answer\/i.test(a)) addQuality(\"examples\");\n        if(\/bias|safe|privacy\/i.test(a)) addQuality(\"safety\");\n        if(\/no fabricated|verify|sources|citation|doi\/i.test(a)) addQuality(\"verification\");\n\n        progress._text = (progress._text||\"\") + \" \" + a;\n        saveProgress();\n\n        const {ok, msg} = scoreAnswer(a);\n        addMsg(\"Coach\", msg);\n        await speakAs(\"A\", msg);\n\n        if(ok){ convStep++; setTimeout(()=> botAsk(), 350); }\n        else { setTimeout(()=> speakAs(\"A\",\"Please try again. \" + convSteps[convStep].bot), 350); }\n      }\n\n      convSend.addEventListener('click', ()=> { handleConversationInput(convText.value); convText.value=\"\"; });\n      convText.addEventListener('keydown', (e)=>{\n        if(e.key === \"Enter\"){ e.preventDefault(); handleConversationInput(convText.value); convText.value=\"\"; }\n      });\n      convHear.addEventListener('click', ()=> speakAs(\"A\", lastPromptSpoken || \"No question yet.\"));\n      convReset.addEventListener('click', ()=>{\n        convChat.innerHTML = \"\";\n        convStep = 0;\n        addMsg(\"Coach\",\"Ready. Let\u2019s build a prompt.\");\n        botAsk();\n      });\n\n      addMsg(\"Coach\",\"Ready. Let\u2019s build a prompt.\");\n      botAsk();\n\n      function activeViewName(){\n        const v = qs('.view.is-active');\n        return v ? v.getAttribute('data-view') : \"conversation\";\n      }\n      function handleVoiceTranscript(t){\n        const text = norm(t);\n        if(!text) return;\n        const v = activeViewName();\n        if(v === \"conversation\"){ handleConversationInput(text); return; }\n        if(v === \"tasks\"){\n          const fields = [qs('#labContext'), qs('#labLearners'), qs('#labTask'), qs('#labConstraints'), qs('#labFormat'), qs('#labChecks')].filter(Boolean);\n          const target = fields.find(f=> !norm(f.value)) || fields[0];\n          target.value = (target.value ? (target.value + \" \") : \"\") + text;\n          speakAs(\"A\",\"I heard: \" + text);\n          updateFinalPrompt();\n          return;\n        }\n        speakAs(\"A\",\"I heard: \" + text);\n      }\n\n      \/* =========================\n         Framework reading + quiz + examples\n      ========================= *\/\n      const frameworkReadBtn = qs('#frameworkReadBtn');\n      if(frameworkReadBtn){\n        frameworkReadBtn.addEventListener('click', ()=>{\n          const parts = qsa('#frameworkReading .reading-p').map(p=>p.textContent).join(\" \");\n          speakAs(\"A\",\"Reading. \" + parts);\n        });\n      }\n\n      const frameworkQuiz = qs('#frameworkQuiz');\n      const frameworkFb = qs('#frameworkFb');\n\n      const frameworkItems = [\n        { q:\"1) What is the main reason a vague prompt often fails?\",\n          ans:\"It produces generic output because the tool lacks clear instructions\",\n          opts:[\n            \"It produces generic output because the tool lacks clear instructions\",\n            \"It always creates perfect lessons automatically\",\n            \"It makes the AI faster and more accurate\",\n            \"It guarantees correct citations\"\n          ]\n        },\n        { q:\"2) In CLEAR, what does C stand for?\",\n          ans:\"Context (course, topic, time, classroom situation)\",\n          opts:[\n            \"Context (course, topic, time, classroom situation)\",\n            \"Correctness (fact checking)\",\n            \"Creativity (more imagination)\",\n            \"Copying (reuse the same prompt)\"\n          ]\n        },\n        { q:\"3) Why is L (Learner level) important?\",\n          ans:\"Without it, the language may be too hard or too easy\",\n          opts:[\n            \"Without it, the language may be too hard or too easy\",\n            \"It forces the AI to write only in British English\",\n            \"It prevents students from speaking in class\",\n            \"It removes the need for a task\"\n          ]\n        },\n        { q:\"4) Which option best represents E (Exact task)?\",\n          ans:\"Create 10 MCQs for B1 reading with an answer key and rationales\",\n          opts:[\n            \"Make something interesting\",\n            \"Create 10 MCQs for B1 reading with an answer key and rationales\",\n            \"Write a long story about anything\",\n            \"Give me ideas, no structure needed\"\n          ]\n        },\n        { q:\"5) What are constraints (A) mainly used for?\",\n          ans:\"To set must\/must not rules so output is safer and more consistent\",\n          opts:[\n            \"To make the output longer\",\n            \"To set must\/must not rules so output is safer and more consistent\",\n            \"To remove the need for teacher review\",\n            \"To make the AI cite sources automatically\"\n          ]\n        },\n        { q:\"6) What is the best example of R (Response format)?\",\n          ans:\"Output as a table with stages, timing, and materials\",\n          opts:[\n            \"Output anything you like\",\n            \"Output as a table with stages, timing, and materials\",\n            \"Use only emojis\",\n            \"Write without headings\"\n          ]\n        }\n      ];\n\n      function renderFrameworkQuiz(){\n        if(!frameworkQuiz) return;\n        frameworkQuiz.innerHTML = frameworkItems.map((it,i)=>{\n          const options = ['<option value=\"\">Choose\u2026<\/option>']\n            .concat(it.opts.map(o=>`<option value=\"${esc(o)}\">${esc(o)}<\/option>`))\n            .join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${esc(it.q)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${options}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderFrameworkQuiz();\n\n      qs('#frameworkCheck').addEventListener('click', ()=>{\n        const sels = qsa('#frameworkQuiz select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        frameworkFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        frameworkFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"framework\", pct);\n      });\n\n      const ex1 = qs('#ex1');\n      const ex2 = qs('#ex2');\n      const ex3 = qs('#ex3');\n      const badBetter = qs('#badBetter');\n\n      if(ex1) ex1.textContent =\n`ROLE: You are an expert EFL teacher.\nC (Context): B1 Speaking | Topic: AI tools in education | Time: 45 minutes | Class size: 30\nL (Learners): B1 mixed ability; needs speaking fluency + safe AI use vocabulary\nE (Exact task): Create a lesson plan with warm-up, guided practice, pair speaking task, wrap-up.\nA (Constraints):\n- MUST include 8 target phrases (provide the list).\n- MUST include pair work and a teacher monitoring checklist.\n- MUST NOT include sensitive\/political topics.\nR (Response format): Table: Stage | Time | Procedure | Teacher role | Student role | Materials\nQuality checks: Ensure CEFR B1 language, include model answers, and avoid fabricated facts\/citations.`;\n\n      if(ex2) ex2.textContent =\n`ROLE: You are an assessment designer.\nC: B1 Reading | Topic: \u201cWhat AI can\/can\u2019t do\u201d | Text length: ~250 words\nL: B1 learners; needs scanning for key ideas\nE: Write 10 questions: 6 MCQ + 2 short answer + 2 vocabulary-in-context\nA:\n- MUST include answer key + 1-line rationale for each MCQ\n- MUST keep distractors plausible (not silly)\n- MUST NOT invent facts not stated in the text\nR: Output in sections: (1) Reading text, (2) Questions, (3) Answer key, (4) Rationales`;\n\n      if(ex3) ex3.textContent =\n`ROLE: You are a writing coach for EFL learners.\nC: B1 Writing | Paragraph task: \u201cMy rule for using AI in class\u201d\nL: B1; common issues: verb tense, article use, cohesion\nE: Give feedback on student text I paste.\nA:\n- MUST score with rubric: Content, Organization, Grammar, Vocabulary, Mechanics (0\u20135)\n- MUST give 3 strengths + 3 improvements + 5 corrected examples with explanations\n- MUST keep tone supportive; do not rewrite everything\nR: Output: Scores table \u2192 Feedback bullets \u2192 Corrected examples \u2192 1 short improved model paragraph (optional)`;\n\n      if(badBetter) badBetter.textContent =\n`BAD PROMPT:\n\u201cMake a great lesson about AI.\u201d\n\nBETTER PROMPT (CLEAR):\nROLE: You are an expert EFL teacher.\nC: B1 Speaking | Topic: AI tools (chatbots, translators, voice tools) | Time: 45 minutes | 30 students\nL: B1 mixed ability; needs speaking fluency + classroom-safe AI rules\nE: Create a lesson plan: warm-up, guided practice, pair role-play, wrap-up (include 10 speaking questions)\nA:\n- MUST include 8 target phrases and a small word bank\n- MUST include 1 safety mini-lecture (privacy + verifying facts)\n- MUST NOT include personal student data examples or sensitive topics\nR:\n- Output as a table: Stage | Time | Procedure | Materials\n- Include model answers + checklist for teacher monitoring\nQuality check:\n- Keep language B1, concise, and practical. If any details are missing, ask 3 questions first.`;\n\n      \/* =========================\n         Templates\n      ========================= *\/\n      const tplA = qs('#tplA');\n      const tplB = qs('#tplB');\n      const tplC = qs('#tplC');\n\n      const templateA =\n`ROLE: You are an expert EFL teacher.\nCONTEXT: [Course + level] | [Topic] | [Time] | [Class size]\nTASK: Create a lesson plan with:\n- Warm-up (5 min)\n- Guided practice (10\u201315 min)\n- Communicative task (pair\/group)\n- Wrap-up + homework\nCONSTRAINTS (MUST): \n1) Include [X] target phrases.\n2) Include differentiation for mixed ability.\nCONSTRAINTS (MUST NOT):\n- Avoid sensitive\/political topics.\nOUTPUT FORMAT: Table: Stage | Time | Procedure | Teacher role | Student role | Materials\nQUALITY CHECKS:\n- Language fits [CEFR level]\n- Include answer key \/ sample responses\n- Do not invent citations; if references are needed, ask me to provide them.`;\n\n      const templateB =\n`ROLE: You are an assessment designer.\nCONTEXT: [CEFR level] | [Skill: reading\/listening\/speaking\/writing] | [Topic]\nTASK: Create a question bank:\n- [10] items total\n- Mix types: MCQ, short answer, matching (specify numbers)\nCONSTRAINTS:\n- Difficulty: [A2\/B1\/B2]\n- Avoid trick questions\nOUTPUT FORMAT:\n1) Questions\n2) Answer key\n3) Brief rationale for each answer (1 line)\nQUALITY CHECKS:\n- No fabricated facts; use general\/common knowledge only unless I provide a text.`;\n\n      const templateC =\n`ROLE: You are a writing coach for EFL learners.\nCONTEXT: [CEFR level] | [Task type: paragraph\/essay]\nINPUT: I will paste student text.\nTASK: Provide feedback aligned to this rubric:\n- Content (0\u20135)\n- Organization (0\u20135)\n- Grammar (0\u20135)\n- Vocabulary (0\u20135)\n- Mechanics (0\u20135)\nCONSTRAINTS:\n- Give 3 strengths + 3 improvements\n- Give 5 targeted corrections with explanations\n- Provide a revised model paragraph (optional)\nOUTPUT FORMAT:\n- Scores table\n- Actionable feedback bullets\n- Corrected examples\nQUALITY CHECKS:\n- Keep feedback supportive, specific, and level-appropriate.`;\n\n      tplA.textContent = templateA;\n      tplB.textContent = templateB;\n      tplC.textContent = templateC;\n\n      qs('#tplSpeakA').addEventListener('click', ()=> speakAs(\"A\", templateA));\n      qs('#tplSpeakB').addEventListener('click', ()=> speakAs(\"A\", templateB));\n\n      \/* =========================\n         Rubrics & feedback\n      ========================= *\/\n      const rubricSet = qs('#rubricSet');\n      const rubricFb = qs('#rubricFb');\n\n      const rubricItems = [\n        {q:\"1) Best constraint to improve consistency?\", ans:\"Use a rubric with criteria + score ranges\",\n          opts:[\"Use a rubric with criteria + score ranges\",\"Say: \u2018Give feedback\u2019 with no details\",\"Ask for \u2018nice comments\u2019 only\"]},\n        {q:\"2) Best constraint to reduce hallucinations?\", ans:\"Require: If uncertain, ask for the missing info\",\n          opts:[\"Require: If uncertain, ask for the missing info\",\"Require: Always answer confidently\",\"Require: Add citations even if not sure\"]},\n        {q:\"3) Best output format for grading?\", ans:\"Table with criteria + evidence + suggestion\",\n          opts:[\"Table with criteria + evidence + suggestion\",\"Long paragraph only\",\"One-word grades\"]},\n        {q:\"4) Best safety constraint?\", ans:\"Do not include personal student data; anonymize\",\n          opts:[\"Do not include personal student data; anonymize\",\"Copy student names into the prompt\",\"Share private records\"]},\n        {q:\"5) Best feedback constraint for actionability?\", ans:\"Give 3 strengths + 3 improvements + examples\",\n          opts:[\"Give 3 strengths + 3 improvements + examples\",\"Say: \u2018Good job\u2019 only\",\"Correct everything with no explanation\"]}\n      ];\n\n      rubricSet.innerHTML = rubricItems.map((it)=>{\n        const options = ['<option value=\"\">Choose\u2026<\/option>'].concat(it.opts.map(o=>`<option value=\"${esc(o)}\">${esc(o)}<\/option>`)).join(\"\");\n        return `\n          <div class=\"qitem\">\n            <div class=\"qtext\">${esc(it.q)}<\/div>\n            <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${options}<\/select>\n          <\/div>\n        `;\n      }).join(\"\");\n\n      qs('#rubricCheck').addEventListener('click', ()=>{\n        const sels = qsa('#rubricSet select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        rubricFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        rubricFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"rubrics\", pct);\n      });\n\n      \/* =========================\n         CEFR adapting\n      ========================= *\/\n      const cefrSet = qs('#cefrSet');\n      const cefrFb = qs('#cefrFb');\n\n      const cefrItems = [\n        {\n          q:\"1) Choose the best A2 prompt for speaking practice:\",\n          ans:\"A2: Use simple sentences + word bank + 6 questions\",\n          opts:[\n            \"A2: Use simple sentences + word bank + 6 questions\",\n            \"A2: Debate the ethics of AI with citations and counterarguments\",\n            \"A2: Write a 1000-word literature review with synthesis\"\n          ]\n        },\n        {\n          q:\"2) Choose the best B1 prompt for a lesson plan:\",\n          ans:\"B1: Include role-play + target phrases + model answers\",\n          opts:[\n            \"B1: Include role-play + target phrases + model answers\",\n            \"B1: Use C2 academic style and advanced theory\",\n            \"B1: Only grammar rules with no practice\"\n          ]\n        },\n        {\n          q:\"3) Choose the best B2 prompt for discussion:\",\n          ans:\"B2: Add constraints for evidence + examples + counterpoint\",\n          opts:[\n            \"B2: Add constraints for evidence + examples + counterpoint\",\n            \"B2: Use only yes\/no questions\",\n            \"B2: Avoid any reasoning\"\n          ]\n        }\n      ];\n\n      cefrSet.innerHTML = cefrItems.map((it)=>{\n        const options = ['<option value=\"\">Choose\u2026<\/option>'].concat(it.opts.map(o=>`<option value=\"${esc(o)}\">${esc(o)}<\/option>`)).join(\"\");\n        return `\n          <div class=\"qitem\">\n            <div class=\"qtext\">${esc(it.q)}<\/div>\n            <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${options}<\/select>\n          <\/div>\n        `;\n      }).join(\"\");\n\n      qs('#cefrCheck').addEventListener('click', ()=>{\n        const sels = qsa('#cefrSet select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        cefrFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        cefrFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"cefr\", pct);\n      });\n\n      \/* =========================\n         Listening (2 voices)\n      ========================= *\/\n      const listenQ = qs('#listenQ');\n      const listenFb = qs('#listenFb');\n\n      const dialogue = [\n        {role:\"A\", text:\"I asked AI to make a lesson plan, but the result was messy.\"},\n        {role:\"B\", text:\"Did you specify the learner level, the exact task, and an output format?\"},\n        {role:\"A\", text:\"Not really. I just said: make a great lesson.\"},\n        {role:\"B\", text:\"That\u2019s why. Add constraints: must include target phrases, must include pair work, and output as a table.\"},\n        {role:\"A\", text:\"What about feedback for writing?\"},\n        {role:\"B\", text:\"Use a rubric. Ask for three strengths, three improvements, and examples. Also add: don\u2019t invent citations.\"},\n        {role:\"A\", text:\"So good prompts are like good instructions for students.\"},\n        {role:\"B\", text:\"Exactly. Clear instructions produce clearer output.\"}\n      ];\n\n      const listenItems = [\n        {q:\"1) Why was the output messy?\", ans:\"The prompt lacked level\/task\/format\"},\n        {q:\"2) What improved the lesson prompt?\", ans:\"Constraints and a table format\"},\n        {q:\"3) What improved writing feedback?\", ans:\"Rubric + strengths\/improvements + examples\"},\n        {q:\"4) What is an important safety constraint?\", ans:\"Don\u2019t invent citations\"}\n      ];\n\n      function renderListenQ(){\n        const optsMap = {\n          \"The prompt lacked level\/task\/format\":[\"The prompt lacked level\/task\/format\",\"AI is always wrong\",\"The teacher used too many constraints\"],\n          \"Constraints and a table format\":[\"Constraints and a table format\",\"No constraints at all\",\"Only one sentence\"],\n          \"Rubric + strengths\/improvements + examples\":[\"Rubric + strengths\/improvements + examples\",\"Only a grade\",\"No explanation\"],\n          \"Don\u2019t invent citations\":[\"Don\u2019t invent citations\",\"Always add random DOIs\",\"Copy references without checking\"]\n        };\n        listenQ.innerHTML = listenItems.map((it)=>{\n          const options = ['<option value=\"\">Choose\u2026<\/option>']\n            .concat((optsMap[it.ans]||[it.ans]).map(o=>`<option value=\"${esc(o)}\">${esc(o)}<\/option>`)).join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${esc(it.q)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${options}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderListenQ();\n\n      qs('#listenPlay').addEventListener('click', async ()=>{\n        if(googleVoicesEN.length >= 2 && voiceA === voiceB){\n          voiceB = googleVoicesEN.find(v => v !== voiceA) || voiceB;\n          voiceBSelect.value = String(googleVoicesEN.indexOf(voiceB));\n        }\n        await speakDialogue(dialogue);\n      });\n      qs('#listenStop').addEventListener('click', stopSpeak);\n\n      qs('#listenCheck').addEventListener('click', ()=>{\n        const sels = qsa('#listenQ select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        listenFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        listenFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"listening\", pct);\n      });\n\n      \/* =========================\n         Practice Lab \u2014 generated prompt\n      ========================= *\/\n      const labContext = qs('#labContext');\n      const labLearners = qs('#labLearners');\n      const labTask = qs('#labTask');\n      const labConstraints = qs('#labConstraints');\n      const labFormat = qs('#labFormat');\n      const labChecks = qs('#labChecks');\n      const finalPrompt = qs('#finalPrompt');\n      const labFb = qs('#labFb');\n\n      function buildPrompt(){\n        const c = norm(labContext.value) || \"[Add context]\";\n        const l = norm(labLearners.value) || \"[Add learner level + needs]\";\n        const t = norm(labTask.value) || \"[Add exact task]\";\n        const con = norm(labConstraints.value) || \"[Add constraints]\";\n        const f = norm(labFormat.value) || \"[Add output format]\";\n        const qc = norm(labChecks.value) || \"[Add quality checks]\";\n        return (\n`ROLE: You are an expert educator and instructional designer.\n\nC (Context):\n${c}\n\nL (Learner level + needs):\n${l}\n\nE (Exact task):\n${t}\n\nA (Acceptable constraints \u2014 must \/ must not):\n${con}\n\nR (Response format):\n${f}\n\nQUALITY CHECKS:\n${qc}\n\nIMPORTANT:\n- If information is missing, ask me up to 3 clarifying questions before generating.\n- Do not fabricate references or citations.`\n        );\n      }\n\n      function updateFinalPrompt(){\n        finalPrompt.textContent = buildPrompt();\n      }\n      [labContext, labLearners, labTask, labConstraints, labFormat, labChecks].forEach(el=>{\n        el.addEventListener('input', updateFinalPrompt);\n      });\n      updateFinalPrompt();\n\n      qs('#labCheck').addEventListener('click', ()=>{\n        const fields = [labContext, labLearners, labTask, labConstraints, labFormat, labChecks];\n        const filled = fields.filter(f=> norm(f.value).length >= 12).length;\n        const pct = Math.round((filled \/ fields.length) * 100);\n        labFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        labFb.textContent = `Prompt completeness: ${filled}\/${fields.length} (${pct}%).`;\n        markDone(\"practice_lab\", pct);\n      });\n\n      qs('#labCopy').addEventListener('click', async ()=>{\n        const txt = buildPrompt();\n        try{\n          await navigator.clipboard.writeText(txt);\n          labFb.className = \"feedback ok\";\n          labFb.textContent = \"\u2705 Copied to clipboard.\";\n        }catch(_){\n          labFb.className = \"feedback bad\";\n          labFb.textContent = \"\u26a0\ufe0f Clipboard blocked. Copy manually from the box.\";\n        }\n      });\n\n      \/* =========================\n         Final init\n      ========================= *\/\n      renderProgress();\n\n    })();\n  <\/script>\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Conversation Prompt Framework Prompt Templates Rubrics &#038; Feedback CEFR Adapting Listening Practice Lab Progress Prompting for Educators Learn to write<\/p>\n","protected":false},"author":1,"featured_media":744,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_layout":"default_layout","footnotes":""},"categories":[53,45],"tags":[],"class_list":["post-743","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai-basics","category-ai-for-teachers"],"_links":{"self":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/743","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/comments?post=743"}],"version-history":[{"count":2,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/743\/revisions"}],"predecessor-version":[{"id":760,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/743\/revisions\/760"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media\/744"}],"wp:attachment":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media?parent=743"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/categories?post=743"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/tags?post=743"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}