{"id":644,"date":"2026-01-10T12:09:45","date_gmt":"2026-01-10T12:09:45","guid":{"rendered":"https:\/\/i-cte.org\/robot\/?p=644"},"modified":"2026-01-11T06:21:50","modified_gmt":"2026-01-11T06:21:50","slug":"ielts-writing-test-2","status":"publish","type":"post","link":"https:\/\/i-cte.org\/robot\/ielts-writing-test-2\/","title":{"rendered":"IELTs &#8211; Writing &#8211; Test 2"},"content":{"rendered":"\n<!-- \u2705 IELTS WRITING \u2013 TEST 2 (WP-SAFE SINGLE BLOCK \u2022 ADAPTED FROM YOUR WORKING TEST 1 PATTERN) -->\n<div id=\"icte-writing-test2\">\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 2\">\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 2<\/span>\n        <\/div>\n\n        <h2 class=\"icte-hero__title\">IELTS Writing Practice \u2013 Test 2<\/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> + comparisons. 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.onerror=null;this.src='https:\/\/i-cte.org\/robot\/wp-content\/uploads\/2026\/01\/4.webp';\"\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\" 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 + 2 body paragraphs with comparisons.<\/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 (same structure as Test 1, but scoped to #icte-writing-test2) -->\n  <style>\n    #icte-writing-test2, #icte-writing-test2 *{ box-sizing:border-box; }\n    #icte-writing-test2{ font-family: Arial, sans-serif; font-size:14px; line-height:1.7; color:#0f172a; width:100%; max-width:100%; }\n\n    #icte-writing-test2 .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-test2 .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-test2 .icte-menu a.is-current{ background:rgba(255,255,255,.22); }\n\n    #icte-writing-test2 .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-test2 .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-test2 .icte-ielts__h3{ margin:0; font-weight:900; font-size:1.1rem; }\n    #icte-writing-test2 .icte-ielts__headRight{ display:flex; gap:.55rem; align-items:center; flex-wrap:wrap; }\n    #icte-writing-test2 .icte-ielts__reading{ padding:1rem 1rem 1.05rem; }\n    #icte-writing-test2 .icte-ielts__qArea{ padding:1rem 1rem 1.05rem; }\n\n    #icte-writing-test2 .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-test2 .icte-btn:hover{ transform: translateY(-1px); filter: brightness(1.03); box-shadow: 0 8px 18px rgba(0,0,0,.10); }\n    #icte-writing-test2 .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-test2 .icte-btn:focus-visible{ outline: 3px solid rgba(14,165,233,.45); outline-offset: 2px; }\n    #icte-writing-test2 .icte-btn:disabled{ opacity:.55; cursor:not-allowed; }\n\n    #icte-writing-test2 .icte-btn--primary{ background:#16a34a; color:#fff; }\n    #icte-writing-test2 .icte-btn--info{ background:#0ea5e9; color:#fff; }\n    #icte-writing-test2 .icte-btn--danger{ background:#dc2626; color:#fff; }\n    #icte-writing-test2 .icte-btn--dark{ background:#334155; color:#fff; }\n    #icte-writing-test2 .icte-btn--ghost{ background:transparent; border-color:rgba(0,0,0,.20); color:inherit; }\n\n    #icte-writing-test2 .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-test2 .icte-pill--big{ padding:.45rem .75rem; }\n\n    #icte-writing-test2 .icte-small{ font-size:1rem; opacity:.88; }\n    #icte-writing-test2 .icte-modeRow, #icte-writing-test2 .icte-timerRow{ display:flex; gap:.6rem; flex-wrap:wrap; align-items:center; }\n    #icte-writing-test2 .icte-grid2{ display:grid; grid-template-columns:1fr 1fr; gap:.85rem; }\n    @media (max-width: 900px){ #icte-writing-test2 .icte-grid2{ grid-template-columns:1fr; } }\n\n    #icte-writing-test2 .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-test2 .icte-sep{ display:none; } }\n\n    #icte-writing-test2 .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-test2 .icte-miniRow{ margin-top:.55rem; display:flex; gap:.75rem; flex-wrap:wrap; }\n    #icte-writing-test2 .icte-actionRow{ display:flex; gap:.6rem; flex-wrap:wrap; align-items:center; }\n\n    #icte-writing-test2 .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-test2 .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-test2 .icte-ul{ margin:.4rem 0 0 1.1rem; }\n    #icte-writing-test2 .icte-ul li{ margin:.35rem 0; }\n\n    #icte-writing-test2 .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-test2 .icte-accordion{ display:flex; flex-direction:column; gap:.85rem; }\n    #icte-writing-test2 .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-test2 .icte-accItem.is-open{ display:block !important; }\n    #icte-writing-test2 .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-test2 .icte-accTitle{ font-weight:1000; font-size:1.05rem; }\n    #icte-writing-test2 .icte-accHint{ opacity:.85; }\n\n    #icte-writing-test2 .icte-chipRow{ display:flex; flex-wrap:wrap; gap:.5rem; margin-top:.45rem; }\n    #icte-writing-test2 .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-test2 .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-test2 .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-test2 .icte-scoreGrid{ grid-template-columns:1fr; } }\n    #icte-writing-test2 .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-test2 .icte-scoreItem .k{ font-weight:1000; }\n    #icte-writing-test2 .icte-scoreItem .v{ opacity:.88; margin-top:.25rem; font-weight:900; }\n    #icte-writing-test2 .icte-range{ width:100%; }\n    #icte-writing-test2 .icte-scoreActions{ display:flex; gap:.6rem; flex-wrap:wrap; align-items:center; margin-top:.85rem; }\n\n    #icte-writing-test2 .icte-warn{\n      border:1px solid #fecaca; background:#fff5f5; color:#7f1d1d;\n      border-radius:14px; padding:.85rem .95rem;\n    }\n\n    #icte-writing-test2 .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-test2 .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-test2 .icte-hero{ grid-template-columns:1fr; } }\n    #icte-writing-test2 .icte-badges{ display:flex; gap:8px; flex-wrap:wrap; margin-bottom:8px; }\n    #icte-writing-test2 .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-test2 .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-test2 .icte-hero__title{ margin:0 0 6px; font-weight:1000; color:#0f5132; font-size:1.35rem; }\n    #icte-writing-test2 .icte-hero__sub{ margin:0; color:#334155; opacity:.95; }\n    #icte-writing-test2 .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-test2 .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-test2 .icte-robotCard img{ width:100%; height:100%; object-fit:cover; display:block; }\n    #icte-writing-test2 .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-test2 .icte-robotOverlay .t1{ font-weight:1000; font-size:1.05rem; }\n    #icte-writing-test2 .icte-robotOverlay .t2{ font-size:.95rem; opacity:.92; }\n    #icte-writing-test2 .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\n    #icte-writing-test2 .icte-promptBox h4{ margin:.1rem 0 .35rem; font-weight:1000; }\n    #icte-writing-test2 .icte-promptBox img{\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  <\/style>\n\n  <!-- \u2705 JS (same approach as your WORKING Test 1 code) -->\n  <script>\n  (function(){\n    function init(){\n      const root = document.getElementById(\"icte-writing-test2\");\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 Replace these with your WordPress Media URLs (Test 2)\n      const IMG_TASK1 = \"https:\/\/i-cte.org\/robot\/wp-content\/uploads\/2026\/01\/Screenshot-2026-01-11-at-11.44.57-AM.png\";\n      const IMG_TASK2 = \"https:\/\/i-cte.org\/robot\/wp-content\/uploads\/2025\/12\/DALL\u00b7E-2025-12-31-20.23.19-A-beautiful-female-student-taking-the-IELTS-exam-in-a-modern-testing-center.-She-is-writing-on-an-answer-sheet-with-focus-sitting-at-a-computer-based.webp\"; \/\/ can be blank; image will hide onerror\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;\">The line graph shows the percentage of tourists who visited four attractions between 1980 and 2010.<\/div>\n              <div style=\"margin-top:.55rem;\"><strong>Summarise<\/strong> the information by selecting and reporting the main features, and make comparisons where relevant.<\/div>\n              <div style=\"margin-top:.55rem;\"><strong>Write at least 150 words.<\/strong><\/div>\n              <img decoding=\"async\" src=\"${escapeHtml(IMG_TASK1)}\" alt=\"Task 1 image\" onerror=\"this.style.display='none';\" \/>\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              <div style=\"margin-top:.55rem;\">\n                At the present time, the population of some countries includes a relatively large number of young adults,\n                compared with the number of older people. Do the advantages of this situation outweigh the disadvantages?\n              <\/div>\n              <div style=\"margin-top:.55rem;\"><strong>Write at least 250 words.<\/strong><\/div>\n              <img decoding=\"async\" src=\"${escapeHtml(IMG_TASK2)}\" alt=\"Task 2 image\" onerror=\"this.style.display='none';\" \/>\n            <\/div>\n          `\n        }\n      };\n\n      const RES = {\n        t1:{\n          vocab:[\n            { cat:\"Task 1 \u2013 Reporting verbs\", items:[\"rose\",\"increased\",\"climbed\",\"fell\",\"declined\",\"dropped\",\"peaked\",\"bottomed out\",\"recovered\",\"remained stable\"] },\n            { cat:\"Task 1 \u2013 Comparison phrases\", items:[\"was higher than\",\"slightly above\",\"in contrast\",\"whereas\",\"by comparison\",\"the most popular\",\"the lowest level\"] },\n            { cat:\"Task 1 \u2013 Numbers & approximations\", items:[\"around\",\"roughly\",\"approximately\",\"just under\",\"just over\",\"hovered near\"] }\n          ],\n          outline: `\n<strong>Task 1 Outline: Overview\u2013Details<\/strong>\n<ul class=\"icte-ul\">\n  <li><strong>Introduction:<\/strong> Paraphrase the task (what the graph shows).<\/li>\n  <li><strong>Overview:<\/strong> 2\u20133 key trends (no numbers).<\/li>\n  <li><strong>Body 1:<\/strong> Biggest rise \/ peak (include key figures).<\/li>\n  <li><strong>Body 2:<\/strong> Biggest fall + ending comparison (include key figures).<\/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;\">\nOverall, the Pavilion rose to become the most popular destination in the mid-1990s, whereas the Art Gallery, after peaking in the 1980s, declined dramatically to the lowest level by 2010. The Festival remained comparatively stable, and the Pier finished the period more popular than it began.\nIn 1980, around 30% of tourists attended the Festival, slightly higher than the Pavilion at about 24%. The Art Gallery accounted for roughly 22%, while only 10% visited the Pier. Gallery visits then climbed to approximately 37% in 1985, but dropped to 20% by 1990 and continued falling, reaching just under 10% in 2010. By contrast, the Pavilion increased sharply, rising from the high 20s in 1985 to about 40% in 1990, peaking near 48% in 1995, and then easing to just over 30% by the end. Festival attendance dipped to around 25% in the mid-1990s and recovered slightly. Pier figures hovered near 10\u201315% until 2000 before climbing to about 22% in 2010.\nIn conclusion, tourist interest shifted away from the Art Gallery towards the Pavilion and, later, the Pier.\n\n<\/pre>`.trim()\n        },\n        t2:{\n          vocab:[\n            { cat:\"Task 2 \u2013 Demographics\", items:[\"youth bulge\",\"working-age population\",\"dependency ratio\",\"demographic dividend\"] },\n            { cat:\"Task 2 \u2013 Advantages\", items:[\"boost productivity\",\"expand the tax base\",\"drive innovation\",\"adapt quickly to change\"] },\n            { cat:\"Task 2 \u2013 Disadvantages\", items:[\"youth unemployment\",\"underemployment\",\"pressure on housing\",\"social instability\",\"brain drain\"] },\n            { cat:\"Task 2 \u2013 Linking\", items:[\"however\",\"nevertheless\",\"despite these risks\",\"in conclusion\",\"overall\"] }\n          ],\n          outline: `\n<strong>Task 2 Outline: Advantages Outweigh Disadvantages<\/strong>\n<ul class=\"icte-ul\">\n  <li><strong>Introduction:<\/strong> Paraphrase + clear opinion.<\/li>\n  <li><strong>Body 1:<\/strong> Main advantages (economy, innovation) + example.<\/li>\n  <li><strong>Body 2:<\/strong> Disadvantages (jobs, services) + why manageable.<\/li>\n  <li><strong>Conclusion:<\/strong> Restate opinion + condition (good policy).<\/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;\">\nIn some countries today, young adults make up a much larger share of the population than older people. This \u201cyouth bulge\u201d can be a powerful asset if it is matched with jobs and skills, and I believe the advantages generally outweigh the disadvantages.\nThe main benefit is economic. When a high proportion of citizens are of working age, a country can enjoy a demographic dividend: more taxpayers, higher production, and greater consumer spending. Governments may also face lower immediate pressure on pensions and elderly healthcare, allowing more public funds to be directed towards education, infrastructure, and innovation. In addition, younger societies tend to be more adaptable. Young adults are often quicker to adopt new technologies, start businesses, and fill emerging roles in fast-growing sectors such as digital services and green energy.\nHowever, the disadvantages can be serious when planning is weak. A large cohort of young people requires substantial investment in schools, vocational training, and affordable housing. If labour markets cannot absorb new graduates, unemployment and underemployment may rise, leading to frustration, crime, or political instability. Some countries also struggle with \u201cbrain drain\u201d when skilled young professionals migrate abroad for better opportunities, reducing the very advantage a youthful population should bring.\nDespite these risks, the balance remains positive because the downsides are largely policy-related, not inevitable. With effective education systems, targeted job creation, and support for entrepreneurship, a youthful population becomes a long-term engine for growth and social dynamism.\nIn conclusion, having relatively more young adults than older people is usually beneficial, provided governments act early to turn potential into productive employment and inclusive development. \n\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: prevent sample text from being loaded into the Draft box (and from old storage)\n      function purgeSampleFromDraft(){\n        const markers = [\"Sample Answer\",\"Overall, the Pavilion rose\",\"In some countries today, young adults\"];\n        const cur = (draftEl.value || \"\").trim();\n        if(markers.some(m => cur.includes(m))) draftEl.value = \"\";\n\n        try{\n          [\"t1\",\"t2\"].forEach(k=>{\n            const key = \"icte_writing_test2_\" + k;\n            const saved = (localStorage.getItem(key) || \"\").trim();\n            if(markers.some(m => saved.includes(m))){\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)\\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      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  \/\/ ===== Extra proxies for \"more appropriate\" scoring =====\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)\\b\/i.test(text);\n\n  \/\/ repetition proxy (very rough): top word share (excluding tiny words)\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  \/\/ punctuation\/format proxies\n  const hasPunc = \/[.!?]\/.test(text);\n  const tooManyExclaim = (text.match(\/!\/g)||[]).length >= 3;\n  const lowercaseI = \/\\bi\\b\/.test(text); \/\/ \"i\" not capitalized often indicates poor accuracy\n\n  \/\/ word length ratios\n  const longRatio = longWords \/ Math.max(1, toks.length);\n\n  \/\/ ===== Underlength penalties (stronger & more IELTS-like) =====\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  \/\/ Start higher (IELTS candidates usually cluster 5\u20137)\n  let ta = 5.0;\n\n  if(w >= minW) ta += 1.0;\n  if(w >= minW * 1.15) ta += 0.5; \/\/ fuller development\n\n  \/\/ paragraph expectations\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(advantages|benefits)\\b\/i.test(text) && \/\\b(disadvantages|drawbacks)\\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;          \/\/ no structure\n  ta = roundHalf(clamp(ta, 0, 9));\n\n  \/\/ ===== CC =====\n  let cc = 5.0;\n\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  \/\/ referencing devices (this\/these\/such) improve cohesion (rough proxy)\n  const refs = (text.match(\/\\b(this|these|such|this trend|this figure|this change)\\b\/gi)||[]).length;\n  if(refs >= 2) cc += 0.5;\n\n  \/\/ penalties\n  if(!hasPunc) cc -= 1.0;\n  if(p <= 1) cc -= 1.0;\n  if(underPenalty >= 2.0) cc -= 0.5;\n\n  cc = roundHalf(clamp(cc, 0, 9));\n\n  \/\/ ===== LR =====\n  let lr = 5.0;\n\n  \/\/ lexical variety\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  \/\/ sophistication (rough)\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  \/\/ repetition penalty\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\n  lr = roundHalf(clamp(lr, 0, 9));\n\n  \/\/ ===== GRA =====\n  let gra = 5.0;\n\n  \/\/ sentence length variety proxy\n  if(asl >= 12) gra += 0.5;\n  if(asl >= 15) gra += 0.5;\n  if(asl >= 18) gra += 0.5;\n\n  \/\/ complexity markers\n  const complex = (text.match(\/\\b(although|whereas|while|because|since|which|who|that|despite|however)\\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  \/\/ penalties\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  return { ta, cc, lr, gra, w, p, s, link, asl };\n}\n\n\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 linking phrases (however, therefore, in contrast) 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> and make comparisons.\"\n          : \"Task 2: State your <strong>opinion<\/strong> clearly and support it with reasons + examples.\";\n\n        const langTip = (est.asl < 12)\n          ? \"Try mixing short and longer sentences (add one 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_test2_\" + 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       if(action === \"score-writing\"){\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  \/\/ Also show feedback text so users understand the score\n  const fb = $('[data-el=\"feedbackText\"]');\n  if(fb) fb.innerHTML = feedbackHTML();\n\n  return;\n}\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 2 IELTS Writing Practice \u2013<\/p>\n","protected":false},"author":1,"featured_media":578,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_layout":"default_layout","footnotes":""},"categories":[25,31,34],"tags":[],"class_list":["post-644","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ielts","category-test-2-ielts","category-writing"],"_links":{"self":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/644","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=644"}],"version-history":[{"count":12,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/644\/revisions"}],"predecessor-version":[{"id":661,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/644\/revisions\/661"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media\/578"}],"wp:attachment":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media?parent=644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/categories?post=644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/tags?post=644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}