{"id":662,"date":"2026-01-11T06:29:26","date_gmt":"2026-01-11T06:29:26","guid":{"rendered":"https:\/\/i-cte.org\/robot\/?p=662"},"modified":"2026-01-11T06:32:24","modified_gmt":"2026-01-11T06:32:24","slug":"ielts-writing-test-3","status":"publish","type":"post","link":"https:\/\/i-cte.org\/robot\/ielts-writing-test-3\/","title":{"rendered":"IELTs &#8211; Writing &#8211; Test 3"},"content":{"rendered":"\n<!-- \u2705 IELTS WRITING \u2013 TEST 3 (WP-SAFE SINGLE BLOCK) -->\n<div id=\"icte-writing-test3\">\n\n  <!-- \u2705 TOP NAV MENU (GREEN) -->\n  <nav class=\"icte-menu\" aria-label=\"IELTS practice navigation\">\n    <a href=\"https:\/\/i-cte.org\/robot\/ielts-writing-overview\/\" class=\"is-current\">Overview<\/a>\n    <a href=\"https:\/\/i-cte.org\/robot\/ielts-writing-test-1\/\">Test 1<\/a>\n    <a href=\"https:\/\/i-cte.org\/robot\/ielts-writing-test-2\/\">Test 2<\/a>\n    <a href=\"https:\/\/i-cte.org\/robot\/ielts-writing-test-3\/\">Test 3<\/a>\n    <a href=\"https:\/\/i-cte.org\/robot\/ielts-writing-test-4\/\">Test 4<\/a>\n    <a href=\"https:\/\/i-cte.org\/robot\/ielts-listening-overview\/\">Listening<\/a>\n    <a href=\"https:\/\/i-cte.org\/robot\/ielts-reading-overview\/\">Reading<\/a>\n    <a href=\"https:\/\/i-cte.org\/robot\/ielts-speaking-overview\/\">Speaking<\/a>\n  <\/nav>\n\n  <section class=\"icte-ielts\" aria-label=\"IELTS Writing Test 3\">\n\n    <!-- \u2705 HERO -->\n    <section class=\"icte-hero\" aria-label=\"Writing header\">\n      <div class=\"icte-hero__left\">\n        <div class=\"icte-badges\">\n          <span class=\"icte-badge\">IELTS Writing<\/span>\n          <span class=\"icte-badge icte-badge--blue\">Test 3<\/span>\n        <\/div>\n\n        <h2 class=\"icte-hero__title\">IELTS Writing Practice \u2013 Test 3<\/h2>\n        <p class=\"icte-hero__sub\">\n          Choose <strong>Task 1<\/strong> (20 minutes) or <strong>Task 2<\/strong> (40 minutes).\n          Use the <strong>timer<\/strong>, <strong>word count<\/strong>, <strong>band-score panel<\/strong>,\n          <strong>vocabulary bank<\/strong>, <strong>outline<\/strong>, <strong>sample answers<\/strong>, and <strong>feedback<\/strong>.\n        <\/p>\n\n        <div class=\"icte-hero__note\">\n          Tip: Task 1 needs a clear <strong>overview<\/strong> + key stages. Task 2 needs a clear <strong>position<\/strong> + reasons + examples.\n        <\/div>\n      <\/div>\n\n      <div class=\"icte-hero__right\">\n        <div class=\"icte-robotCard\" aria-label=\"Writing illustration\">\n          <img decoding=\"async\"\n            src=\"https:\/\/i-cte.org\/robot\/wp-content\/uploads\/2026\/01\/4.webp\"\n            alt=\"A friendly robot helping with IELTS writing\"\n            onerror=\"this.style.display='none';\"\n          \/>\n          <div class=\"icte-robotOverlay\">\n            <div class=\"t1\">Writing Coach<\/div>\n            <div class=\"t2\">Band \u2022 Vocab \u2022 Outline \u2022 Feedback<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"icte-heroHint\" role=\"note\">\n          <strong>Note:<\/strong> Draft autosaves in this browser (localStorage).\n        <\/div>\n      <\/div>\n    <\/section>\n\n    <!-- \u2705 TASK SELECT + TIMER -->\n    <section class=\"icte-ielts__panel\" aria-label=\"Choose task\">\n      <div class=\"icte-ielts__panelHead\">\n        <h3 class=\"icte-ielts__h3\">Choose Task<\/h3>\n        <div class=\"icte-ielts__headRight\">\n          <span class=\"icte-pill\" data-el=\"taskPill\">Task: Task 1<\/span>\n          <span class=\"icte-pill\" data-el=\"timePill\">Time: 20:00<\/span>\n          <span class=\"icte-pill\" data-el=\"wordPill\">Words: 0<\/span>\n        <\/div>\n      <\/div>\n\n      <div class=\"icte-ielts__qArea\">\n        <div class=\"icte-modeRow\">\n          <button class=\"icte-btn icte-btn--primary is-active\" type=\"button\" data-action=\"task\" data-task=\"t1\">Task 1<\/button>\n          <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"task\" data-task=\"t2\">Task 2<\/button>\n\n          <span class=\"icte-sep\"><\/span>\n\n          <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"toggle-panel\" data-panel=\"vocab\">Vocabulary &amp; Phrases<\/button>\n          <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"toggle-panel\" data-panel=\"outline\">Suggested Outline<\/button>\n        <\/div>\n\n        <div class=\"icte-timerRow\" style=\"margin-top:.85rem;\">\n          <button class=\"icte-btn icte-btn--info\" type=\"button\" data-action=\"start\">\u25b6 Start<\/button>\n          <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"pause\" disabled>\u23f8 Pause<\/button>\n          <button class=\"icte-btn icte-btn--danger\" type=\"button\" data-action=\"reset\">\u21ba Reset Timer<\/button>\n          <span class=\"icte-small\" data-el=\"timerHint\" style=\"opacity:.9\"><\/span>\n        <\/div>\n\n        <div class=\"icte-warn\" data-el=\"timeUpBox\" style=\"display:none;margin-top:.85rem;\">\n          Time is up. You can keep writing, but try to finish and quickly proofread now.\n        <\/div>\n\n        <div class=\"icte-note\" style=\"margin-top:.85rem;\">\n          <strong>Auto band\/feedback is only an estimate<\/strong>. It is not an official IELTS score.\n        <\/div>\n      <\/div>\n    <\/section>\n\n    <!-- \u2705 PROMPT -->\n    <section class=\"icte-ielts__panel\" aria-label=\"Task prompt\">\n      <div class=\"icte-ielts__panelHead\">\n        <h3 class=\"icte-ielts__h3\">Task Prompt<\/h3>\n        <div class=\"icte-ielts__headRight\">\n          <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"toggle-prompt\">Hide Prompt<\/button>\n        <\/div>\n      <\/div>\n      <div class=\"icte-ielts__reading\" data-el=\"promptArea\"><\/div>\n    <\/section>\n\n    <!-- \u2705 RESOURCE PANELS -->\n    <section class=\"icte-ielts__panel\" aria-label=\"Learning tools\">\n      <div class=\"icte-ielts__panelHead\">\n        <h3 class=\"icte-ielts__h3\">Learning Tools<\/h3>\n        <div class=\"icte-ielts__headRight\">\n          <span class=\"icte-pill\" data-el=\"openPanelPill\">Open: None<\/span>\n        <\/div>\n      <\/div>\n\n      <div class=\"icte-ielts__qArea\">\n        <div class=\"icte-accordion\">\n\n          <!-- VOCAB -->\n          <div class=\"icte-accItem\" data-panel=\"vocab\">\n            <div class=\"icte-accTop\">\n              <div class=\"icte-accTitle\">Vocabulary &amp; Phrases (study only)<\/div>\n              <div class=\"icte-accHint\">Tip: Use 2\u20134 strong phrases naturally (don\u2019t overuse).<\/div>\n            <\/div>\n            <div class=\"icte-card\" data-el=\"vocabArea\"><\/div>\n          <\/div>\n\n          <!-- OUTLINE -->\n          <div class=\"icte-accItem\" data-panel=\"outline\">\n            <div class=\"icte-accTop\">\n              <div class=\"icte-accTitle\">Suggested Outline (structure to copy)<\/div>\n              <div class=\"icte-accHint\">Tip: Clear structure improves Coherence &amp; Cohesion.<\/div>\n            <\/div>\n            <div class=\"icte-card\" data-el=\"outlineArea\"><\/div>\n          <\/div>\n\n          <!-- SAMPLES -->\n          <div class=\"icte-accItem\" data-panel=\"samples\">\n            <div class=\"icte-accTop\">\n              <div class=\"icte-accTitle\">Sample Answers<\/div>\n              <div class=\"icte-accHint\">Tip: Study structure (don\u2019t memorise).<\/div>\n            <\/div>\n            <div class=\"icte-card\" data-el=\"samplesArea\"><\/div>\n          <\/div>\n\n          <!-- BAND -->\n          <div class=\"icte-accItem\" data-panel=\"band\">\n            <div class=\"icte-accTop\">\n              <div class=\"icte-accTitle\">Band Score Panel (Auto-estimate + Self-adjust)<\/div>\n              <div class=\"icte-accHint\">Official IELTS uses 4 criteria; this is a practice tool.<\/div>\n            <\/div>\n\n            <div class=\"icte-scoreWrap\">\n              <div class=\"icte-scoreGrid\">\n                <div class=\"icte-scoreItem\">\n                  <div class=\"k\">Task Achievement \/ Task Response<\/div>\n                  <input class=\"icte-range\" type=\"range\" min=\"0\" max=\"9\" step=\"0.5\" value=\"0\" data-crit=\"ta\">\n                  <div class=\"v\"><span data-el=\"taVal\">0<\/span> \/ 9<\/div>\n                <\/div>\n                <div class=\"icte-scoreItem\">\n                  <div class=\"k\">Coherence &amp; Cohesion<\/div>\n                  <input class=\"icte-range\" type=\"range\" min=\"0\" max=\"9\" step=\"0.5\" value=\"0\" data-crit=\"cc\">\n                  <div class=\"v\"><span data-el=\"ccVal\">0<\/span> \/ 9<\/div>\n                <\/div>\n                <div class=\"icte-scoreItem\">\n                  <div class=\"k\">Lexical Resource<\/div>\n                  <input class=\"icte-range\" type=\"range\" min=\"0\" max=\"9\" step=\"0.5\" value=\"0\" data-crit=\"lr\">\n                  <div class=\"v\"><span data-el=\"lrVal\">0<\/span> \/ 9<\/div>\n                <\/div>\n                <div class=\"icte-scoreItem\">\n                  <div class=\"k\">Grammar Range &amp; Accuracy<\/div>\n                  <input class=\"icte-range\" type=\"range\" min=\"0\" max=\"9\" step=\"0.5\" value=\"0\" data-crit=\"gra\">\n                  <div class=\"v\"><span data-el=\"graVal\">0<\/span> \/ 9<\/div>\n                <\/div>\n              <\/div>\n\n              <div class=\"icte-scoreActions\">\n                <button class=\"icte-btn icte-btn--primary\" type=\"button\" data-action=\"score-writing\">Score Writing<\/button>\n                <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"reset-band\">Reset scores<\/button>\n                <span class=\"icte-pill icte-pill--big\" data-el=\"overallBand\">Overall: \u2014<\/span>\n              <\/div>\n\n              <div class=\"icte-note\" style=\"margin-top:.75rem;\">\n                Tip: After \u201cScore Writing\u201d, you can still move the sliders manually. The Overall band updates automatically.\n              <\/div>\n            <\/div>\n          <\/div>\n\n        <\/div>\n      <\/div>\n    <\/section>\n\n    <!-- \u2705 WRITING AREA + FEEDBACK -->\n    <section class=\"icte-ielts__panel\" aria-label=\"Write your answer\">\n      <div class=\"icte-ielts__panelHead\">\n        <h3 class=\"icte-ielts__h3\">Your Writing<\/h3>\n        <div class=\"icte-ielts__headRight\">\n          <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"copy\">Copy<\/button>\n          <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"download\">Download (.txt)<\/button>\n          <span class=\"icte-loader\" data-el=\"loader\" aria-hidden=\"true\"><\/span>\n        <\/div>\n      <\/div>\n\n      <div class=\"icte-ielts__qArea\">\n        <div class=\"icte-grid2\">\n          <div>\n            <div class=\"icte-small\">\n              <strong>Draft (autosaves)<\/strong> \u2014 write your essay here (no sample answer will appear in this box).\n            <\/div>\n\n            <textarea class=\"icte-textarea\" data-el=\"draft\" rows=\"14\" spellcheck=\"true\"\n              placeholder=\"Start writing here...\"><\/textarea>\n\n            <div class=\"icte-miniRow\">\n              <span class=\"icte-small\">Min words: <strong data-el=\"minWords\">150<\/strong><\/span>\n              <span class=\"icte-small\">Paragraphs: <strong data-el=\"paraCount\">0<\/strong><\/span>\n              <span class=\"icte-small\">Sentences: <strong data-el=\"sentCount\">0<\/strong><\/span>\n            <\/div>\n\n            <div class=\"icte-check\" data-el=\"lengthWarn\" style=\"display:none;\">\n              You are under the minimum word count. Add more details\/examples.\n            <\/div>\n\n            <div class=\"icte-actionRow\" style=\"margin-top:.85rem;\">\n              <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"toggle-panel\" data-panel=\"samples\">Sample Answers<\/button>\n              <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"toggle-panel\" data-panel=\"band\">Band Score<\/button>\n              <button class=\"icte-btn icte-btn--dark\" type=\"button\" data-action=\"clear\" title=\"Clears current task text only\">Clear task<\/button>\n\n              <span class=\"icte-sep\"><\/span>\n\n              <button class=\"icte-btn icte-btn--primary\" type=\"button\" data-action=\"feedback\">Get Feedback<\/button>\n              <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"copy-feedback\">Copy Feedback<\/button>\n              <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"download-feedback\">Download Feedback (.txt)<\/button>\n            <\/div>\n          <\/div>\n\n          <div>\n            <div class=\"icte-small\"><strong>Feedback<\/strong><\/div>\n            <div class=\"icte-card\" data-el=\"feedbackBox\">\n              <div class=\"icte-small\" data-el=\"feedbackText\" style=\"opacity:.92\">\n                Click <strong>Get Feedback<\/strong> after writing at least 120\u2013150 words.\n              <\/div>\n            <\/div>\n\n            <div class=\"icte-small\" style=\"margin-top:.85rem;\"><strong>Quick Checklist<\/strong><\/div>\n            <div class=\"icte-card\">\n              <ul class=\"icte-ul\">\n                <li><strong>Task 1:<\/strong> Intro + overview + describe key stages in order.<\/li>\n                <li><strong>Task 2:<\/strong> Clear position + develop 2\u20133 reasons + examples + conclusion.<\/li>\n                <li>Use linking words and topic sentences.<\/li>\n                <li>Proofread: tense, articles, agreement, punctuation.<\/li>\n              <\/ul>\n            <\/div>\n          <\/div>\n        <\/div>\n\n      <\/div>\n    <\/section>\n\n  <\/section>\n\n  <!-- \u2705 CSS (scoped) -->\n  <style>\n    #icte-writing-test3, #icte-writing-test3 *{ box-sizing:border-box; }\n    #icte-writing-test3{ font-family: Arial, sans-serif; font-size:14px; line-height:1.7; color:#0f172a; width:100%; max-width:100%; }\n\n    #icte-writing-test3 .icte-menu{\n      width:100%;\n      display:flex; flex-wrap:wrap; gap:.5rem; justify-content:center; align-items:center;\n      padding:.8rem .95rem; margin:0 0 1rem 0;\n      background:#16a34a; border-radius:14px; box-shadow:0 2px 8px rgba(0,0,0,.10);\n    }\n    #icte-writing-test3 .icte-menu a{\n      display:inline-block; text-decoration:none; font-weight:900; font-size:1rem; color:#fff;\n      padding:.6rem .9rem; border-radius:999px; border:1px solid rgba(255,255,255,.35);\n      background:rgba(255,255,255,.12);\n    }\n    #icte-writing-test3 .icte-menu a.is-current{ background:rgba(255,255,255,.22); }\n\n    #icte-writing-test3 .icte-ielts__panel{\n      border:1px solid rgba(0,0,0,.10); border-radius:14px; background:rgba(255,255,255,.85);\n      overflow:hidden; margin-bottom:1rem;\n    }\n    #icte-writing-test3 .icte-ielts__panelHead{\n      display:flex; align-items:center; justify-content:space-between; gap:.75rem;\n      padding:.9rem 1rem; border-bottom:1px solid rgba(0,0,0,.08); background:rgba(0,0,0,.03);\n      flex-wrap:wrap;\n    }\n    #icte-writing-test3 .icte-ielts__h3{ margin:0; font-weight:900; font-size:1.1rem; }\n    #icte-writing-test3 .icte-ielts__headRight{ display:flex; gap:.55rem; align-items:center; flex-wrap:wrap; }\n    #icte-writing-test3 .icte-ielts__reading{ padding:1rem 1rem 1.05rem; }\n    #icte-writing-test3 .icte-ielts__qArea{ padding:1rem 1rem 1.05rem; }\n\n    #icte-writing-test3 .icte-btn{\n      appearance:none; border:1px solid transparent; border-radius:12px;\n      padding:.7rem .95rem; font-weight:900; cursor:pointer; font:inherit; font-size:1rem;\n      transition: transform .12s ease, filter .12s ease, box-shadow .12s ease, background-color .12s ease, border-color .12s ease;\n      will-change: transform;\n    }\n    #icte-writing-test3 .icte-btn:hover{ transform: translateY(-1px); filter: brightness(1.03); box-shadow: 0 8px 18px rgba(0,0,0,.10); }\n    #icte-writing-test3 .icte-btn:active{ transform: translateY(0px) scale(0.99); box-shadow: 0 5px 12px rgba(0,0,0,.08); filter: brightness(0.98); }\n    #icte-writing-test3 .icte-btn:focus-visible{ outline: 3px solid rgba(14,165,233,.45); outline-offset: 2px; }\n    #icte-writing-test3 .icte-btn:disabled{ opacity:.55; cursor:not-allowed; }\n\n    #icte-writing-test3 .icte-btn--primary{ background:#16a34a; color:#fff; }\n    #icte-writing-test3 .icte-btn--info{ background:#0ea5e9; color:#fff; }\n    #icte-writing-test3 .icte-btn--danger{ background:#dc2626; color:#fff; }\n    #icte-writing-test3 .icte-btn--dark{ background:#334155; color:#fff; }\n    #icte-writing-test3 .icte-btn--ghost{ background:transparent; border-color:rgba(0,0,0,.20); color:inherit; }\n\n    #icte-writing-test3 .icte-pill{\n      display:inline-block; padding:.3rem .65rem; border-radius:999px;\n      border:1px solid rgba(0,0,0,.12); background:rgba(255,255,255,.75);\n      font-weight:900;\n    }\n    #icte-writing-test3 .icte-pill--big{ padding:.45rem .75rem; }\n\n    #icte-writing-test3 .icte-small{ font-size:1rem; opacity:.88; }\n    #icte-writing-test3 .icte-modeRow, #icte-writing-test3 .icte-timerRow{ display:flex; gap:.6rem; flex-wrap:wrap; align-items:center; }\n    #icte-writing-test3 .icte-grid2{ display:grid; grid-template-columns:1fr 1fr; gap:.85rem; }\n    @media (max-width: 900px){ #icte-writing-test3 .icte-grid2{ grid-template-columns:1fr; } }\n\n    #icte-writing-test3 .icte-sep{ width:1px; height:30px; background:rgba(0,0,0,.12); display:inline-block; margin:0 .2rem; }\n    @media (max-width: 720px){ #icte-writing-test3 .icte-sep{ display:none; } }\n\n    #icte-writing-test3 .icte-textarea{\n      width:100%; border-radius:14px; border:1px solid rgba(0,0,0,.12);\n      background:rgba(255,255,255,.80); padding:.95rem 1rem; font:inherit;\n      font-size:1.05rem; line-height:1.75; resize:vertical; min-height:220px;\n    }\n\n    #icte-writing-test3 .icte-miniRow{ margin-top:.55rem; display:flex; gap:.75rem; flex-wrap:wrap; }\n    #icte-writing-test3 .icte-actionRow{ display:flex; gap:.6rem; flex-wrap:wrap; align-items:center; }\n\n    #icte-writing-test3 .icte-check{\n      margin-top:.75rem; border:1px solid rgba(245,158,11,.35);\n      background:rgba(254,243,199,.65); border-radius:14px; padding:.75rem .85rem;\n      color:#7c2d12; font-weight:900;\n    }\n    #icte-writing-test3 .icte-card{\n      border:1px solid rgba(0,0,0,.10); border-radius:14px;\n      background:rgba(255,255,255,.75); padding:.85rem .95rem;\n    }\n    #icte-writing-test3 .icte-ul{ margin:.4rem 0 0 1.1rem; }\n    #icte-writing-test3 .icte-ul li{ margin:.35rem 0; }\n\n    #icte-writing-test3 .icte-note{\n      border:1px solid rgba(14,165,233,.22);\n      background: rgba(14,165,233,.10);\n      color:#1e3a8a;\n      border-radius:14px;\n      padding:.75rem .85rem;\n    }\n\n    #icte-writing-test3 .icte-accordion{ display:flex; flex-direction:column; gap:.85rem; }\n    #icte-writing-test3 .icte-accItem{\n      border:1px solid rgba(0,0,0,.10);\n      border-radius:14px;\n      background:rgba(255,255,255,.70);\n      padding:.85rem .95rem;\n      display:none !important;\n    }\n    #icte-writing-test3 .icte-accItem.is-open{ display:block !important; }\n    #icte-writing-test3 .icte-accTop{\n      display:flex; align-items:flex-start; justify-content:space-between; gap:.75rem; flex-wrap:wrap;\n      margin-bottom:.65rem;\n    }\n    #icte-writing-test3 .icte-accTitle{ font-weight:1000; font-size:1.05rem; }\n    #icte-writing-test3 .icte-accHint{ opacity:.85; }\n\n    #icte-writing-test3 .icte-chipRow{ display:flex; flex-wrap:wrap; gap:.5rem; margin-top:.45rem; }\n    #icte-writing-test3 .icte-chip{\n      display:inline-flex; gap:.45rem; align-items:center;\n      border:1px solid rgba(0,0,0,.12);\n      background:#fff;\n      border-radius:999px;\n      padding:.35rem .55rem;\n      font-weight:900;\n    }\n\n    #icte-writing-test3 .icte-scoreWrap{\n      border:1px solid rgba(14,165,233,.18);\n      background:rgba(219,234,254,.45);\n      border-radius:14px;\n      padding:.95rem 1rem;\n    }\n    #icte-writing-test3 .icte-scoreGrid{\n      display:grid;\n      grid-template-columns:repeat(2, minmax(0,1fr));\n      gap:.75rem;\n    }\n    @media (max-width: 760px){ #icte-writing-test3 .icte-scoreGrid{ grid-template-columns:1fr; } }\n    #icte-writing-test3 .icte-scoreItem{\n      border:1px solid rgba(0,0,0,.10);\n      background:#fff;\n      border-radius:14px;\n      padding:.75rem .85rem;\n    }\n    #icte-writing-test3 .icte-scoreItem .k{ font-weight:1000; }\n    #icte-writing-test3 .icte-scoreItem .v{ opacity:.88; margin-top:.25rem; font-weight:900; }\n    #icte-writing-test3 .icte-range{ width:100%; }\n    #icte-writing-test3 .icte-scoreActions{ display:flex; gap:.6rem; flex-wrap:wrap; align-items:center; margin-top:.85rem; }\n\n    #icte-writing-test3 .icte-warn{\n      border:1px solid #fecaca; background:#fff5f5; color:#7f1d1d;\n      border-radius:14px; padding:.85rem .95rem;\n    }\n\n    \/* Prompt image *\/\n    #icte-writing-test3 .icte-promptBox h4{ margin:.1rem 0 .35rem; font-weight:1000; }\n    #icte-writing-test3 .icte-promptImg{\n      margin-top:.75rem; width:100%; max-width:860px; height:auto;\n      border-radius:14px; border:1px solid rgba(0,0,0,.10); display:block;\n    }\n\n    #icte-writing-test3 .icte-loader{\n      width:14px; height:14px; border-radius:50%;\n      border:2px solid rgba(0,0,0,.18);\n      border-top-color: rgba(0,0,0,.55);\n      display:none; animation: icteSpin .8s linear infinite;\n    }\n    @keyframes icteSpin{ to{ transform:rotate(360deg);} }\n\n    \/* Hero *\/\n    #icte-writing-test3 .icte-hero{\n      display:grid;\n      grid-template-columns: 1.1fr .9fr;\n      gap:14px;\n      align-items:stretch;\n      border:1px solid rgba(0,0,0,.10);\n      border-radius:16px;\n      padding:14px;\n      margin-bottom:14px;\n      background:\n        radial-gradient(900px 300px at 20% -10%, rgba(34,197,94,.18), transparent 60%),\n        radial-gradient(900px 300px at 100% 0%, rgba(14,165,233,.14), transparent 55%),\n        rgba(255,255,255,.85);\n      box-shadow:0 10px 24px rgba(0,0,0,.06);\n    }\n    @media (max-width: 980px){ #icte-writing-test3 .icte-hero{ grid-template-columns:1fr; } }\n    #icte-writing-test3 .icte-badges{ display:flex; gap:8px; flex-wrap:wrap; margin-bottom:8px; }\n    #icte-writing-test3 .icte-badge{\n      display:inline-block;\n      padding:.35rem .7rem;\n      border-radius:999px;\n      font-weight:1000;\n      color:#064e3b;\n      background:rgba(34,197,94,.14);\n      border:1px solid rgba(34,197,94,.25);\n    }\n    #icte-writing-test3 .icte-badge--blue{\n      color:#1e3a8a;\n      background:rgba(14,165,233,.12);\n      border-color:rgba(14,165,233,.20);\n    }\n    #icte-writing-test3 .icte-hero__title{ margin:0 0 6px; font-weight:1000; color:#0f5132; font-size:1.35rem; }\n    #icte-writing-test3 .icte-hero__sub{ margin:0; color:#334155; opacity:.95; }\n    #icte-writing-test3 .icte-hero__note{\n      margin-top:10px;\n      color:#334155;\n      padding:.65rem .8rem;\n      border-radius:14px;\n      border:1px solid rgba(34,197,94,.22);\n      background:rgba(240,253,244,.85);\n    }\n    #icte-writing-test3 .icte-robotCard{\n      position:relative;\n      border-radius:16px;\n      overflow:hidden;\n      border:1px solid rgba(0,0,0,.10);\n      background:#f8fafc;\n      min-height: 260px;\n      box-shadow:0 12px 22px rgba(0,0,0,.08);\n    }\n    #icte-writing-test3 .icte-robotCard img{ width:100%; height:100%; object-fit:cover; display:block; }\n    #icte-writing-test3 .icte-robotOverlay{\n      position:absolute; left:0; right:0; bottom:0;\n      padding:12px 14px;\n      background: linear-gradient(180deg, transparent, rgba(2,6,23,.65));\n      color:#fff;\n    }\n    #icte-writing-test3 .icte-robotOverlay .t1{ font-weight:1000; font-size:1.05rem; }\n    #icte-writing-test3 .icte-robotOverlay .t2{ font-size:.95rem; opacity:.92; }\n    #icte-writing-test3 .icte-heroHint{\n      margin-top:10px;\n      border-radius:14px;\n      border:1px solid rgba(14,165,233,.22);\n      background: rgba(14,165,233,.10);\n      color:#1e3a8a;\n      padding:.75rem .85rem;\n    }\n  <\/style>\n\n  <script>\n  (function(){\n    function init(){\n      const root = document.getElementById(\"icte-writing-test3\");\n      if(!root) return;\n      if(root.__icteInited) return;\n      root.__icteInited = true;\n\n      const $ = (sel, base)=> (base||root).querySelector(sel);\n      const $$ = (sel, base)=> Array.from((base||root).querySelectorAll(sel));\n\n      function escapeHtml(str){\n        return (str||\"\")\n          .replace(\/&\/g,\"&amp;\").replace(\/<\/g,\"&lt;\").replace(\/>\/g,\"&gt;\")\n          .replace(\/\"\/g,\"&quot;\").replace(\/'\/g,\"&#039;\");\n      }\n\n      \/\/ \u2705 IMPORTANT (Test 3): Upload the geothermal diagram image to WordPress Media,\n      \/\/ then paste its URL here:\n      const IMG_TASK1 = \"https:\/\/i-cte.org\/robot\/wp-content\/uploads\/2026\/01\/W3a.png\";\n      \/\/ Task 2 has no required image. Leave blank unless you want to add one.\n      const IMG_TASK2 = \"https:\/\/i-cte.org\/robot\/wp-content\/uploads\/2025\/12\/2.webp\";\n\n      const TASKS = {\n        t1:{ key:\"t1\", label:\"Task 1\", seconds:20*60, minWords:150,\n          promptHtml: `\n            <div class=\"icte-promptBox\">\n              <h4>WRITING TASK 1<\/h4>\n              <div>You should spend about <strong>20 minutes<\/strong> on this task.<\/div>\n              <div style=\"margin-top:.55rem;\">\n                The diagram below shows how geothermal energy is used to produce electricity.\n              <\/div>\n              <div style=\"margin-top:.55rem;\">\n                <strong>Summarise<\/strong> the information by selecting and reporting the main features, and make comparisons where relevant.\n              <\/div>\n              <div style=\"margin-top:.55rem;\"><strong>Write at least 150 words.<\/strong><\/div>\n\n              ${IMG_TASK1 && IMG_TASK1.indexOf(\"REPLACE_\") === -1 ? `\n                <img decoding=\"async\" class=\"icte-promptImg\"\n                     src=\"${escapeHtml(IMG_TASK1)}\"\n                     alt=\"Geothermal power plant diagram\"\n                     onerror=\"this.style.display='none';\" \/>\n              ` : `\n                <div class=\"icte-note\" style=\"margin-top:.75rem;\">\n                  <strong>Admin note:<\/strong> Add the Task 1 diagram image URL in the code (IMG_TASK1) to show it here.\n                <\/div>\n              `}\n            <\/div>\n          `\n        },\n        t2:{ key:\"t2\", label:\"Task 2\", seconds:40*60, minWords:250,\n          promptHtml: `\n            <div class=\"icte-promptBox\">\n              <h4>WRITING TASK 2<\/h4>\n              <div>You should spend about <strong>40 minutes<\/strong> on this task.<\/div>\n              <div style=\"margin-top:.55rem;\"><strong>Write about the following topic:<\/strong><\/div>\n\n              <div style=\"margin-top:.55rem;\">\n                Some people believe that allowing children to make their own choices on everyday matters (such as food, clothes and entertainment) is likely to result in a society of individuals who only think about their own wishes.\n                Other people believe that it is important for children to make decisions about matters that affect them.\n              <\/div>\n\n              <div style=\"margin-top:.55rem;\"><strong>Discuss both these views and give your own opinion.<\/strong><\/div>\n              <div style=\"margin-top:.55rem;\"><strong>Write at least 250 words.<\/strong><\/div>\n\n              ${IMG_TASK2 ? `\n                <img decoding=\"async\" class=\"icte-promptImg\"\n                     src=\"${escapeHtml(IMG_TASK2)}\"\n                     alt=\"Task 2 image\"\n                     onerror=\"this.style.display='none';\" \/>\n              ` : ``}\n            <\/div>\n          `\n        }\n      };\n\n      const RES = {\n        t1:{\n          vocab:[\n            { cat:\"Process language (Task 1)\", items:[\"overall\",\"at the first stage\",\"subsequently\",\"thereafter\",\"finally\",\"the process begins with...\",\"this is followed by...\"] },\n            { cat:\"Geothermal terms\", items:[\"injection well\",\"production well\",\"geothermal zone\",\"hot rocks\",\"fissures\",\"condenser \/ heat exchanger\",\"steam\",\"turbine\",\"generator\"] },\n            { cat:\"High-band verbs\", items:[\"is pumped\",\"is forced down\",\"is heated\",\"is converted into\",\"is directed to\",\"drives\",\"powers\",\"is transmitted\"] }\n          ],\n          outline: `\n<strong>Task 1 Outline: Process Diagram<\/strong>\n<ul class=\"icte-ul\">\n  <li><strong>Introduction:<\/strong> Paraphrase what the diagram shows.<\/li>\n  <li><strong>Overview:<\/strong> 2 sentences: number of stages + start\/end points.<\/li>\n  <li><strong>Body 1:<\/strong> Early stages (cold water \u2192 geothermal zone \u2192 hot water).<\/li>\n  <li><strong>Body 2:<\/strong> Final stages (condenser\/steam \u2192 turbine \u2192 generator\/electricity).<\/li>\n<\/ul>`.trim(),\n          sample: `\n<strong>Sample Answer (Task 1)<\/strong>\n<div class=\"icte-small\" style=\"opacity:.85;margin-bottom:.45rem;\">Study structure (do not memorise).<\/div>\n<pre style=\"white-space:pre-wrap;margin:0;\">\nThe diagram illustrates how electricity is generated in a geothermal power plant using underground heat.\nOverall, the process involves five main stages. Cold water is pumped deep below the ground, heated by hot rocks in the geothermal zone, brought back to the surface as hot water, and then converted into steam to drive a turbine connected to a generator.\nFirst, cold water from a storage tank is forced down about 4.5 kilometres through an injection well. It then enters the geothermal zone, where it passes through fissures in hot rocks and absorbs heat. Next, the heated water is pumped back up to the surface via a separate production well. At this point, it flows into a condenser (or heat-exchange chamber), where it is transformed into steam. The steam is directed to a turbine, causing the blades to spin. Finally, the rotating turbine powers a generator, which produces electricity that can be transmitted to the grid.\nIn conclusion, geothermal power plants generate electricity by circulating water through hot underground rocks and using the resulting steam energy to operate a turbine\u2013generator system.\n<\/pre>`.trim()\n        },\n        t2:{\n          vocab:[\n            { cat:\"Opinion language (Task 2)\", items:[\"in my view\",\"i would argue\",\"it is preferable to\",\"to some extent\",\"provided that\",\"the key is...\",\"a balanced approach\"] },\n            { cat:\"Discuss both views\", items:[\"supporters claim that...\",\"opponents argue that...\",\"one concern is...\",\"however\",\"on the other hand\",\"nevertheless\"] },\n            { cat:\"Useful collocations\", items:[\"age-appropriate choices\",\"clear boundaries\",\"self-control\",\"unrealistic expectations\",\"non-negotiable rules\",\"freedom with accountability\"] }\n          ],\n          outline: `\n<strong>Task 2 Outline: Discuss both views + opinion<\/strong>\n<ul class=\"icte-ul\">\n  <li><strong>Introduction:<\/strong> Paraphrase + state your opinion.<\/li>\n  <li><strong>Body 1:<\/strong> View 1 (selfishness risk) + example.<\/li>\n  <li><strong>Body 2:<\/strong> View 2 (learning responsibility) + example.<\/li>\n  <li><strong>Conclusion:<\/strong> Restate opinion + condition (boundaries).<\/li>\n<\/ul>`.trim(),\n          sample: `\n<strong>Sample Answer (Task 2)<\/strong>\n<div class=\"icte-small\" style=\"opacity:.85;margin-bottom:.45rem;\">Study argument balance (do not memorise).<\/div>\n<pre style=\"white-space:pre-wrap;margin:0;\">\nSome people argue that giving children freedom to choose everyday things\u2014such as what to eat, wear, or watch\u2014will encourage selfishness. Others believe children should make decisions about matters that affect them. In my view, allowing age-appropriate choices is beneficial, provided that parents set clear boundaries and teach children to consider others.\nThose who oppose child autonomy often point to the risk of indulgence. If children always get what they want, they may prioritise personal comfort over family needs. For example, a child who insists on expensive brands or refuses healthy meals can create conflict at home and develop unrealistic expectations. Moreover, when entertainment choices are unlimited, children may gravitate towards screen-based activities and ignore responsibilities. In this sense, constant permission without guidance can produce impulsive behaviour and a \u201cme first\u201d attitude.\nHowever, supporters of child decision-making emphasise that choice is essential for learning. Small decisions help children practise responsibility, understand consequences, and develop self-control. Selecting clothing, for instance, teaches them to plan for the weather and social context, while choosing hobbies can build motivation and confidence. Importantly, making choices does not have to be individualistic. Parents can encourage children to weigh options that also respect others, such as taking turns picking a family movie or agreeing on meals that suit everyone\u2019s health needs.\nIn my opinion, the key is balanced autonomy. Children should be offered limited, meaningful choices within non-negotiable rules related to safety, health, and respect. When adults explain reasons and model empathy, children learn that freedom comes with accountability.\nIn conclusion, letting children decide on everyday matters is more likely to produce responsible, thoughtful adults than selfish individuals, as long as it is guided by firm and caring boundaries.\n<\/pre>`.trim()\n        }\n      };\n\n      \/\/ ===== State =====\n      let currentTaskKey = \"t1\";\n      let timer = null;\n      let running = false;\n      let remaining = TASKS[currentTaskKey].seconds;\n      let promptVisible = true;\n      let openPanel = \"none\";\n      let panelRendered = { vocab:false, outline:false, samples:false };\n\n      const draftEl = $('[data-el=\"draft\"]');\n      const promptArea = $('[data-el=\"promptArea\"]');\n\n      \/\/ \u2705 Safety: never allow Sample Answer text to appear in the Draft box\n      function purgeSampleFromDraft(){\n        const markers = [\n          \"Sample Answer\",\n          \"The diagram illustrates how electricity is generated\",\n          \"Some people argue that giving children freedom\"\n        ];\n\n        const cur = (draftEl.value || \"\").trim();\n        if(markers.some(m => cur.indexOf(m) !== -1)){\n          draftEl.value = \"\";\n        }\n\n        try{\n          [\"t1\",\"t2\"].forEach(k=>{\n            const key = \"icte_writing_test3_\" + k;\n            const saved = (localStorage.getItem(key) || \"\").trim();\n            if(markers.some(m => saved.indexOf(m) !== -1)){\n              localStorage.removeItem(key);\n            }\n          });\n        }catch(e){}\n      }\n      purgeSampleFromDraft();\n\n      \/\/ ===== Band helpers =====\n      const BAND = { ta:\"taVal\", cc:\"ccVal\", lr:\"lrVal\", gra:\"graVal\" };\n      function clamp(n,min,max){ return Math.min(max, Math.max(min,n)); }\n      function roundHalf(n){ return Math.round(n*2)\/2; }\n      function toNum(x){ const n = parseFloat(x); return Number.isFinite(n) ? n : 0; }\n\n      function updateOverall(){\n        const overallEl = $('[data-el=\"overallBand\"]');\n        if(!overallEl) return;\n        const vals = [\"ta\",\"cc\",\"lr\",\"gra\"].map(k=>{\n          const input = root.querySelector(`input[data-crit=\"${k}\"]`);\n          return input ? toNum(input.value) : 0;\n        });\n        const hasAny = vals.some(v=>v>0);\n        if(!hasAny){ overallEl.textContent = \"Overall: \u2014\"; return; }\n        const avg = vals.reduce((a,b)=>a+b,0)\/vals.length;\n        overallEl.textContent = \"Overall: \" + String(roundHalf(avg)).replace(\/\\.0$\/,\"\");\n      }\n      function setCrit(k,val){\n        const input = root.querySelector(`input[data-crit=\"${k}\"]`);\n        const out = root.querySelector(`[data-el=\"${BAND[k]}\"]`);\n        if(!input || !out) return;\n        val = roundHalf(clamp(val,0,9));\n        input.value = String(val);\n        out.textContent = String(val);\n        updateOverall();\n      }\n      function resetBand(){\n        [\"ta\",\"cc\",\"lr\",\"gra\"].forEach(k=>setCrit(k,0));\n        const overallEl = $('[data-el=\"overallBand\"]');\n        if(overallEl) overallEl.textContent = \"Overall: \u2014\";\n      }\n\n      \/\/ ===== Counts \/ analysis =====\n      function wordsCount(text){\n        const t = (text||\"\").trim();\n        if(!t) return 0;\n        return t.split(\/\\s+\/).filter(Boolean).length;\n      }\n      function paraCount(text){\n        const blocks = (text||\"\").trim().split(\/\\n\\s*\\n\/).filter(b=>b.trim().length>0);\n        return blocks.length;\n      }\n      function sentCount(text){\n        const t = (text||\"\").replace(\/\\s+\/g,\" \").trim();\n        if(!t) return 0;\n        const m = t.match(\/[.!?]+\/g);\n        return m ? m.length : 0;\n      }\n      function countLinkers(text){\n        const re = \/\\b(however|therefore|moreover|furthermore|in addition|also|on the other hand|on the one hand|nevertheless|in contrast|by contrast|consequently|as a result|for example|for instance|overall|in summary|to conclude|in conclusion|despite|provided that)\\b\/gi;\n        const m = (text||\"\").match(re);\n        return m ? m.length : 0;\n      }\n      function avgSentenceLen(text){\n        const s = (text||\"\").split(\/[.!?]+\/).map(x=>x.trim()).filter(Boolean);\n        if(!s.length) return 0;\n        const lens = s.map(x=>wordsCount(x));\n        return lens.reduce((a,b)=>a+b,0)\/lens.length;\n      }\n      function tokenize(text){\n        return (text||\"\").toLowerCase().replace(\/[^a-z0-9'\\s]\/g,\" \").split(\/\\s+\/).filter(Boolean);\n      }\n      function varietyScore(text){\n        const toks = tokenize(text);\n        if(toks.length < 40) return 0;\n        const uniq = new Set(toks).size;\n        return uniq \/ toks.length;\n      }\n\n      \/\/ \u2705 Band-9-capable estimator (more appropriate heuristics)\n      function estimateBand(){\n        const text = draftEl.value || \"\";\n        const w = wordsCount(text);\n        const p = paraCount(text);\n        const s = sentCount(text);\n        const link = countLinkers(text);\n        const asl = avgSentenceLen(text);\n        const v = varietyScore(text);\n        const toks = tokenize(text);\n        const longWords = toks.filter(t=>t.length>=9).length;\n        const minW = TASKS[currentTaskKey].minWords;\n\n        const hasNumbers = \/(\\d{2,}|\\d+\\.\\d+|%)\/.test(text);\n        const hasYears = \/\\b(19|20)\\d{2}\\b\/.test(text);\n        const hasOverview = \/\\b(overall|in general|it is clear that|generally)\\b\/i.test(text);\n        const hasOpinion = \/\\b(i believe|in my view|i think|my opinion|i would argue)\\b\/i.test(text);\n        const hasConclusion = \/\\b(in conclusion|to conclude|overall)\\b\/i.test(text);\n        const hasExamples = \/\\b(for example|for instance|such as)\\b\/i.test(text);\n\n        const hasCompare = \/\\b(whereas|while|compared with|in contrast|by contrast|higher than|lower than|more than|less than)\\b\/i.test(text);\n        const hasTrendVerbs = \/\\b(increased|rose|grew|fell|declined|dropped|peaked|remained|fluctuated|is pumped|is heated|is converted)\\b\/i.test(text);\n\n        \/\/ repetition proxy\n        const stop = new Set([\"the\",\"a\",\"an\",\"and\",\"or\",\"but\",\"so\",\"to\",\"of\",\"in\",\"on\",\"for\",\"with\",\"as\",\"at\",\"by\",\"from\",\"that\",\"this\",\"these\",\"those\",\"is\",\"are\",\"was\",\"were\",\"be\",\"been\",\"being\",\"it\",\"they\",\"we\",\"i\",\"you\",\"he\",\"she\",\"them\",\"us\",\"our\"]);\n        const contentWords = toks.filter(t=>t.length>2 && !stop.has(t));\n        const freq = {};\n        contentWords.forEach(t=>freq[t]=(freq[t]||0)+1);\n        const top = Object.keys(freq).sort((a,b)=>freq[b]-freq[a])[0];\n        const topShare = top ? (freq[top] \/ Math.max(1, contentWords.length)) : 0;\n\n        const hasPunc = \/[.!?]\/.test(text);\n        const tooManyExclaim = (text.match(\/!\/g)||[]).length >= 3;\n        const lowercaseI = \/\\bi\\b\/.test(text);\n\n        const longRatio = longWords \/ Math.max(1, toks.length);\n\n        \/\/ underlength penalties\n        let underPenalty = 0;\n        if(w > 0 && w < minW) underPenalty = 1;\n        if(w > 0 && w < minW * 0.9) underPenalty = 1.5;\n        if(w > 0 && w < minW * 0.75) underPenalty = 2.5;\n\n        \/\/ TA\/TR\n        let ta = 5.0;\n        if(w >= minW) ta += 1.0;\n        if(w >= minW * 1.15) ta += 0.5;\n\n        if(currentTaskKey === \"t1\"){\n          if(p >= 3) ta += 0.5;\n          if(p >= 4) ta += 0.5;\n          if(hasOverview) ta += 1.0;\n          if(hasCompare) ta += 0.5;\n          if(hasNumbers || hasYears) ta += 0.5;\n          if(hasTrendVerbs) ta += 0.5;\n        }else{\n          if(p >= 4) ta += 0.75;\n          if(p >= 5) ta += 0.25;\n          if(hasOpinion) ta += 1.0;\n          if(\/\\b(allowing children|children should)\\b\/i.test(text)) ta += 0.5;\n          if(hasExamples) ta += 0.5;\n          if(hasConclusion) ta += 0.5;\n        }\n\n        ta -= underPenalty;\n        if(p <= 1) ta -= 1.0;\n        ta = roundHalf(clamp(ta, 0, 9));\n\n        \/\/ CC\n        let cc = 5.0;\n        if(p >= (currentTaskKey===\"t2\" ? 4 : 3)) cc += 1.0;\n        if(link >= 3) cc += 0.5;\n        if(link >= 6) cc += 0.5;\n        if(link >= 10) cc += 0.5;\n\n        const refs = (text.match(\/\\b(this|these|such|this stage|this process|this trend|this figure)\\b\/gi)||[]).length;\n        if(refs >= 2) cc += 0.5;\n\n        if(!hasPunc) cc -= 1.0;\n        if(p <= 1) cc -= 1.0;\n        if(underPenalty >= 2.0) cc -= 0.5;\n        cc = roundHalf(clamp(cc, 0, 9));\n\n        \/\/ LR\n        let lr = 5.0;\n        if(v >= 0.42) lr += 0.5;\n        if(v >= 0.48) lr += 0.5;\n        if(v >= 0.54) lr += 0.5;\n        if(v >= 0.60) lr += 0.5;\n\n        if(longRatio >= 0.10) lr += 0.5;\n        if(longRatio >= 0.14) lr += 0.5;\n        if(longRatio >= 0.18) lr += 0.5;\n\n        if(topShare >= 0.06) lr -= 0.5;\n        if(topShare >= 0.08) lr -= 0.5;\n\n        if(underPenalty >= 2.0) lr -= 0.5;\n        lr = roundHalf(clamp(lr, 0, 9));\n\n        \/\/ GRA\n        let gra = 5.0;\n        if(asl >= 12) gra += 0.5;\n        if(asl >= 15) gra += 0.5;\n        if(asl >= 18) gra += 0.5;\n\n        const complex = (text.match(\/\\b(although|whereas|while|because|since|which|who|that|despite|however|provided that)\\b\/gi)||[]).length;\n        if(complex >= 4) gra += 0.5;\n        if(complex >= 8) gra += 0.5;\n        if(complex >= 12) gra += 0.5;\n\n        if(lowercaseI) gra -= 0.5;\n        if(tooManyExclaim) gra -= 0.5;\n        if(!hasPunc) gra -= 1.0;\n        if(underPenalty >= 2.0) gra -= 0.5;\n\n        gra = roundHalf(clamp(gra, 0, 9));\n\n        \/\/ Optional realism: block 8.5\u20139 if basic requirements are missing\n        function capTopScore(x){\n          if(w < minW) return Math.min(x, 7.0);\n          if(p < (currentTaskKey===\"t2\" ? 4 : 3)) return Math.min(x, 7.5);\n          if(!hasPunc) return Math.min(x, 6.5);\n          return x;\n        }\n        ta = capTopScore(ta);\n        cc = capTopScore(cc);\n        lr = capTopScore(lr);\n        gra = capTopScore(gra);\n\n        return { ta, cc, lr, gra, w, p, s, link, asl };\n      }\n\n      \/\/ ===== Feedback generator =====\n      function feedbackHTML(){\n        const text = draftEl.value || \"\";\n        const w = wordsCount(text);\n        const minW = TASKS[currentTaskKey].minWords;\n        const p = paraCount(text);\n\n        if(w < 30){\n          return `\n            <div style=\"font-weight:1000;margin-bottom:.35rem;\">Not enough text yet<\/div>\n            <div>Please write a fuller response (at least 120\u2013150 words) and try again.<\/div>\n          `;\n        }\n\n        const est = estimateBand();\n        setCrit(\"ta\", est.ta);\n        setCrit(\"cc\", est.cc);\n        setCrit(\"lr\", est.lr);\n        setCrit(\"gra\", est.gra);\n\n        const overall = roundHalf((est.ta+est.cc+est.lr+est.gra)\/4);\n\n        const lenMsg = (w < minW)\n          ? `<div class=\"icte-check\" style=\"margin-top:.65rem;\">Word count is under the minimum (${w}\/${minW}). Add details\/examples.<\/div>`\n          : `<div style=\"margin-top:.35rem;opacity:.9;\">Word count: <strong>${w}<\/strong> (min ${minW})<\/div>`;\n\n        const paraTip = (currentTaskKey===\"t1\")\n          ? (p < 3 ? \"Use 3\u20134 paragraphs: Introduction + Overview + 1\u20132 detail paragraphs.\" : \"Paragraphing looks OK for Task 1. Ensure you include a clear overview.\")\n          : (p < 4 ? \"Use 4\u20135 paragraphs: Introduction + 2 body paragraphs + Conclusion.\" : \"Paragraphing looks OK for Task 2. Ensure your position is clear.\");\n\n        const linkerTip = (est.link < 3)\n          ? \"Add a few natural linkers (however, therefore, by contrast, for example) to improve flow.\"\n          : \"Linking words are present. Make sure each paragraph has a clear topic sentence.\";\n\n        const taskTip = (currentTaskKey===\"t1\")\n          ? \"Task 1: Include a clear <strong>overview<\/strong> + describe stages in order using passive verbs (is pumped \/ is heated \/ is converted).\"\n          : \"Task 2: Discuss <strong>both views<\/strong> and state your <strong>opinion<\/strong> clearly, supported by examples.\";\n\n        const langTip = (est.asl < 12)\n          ? \"Try mixing short and longer sentences (add 1 complex sentence per paragraph).\"\n          : \"Sentence length variety is acceptable; proofread for accuracy (articles, S-V agreement).\";\n\n        return `\n          <div style=\"font-weight:1000;font-size:1.05rem;margin-bottom:.35rem;\">\n            Estimated Overall Band: ${String(overall).replace(\/\\.0$\/,\"\")}\n          <\/div>\n          <div style=\"opacity:.92;margin-bottom:.55rem;\">\n            TA\/TR: <strong>${est.ta}<\/strong> \u2022 CC: <strong>${est.cc}<\/strong> \u2022 LR: <strong>${est.lr}<\/strong> \u2022 GRA: <strong>${est.gra}<\/strong>\n          <\/div>\n\n          ${lenMsg}\n\n          <div style=\"margin-top:.75rem;\">\n            <div style=\"font-weight:1000;margin-bottom:.25rem;\">What to improve next<\/div>\n            <ul class=\"icte-ul\" style=\"margin-top:.25rem;\">\n              <li>${taskTip}<\/li>\n              <li>${paraTip}<\/li>\n              <li>${linkerTip}<\/li>\n              <li>${langTip}<\/li>\n            <\/ul>\n          <\/div>\n\n          <div style=\"margin-top:.65rem;opacity:.9;\">\n            Tip: Click <strong>Band Score<\/strong> to adjust sliders manually after scoring.\n          <\/div>\n        `;\n      }\n\n      \/\/ ===== UI helpers =====\n      function storageKey(taskKey){ return \"icte_writing_test3_\" + taskKey; }\n      function fmtTime(sec){\n        sec = Math.max(0, Math.floor(sec));\n        const m = String(Math.floor(sec \/ 60)).padStart(2,\"0\");\n        const s = String(sec % 60).padStart(2,\"0\");\n        return m + \":\" + s;\n      }\n      function setTaskPill(){ $('[data-el=\"taskPill\"]').textContent = \"Task: \" + TASKS[currentTaskKey].label; }\n      function setTimePill(){ $('[data-el=\"timePill\"]').textContent = \"Time: \" + fmtTime(remaining); }\n      function setWordPill(words){ $('[data-el=\"wordPill\"]').textContent = \"Words: \" + String(words); }\n\n      function renderPrompt(){\n        promptArea.innerHTML = TASKS[currentTaskKey].promptHtml;\n        promptArea.style.display = promptVisible ? \"block\" : \"none\";\n        const btn = root.querySelector('[data-action=\"toggle-prompt\"]');\n        if(btn) btn.textContent = promptVisible ? \"Hide Prompt\" : \"Show Prompt\";\n      }\n\n      function updateStats(){\n        const text = draftEl.value || \"\";\n        const w = wordsCount(text);\n        const p = paraCount(text);\n        const s = sentCount(text);\n\n        setWordPill(w);\n        $('[data-el=\"minWords\"]').textContent = String(TASKS[currentTaskKey].minWords);\n        $('[data-el=\"paraCount\"]').textContent = String(p);\n        $('[data-el=\"sentCount\"]').textContent = String(s);\n\n        const under = w > 0 && w < TASKS[currentTaskKey].minWords;\n        const warn = $('[data-el=\"lengthWarn\"]');\n        if(warn) warn.style.display = under ? \"block\" : \"none\";\n\n        try{ localStorage.setItem(storageKey(currentTaskKey), text); }catch(e){}\n      }\n\n      function loadDraft(){\n        let t = \"\";\n        try{ t = localStorage.getItem(storageKey(currentTaskKey)) || \"\"; }catch(e){}\n        draftEl.value = t;\n        updateStats();\n      }\n\n      function setActiveTaskButton(){\n        $$('button[data-action=\"task\"]').forEach(b => b.classList.remove(\"is-active\"));\n        const active = root.querySelector(`button[data-action=\"task\"][data-task=\"${currentTaskKey}\"]`);\n        if(active) active.classList.add(\"is-active\");\n      }\n\n      function ensurePanelRendered(panel){\n        if(panel === \"vocab\" && !panelRendered.vocab){\n          const vocabArea = $('[data-el=\"vocabArea\"]');\n          vocabArea.innerHTML = \"\";\n          (RES[currentTaskKey].vocab || []).forEach(group => {\n            const wrap = document.createElement(\"div\");\n            wrap.style.marginBottom = \".85rem\";\n\n            const title = document.createElement(\"div\");\n            title.style.fontWeight = \"1000\";\n            title.style.marginBottom = \".35rem\";\n            title.textContent = group.cat;\n\n            const row = document.createElement(\"div\");\n            row.className = \"icte-chipRow\";\n\n            (group.items || []).forEach(item => {\n              const chip = document.createElement(\"span\");\n              chip.className = \"icte-chip\";\n              chip.textContent = item;\n              row.appendChild(chip);\n            });\n\n            wrap.appendChild(title);\n            wrap.appendChild(row);\n            vocabArea.appendChild(wrap);\n          });\n          panelRendered.vocab = true;\n        }\n\n        if(panel === \"outline\" && !panelRendered.outline){\n          $('[data-el=\"outlineArea\"]').innerHTML = RES[currentTaskKey].outline || \"\";\n          panelRendered.outline = true;\n        }\n\n        if(panel === \"samples\" && !panelRendered.samples){\n          $('[data-el=\"samplesArea\"]').innerHTML = RES[currentTaskKey].sample || \"\";\n          panelRendered.samples = true;\n        }\n\n        if(panel === \"band\"){\n          [\"ta\",\"cc\",\"lr\",\"gra\"].forEach(k=>{\n            const input = root.querySelector(`input[data-crit=\"${k}\"]`);\n            const out = root.querySelector(`[data-el=\"${BAND[k]}\"]`);\n            if(input && out) out.textContent = String(toNum(input.value));\n          });\n          updateOverall();\n        }\n      }\n\n      function setOpenPanel(panel){\n        openPanel = panel || \"none\";\n        $('[data-el=\"openPanelPill\"]').textContent = \"Open: \" + (openPanel === \"none\" ? \"None\" : openPanel);\n\n        $$('.icte-accItem').forEach(it => it.classList.remove(\"is-open\"));\n\n        if(openPanel !== \"none\"){\n          const target = root.querySelector(`.icte-accItem[data-panel=\"${openPanel}\"]`);\n          if(target) target.classList.add(\"is-open\");\n          ensurePanelRendered(openPanel);\n        }\n      }\n\n      \/\/ ===== Timer =====\n      function stopTimer(timeUp){\n        running = false;\n        if(timer){ clearInterval(timer); timer = null; }\n        $('[data-action=\"start\"]').disabled = false;\n        $('[data-action=\"pause\"]').disabled = true;\n        if(!timeUp) $('[data-el=\"timerHint\"]').textContent = \"Timer paused.\";\n      }\n      function tick(){\n        if(!running) return;\n        remaining -= 1;\n        setTimePill();\n        if(remaining <= 0){\n          remaining = 0;\n          setTimePill();\n          $('[data-el=\"timeUpBox\"]').style.display = \"block\";\n          $('[data-el=\"timerHint\"]').textContent = \"Time up \u2014 finish and proofread.\";\n          stopTimer(true);\n        }\n      }\n      function startTimer(){\n        if(running) return;\n        running = true;\n        $('[data-action=\"start\"]').disabled = true;\n        $('[data-action=\"pause\"]').disabled = false;\n        $('[data-el=\"timerHint\"]').textContent = \"Timer running...\";\n        timer = setInterval(tick, 1000);\n      }\n      function resetTimer(){\n        stopTimer(false);\n        remaining = TASKS[currentTaskKey].seconds;\n        setTimePill();\n        $('[data-el=\"timeUpBox\"]').style.display = \"none\";\n        $('[data-el=\"timerHint\"]').textContent = \"\";\n      }\n\n      function togglePrompt(){ promptVisible = !promptVisible; renderPrompt(); }\n\n      function switchTask(taskKey){\n        stopTimer(false);\n        currentTaskKey = taskKey;\n        remaining = TASKS[currentTaskKey].seconds;\n\n        setActiveTaskButton();\n        setTaskPill();\n        setTimePill();\n        renderPrompt();\n        loadDraft();\n\n        panelRendered = { vocab:false, outline:false, samples:false };\n        setOpenPanel(\"none\");\n        resetBand();\n\n        const fb = $('[data-el=\"feedbackText\"]');\n        if(fb){\n          fb.innerHTML = 'Click <strong>Get Feedback<\/strong> after writing at least 120\u2013150 words.';\n        }\n\n        $('[data-el=\"timeUpBox\"]').style.display = \"none\";\n        $('[data-el=\"timerHint\"]').textContent = \"\";\n      }\n\n      function clearTask(){\n        draftEl.value = \"\";\n        try{ localStorage.removeItem(storageKey(currentTaskKey)); }catch(e){}\n        updateStats();\n        resetBand();\n        const fb = $('[data-el=\"feedbackText\"]');\n        if(fb){\n          fb.innerHTML = 'Cleared \u2705 Write a new response, then click <strong>Get Feedback<\/strong>.';\n        }\n      }\n\n      function showLoader(on){\n        const el = $('[data-el=\"loader\"]');\n        if(!el) return;\n        el.style.display = on ? \"inline-block\" : \"none\";\n      }\n\n      function doFeedback(){\n        const w = wordsCount(draftEl.value || \"\");\n        if(w < 30){\n          const fb = $('[data-el=\"feedbackText\"]');\n          if(fb) fb.innerHTML = \"<strong>Please write more text first.<\/strong> (Try at least 120\u2013150 words.)\";\n          return;\n        }\n        showLoader(true);\n        setTimeout(()=>{\n          const fb = $('[data-el=\"feedbackText\"]');\n          if(fb) fb.innerHTML = feedbackHTML();\n          showLoader(false);\n        }, 180);\n      }\n\n      function copyText(text){\n        if(!text) return;\n        if(navigator.clipboard && navigator.clipboard.writeText){\n          navigator.clipboard.writeText(text).catch(()=>{});\n          return;\n        }\n        const ta = document.createElement(\"textarea\");\n        ta.value = text;\n        ta.style.position=\"fixed\";\n        ta.style.left=\"-9999px\";\n        document.body.appendChild(ta);\n        ta.select();\n        try{ document.execCommand(\"copy\"); }catch(e){}\n        document.body.removeChild(ta);\n      }\n\n      function downloadText(filename, text){\n        const blob = new Blob([text], {type:\"text\/plain;charset=utf-8\"});\n        const url = URL.createObjectURL(blob);\n        const a = document.createElement(\"a\");\n        a.href = url;\n        a.download = filename;\n        document.body.appendChild(a);\n        a.click();\n        document.body.removeChild(a);\n        URL.revokeObjectURL(url);\n      }\n\n      function getFeedbackPlain(){\n        const fb = $('[data-el=\"feedbackText\"]');\n        if(!fb) return \"\";\n        return fb.innerText || fb.textContent || \"\";\n      }\n\n      \/\/ ===== Events =====\n      draftEl.addEventListener(\"input\", updateStats);\n\n      root.addEventListener(\"input\", (e)=>{\n        const range = e.target.closest('input.icte-range[data-crit]');\n        if(!range) return;\n        const key = range.getAttribute(\"data-crit\");\n        const out = root.querySelector(`[data-el=\"${BAND[key]}\"]`);\n        if(out) out.textContent = String(toNum(range.value));\n        updateOverall();\n      });\n\n      root.addEventListener(\"click\", (e)=>{\n        const btn = e.target.closest(\"[data-action]\");\n        if(!btn) return;\n        const action = btn.getAttribute(\"data-action\");\n\n        if(action === \"task\"){\n          const key = btn.getAttribute(\"data-task\");\n          if(key && TASKS[key]) switchTask(key);\n          return;\n        }\n        if(action === \"toggle-panel\"){\n          const panel = btn.getAttribute(\"data-panel\") || \"none\";\n          setOpenPanel(openPanel === panel ? \"none\" : panel);\n          return;\n        }\n        if(action === \"start\") return startTimer();\n        if(action === \"pause\") return stopTimer(false);\n        if(action === \"reset\") return resetTimer();\n        if(action === \"toggle-prompt\") return togglePrompt();\n\n        if(action === \"clear\") return clearTask();\n        if(action === \"feedback\") return doFeedback();\n\n        \/\/ \u2705 Improved: Score Writing updates sliders + also shows feedback explanation\n        if(action === \"score-writing\"){\n          const est = estimateBand();\n          setCrit(\"ta\", est.ta); setCrit(\"cc\", est.cc); setCrit(\"lr\", est.lr); setCrit(\"gra\", est.gra);\n          const fb = $('[data-el=\"feedbackText\"]');\n          if(fb) fb.innerHTML = feedbackHTML();\n          return;\n        }\n        if(action === \"reset-band\") return resetBand();\n\n        if(action === \"copy\") return copyText(draftEl.value || \"\");\n        if(action === \"download\") return downloadText(`IELTS-Writing-${TASKS[currentTaskKey].label}.txt`, draftEl.value || \"\");\n\n        if(action === \"copy-feedback\") return copyText(getFeedbackPlain());\n        if(action === \"download-feedback\") return downloadText(`IELTS-Feedback-${TASKS[currentTaskKey].label}.txt`, getFeedbackPlain());\n      });\n\n      \/\/ ===== Init =====\n      setTaskPill();\n      setActiveTaskButton();\n      renderPrompt();\n      loadDraft();\n      setTimePill();\n      setWordPill(wordsCount(draftEl.value || \"\"));\n      setOpenPanel(\"none\");\n      resetBand();\n    }\n\n    if(document.readyState === \"loading\"){\n      document.addEventListener(\"DOMContentLoaded\", init);\n    }else{\n      init();\n    }\n  })();\n  <\/script>\n\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Overview Test 1 Test 2 Test 3 Test 4 Listening Reading Speaking IELTS Writing Test 3 IELTS Writing Practice \u2013<\/p>\n","protected":false},"author":1,"featured_media":583,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_layout":"default_layout","footnotes":""},"categories":[25,32,34],"tags":[],"class_list":["post-662","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ielts","category-test-3","category-writing"],"_links":{"self":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/662","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=662"}],"version-history":[{"count":2,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/662\/revisions"}],"predecessor-version":[{"id":664,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/662\/revisions\/664"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media\/583"}],"wp:attachment":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media?parent=662"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/categories?post=662"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/tags?post=662"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}