{"id":461,"date":"2026-01-06T02:31:51","date_gmt":"2026-01-06T02:31:51","guid":{"rendered":"https:\/\/i-cte.org\/robot\/?p=461"},"modified":"2026-01-06T15:28:47","modified_gmt":"2026-01-06T15:28:47","slug":"ielts-listening-section-1","status":"publish","type":"post","link":"https:\/\/i-cte.org\/robot\/ielts-listening-section-1\/","title":{"rendered":"IELTs &#8211; Listening &#8211; Section 1"},"content":{"rendered":"\n<div id=\"icte-listening-s1\">\n\n  <!-- Top green menu bar -->\n  <div class=\"icte-menu\">\n<a href=\"https:\/\/i-cte.org\/robot\/ielts-listening-overview\/\">Overview<\/a>\n      <a href=\"https:\/\/i-cte.org\/robot\/ielts-listening-section-1\/\">Section 1<\/a>\n      <a href=\"https:\/\/i-cte.org\/robot\/ielts-listening-section-2\/\">Section 2<\/a>\n      <a href=\"https:\/\/i-cte.org\/robot\/ielts-listening-section-3\/\">Section 3<\/a>\n      <a href=\"https:\/\/i-cte.org\/robot\/ielts-listening-section-4\/\">Section 4<\/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      <a href=\"https:\/\/i-cte.org\/robot\/ielts-writing-overview\/\">Writing<\/a>\n  <\/div>\n\n  <section class=\"icte-ielts\" aria-label=\"IELTS Listening Section 1 - Family Excursions\">\n    <header class=\"icte-ielts__intro\">\n      <h2 class=\"icte-ielts__title\">IELTS Listening \u2013 Section 1 (Questions 1\u201310): Family Excursions<\/h2>\n      <p class=\"icte-ielts__sub\">\n        Complete the notes below. Write <strong>ONE WORD AND\/OR A NUMBER<\/strong> for each answer.\n      <\/p>\n    <\/header>\n\n    <!-- Transcript (hidden by default) -->\n    <section class=\"icte-ielts__panel\" aria-label=\"Transcript\">\n      <div class=\"icte-ielts__panelHead\">\n        <h3 class=\"icte-ielts__h3\">Transcript (for practice)<\/h3>\n        <div class=\"icte-ielts__headRight\">\n          <button class=\"icte-btn icte-btn--dark\" type=\"button\" data-action=\"toggle-transcript\">Show Transcript<\/button>\n          <span class=\"icte-loader\" data-el=\"synthesis-loader\" aria-hidden=\"true\"><\/span>\n        <\/div>\n      <\/div>\n\n      <div class=\"icte-ielts__reading\" data-el=\"transcript-area\" role=\"region\" aria-label=\"Transcript text\" style=\"display:none;\"><\/div>\n\n      <div class=\"icte-ielts__btnRow icte-ielts__btnRow--tight\">\n        <button class=\"icte-btn icte-btn--info\" type=\"button\" data-action=\"play-conversation\">\ud83d\udd0a Listen to the Conversation<\/button>\n        <button class=\"icte-btn icte-btn--danger\" type=\"button\" data-action=\"stop-audio\">\u23f9 Stop Audio<\/button>\n        <a class=\"icte-link\" href=\"#icte-questions\">Jump to questions \u2193<\/a>\n      <\/div>\n    <\/section>\n\n    <!-- Controls -->\n    <section class=\"icte-ielts__panel\" aria-label=\"Controls\">\n      <div class=\"icte-ielts__row\" style=\"align-items:flex-start;\">\n        <div class=\"icte-ielts__control\" style=\"flex:1; min-width:240px;\">\n          <label><strong>TC Employee Voice<\/strong><\/label>\n          <select data-el=\"voice-employee\" aria-label=\"Select TC Employee Voice\">\n            <option value=\"\">Loading voices&#8230;<\/option>\n          <\/select>\n        <\/div>\n\n        <div class=\"icte-ielts__control\" style=\"flex:1; min-width:240px;\">\n          <label><strong>Visitor Voice<\/strong><\/label>\n          <select data-el=\"voice-visitor\" aria-label=\"Select Visitor Voice\">\n            <option value=\"\">Loading voices&#8230;<\/option>\n          <\/select>\n        <\/div>\n\n        <div class=\"icte-ielts__score\" data-el=\"scoreBox\" aria-live=\"polite\"><\/div>\n      <\/div>\n\n      <div class=\"icte-ielts__btnGrid\" aria-label=\"Action buttons\">\n        <button class=\"icte-btn icte-btn--info\" type=\"button\" data-action=\"play-instructions\">\ud83d\udd0a Read Instructions<\/button>\n        <button class=\"icte-btn icte-btn--info\" type=\"button\" data-action=\"read-questions\">\ud83d\udd0a Read Questions<\/button>\n        <button class=\"icte-btn icte-btn--primary\" type=\"button\" data-action=\"check\">Check Answers<\/button>\n        <button class=\"icte-btn icte-btn--dark\" type=\"button\" data-action=\"show\">\ud83d\udc40 Show Answers<\/button>\n        <button class=\"icte-btn icte-btn--dark\" type=\"button\" data-action=\"summary\">\ud83e\udde0 Summary<\/button>\n        <button class=\"icte-btn icte-btn--dark\" type=\"button\" data-action=\"main-ideas\">\ud83d\udccc Main ideas<\/button>\n        <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"reset\">Reset<\/button>\n      <\/div>\n    <\/section>\n\n    <!-- Support -->\n    <section class=\"icte-ielts__panel\" aria-label=\"Learning support\">\n      <div class=\"icte-ielts__panelHead\">\n        <h3 class=\"icte-ielts__h3\">Support<\/h3>\n        <div class=\"icte-ielts__headRight\">\n          <button class=\"icte-btn icte-btn--ghost\" type=\"button\" data-action=\"clear-support\">Clear<\/button>\n        <\/div>\n      <\/div>\n\n      <div class=\"icte-ielts__helper\" data-el=\"helper-area\" role=\"region\" aria-live=\"polite\">\n        Click <strong>Summary<\/strong> or <strong>Main ideas<\/strong>.\n      <\/div>\n    <\/section>\n\n    <!-- Questions -->\n    <section class=\"icte-ielts__panel\" id=\"icte-questions\" aria-label=\"Questions 1 to 10\">\n      <div class=\"icte-ielts__panelHead\">\n        <h3 class=\"icte-ielts__h3\">Questions 1\u201310<\/h3>\n      <\/div>\n\n      <div class=\"icte-ielts__qArea\">\n        <div class=\"icte-q\">\n          <div class=\"icte-q__label\">FAMILY EXCURSIONS<\/div>\n          <div style=\"opacity:.9; line-height:1.65;\">\n            Complete the notes below. Write <strong>ONE WORD AND\/OR A NUMBER<\/strong> for each answer.\n          <\/div>\n        <\/div>\n\n        <div class=\"icte-q\">\n          <div class=\"icte-q__label\">Cruise on a lake<\/div>\n          <div class=\"icte-q__controls\">\n            <div class=\"icte-note\">\n              <div>Example: Travel on an old <strong>steamship<\/strong><\/div>\n              <div>\n                \u2022 Can take photos of the\n                <span class=\"blank\">\n                  1 <input type=\"text\" data-q=\"1\" placeholder=\"ONE WORD\" \/>\n                <\/span>\n                that surround the lake\n              <\/div>\n            <\/div>\n          <\/div>\n          <div class=\"icte-q__fb\" data-fb=\"1\"><\/div>\n        <\/div>\n\n        <div class=\"icte-q\">\n          <div class=\"icte-q__label\">Farm visit<\/div>\n          <div class=\"icte-note\">\n            <div>\u2022 Children can help feed the sheep<\/div>\n            <div>\n              \u2022 Visit can include a 40-minute ride on a\n              <span class=\"blank\">\n                2 <input type=\"text\" data-q=\"2\" placeholder=\"ONE WORD\" \/>\n              <\/span>\n            <\/div>\n            <div>\n              \u2022 Visitors can walk in the farm\u2019s\n              <span class=\"blank\">\n                3 <input type=\"text\" data-q=\"3\" placeholder=\"ONE WORD\" \/>\n              <\/span>\n              by the lake\n            <\/div>\n            <div>\n              \u2022\n              <span class=\"blank\">\n                4 <input type=\"text\" data-q=\"4\" placeholder=\"ONE WORD\" \/>\n              <\/span>\n              is available at extra cost\n            <\/div>\n          <\/div>\n          <div class=\"icte-q__fb\" data-fb=\"2\"><\/div>\n          <div class=\"icte-q__fb\" data-fb=\"3\"><\/div>\n          <div class=\"icte-q__fb\" data-fb=\"4\"><\/div>\n        <\/div>\n\n        <div class=\"icte-q\">\n          <div class=\"icte-q__label\">Cycling trips<\/div>\n          <div class=\"icte-note\">\n            <div>\u2022 Cyclists explore the Back Road<\/div>\n            <div>\n              \u2022 A\n              <span class=\"blank\">\n                5 <input type=\"text\" data-q=\"5\" placeholder=\"ONE WORD\" \/>\n              <\/span>\n              is provided\n            <\/div>\n            <div>\n              \u2022 Only suitable for cyclists who have some\n              <span class=\"blank\">\n                6 <input type=\"text\" data-q=\"6\" placeholder=\"ONE WORD\" \/>\n              <\/span>\n            <\/div>\n            <div>\n              \u2022 Bikes can be hired from\n              <span class=\"blank\">\n                7 <input type=\"text\" data-q=\"7\" placeholder=\"ONE WORD\" \/>\n              <\/span>\n              (near the Cruise Ship Terminal)\n            <\/div>\n            <div>\u2022 Cyclists need: a repair kit, food and drink,<\/div>\n            <div>\n              a\n              <span class=\"blank\">\n                8 <input type=\"text\" data-q=\"8\" placeholder=\"ONE WORD\" \/>\n              <\/span>\n              (can be hired)\n            <\/div>\n            <div>\n              \u2022 There are no\n              <span class=\"blank\">\n                9 <input type=\"text\" data-q=\"9\" placeholder=\"ONE WORD\" \/>\n              <\/span>\n              or accommodation in the area\n            <\/div>\n          <\/div>\n          <div class=\"icte-q__fb\" data-fb=\"5\"><\/div>\n          <div class=\"icte-q__fb\" data-fb=\"6\"><\/div>\n          <div class=\"icte-q__fb\" data-fb=\"7\"><\/div>\n          <div class=\"icte-q__fb\" data-fb=\"8\"><\/div>\n          <div class=\"icte-q__fb\" data-fb=\"9\"><\/div>\n        <\/div>\n\n        <div class=\"icte-q\">\n          <div class=\"icte-q__label\">Cost<\/div>\n          <div class=\"icte-note\">\n            <div>\n              \u2022 Total cost for whole family of cruise and farm visit:\n              <span class=\"blank\">\n                10 $ <input type=\"text\" data-q=\"10\" placeholder=\"NUMBER\" \/>\n              <\/span>\n            <\/div>\n          <\/div>\n          <div class=\"icte-q__fb\" data-fb=\"10\"><\/div>\n        <\/div>\n\n      <\/div>\n    <\/section>\n\n    <style>\n      \/* Menu *\/\n      #icte-listening-s1 .icte-menu{\n        width:100%; max-width:100%; box-sizing:border-box;\n        display:flex; flex-wrap:wrap; gap:.5rem; justify-content:center; align-items:center;\n        padding:.75rem .9rem; margin:0 0 1rem 0;\n        background:#16a34a; border-radius:14px; box-shadow:0 2px 8px rgba(0,0,0,.10);\n      }\n      #icte-listening-s1 .icte-menu a{\n        display:inline-block; text-decoration:none; font-weight:900; font-size:.95rem; color:#fff;\n        padding:.55rem .85rem; border-radius:999px; border:1px solid rgba(255,255,255,.35);\n        background:rgba(255,255,255,.12);\n      }\n      #icte-listening-s1 .icte-menu a.is-current{ background:#fff; color:#16a34a; border-color:#fff; }\n      @media (max-width:600px){\n        #icte-listening-s1 .icte-menu{ justify-content:flex-start; }\n        #icte-listening-s1 .icte-menu a{ width:100%; text-align:center; }\n      }\n\n      \/* Shared styling *\/\n      #icte-listening-s1 .icte-ielts{ width:100%; margin:1rem 0; }\n      #icte-listening-s1 .icte-ielts__intro{\n        padding:.9rem 1rem; border:1px solid rgba(0,0,0,.10); border-radius:14px;\n        background:rgba(255,255,255,.7); margin-bottom:1rem;\n      }\n      #icte-listening-s1 .icte-ielts__title{ margin:0 0 .35rem; font-size:1.2rem; font-weight:900; }\n      #icte-listening-s1 .icte-ielts__sub{ margin:0; opacity:.85; }\n\n      #icte-listening-s1 .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-listening-s1 .icte-ielts__panelHead{\n        display:flex; align-items:center; justify-content:space-between; gap:.75rem;\n        padding:.85rem 1rem; border-bottom:1px solid rgba(0,0,0,.08); background:rgba(0,0,0,.03);\n      }\n      #icte-listening-s1 .icte-ielts__h3{ margin:0; font-size:1.03rem; font-weight:900; }\n      #icte-listening-s1 .icte-ielts__headRight{ display:flex; gap:.55rem; align-items:center; }\n\n      #icte-listening-s1 .icte-ielts__reading{\n        padding:.95rem 1rem 1.05rem; line-height:1.75; max-height:420px; overflow:auto;\n        white-space:pre-wrap;\n      }\n\n      #icte-listening-s1 .icte-ielts__row{\n        display:flex; justify-content:space-between; gap:.75rem;\n        padding:.85rem 1rem .25rem;\n      }\n      #icte-listening-s1 .icte-ielts__control label{ display:block; margin-bottom:.35rem; }\n      #icte-listening-s1 select{\n        width:100%; max-width:520px; padding:.6rem .7rem; border-radius:12px;\n        border:1px solid rgba(0,0,0,.18); background:#fff; font:inherit;\n      }\n      #icte-listening-s1 .icte-ielts__score{\n        font-weight:900; font-size:.95rem; opacity:.9; white-space:nowrap;\n        margin-top:.25rem;\n      }\n\n      #icte-listening-s1 .icte-ielts__btnRow{\n        padding:.75rem 1rem 1rem; display:flex; gap:.6rem; flex-wrap:wrap; align-items:center;\n      }\n      #icte-listening-s1 .icte-ielts__btnRow--tight{ padding-top:0; }\n      #icte-listening-s1 .icte-ielts__btnGrid{\n        padding:.75rem 1rem 1rem;\n        display:grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap:.6rem;\n      }\n\n      #icte-listening-s1 .icte-link{\n        font-weight:900; text-decoration:none; border:1px solid rgba(0,0,0,.14);\n        border-radius:12px; padding:.55rem .75rem; color:inherit; background:rgba(255,255,255,.6);\n      }\n\n      #icte-listening-s1 .icte-ielts__qArea{ padding:.9rem 1rem 1rem; }\n      #icte-listening-s1 .icte-q{\n        padding:.75rem .8rem; border:1px solid rgba(0,0,0,.10); border-radius:12px;\n        background:rgba(255,255,255,.75); margin:0 0 .75rem;\n      }\n      #icte-listening-s1 .icte-q__label{ font-weight:900; display:block; margin-bottom:.4rem; }\n\n      #icte-listening-s1 .icte-note{ line-height:1.7; opacity:.95; }\n      #icte-listening-s1 .blank{\n        display:inline-flex; align-items:center; gap:.4rem;\n        padding:.15rem .35rem; border-radius:10px; border:1px dashed rgba(0,0,0,.25);\n        background:rgba(255,255,255,.6); margin:0 .25rem;\n      }\n      #icte-listening-s1 input[type=\"text\"]{\n        width:160px; max-width:100%;\n        padding:.55rem .65rem; border-radius:12px;\n        border:1px solid rgba(0,0,0,.18); font:inherit;\n      }\n      #icte-listening-s1 .icte-q__fb{ margin-top:.35rem; font-size:.95rem; font-weight:800; }\n\n      #icte-listening-s1 .icte-btn{\n        appearance:none; border:1px solid transparent; border-radius:12px;\n        padding:.65rem .85rem; font-weight:900; cursor:pointer; font:inherit;\n      }\n      #icte-listening-s1 .icte-btn--primary{ background:#16a34a; color:#fff; }\n      #icte-listening-s1 .icte-btn--info{ background:#0ea5e9; color:#fff; }\n      #icte-listening-s1 .icte-btn--danger{ background:#dc2626; color:#fff; }\n      #icte-listening-s1 .icte-btn--dark{ background:#334155; color:#fff; }\n      #icte-listening-s1 .icte-btn--ghost{ background:transparent; border-color:rgba(0,0,0,.20); color:inherit; }\n\n      #icte-listening-s1 .icte-loader{\n        width:18px; height:18px; border-radius:999px;\n        border:3px solid rgba(0,0,0,.15); border-top-color:#0ea5e9;\n        display:none; animation: icteSpin 1s linear infinite;\n      }\n      @keyframes icteSpin{ to{ transform: rotate(360deg); } }\n\n      \/* Support *\/\n      #icte-listening-s1 .icte-ielts__helper{\n        padding:.95rem 1rem 1.05rem; line-height:1.7; overflow-wrap:anywhere; word-break:break-word;\n      }\n      #icte-listening-s1 .icte-ielts__helper ul{ margin:.4rem 0 0 1.1rem; }\n      #icte-listening-s1 .icte-ielts__helper li{ margin:.35rem 0; }\n      #icte-listening-s1 .icte-ielts__helper .tag{\n        display:inline-block; padding:.15rem .5rem; border-radius:999px;\n        border:1px solid rgba(0,0,0,.12); background:rgba(255,255,255,.7);\n        font-weight:900; font-size:.85rem; margin-right:.4rem;\n      }\n\n      @media (max-width: 900px){\n        #icte-listening-s1 .icte-ielts__btnGrid{ grid-template-columns: repeat(2, minmax(0, 1fr)); }\n      }\n      @media (max-width: 600px){\n        #icte-listening-s1 .icte-ielts__row{ flex-direction:column; align-items:stretch; }\n        #icte-listening-s1 .icte-ielts__btnGrid{ grid-template-columns: 1fr; }\n        #icte-listening-s1 input[type=\"text\"]{ width:100%; }\n      }\n    <\/style>\n\n    <script>\n      (function(){\n        const root = document.getElementById(\"icte-listening-s1\");\n        if (!root) return;\n\n        \/\/ ===== Conversation lines with roles (NO spoken labels) =====\n        const lines = [\n          { speaker:\"EMPLOYEE\", text:\"Hi. Can I help you?\" },\n          { speaker:\"VISITOR\",  text:\"I'd like to find out if you have any excursions suitable for families.\" },\n          { speaker:\"EMPLOYEE\", text:\"Sure. How about taking your family for a cruise? We have a steamship that takes passengers out several times a day\u2014it's over 100 years old.\" },\n          { speaker:\"VISITOR\",  text:\"That sounds interesting. How long is the trip?\" },\n          { speaker:\"EMPLOYEE\", text:\"About an hour and a half. And don't forget to take pictures of the mountains. They're all around you when you're on the boat and they look fantastic.\" },\n          { speaker:\"VISITOR\",  text:\"OK. And I assume there's a caf\u00e9 or something on board?\" },\n          { speaker:\"EMPLOYEE\", text:\"Sure. How old are your children?\" },\n          { speaker:\"VISITOR\",  text:\"Er, my daughter's fifteen and my son's seven.\" },\n          { speaker:\"EMPLOYEE\", text:\"Right. Well there are various things you can do once you've crossed the lake, to make a day of it. One thing that's very popular is a visit to the Country Farm. You're met off the boat by the farmer and he'll take you to the holding pens, where the sheep are kept. Children love feeding them!\" },\n          { speaker:\"VISITOR\",  text:\"My son would love that. He really likes animals.\" },\n          { speaker:\"EMPLOYEE\", text:\"Well, there's also a 40-minute trek round the farm on a horse, if he wants.\" },\n          { speaker:\"VISITOR\",  text:\"Do you think he'd manage it? He hasn't done that before.\" },\n          { speaker:\"EMPLOYEE\", text:\"Sure, it's suitable for complete beginners.\" },\n          { speaker:\"VISITOR\",  text:\"Ah, good.\" },\n          { speaker:\"EMPLOYEE\", text:\"And again, visitors are welcome to explore the farm on their own, as long as they take care to close gates and so on. There are some very beautiful gardens along the side of the lake which also belong to the farm - they'll be just at their best now. You could easily spend an hour or two there.\" },\n          { speaker:\"VISITOR\",  text:\"OK. Well that all sounds good. And can we get lunch there?\" },\n          { speaker:\"EMPLOYEE\", text:\"You can, and it's very good, though it's not included in the basic cost. You pay when you get there.\" },\n          { speaker:\"VISITOR\",  text:\"Right.\" },\n          { speaker:\"VISITOR\",  text:\"So is there anything else to do over on that side of the lake?\" },\n          { speaker:\"EMPLOYEE\", text:\"Well, what you can do is take a bike over on the ship and then go on a cycling trip. There's a trail there called the Back Road\u2014you could easily spend three or four hours exploring it, and the scenery's wonderful. They'll give you a map when you get your ticket for the cruise\u2014there's no extra charge.\" },\n          { speaker:\"VISITOR\",  text:\"What's the trail like in terms of difficulty?\" },\n          { speaker:\"EMPLOYEE\", text:\"Quite challenging in places. It wouldn't be suitable for your seven-year-old. It needs someone who's got a bit more experience.\" },\n          { speaker:\"VISITOR\",  text:\"Hmm. Well, my daughter loves cycling and so do I, so maybe the two of us could go, and my wife and son could stay on the farm. That might work out quite well. But we don't have bikes here... is there somewhere we could rent them?\" },\n          { speaker:\"EMPLOYEE\", text:\"Yes, there's a place here in the city. It's called Ratchesons.\" },\n          { speaker:\"VISITOR\",  text:\"I'll just make a note of that\u2014er, how do you spell it?\" },\n          { speaker:\"EMPLOYEE\", text:\"R-A-T-C-H-E-S-O-N-S. It's just by the cruise ship terminal.\" },\n          { speaker:\"VISITOR\",  text:\"OK.\" },\n          { speaker:\"EMPLOYEE\", text:\"You'd also need to pick up a repair kit for the bike from there to take along with you, and you'd need to take along a snack and some water - it'd be best to get those in the city.\" },\n          { speaker:\"VISITOR\",  text:\"Fine. That shouldn't be a problem. And I assume I can rent a helmet from the bike place?\" },\n          { speaker:\"EMPLOYEE\", text:\"Sure, you should definitely get that. It's a great ride, but you want to be well prepared because it's very remote - you won't see any shops round there, or anywhere to stay, so you need to get back in time for the last boat.\" },\n          { speaker:\"VISITOR\",  text:\"Yeah. So what sort of prices are we looking at here?\" },\n          { speaker:\"EMPLOYEE\", text:\"Let's see ... Oh, wait a minute, how old did you say your daughter was?\" },\n          { speaker:\"VISITOR\",  text:\"Fifteen.\" },\n          { speaker:\"EMPLOYEE\", text:\"Then I'm afraid it's $267 because she has to pay the adult fare ...\" }\n        ];\n\n        const transcriptText = lines.map(l => (l.speaker===\"EMPLOYEE\" ? \"TC EMPLOYEE: \" : \"VISITOR: \") + l.text).join(\"\\n\");\n\n        \/\/ Answers\n        const answers = {\n          1: [\"mountains\"],\n          2: [\"horse\"],\n          3: [\"garden\", \"gardens\"],\n          4: [\"lunch\"],\n          5: [\"map\"],\n          6: [\"experience\"],\n          7: [\"ratchesons\"],\n          8: [\"helmet\"],\n          9: [\"shops\"],\n          10: [\"267\"]\n        };\n\n        const $ = (sel) => root.querySelector(sel);\n        const $$ = (sel) => Array.from(root.querySelectorAll(sel));\n\n        function showLoader(show){\n          const el = $('[data-el=\"synthesis-loader\"]');\n          if (el) el.style.display = show ? \"inline-block\" : \"none\";\n        }\n\n        \/\/ ===== Speech synthesis (FIXED stop + 2 voices) =====\n        const speechOk = (\"speechSynthesis\" in window);\n        let voicesAll = [];\n        let voiceEmployee = null;\n        let voiceVisitor = null;\n\n        \/\/ Run token: incrementing this cleanly stops any in-progress playback,\n        \/\/ even on browsers where cancel() doesn't fire onend\/onerror reliably.\n        let playRunId = 0;\n\n        function stopSpeaking(){\n          if (!speechOk) return;\n          playRunId++;                 \/\/ invalidate any awaiting promises\n          window.speechSynthesis.cancel();\n          showLoader(false);\n        }\n\n        function sayWithVoice(text, voice, opts){\n          const myRun = playRunId;\n          const options = opts || {};\n          return new Promise((resolve) => {\n            if (!speechOk) return resolve();\n\n            const u = new SpeechSynthesisUtterance(String(text || \"\"));\n            u.lang  = options.lang  || (voice && voice.lang) || \"en-US\";\n            u.rate  = (typeof options.rate === \"number\") ? options.rate : 1.0;\n            u.pitch = (typeof options.pitch === \"number\") ? options.pitch : 1.0;\n            if (voice) u.voice = voice;\n\n            let done = false;\n            const finish = () => {\n              if (done) return;\n              done = true;\n              clearInterval(timer);\n              u.onend = null;\n              u.onerror = null;\n              resolve();\n            };\n\n            u.onend = finish;\n            u.onerror = finish;\n\n            \/\/ Fallback resolver: if user presses Stop, playRunId changes and we resolve.\n            \/\/ Also resolves if synthesis is no longer speaking\/pending.\n            const timer = setInterval(() => {\n              if (done) return;\n              if (playRunId !== myRun) return finish();\n              const speaking = window.speechSynthesis.speaking;\n              const pending  = window.speechSynthesis.pending;\n              if (!speaking && !pending) finish();\n            }, 120);\n\n            window.speechSynthesis.speak(u);\n          });\n        }\n\n        function pickDefaults(usable){\n          const a = usable[0] || null;\n          let b = usable.find(v => v.name !== (a && a.name)) || null;\n          if (!b) b = usable[0] || null;\n          voiceEmployee = a;\n          voiceVisitor = b;\n        }\n\n        function populateVoiceSelects(){\n          if (!speechOk) return;\n\n          voicesAll = window.speechSynthesis.getVoices() || [];\n          const en = voicesAll.filter(v => (v.lang || \"\").toLowerCase().startsWith(\"en\"));\n          const usable = en.length ? en : voicesAll;\n\n          const selE = $('[data-el=\"voice-employee\"]');\n          const selV = $('[data-el=\"voice-visitor\"]');\n          if (!selE || !selV) return;\n\n          selE.innerHTML = \"\";\n          selV.innerHTML = \"\";\n\n          usable.forEach((v, idx) => {\n            const opt1 = document.createElement(\"option\");\n            opt1.value = String(idx);\n            opt1.textContent = `${v.name} (${v.lang})`;\n            selE.appendChild(opt1);\n\n            const opt2 = document.createElement(\"option\");\n            opt2.value = String(idx);\n            opt2.textContent = `${v.name} (${v.lang})`;\n            selV.appendChild(opt2);\n          });\n\n          pickDefaults(usable);\n\n          if (voiceEmployee){\n            const idx = usable.findIndex(v => v.name === voiceEmployee.name && v.lang === voiceEmployee.lang);\n            if (idx >= 0) selE.value = String(idx);\n          }\n          if (voiceVisitor){\n            const idx = usable.findIndex(v => v.name === voiceVisitor.name && v.lang === voiceVisitor.lang);\n            if (idx >= 0) selV.value = String(idx);\n          }\n\n          selE.onchange = () => { voiceEmployee = usable[Number(selE.value)] || usable[0] || null; };\n          selV.onchange = () => { voiceVisitor  = usable[Number(selV.value)] || usable[0] || null; };\n        }\n\n        function loadVoices(){\n          if (!speechOk) return;\n          const got = window.speechSynthesis.getVoices();\n          if (got && got.length) populateVoiceSelects();\n          else window.speechSynthesis.onvoiceschanged = populateVoiceSelects;\n        }\n\n        \/\/ ===== Validation helpers =====\n        function norm(x){\n          return String(x || \"\")\n            .trim()\n            .toLowerCase()\n            .replace(\/[.,!?;:()\"']\/g, \"\")\n            .replace(\/\\s+\/g, \" \");\n        }\n        function tokenCount(x){\n          const t = String(x || \"\").trim();\n          if (!t) return 0;\n          return t.split(\/\\s+\/).length;\n        }\n        function setScore(msg){\n          const box = $('[data-el=\"scoreBox\"]');\n          if (box) box.textContent = msg || \"\";\n        }\n        function setFB(q, msg, color){\n          const fb = root.querySelector(`[data-fb=\"${q}\"]`);\n          if (!fb) return;\n          fb.textContent = msg || \"\";\n          fb.style.color = color || \"#0f172a\";\n        }\n\n        \/\/ ===== Support =====\n        function setHelperContent(nodesBuilder){\n          const area = $('[data-el=\"helper-area\"]');\n          if (!area) return;\n          area.innerHTML = \"\";\n          nodesBuilder(area);\n          area.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n        }\n        function getSummaryText(){\n          return [\n            \"A visitor asks about family-friendly excursions.\",\n            \"The employee recommends a lake cruise and suggests taking photos of the surrounding mountains.\",\n            \"After crossing the lake, families can visit the Country Farm, feed sheep, and take a horse ride; gardens are also available and lunch can be bought there.\",\n            \"For experienced cyclists, there is a challenging trail called the Back Road; bikes can be rented from Ratchesons and riders should take a repair kit, water, snacks, and a helmet.\",\n            \"Because the daughter is fifteen, she pays the adult fare, making the total cost $267.\"\n          ].join(\" \");\n        }\n        function getMainIdeas(){\n          return [\n            { tag: \"Before you listen\", text: \"Read the notes and predict the type of word needed (place, item, number).\" },\n            { tag: \"Numbers\", text: \"Write prices as numbers only (e.g., 267). Check if a child pays adult fare.\" },\n            { tag: \"ONE WORD\", text: \"Keep answers to one word (or a number). Don\u2019t add extra words.\" },\n            { tag: \"Spelling\", text: \"Proper names may be spelled out (e.g., Ratchesons).\" },\n            { tag: \"Distractors\", text: \"You may hear options (farm vs cycling). Choose what fits each blank.\" }\n          ];\n        }\n        async function showSummary(){\n          const summary = getSummaryText();\n          setHelperContent((area) => {\n            const p = document.createElement(\"p\");\n            const tag = document.createElement(\"span\");\n            tag.className = \"tag\";\n            tag.textContent = \"Summary\";\n            p.appendChild(tag);\n            p.append(\" \" + summary);\n            area.appendChild(p);\n          });\n\n          if (speechOk){\n            stopSpeaking();\n            showLoader(true);\n            await sayWithVoice(\"Summary. \" + summary, voiceEmployee || null, { lang:\"en-US\" });\n            showLoader(false);\n          }\n        }\n        async function showMainIdeas(){\n          const items = getMainIdeas();\n          setHelperContent((area) => {\n            const p = document.createElement(\"p\");\n            const tag = document.createElement(\"span\");\n            tag.className = \"tag\";\n            tag.textContent = \"Main ideas\";\n            p.appendChild(tag);\n            p.append(\" Tips for answering the notes:\");\n            area.appendChild(p);\n\n            const ul = document.createElement(\"ul\");\n            items.forEach(i => {\n              const li = document.createElement(\"li\");\n              const t = document.createElement(\"span\");\n              t.className = \"tag\";\n              t.textContent = i.tag;\n              li.appendChild(t);\n              li.append(i.text);\n              ul.appendChild(li);\n            });\n            area.appendChild(ul);\n          });\n\n          if (speechOk){\n            stopSpeaking();\n            showLoader(true);\n            const speakText = \"Main ideas. \" + items.map(i => `${i.tag}. ${i.text}`).join(\" \");\n            await sayWithVoice(speakText, voiceEmployee || null, { lang:\"en-US\" });\n            showLoader(false);\n          }\n        }\n        function clearSupport(){\n          const area = $('[data-el=\"helper-area\"]');\n          if (area) area.innerHTML = 'Click <strong>Summary<\/strong> or <strong>Main ideas<\/strong>.';\n        }\n\n        \/\/ ===== Transcript render =====\n        function renderTranscript(){\n          const area = $('[data-el=\"transcript-area\"]');\n          if (area) area.textContent = transcriptText;\n        }\n\n        \/\/ ===== Audio actions =====\n        async function playInstructions(){\n          if (!speechOk) return;\n          stopSpeaking();\n          showLoader(true);\n          await sayWithVoice(\n            \"Listening Section 1. Questions one to ten. Complete the notes. Write one word and or a number for each answer.\",\n            voiceEmployee || null,\n            { lang:\"en-US\" }\n          );\n          showLoader(false);\n        }\n\n        async function readQuestions(){\n          if (!speechOk) return;\n          stopSpeaking();\n          showLoader(true);\n          await sayWithVoice(\n            \"Questions one to ten. Family excursions notes. \" +\n            \"Question one: photos of the blank that surround the lake. \" +\n            \"Question two: a forty-minute ride on a blank. \" +\n            \"Question three: walk in the farm's blank by the lake. \" +\n            \"Question four: blank is available at extra cost. \" +\n            \"Question five: a blank is provided. \" +\n            \"Question six: only suitable for cyclists who have some blank. \" +\n            \"Question seven: bikes can be hired from blank. \" +\n            \"Question eight: a blank can be hired. \" +\n            \"Question nine: there are no blank or accommodation in the area. \" +\n            \"Question ten: total cost is blank dollars.\",\n            voiceEmployee || null,\n            { lang:\"en-US\" }\n          );\n          showLoader(false);\n        }\n\n        \/\/ Two-role playback WITHOUT speaking labels + STOP reliably cancels\n        async function playConversation(){\n          if (!speechOk) return;\n\n          \/\/ Start a fresh run and stop anything currently speaking\n          stopSpeaking();\n          const myRun = playRunId; \/\/ capture token AFTER stop\n\n          \/\/ Ensure voices are loaded (some browsers are late)\n          if (!voiceEmployee || !voiceVisitor) populateVoiceSelects();\n\n          showLoader(true);\n\n          \/\/ Optional short intro (no labels)\n          await sayWithVoice(\"Now listen to the conversation.\", voiceEmployee || null, { lang:\"en-US\" });\n          if (playRunId !== myRun) { showLoader(false); return; }\n\n          for (const l of lines){\n            if (playRunId !== myRun) { showLoader(false); return; }\n\n            const v = (l.speaker === \"EMPLOYEE\") ? (voiceEmployee || null) : (voiceVisitor || null);\n\n            \/\/ Small natural variation even if voices are similar\n            const opts = (l.speaker === \"EMPLOYEE\")\n              ? { lang:\"en-US\", rate:1.00, pitch:1.00 }\n              : { lang:\"en-US\", rate:1.02, pitch:1.05 };\n\n            await sayWithVoice(l.text, v, opts);\n          }\n\n          showLoader(false);\n        }\n\n        \/\/ ===== Checking =====\n        function check(){\n          let correct = 0;\n          const total = 10;\n\n          for (let i=1;i<=10;i++) setFB(i, \"\", \"\");\n\n          $$('input[data-q]').forEach(inp => {\n            const q = Number(inp.getAttribute(\"data-q\"));\n            const raw = String(inp.value || \"\").trim();\n\n            if (!raw){\n              setFB(q, \"Please write ONE WORD and\/or A NUMBER.\", \"#8a5a00\");\n              return;\n            }\n            if (tokenCount(raw) > 1){\n              setFB(q, \"\u26a0\ufe0f ONE WORD and\/or A NUMBER only.\", \"#8a5a00\");\n              return;\n            }\n\n            const user = norm(raw);\n            const ok = (answers[q] || []).some(a => norm(a) === user);\n\n            if (ok){\n              correct++;\n              setFB(q, `\u2705 Correct (${answers[q][0]})`, \"#065f46\");\n            } else {\n              setFB(q, `\u274c Not correct. Correct answer: ${answers[q][0]}`, \"#991b1b\");\n            }\n          });\n\n          setScore(`Score: ${correct}\/${total}`);\n\n          if (speechOk){\n            showLoader(true);\n            sayWithVoice(`Your score is ${correct} out of ${total}.`, voiceEmployee || null, { lang:\"en-US\" })\n              .then(() => showLoader(false));\n          }\n        }\n\n        function showAll(){\n          for (let i=1;i<=10;i++){\n            setFB(i, `Correct answer: ${answers[i][0]}`, \"#0f172a\");\n          }\n          setScore(\"Correct answers are shown.\");\n        }\n\n        function reset(){\n          $$('input[data-q]').forEach(inp => inp.value = \"\");\n          for (let i=1;i<=10;i++) setFB(i, \"\", \"\");\n          setScore(\"\");\n          clearSupport();\n          stopSpeaking();\n        }\n\n        \/\/ Transcript toggle\n        function toggleTranscript(){\n          const area = $('[data-el=\"transcript-area\"]');\n          const btn = root.querySelector('[data-action=\"toggle-transcript\"]');\n          if (!area || !btn) return;\n\n          const hidden = area.style.display === \"none\";\n          area.style.display = hidden ? \"block\" : \"none\";\n          btn.textContent = hidden ? \"Hide Transcript\" : \"Show Transcript\";\n          if (hidden) area.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n        }\n\n        function markCurrentMenu(){\n          const here = (location.href || \"\").replace(\/\\\/$\/, \"\");\n          root.querySelectorAll(\".icte-menu a\").forEach(a => {\n            const href = (a.href || \"\").replace(\/\\\/$\/, \"\");\n            if (href && (here === href || here.startsWith(href + \"\/\"))) a.classList.add(\"is-current\");\n          });\n        }\n\n        function wire(){\n          const bind = (action, fn) => {\n            const el = root.querySelector(`[data-action=\"${action}\"]`);\n            if (el) el.addEventListener(\"click\", fn);\n          };\n\n          bind(\"toggle-transcript\", toggleTranscript);\n          bind(\"play-instructions\", playInstructions);\n          bind(\"read-questions\", readQuestions);\n          bind(\"play-conversation\", playConversation);\n          bind(\"stop-audio\", stopSpeaking);     \/\/ FIXED: now reliably stops playback\n          bind(\"check\", check);\n          bind(\"show\", showAll);\n          bind(\"summary\", showSummary);\n          bind(\"main-ideas\", showMainIdeas);\n          bind(\"clear-support\", clearSupport);\n          bind(\"reset\", reset);\n        }\n\n        function init(){\n          renderTranscript();\n          loadVoices();\n          wire();\n          markCurrentMenu();\n          clearSupport();\n        }\n\n        if (document.readyState === \"loading\") document.addEventListener(\"DOMContentLoaded\", init);\n        else init();\n\n      })();\n    <\/script>\n\n  <\/section>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Overview Section 1 Section 2 Section 3 Section 4 Reading Speaking Writing IELTS Listening \u2013 Section 1 (Questions 1\u201310): Family<\/p>\n","protected":false},"author":1,"featured_media":253,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_layout":"default_layout","footnotes":""},"categories":[25,28,27],"tags":[],"class_list":["post-461","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ielts","category-listening","category-test-1"],"_links":{"self":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/461","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=461"}],"version-history":[{"count":3,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/461\/revisions"}],"predecessor-version":[{"id":493,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/461\/revisions\/493"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media\/253"}],"wp:attachment":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media?parent=461"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/categories?post=461"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/tags?post=461"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}