{"id":721,"date":"2026-03-04T07:37:23","date_gmt":"2026-03-04T07:37:23","guid":{"rendered":"https:\/\/i-cte.org\/robot\/?p=721"},"modified":"2026-03-04T07:37:23","modified_gmt":"2026-03-04T07:37:23","slug":"food-for-thought","status":"publish","type":"post","link":"https:\/\/i-cte.org\/robot\/food-for-thought\/","title":{"rendered":"Food for thought"},"content":{"rendered":"\n<!-- \u2705 ICTE Chatbot Lesson \u2014 Personal Best (B1) Unit 8 (WP-safe single block) -->\n<div id=\"icte-u8\">\n\n  <!-- \u2705 TOP MENU -->\n  <nav class=\"icte-menu\" aria-label=\"Unit 8 lesson navigation\">\n    <a href=\"#\" class=\"is-current\" data-view=\"conversation\">Conversation<\/a>\n    <a href=\"#\" data-view=\"vocab\">Vocabulary<\/a>\n    <a href=\"#\" data-view=\"grammar\">Grammar<\/a>\n    <a href=\"#\" data-view=\"discussion\">Discussion<\/a>\n    <a href=\"#\" data-view=\"reading\">Reading<\/a>\n    <a href=\"#\" data-view=\"listening\">Listening<\/a>\n    <a href=\"#\" data-view=\"problemsolving\">Problem-solving<\/a>\n    <a href=\"#\" data-view=\"progress\">Progress<\/a>\n  <\/nav>\n\n  <section class=\"icte-shell\" aria-label=\"ICTE Unit 8 practice\">\n\n    <!-- \u2705 Header -->\n    <header class=\"icte-hero\">\n      <div class=\"icte-hero__text\">\n        <h2>Unit 8 \u2014 Food for thought<\/h2>\n        <p class=\"muted\">\n          Practice <b>too \/ too much \/ too many \/ (not) enough<\/b>, <b>have to \/ don\u2019t have to \/ can\u2019t<\/b>,\n          food vocabulary, and reading skills (<b>scanning<\/b> + <b>linkers of contrast<\/b>).\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        <label class=\"icte-label\">\n          Voice (Narrator)\n          <select id=\"icteVoiceSelect\" class=\"icte-select\" aria-label=\"Voice selection\"><\/select>\n        <\/label>\n\n        <div class=\"icte-small muted\">\n          Tip: If you don\u2019t see voices yet, click anywhere once and wait 2\u20133 seconds.\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 (Voice Interactive)<\/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            Speak your answers. Try to use <b>too \/ too much \/ too many<\/b> and <b>(not) enough<\/b>.\n            Also try <b>have to \/ don\u2019t have to \/ can\u2019t<\/b> when you talk about rules and health.\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            Targets: food vocabulary + quantifiers + obligation\/prohibition.\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 2) VOCABULARY -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"vocab\" aria-label=\"Vocabulary practice\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>2) Vocabulary Matching + Use It<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"vocab-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"vocabReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Match the words to the meanings, then complete the sentences using the same vocabulary.\n          <\/p>\n\n          <div class=\"grid2\">\n            <div>\n              <h4 class=\"h4\">A) Matching<\/h4>\n              <div id=\"vocabMatch\" class=\"stack\"><\/div>\n              <button class=\"btn\" id=\"vocabCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"vocabFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n\n            <div>\n              <h4 class=\"h4\">B) Use the words (Fill in the blanks)<\/h4>\n              <div id=\"vocabUse\" class=\"stack\"><\/div>\n              <button class=\"btn\" id=\"vocabUseCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"vocabUseFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 3) GRAMMAR -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"grammar\" aria-label=\"Grammar practice\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>3) Grammar \u2014 too \/ too much \/ too many \/ (not) enough + have to \/ don\u2019t have to \/ can\u2019t<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"gram-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"gramReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n\n          <div class=\"note\">\n            <b>Reminder:<\/b>\n            <b>too much<\/b> (uncountable), <b>too many<\/b> (countable plural), <b>enough<\/b> (before a noun or after an adjective).\n            Use <b>have to<\/b> for obligation, <b>don\u2019t have to<\/b> for no obligation, and <b>can\u2019t<\/b> for prohibition.\n          <\/div>\n\n          <div id=\"gramQuiz\" class=\"stack\"><\/div>\n          <button class=\"btn\" id=\"gramCheck\" type=\"button\">Check<\/button>\n          <div class=\"feedback\" id=\"gramFb\" aria-live=\"polite\"><\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 4) DISCUSSION -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"discussion\" aria-label=\"Discussion practice\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>4) Discussion (Voice or typing)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"disc-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"discNext\">Next question<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Answer with reasons. Try to include at least <b>2 vocabulary items<\/b> and at least <b>one<\/b> target grammar pattern:\n            <i>too much \/ too many \/ (not) enough<\/i> or <i>have to \/ don\u2019t have to \/ can\u2019t<\/i>.\n          <\/p>\n\n          <div class=\"qa\">\n            <div class=\"q\" id=\"discQ\">Click <b>Next question<\/b> to begin.<\/div>\n            <textarea id=\"discA\" class=\"textarea\" rows=\"4\" placeholder=\"Write your answer here...\"><\/textarea>\n            <div class=\"row\">\n              <button class=\"btn\" id=\"discCheck\" type=\"button\">Check my language<\/button>\n              <button class=\"btn ghost\" id=\"discSpeakQ\" type=\"button\">\ud83d\udd0a Read question<\/button>\n            <\/div>\n            <div class=\"feedback\" id=\"discFb\" aria-live=\"polite\"><\/div>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 5) READING -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"reading\" aria-label=\"Reading comprehension\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>5) Reading \u2014 Hidden sugar (scanning + main ideas)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"read-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini\" type=\"button\" id=\"readTextBtn\">\ud83d\udd0a Read the text<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Read the text, then answer the questions.\n          <\/p>\n\n          <article class=\"reading\" id=\"readingText\">\n            <div class=\"reading-title\">Hidden sugar<\/div>\n            <div class=\"reading-p\"><b>1<\/b> Most of us know that too much sugar isn\u2019t good for us. But how much do we really know about the other kinds of food we eat?<\/div>\n            <div class=\"reading-p\"><b>2<\/b> Australian moviemaker Damon Gameau investigated \u201chidden\u201d sugar in food. He spent 60 days eating only products advertised as \u201chealthy,\u201d like low-fat yogurt, cereal bars, fruit juices, and sports drinks.<\/div>\n            <div class=\"reading-p\"><b>3<\/b> Instead of feeling healthier, Damon gained weight and had health problems because manufacturers add sugar to many products to make them taste better.<\/div>\n            <div class=\"reading-p\"><b>4<\/b> The World Health Organization recommends a daily limit of 25 g (about six teaspoons). Some \u201chealthy\u201d products can contain a lot of added sugar.<\/div>\n            <div class=\"reading-p\"><b>5<\/b> After the experiment, Damon returned to a diet of fresh fruit, vegetables, meat, and fish. He still eats a little chocolate sometimes, but many processed foods now taste too sweet to him.<\/div>\n            <div class=\"reading-p\"><b>6<\/b> Next time you shop, check how much sugar is in a \u201chealthy\u201d cereal before you buy it.<\/div>\n          <\/article>\n\n          <div class=\"grid2\">\n            <div>\n              <h4 class=\"h4\">A) Main idea<\/h4>\n              <div class=\"qitem\">\n                <div class=\"qtext\">1) What is the main message?<\/div>\n                <select class=\"icte-select\" id=\"rQ1\">\n                  <option value=\"\">Choose\u2026<\/option>\n                  <option value=\"A\">A: Sugar is only a problem in desserts.<\/option>\n                  <option value=\"B\">B: Some \u201chealthy\u201d foods can have hidden sugar, so check labels.<\/option>\n                  <option value=\"C\">C: You should never eat chocolate.<\/option>\n                <\/select>\n              <\/div>\n\n              <h4 class=\"h4\" style=\"margin-top:14px;\">B) Headings \u2192 Paragraphs<\/h4>\n              <p class=\"muted icte-small\">Match each heading to a paragraph number (1\u20136).<\/p>\n              <div id=\"readMatch\" class=\"stack\"><\/div>\n\n              <button class=\"btn\" id=\"readCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"readFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n\n            <div>\n              <h4 class=\"h4\">C) Find evidence (short answers)<\/h4>\n              <div id=\"readShort\" class=\"stack\"><\/div>\n              <button class=\"btn\" id=\"readShortCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"readShortFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 6) LISTENING -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"listening\" aria-label=\"Listening comprehension\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>6) Listening \u2014 Restaurant shopping list (TTS)<\/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 listening (TTS)<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"listenStop\">\u23f9 Stop<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Click <b>Play listening<\/b>. Listen and complete the gaps (meat, fish\/seafood, fruit\/vegetables).\n          <\/p>\n\n          <div id=\"listenGaps\" 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) PROBLEM-SOLVING -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"problemsolving\" aria-label=\"Problem-solving tasks\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>7) Problem-solving (Real-life food scenarios)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"prob-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"probReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Choose the best solution. Then write one sentence using\n            <b>too much \/ too many \/ (not) enough<\/b> or <b>have to \/ don\u2019t have to \/ can\u2019t<\/b>.\n          <\/p>\n\n          <div id=\"probSet\" class=\"stack\"><\/div>\n          <button class=\"btn\" id=\"probCheck\" type=\"button\">Check<\/button>\n          <div class=\"feedback\" id=\"probFb\" 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=\"pVocab\">0<\/div>\n              <div class=\"muted\">Vocab used (detected)<\/div>\n            <\/div>\n          <\/div>\n\n          <div class=\"note\">\n            Completion is saved in your browser (local storage). If you change device\/browser, progress resets.\n          <\/div>\n\n          <h4 class=\"h4\">Vocabulary Bank (Unit 8)<\/h4>\n          <div class=\"bank\" id=\"vocabBank\"><\/div>\n        <\/div>\n      <\/section>\n\n    <\/main>\n  <\/section>\n\n  <style>\n    \/* ===== WP-SAFE STYLES (scoped) ===== *\/\n    #icte-u8 *{ box-sizing:border-box; }\n    #icte-u8{\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-u8 .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-u8 .icte-menu a{\n      display:inline-block;\n      color:#fff;\n      text-decoration:none;\n      font-weight:700;\n      padding:8px 10px;\n      border-radius:999px;\n      margin:0 3px;\n      opacity:.92;\n      transition:.15s;\n    }\n    #icte-u8 .icte-menu a:hover{ opacity:1; background:rgba(255,255,255,.14); }\n    #icte-u8 .icte-menu a.is-current{ background:#fff; color:var(--dark); opacity:1; }\n\n    #icte-u8 .icte-shell{ max-width:1100px; margin:0 auto; }\n    #icte-u8 .icte-hero{\n      display:grid;\n      grid-template-columns: 1.2fr .8fr;\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-u8 .icte-hero{ grid-template-columns:1fr; } }\n\n    #icte-u8 h2{ margin:0 0 6px 0; font-size:22px; }\n    #icte-u8 .muted{ color:var(--muted); }\n\n    #icte-u8 .icte-hero__controls{\n      border-left:1px dashed var(--line);\n      padding-left:14px;\n    }\n    @media (max-width: 920px){\n      #icte-u8 .icte-hero__controls{ border-left:none; padding-left:0; border-top:1px dashed var(--line); padding-top:12px; }\n    }\n\n    #icte-u8 .icte-row{ display:flex; gap:8px; flex-wrap:wrap; }\n    #icte-u8 .icte-label{ display:block; font-size:12px; font-weight:800; margin-top:10px; }\n    #icte-u8 .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-u8 .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:800;\n    }\n    #icte-u8 .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-u8 .dot.on{\n      background:#22c55e;\n      box-shadow:0 0 0 4px rgba(34,197,94,.18);\n    }\n\n    #icte-u8 .btn{\n      border:none;\n      padding:10px 12px;\n      border-radius:12px;\n      background:var(--green);\n      color:#fff;\n      font-weight:800;\n      cursor:pointer;\n      transition:.15s;\n    }\n    #icte-u8 .btn:hover{ filter:brightness(.95); transform:translateY(-1px); }\n    #icte-u8 .btn:active{ transform:translateY(0); }\n    #icte-u8 .btn.ghost{\n      background:#fff;\n      color:#111827;\n      border:1px solid var(--line);\n    }\n    #icte-u8 .btn.mini{ padding:8px 10px; border-radius:10px; font-size:13px; }\n    #icte-u8 .icte-small{ font-size:12px; }\n\n    #icte-u8 .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-u8 .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-u8 .card-h h3{ margin:0; font-size:18px; }\n    #icte-u8 .card-actions{ display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end; }\n\n    #icte-u8 .view{ display:none; }\n    #icte-u8 .view.is-active{ display:block; }\n\n    #icte-u8 .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-u8 .msg{ margin:10px 0; display:flex; gap:10px; align-items:flex-start; }\n    #icte-u8 .who{\n      min-width:72px;\n      font-weight:900;\n      font-size:12px;\n      color:#93c5fd;\n      text-transform:uppercase;\n      letter-spacing:.06em;\n    }\n    #icte-u8 .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    }\n    #icte-u8 .msg.user .who{ color:#86efac; }\n    #icte-u8 .msg.user .bubble{ background:rgba(34,197,94,.10); border-color:rgba(34,197,94,.18); }\n\n    #icte-u8 .chatbar{\n      margin-top:10px;\n      display:flex;\n      gap:8px;\n      align-items:center;\n    }\n    #icte-u8 .input{\n      flex:1;\n      padding:12px 12px;\n      border:1px solid var(--line);\n      border-radius:12px;\n      outline:none;\n    }\n    #icte-u8 .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-u8 .grid2{\n      display:grid;\n      grid-template-columns:1fr 1fr;\n      gap:14px;\n      margin-top:10px;\n    }\n    @media (max-width: 920px){ #icte-u8 .grid2{ grid-template-columns:1fr; } }\n\n    #icte-u8 .stack{ display:flex; flex-direction:column; gap:10px; }\n    #icte-u8 .h4{ margin:0 0 6px 0; font-size:15px; }\n    #icte-u8 .qitem{\n      padding:10px;\n      border:1px solid var(--line);\n      border-radius:14px;\n      background:#fafafa;\n    }\n    #icte-u8 .qtext{ font-weight:800; margin-bottom:8px; }\n    #icte-u8 .row{ display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }\n\n    #icte-u8 .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:700;\n      display:none;\n      white-space:pre-line;\n    }\n    #icte-u8 .feedback.ok{ display:block; border-color:rgba(34,197,94,.35); background:#ecfdf5; }\n    #icte-u8 .feedback.bad{ display:block; border-color:rgba(239,68,68,.35); background:#fef2f2; }\n\n    #icte-u8 .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-u8 .reading{\n      border:1px solid var(--line);\n      border-radius:14px;\n      padding:12px;\n      background:#fff;\n      margin-top:10px;\n    }\n    #icte-u8 .reading-title{ font-weight:900; margin-bottom:8px; }\n    #icte-u8 .reading-p{ padding:8px 0; border-top:1px dashed var(--line); }\n    #icte-u8 .reading-p:first-of-type{ border-top:none; }\n\n    #icte-u8 .qa .q{\n      padding:12px;\n      border-radius:14px;\n      border:1px solid var(--line);\n      background:#fff;\n      font-weight:900;\n    }\n\n    #icte-u8 .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-u8 .progress-grid{ grid-template-columns:1fr; } }\n    #icte-u8 .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-u8 .pnum{ font-size:28px; font-weight:1000; }\n\n    #icte-u8 .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-u8 .tag{\n      border:1px solid var(--line);\n      background:#f9fafb;\n      padding:6px 10px;\n      border-radius:999px;\n      font-weight:800;\n      font-size:13px;\n    }\n  <\/style>\n\n  <script>\n    (function(){\n      const root = document.getElementById('icte-u8');\n      if(!root) return;\n\n      \/* ========= Helpers ========= *\/\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      \/* ========= Navigation ========= *\/\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      \/* ========= Speech (TTS + ASR) ========= *\/\n      const micDot = qs('#icteMicDot');\n      const micStatus = qs('#icteMicStatus');\n      const voiceSel = qs('#icteVoiceSelect');\n      const btnStartVoice = qs('#icteStartVoice');\n      const btnStopVoice = qs('#icteStopVoice');\n\n      let chosenVoice = null;\n      let recognition = null;\n      let listening = false;\n      let lastPromptSpoken = \"\";\n\n      function loadVoices(){\n        if(!window.speechSynthesis) return;\n        const all = speechSynthesis.getVoices() || [];\n        let list = all.filter(v => (v.lang||\"\").toLowerCase().startsWith(\"en\"));\n        if(list.length === 0) list = all;\n\n        voiceSel.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          voiceSel.appendChild(opt);\n        });\n\n        chosenVoice = list[0] || null;\n        voiceSel.onchange = ()=>{\n          const idx = parseInt(voiceSel.value,10);\n          chosenVoice = list[idx] || chosenVoice;\n        };\n      }\n      if(window.speechSynthesis){\n        loadVoices();\n        speechSynthesis.onvoiceschanged = loadVoices;\n      }\n\n      function speak(text){\n        const t = norm(text);\n        if(!t || !window.speechSynthesis) return;\n        speechSynthesis.cancel();\n        const u = new SpeechSynthesisUtterance(t);\n        if(chosenVoice) u.voice = chosenVoice;\n        u.rate = 1.02; u.pitch = 1.0; u.volume = 1.0;\n        speechSynthesis.speak(u);\n      }\n      function stopSpeak(){ if(window.speechSynthesis) speechSynthesis.cancel(); }\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 = ()=>{\n          if(listening){ try{ recognition.start(); }catch(_){ } }\n        };\n        setMicUI(true);\n        try{ recognition.start(); }catch(_){ }\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      \/* ========= Progress ========= *\/\n      const LS_KEY = \"icte_u8_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      \/* ========= Content: Vocabulary ========= *\/\n      const vocabFood = [\n        {word:\"cereal\", def:\"breakfast food made from grains\"},\n        {word:\"fruit juice\", def:\"drink made from fruit\"},\n        {word:\"salmon\", def:\"a pink fish\"},\n        {word:\"tuna\", def:\"a large fish used in cooking\"},\n        {word:\"shrimp\", def:\"small seafood (prawns)\"},\n        {word:\"beef\", def:\"meat from a cow\"},\n        {word:\"lamb\", def:\"meat from a young sheep\"},\n        {word:\"turkey\", def:\"a type of poultry (bird)\"},\n        {word:\"cucumber\", def:\"a long green vegetable\"},\n        {word:\"eggplant\", def:\"a purple vegetable (aubergine)\"},\n        {word:\"lettuce\", def:\"leafy vegetable used in salads\"},\n        {word:\"strawberry\", def:\"a small red fruit\"},\n        {word:\"pineapple\", def:\"a tropical fruit\"},\n        {word:\"coconut\", def:\"a large tropical nut\/fruit\"},\n        {word:\"tomato sauce\", def:\"sauce made from tomatoes\"}\n      ];\n      const vocabAdj = [\n        {word:\"fresh\", def:\"newly made; not old\"},\n        {word:\"healthy\", def:\"good for your body\"},\n        {word:\"unhealthy\", def:\"not good for your body\"},\n        {word:\"sweet\", def:\"sugary taste\"},\n        {word:\"salty\", def:\"with a lot of salt\"},\n        {word:\"spicy\", def:\"hot with strong flavor\"},\n        {word:\"crunchy\", def:\"hard and makes a noise when you bite\"},\n        {word:\"creamy\", def:\"smooth like cream\"},\n        {word:\"delicious\", def:\"very tasty\"},\n        {word:\"disgusting\", def:\"very unpleasant\"}\n      ];\n      const vocabAll = [...vocabFood, ...vocabAdj];\n\n      const bank = qs('#vocabBank');\n      bank.innerHTML = vocabAll.map(v=>`<span class=\"tag\" title=\"${esc(v.def)}\">${esc(v.word)}<\/span>`).join(\"\");\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\n        const used = new Set();\n        const txt = (progress._vocabUsedText||\"\");\n        vocabAll.forEach(w=>{\n          if(lower(txt).includes(lower(w.word))) used.add(w.word);\n        });\n        qs('#pVocab').textContent = String(used.size);\n      }\n\n      \/* ========= Instruction TTS ========= *\/\n      const SAY = {\n        \"conv-instr\":\n          \"Conversation. Start Voice, then answer the questions. Use too much, too many, not enough, and have to, don't have to, can't.\",\n        \"vocab-instr\":\n          \"Vocabulary. Match the words to meanings. Then complete the sentences. Check your answers when you finish.\",\n        \"gram-instr\":\n          \"Grammar. Choose the best option: too, too much, too many, enough, have to, don't have to, or can't.\",\n        \"disc-instr\":\n          \"Discussion. Answer with reasons. Include at least two vocabulary items and one grammar pattern.\",\n        \"read-instr\":\n          \"Reading. Read the text about hidden sugar. Then answer main idea, headings, and evidence questions.\",\n        \"list-instr\":\n          \"Listening. Click play. Listen and complete the gaps using the word bank.\",\n        \"prob-instr\":\n          \"Problem-solving. Choose the best solution. Then write one sentence using the target grammar.\"\n      };\n      qsa('[data-say]').forEach(btn=>{\n        btn.addEventListener('click', ()=>{\n          const k = btn.getAttribute('data-say');\n          if(SAY[k]) speak(SAY[k]);\n        });\n      });\n\n      \/* ========= 1) Conversation ========= *\/\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: \"Hi! Welcome to Unit 8. What did you eat or drink today? Was it healthy? Give one reason.\",\n          check: (a)=> a.length >= 10,\n          tips: \"Mention at least one food or drink (e.g., cereal, fruit juice, salad).\"\n        },\n        {\n          bot: \"Do people eat too much sugar in your country? Why?\",\n          check: (a)=> \/\\btoo much\\b\/i.test(a) || \/\\btoo many\\b\/i.test(a),\n          tips: \"Try: People eat too much sugar because...\"\n        },\n        {\n          bot: \"Say one thing you eat too many of, and one thing you don\u2019t eat enough of.\",\n          check: (a)=> \/\\btoo many\\b\/i.test(a) && \/\\bnot enough\\b\/i.test(a),\n          tips: \"Use both: too many + not enough.\"\n        },\n        {\n          bot: \"If you want to be healthier, what do you have to change? Use: have to \/ don't have to \/ can't.\",\n          check: (a)=> \/\\bhave to\\b\/i.test(a) || \/\\bdon't have to\\b\/i.test(a) || \/\\bcan't\\b\/i.test(a),\n          tips: \"Example: I have to drink less soda. I can't eat too many sweets.\"\n        },\n        {\n          bot: \"Describe a dish using 3 adjectives (for example: sweet, crunchy, fresh).\",\n          check: (a)=> {\n            const hits = [\"fresh\",\"healthy\",\"unhealthy\",\"sweet\",\"salty\",\"spicy\",\"crunchy\",\"creamy\",\"delicious\",\"disgusting\"]\n              .filter(w => lower(a).includes(w));\n            return hits.length >= 3;\n          },\n          tips: \"Use at least 3 adjectives from the vocabulary bank.\"\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      function botAsk(){\n        const step = convSteps[convStep];\n        if(!step){\n          addMsg(\"Bot\",\"Great work! You finished Unit 8 conversation. Try other sections.\");\n          speak(\"Great work! You finished Unit 8 conversation. Try other sections.\");\n          markDone(\"conversation\", 100);\n          return;\n        }\n        addMsg(\"Bot\", step.bot);\n        lastPromptSpoken = step.bot;\n        speak(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. Nice use of the target language.\" : \"\u26a0\ufe0f Try again. \" + step.tips;\n        return {ok, msg};\n      }\n\n      function handleConversationInput(text){\n        const a = norm(text);\n        if(!a) return;\n        addMsg(\"You\", a);\n\n        progress._vocabUsedText = (progress._vocabUsedText||\"\") + \" \" + a;\n        saveProgress();\n\n        const {ok, msg} = scoreAnswer(a);\n        addMsg(\"Bot\", msg);\n        speak(msg);\n\n        if(ok){ convStep++; setTimeout(botAsk, 450); }\n        else { setTimeout(()=> speak(\"Please try again. \" + convSteps[convStep].bot), 450); }\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', ()=> speak(lastPromptSpoken || \"No question yet.\"));\n      convReset.addEventListener('click', ()=>{\n        convChat.innerHTML = \"\";\n        convStep = 0;\n        addMsg(\"Bot\",\"Ready! Start Voice (optional) and answer. Let\u2019s begin.\");\n        botAsk();\n      });\n\n      addMsg(\"Bot\",\"Ready! Start Voice (optional) and answer. Let\u2019s begin.\");\n      botAsk();\n\n      \/* ========= Route voice transcripts ========= *\/\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\n        const v = activeViewName();\n        if(v === \"conversation\"){\n          handleConversationInput(text);\n          return;\n        }\n        if(v === \"discussion\"){\n          const ta = qs('#discA');\n          ta.value = (ta.value ? (ta.value + \" \") : \"\") + text;\n          speak(\"I heard: \" + text);\n          return;\n        }\n        const input = qs('.view.is-active input.input');\n        if(input){ input.value = text; speak(\"I heard: \" + text); return; }\n        speak(\"I heard: \" + text);\n      }\n\n      \/* ========= 2) Vocabulary ========= *\/\n      const vocabMatch = qs('#vocabMatch');\n      const vocabFb = qs('#vocabFb');\n\n      const matchSet = shuffle([\n        {word:\"cereal\", def:\"breakfast food made from grains\"},\n        {word:\"fruit juice\", def:\"drink made from fruit\"},\n        {word:\"salmon\", def:\"a pink fish\"},\n        {word:\"shrimp\", def:\"small seafood (prawns)\"},\n        {word:\"eggplant\", def:\"a purple vegetable (aubergine)\"},\n        {word:\"lettuce\", def:\"leafy vegetable used in salads\"},\n        {word:\"fresh\", def:\"newly made; not old\"},\n        {word:\"crunchy\", def:\"hard and makes a noise when you bite\"},\n        {word:\"creamy\", def:\"smooth like cream\"},\n        {word:\"spicy\", def:\"hot with strong flavor\"}\n      ]);\n\n      function renderVocabMatching(){\n        const defs = shuffle(matchSet.map(x=>x.def));\n        vocabMatch.innerHTML = matchSet.map((x,i)=>{\n          const options = ['<option value=\"\">Choose meaning\u2026<\/option>']\n            .concat(defs.map(d=>`<option value=\"${esc(d)}\">${esc(d)}<\/option>`))\n            .join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${i+1}) <b>${esc(x.word)}<\/b><\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(x.def)}\">${options}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderVocabMatching();\n\n      qs('#vocabCheck').addEventListener('click', ()=>{\n        const sels = qsa('#vocabMatch 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        vocabFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        vocabFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"vocab_match\", pct);\n      });\n\n      const vocabUse = qs('#vocabUse');\n      const vocabUseFb = qs('#vocabUseFb');\n      const useItems = [\n        {sent:\"I usually eat ____ for breakfast.\", ans:\"cereal\"},\n        {sent:\"This soup is too ____. I need water.\", ans:\"salty\"},\n        {sent:\"We don\u2019t have enough ____. Let\u2019s buy fish.\", ans:\"salmon\"},\n        {sent:\"The salad is very ____ and tasty.\", ans:\"fresh\"},\n        {sent:\"I don\u2019t like it. It tastes ____.\", ans:\"disgusting\"},\n        {sent:\"This snack is ____. I like the sound when I bite it.\", ans:\"crunchy\"}\n      ];\n\n      function renderVocabUse(){\n        const bank2 = shuffle(useItems.map(x=>x.ans));\n        vocabUse.innerHTML = useItems.map((x,i)=>{\n          const opts = ['<option value=\"\">Choose\u2026<\/option>']\n            .concat(bank2.map(w=>`<option value=\"${esc(w)}\">${esc(w)}<\/option>`)).join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${i+1}) ${esc(x.sent)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(x.ans)}\">${opts}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderVocabUse();\n\n      qs('#vocabUseCheck').addEventListener('click', ()=>{\n        const sels = qsa('#vocabUse 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        vocabUseFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        vocabUseFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"vocab_use\", pct);\n      });\n\n      qs('#vocabReset').addEventListener('click', ()=>{\n        renderVocabMatching();\n        renderVocabUse();\n        vocabFb.style.display=\"none\";\n        vocabUseFb.style.display=\"none\";\n      });\n\n      \/* ========= 3) Grammar ========= *\/\n      const gramQuiz = qs('#gramQuiz');\n      const gramFb = qs('#gramFb');\n\n      const gramItems = [\n        {q:\"We shouldn\u2019t drink ____ soft drinks.\", opts:[\"too\",\"too much\",\"too many\",\"enough\"], ans:\"too many\"},\n        {q:\"____ sugar isn\u2019t good for us.\", opts:[\"Too\",\"Too much\",\"Too many\",\"Enough\"], ans:\"Too much\"},\n        {q:\"This salad isn\u2019t big ____. I\u2019m still hungry.\", opts:[\"too\",\"much\",\"many\",\"enough\"], ans:\"enough\"},\n        {q:\"There are ____ cookies on the plate.\", opts:[\"too\",\"too much\",\"too many\",\"enough\"], ans:\"too many\"},\n        {q:\"This soup is ____ salty.\", opts:[\"too\",\"too much\",\"too many\",\"enough\"], ans:\"too\"},\n        {q:\"Students ____ bring healthy snacks to school.\", opts:[\"have to\",\"don't have to\",\"can't\"], ans:\"have to\"},\n        {q:\"You ____ eat in the classroom.\", opts:[\"have to\",\"don't have to\",\"can't\"], ans:\"can't\"},\n        {q:\"You ____ buy expensive food to be healthy.\", opts:[\"have to\",\"don't have to\",\"can't\"], ans:\"don't have to\"}\n      ];\n\n      function renderGrammar(){\n        gramQuiz.innerHTML = gramItems.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\">${i+1}) ${esc(it.q)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${options}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderGrammar();\n\n      qs('#gramCheck').addEventListener('click', ()=>{\n        const sels = qsa('#gramQuiz 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        gramFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        gramFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"grammar\", pct);\n      });\n\n      qs('#gramReset').addEventListener('click', ()=>{\n        renderGrammar();\n        gramFb.style.display=\"none\";\n      });\n\n      \/* ========= 4) Discussion ========= *\/\n      const discQ = qs('#discQ');\n      const discA = qs('#discA');\n      const discFb = qs('#discFb');\n\n      const discQs = [\n        \"Do people eat too much sugar in your country? Give two reasons.\",\n        \"What healthy food do students have to eat at school? What can't they eat?\",\n        \"What food do you eat too many of? What food don\u2019t you eat enough of?\",\n        \"How can families cook healthier meals when they don\u2019t have enough time?\",\n        \"What is your favorite food? Describe it using three adjectives (sweet, spicy, crunchy, etc.).\"\n      ];\n      let discIdx = -1;\n\n      function nextDiscQ(){\n        discIdx = (discIdx + 1) % discQs.length;\n        discQ.textContent = discQs[discIdx];\n        discA.value = \"\";\n        discFb.style.display = \"none\";\n        speak(discQs[discIdx]);\n      }\n      qs('#discNext').addEventListener('click', nextDiscQ);\n      qs('#discSpeakQ').addEventListener('click', ()=> speak(discQs[Math.max(0,discIdx)] || \"Click next question to begin.\"));\n\n      function detectTargets(text){\n        const t = lower(text);\n        const vocabHits = vocabAll.filter(v => t.includes(lower(v.word))).map(v=>v.word);\n        const hasQuant = \/\\btoo much\\b|\\btoo many\\b|\\bnot enough\\b|\\benough\\b\/i.test(text);\n        const hasModal = \/\\bhave to\\b|\\bdon't have to\\b|\\bcan't\\b\/i.test(text);\n        return { vocabHits, hasQuant, hasModal };\n      }\n\n      qs('#discCheck').addEventListener('click', ()=>{\n        const ans = norm(discA.value);\n        if(!ans){\n          discFb.className = \"feedback bad\";\n          discFb.textContent = \"Please write or speak an answer first.\";\n          return;\n        }\n\n        progress._vocabUsedText = (progress._vocabUsedText||\"\") + \" \" + ans;\n        saveProgress();\n\n        const {vocabHits, hasQuant, hasModal} = detectTargets(ans);\n        const okV = vocabHits.length >= 2;\n        const okG = hasQuant || hasModal;\n\n        let score = 0;\n        if(okV) score += 50;\n        if(okG) score += 50;\n\n        discFb.className = \"feedback \" + (score>=70 ? \"ok\":\"bad\");\n        discFb.textContent =\n          `Detected vocab: ${vocabHits.slice(0,8).join(\", \") || \"none\"}\\n` +\n          `Grammar: ${okG ? \"\u2705 target grammar detected\" : \"\u26a0\ufe0f add too much\/too many\/not enough or have to\/don't have to\/can't\"}\\n` +\n          `Score: ${score}%`;\n\n        markDone(\"discussion\", score);\n      });\n\n      \/* ========= 5) Reading ========= *\/\n      const readMatch = qs('#readMatch');\n      const readFb = qs('#readFb');\n      const readShort = qs('#readShort');\n      const readShortFb = qs('#readShortFb');\n\n      const headings = [\n        \"What people think about sugar\",\n        \"The 60-day experiment\",\n        \"Why \u201chealthy\u201d foods can be unhealthy\",\n        \"The recommendation\",\n        \"After the experiment\",\n        \"Advice for shoppers\"\n      ];\n      const headAns = {\n        \"What people think about sugar\":\"1\",\n        \"The 60-day experiment\":\"2\",\n        \"Why \u201chealthy\u201d foods can be unhealthy\":\"3\",\n        \"The recommendation\":\"4\",\n        \"After the experiment\":\"5\",\n        \"Advice for shoppers\":\"6\"\n      };\n\n      function renderReadMatch(){\n        readMatch.innerHTML = headings.map(h=>{\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${esc(h)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(headAns[h])}\">\n                <option value=\"\">Paragraph\u2026<\/option>\n                <option>1<\/option><option>2<\/option><option>3<\/option><option>4<\/option><option>5<\/option><option>6<\/option>\n              <\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderReadMatch();\n\n      const shortItems = [\n        {q:\"Which paragraph mentions a 60-day experiment?\", ans:\"2\"},\n        {q:\"Which paragraph explains why he had health problems?\", ans:\"3\"},\n        {q:\"Which paragraph gives the recommended daily limit?\", ans:\"4\"},\n        {q:\"Which paragraph tells you to check labels?\", ans:\"6\"}\n      ];\n      function renderReadShort(){\n        readShort.innerHTML = shortItems.map((it,i)=>`\n          <div class=\"qitem\">\n            <div class=\"qtext\">${i+1}) ${esc(it.q)}<\/div>\n            <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">\n              <option value=\"\">Choose\u2026<\/option>\n              <option>1<\/option><option>2<\/option><option>3<\/option><option>4<\/option><option>5<\/option><option>6<\/option>\n            <\/select>\n          <\/div>\n        `).join(\"\");\n      }\n      renderReadShort();\n\n      qs('#readCheck').addEventListener('click', ()=>{\n        let score = 0;\n\n        const q1 = qs('#rQ1');\n        const ok1 = q1.value === \"B\";\n        if(ok1) score += 40;\n        q1.style.borderColor = ok1 ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n\n        const sels = qsa('#readMatch 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        score += Math.round((correct \/ sels.length) * 60);\n\n        readFb.className = \"feedback \" + (score>=70 ? \"ok\":\"bad\");\n        readFb.textContent = `Score: ${score}%. (Main idea + headings)`;\n        markDone(\"reading\", score);\n      });\n\n      qs('#readShortCheck').addEventListener('click', ()=>{\n        const sels = qsa('#readShort 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        readShortFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        readShortFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"reading_evidence\", pct);\n      });\n\n      qs('#readTextBtn').addEventListener('click', ()=>{\n        const text = qsa('#readingText .reading-p').map(p=>p.textContent).join(\" \");\n        speak(\"Reading text. \" + text);\n      });\n\n      \/* ========= 6) Listening ========= *\/\n      const listeningScript =\n        \"Restaurant Manager: OK Marcel, what do we need to buy for next week? Do we have enough meat? \" +\n        \"Marcel: We have enough chicken and enough turkey, but we have too much lamb. And we don\u2019t have enough beef. \" +\n        \"Restaurant Manager: What about fish and seafood? \" +\n        \"Marcel: We don\u2019t have enough salmon. Tuna looks OK, we have enough. And we need to buy more shrimp. \" +\n        \"Restaurant Manager: Great. And how are we for fruit and vegetables? \" +\n        \"Marcel: We don\u2019t have many strawberries, but we have enough for next week. We have enough pineapples. \" +\n        \"But one coconut is not enough \u2014 we need more. We have lettuce, but we don\u2019t have enough eggplants. \" +\n        \"And the tomatoes last week weren\u2019t fresh enough \u2014 buy better ones.\";\n\n      const gapItems = [\n        {q:\"1) We have enough ____ and enough turkey.\", ans:\"chicken\"},\n        {q:\"2) We have too much ____.\", ans:\"lamb\"},\n        {q:\"3) We don\u2019t have enough ____.\", ans:\"beef\"},\n        {q:\"4) We don\u2019t have enough ____ (fish).\", ans:\"salmon\"},\n        {q:\"5) We need to buy more ____.\", ans:\"shrimp\"},\n        {q:\"6) We don\u2019t have many ____.\", ans:\"strawberries\"},\n        {q:\"7) One ____ is not enough.\", ans:\"coconut\"},\n        {q:\"8) We don\u2019t have enough ____.\", ans:\"eggplants\"},\n        {q:\"9) The ____ weren\u2019t fresh enough.\", ans:\"tomatoes\"},\n        {q:\"10) We have enough ____ (fish).\", ans:\"tuna\"}\n      ];\n\n      const listenGaps = qs('#listenGaps');\n      const listenFb = qs('#listenFb');\n\n      function renderListeningGaps(){\n        const wordBank = shuffle([\"chicken\",\"lamb\",\"beef\",\"salmon\",\"shrimp\",\"strawberries\",\"coconut\",\"eggplants\",\"tomatoes\",\"tuna\"]);\n        listenGaps.innerHTML =\n          `<div class=\"note\"><b>Word bank:<\/b> ${wordBank.map(w=>`<span class=\"tag\">${esc(w)}<\/span>`).join(\" \")}<\/div>` +\n          gapItems.map((it)=>{\n            const opts = ['<option value=\"\">Choose\u2026<\/option>']\n              .concat(wordBank.map(w=>`<option value=\"${esc(w)}\">${esc(w)}<\/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)}\">${opts}<\/select>\n              <\/div>\n            `;\n          }).join(\"\");\n      }\n      renderListeningGaps();\n\n      qs('#listenPlay').addEventListener('click', ()=> speak(listeningScript));\n      qs('#listenStop').addEventListener('click', stopSpeak);\n\n      qs('#listenCheck').addEventListener('click', ()=>{\n        const sels = qsa('#listenGaps 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      \/* ========= 7) Problem-solving ========= *\/\n      const probSet = qs('#probSet');\n      const probFb = qs('#probFb');\n\n      const problems = [\n        {\n          scenario: \"Scenario 1: Your lunch is too salty. What is the best solution?\",\n          choices: [\"Add more salt.\", \"Drink water and eat a fresh salad.\", \"Stop eating vegetables forever.\"],\n          correct: 1,\n          followup: \"Write ONE sentence using too \/ too much \/ too many \/ (not) enough.\"\n        },\n        {\n          scenario: \"Scenario 2: A student eats too many sweets at school. What should the school do?\",\n          choices: [\"The school can\u2019t allow sugary snacks in class.\", \"The school has to sell only candy.\", \"Students don\u2019t have to eat any food all day.\"],\n          correct: 0,\n          followup: \"Write ONE sentence using have to \/ don't have to \/ can't.\"\n        },\n        {\n          scenario: \"Scenario 3: You don\u2019t have enough time to cook. What is the best plan?\",\n          choices: [\"Buy only processed food every day.\", \"Cook simple meals with fresh ingredients on weekends.\", \"Eat nothing because you are busy.\"],\n          correct: 1,\n          followup: \"Write ONE sentence using not enough or don't have to.\"\n        }\n      ];\n\n      function renderProblems(){\n        probSet.innerHTML = problems.map((p,idx)=>{\n          const opts = p.choices.map((c,i)=>`\n            <label class=\"opt\" style=\"display:flex;gap:10px;align-items:flex-start;padding:8px 10px;border:1px solid var(--line);border-radius:12px;background:#fff;\">\n              <input type=\"radio\" name=\"prob_${idx}\" value=\"${i}\">\n              <span>${esc(c)}<\/span>\n            <\/label>\n          `).join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${idx+1}) ${esc(p.scenario)}<\/div>\n              <div class=\"stack\" style=\"gap:8px;margin-top:8px\">${opts}<\/div>\n              <div class=\"muted icte-small\" style=\"margin-top:8px\">${esc(p.followup)}<\/div>\n              <textarea class=\"textarea\" rows=\"2\" data-followup=\"${idx}\" placeholder=\"Write your sentence here...\"><\/textarea>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderProblems();\n\n      function hasTargetGrammar(txt){\n        return \/\\btoo much\\b|\\btoo many\\b|\\bnot enough\\b|\\benough\\b|\\bhave to\\b|\\bdon't have to\\b|\\bcan't\\b\/i.test(txt);\n      }\n\n      qs('#probCheck').addEventListener('click', ()=>{\n        let score = 0;\n        const total = problems.length * 2;\n\n        problems.forEach((p,idx)=>{\n          const sel = qs(`input[name=\"prob_${idx}\"]:checked`);\n          const okChoice = sel && parseInt(sel.value,10) === p.correct;\n          if(okChoice) score++;\n\n          const ta = qs(`textarea[data-followup=\"${idx}\"]`);\n          const txt = norm(ta.value);\n          const okSentence = txt.length >= 8 && hasTargetGrammar(txt);\n          if(okSentence) score++;\n\n          ta.style.borderColor = okSentence ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n        });\n\n        const pct = Math.round((score \/ total) * 100);\n        probFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        probFb.textContent =\n          `Score: ${score}\/${total} (${pct}%).\\nTip: Your sentence must include target grammar (too much\/too many\/not enough or have to\/don't have to\/can't).`;\n        markDone(\"problemsolving\", pct);\n      });\n\n      qs('#probReset').addEventListener('click', ()=>{\n        renderProblems();\n        probFb.style.display=\"none\";\n      });\n\n      \/* ========= Init ========= *\/\n      renderProgress();\n\n    })();\n  <\/script>\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Conversation Vocabulary Grammar Discussion Reading Listening Problem-solving Progress Unit 8 \u2014 Food for thought Practice too \/ too much \/<\/p>\n","protected":false},"author":1,"featured_media":722,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_layout":"default_layout","footnotes":""},"categories":[37],"tags":[],"class_list":["post-721","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-b1"],"_links":{"self":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/721","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=721"}],"version-history":[{"count":1,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/721\/revisions"}],"predecessor-version":[{"id":723,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/721\/revisions\/723"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media\/722"}],"wp:attachment":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media?parent=721"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/categories?post=721"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/tags?post=721"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}