{"id":738,"date":"2026-03-04T10:01:13","date_gmt":"2026-03-04T10:01:13","guid":{"rendered":"https:\/\/i-cte.org\/robot\/?p=738"},"modified":"2026-03-04T10:01:13","modified_gmt":"2026-03-04T10:01:13","slug":"people-and-relationships","status":"publish","type":"post","link":"https:\/\/i-cte.org\/robot\/people-and-relationships\/","title":{"rendered":"People and relationships"},"content":{"rendered":"\n<!-- \u2705 ICTE Chatbot Lesson \u2014 Personal Best (B1) Unit 12 (WP-safe single block) -->\n<div id=\"icte-u12\">\n\n  <!-- \u2705 TOP MENU -->\n  <nav class=\"icte-menu\" aria-label=\"Unit 12 lesson navigation\">\n    <a href=\"#\" class=\"is-current\" data-view=\"conversation\">Conversation<\/a>\n    <a href=\"#\" data-view=\"vocab\">Vocabulary<\/a>\n    <a href=\"#\" data-view=\"grammar\">Grammar<\/a>\n    <a href=\"#\" data-view=\"discussion\">Discussion<\/a>\n    <a href=\"#\" data-view=\"reading\">Reading<\/a>\n    <a href=\"#\" data-view=\"listening\">Listening<\/a>\n    <a href=\"#\" data-view=\"problemsolving\">Problem-solving<\/a>\n    <a href=\"#\" data-view=\"progress\">Progress<\/a>\n  <\/nav>\n\n  <section class=\"icte-shell\" aria-label=\"ICTE Unit 12 practice\">\n\n    <!-- \u2705 Header -->\n    <header class=\"icte-hero\">\n      <div class=\"icte-hero__text\">\n        <h2>Unit 12 \u2014 People and relationships<\/h2>\n        <p class=\"muted\">\n          Practice <b>defining relative clauses<\/b> (<i>who \/ that \/ where<\/i>), <b>relationships<\/b> + <b>relationship verbs<\/b>,\n          reading skill (<b>interpreting data<\/b>) and text builder (<b>approximate quantities<\/b>),\n          and speaking skills (<b>saying thanks<\/b> + <b>responding modestly<\/b>).\n        <\/p>\n      <\/div>\n\n      <div class=\"icte-hero__controls\">\n        <div class=\"icte-pill\">\n          <span class=\"dot\" id=\"icteMicDot\" aria-hidden=\"true\"><\/span>\n          <span id=\"icteMicStatus\">Mic: Off<\/span>\n        <\/div>\n\n        <div class=\"icte-row\">\n          <button class=\"btn\" id=\"icteStartVoice\" type=\"button\">Start Voice<\/button>\n          <button class=\"btn ghost\" id=\"icteStopVoice\" type=\"button\">Stop<\/button>\n        <\/div>\n\n        <label class=\"icte-label\">\n          Voice (Narrator)\n          <select id=\"icteVoiceSelect\" class=\"icte-select\" aria-label=\"Voice selection\"><\/select>\n        <\/label>\n\n        <div class=\"icte-small muted\">\n          Tip: If you don\u2019t see voices yet, click anywhere once and wait 2\u20133 seconds.\n        <\/div>\n      <\/div>\n    <\/header>\n\n    <!-- \u2705 Views -->\n    <main class=\"icte-main\">\n\n      <!-- ===================== -->\n      <!-- \u2705 1) CONVERSATION -->\n      <!-- ===================== -->\n      <section class=\"view is-active\" data-view=\"conversation\" aria-label=\"Conversation practice\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>1) Conversation (Voice Interactive)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"conv-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"convReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Speak your answers. Try to use <b>who \/ that \/ where<\/b> (defining relative clauses),\n            and at least one <b>relationship word<\/b> (e.g., <i>colleague, in-laws, roommate<\/i>).\n            Bonus: use an <b>approximate quantity<\/b> (<i>about, around, roughly, nearly, at least<\/i>)\n            or a <b>thank-you<\/b> expression.\n          <\/p>\n\n          <div class=\"chat\" id=\"convChat\" aria-live=\"polite\" aria-label=\"Conversation chat log\"><\/div>\n\n          <div class=\"chatbar\">\n            <input id=\"convText\" class=\"input\" type=\"text\" placeholder=\"Type your answer (optional)...\" autocomplete=\"off\" \/>\n            <button class=\"btn\" id=\"convSend\" type=\"button\">Send<\/button>\n            <button class=\"btn ghost\" id=\"convHear\" type=\"button\">\ud83d\udd0a Read last question<\/button>\n          <\/div>\n\n          <div class=\"muted icte-small\">\n            Targets: defining relative clauses + relationships + polite thanking.\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 2) VOCABULARY -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"vocab\" aria-label=\"Vocabulary practice\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>2) Vocabulary (Relationships + Relationship verbs)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"vocab-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"vocabReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Match the words to the meanings, then complete the sentences using the same vocabulary.\n          <\/p>\n\n          <div class=\"grid2\">\n            <div>\n              <h4 class=\"h4\">A) Matching<\/h4>\n              <div id=\"vocabMatch\" class=\"stack\"><\/div>\n              <button class=\"btn\" id=\"vocabCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"vocabFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n\n            <div>\n              <h4 class=\"h4\">B) Use the words (Fill in the blanks)<\/h4>\n              <div id=\"vocabUse\" class=\"stack\"><\/div>\n              <button class=\"btn\" id=\"vocabUseCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"vocabUseFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 3) GRAMMAR -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"grammar\" aria-label=\"Grammar practice\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>3) Grammar \u2014 Defining relative clauses + Approximate quantities<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"gram-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"gramReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n\n          <div class=\"note\">\n            <b>Relative clauses:<\/b> use <b>who<\/b> (people), <b>that<\/b> (things\/people), <b>where<\/b> (places). :contentReference[oaicite:0]{index=0}<br>\n            <b>Approximate quantities:<\/b> use <b>about \/ around \/ roughly<\/b>, <b>at least<\/b>, <b>nearly \/ almost<\/b>, <b>just over<\/b>. :contentReference[oaicite:1]{index=1}\n          <\/div>\n\n          <div class=\"grid2\">\n            <div>\n              <h4 class=\"h4\">A) who \/ that \/ where<\/h4>\n              <div id=\"relQuiz\" class=\"stack\"><\/div>\n              <button class=\"btn\" id=\"relCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"relFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n            <div>\n              <h4 class=\"h4\">B) Approximate quantities<\/h4>\n              <div id=\"qtyQuiz\" class=\"stack\"><\/div>\n              <button class=\"btn\" id=\"qtyCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"qtyFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 4) DISCUSSION -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"discussion\" aria-label=\"Discussion practice\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>4) Discussion (Voice or typing)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"disc-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"discNext\">Next question<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Answer with reasons. Try to include:\n            <b>(1)<\/b> at least <b>2 vocabulary items<\/b>,\n            <b>(2)<\/b> one <b>relative clause<\/b>,\n            <b>(3)<\/b one <b>approximate quantity<\/b> OR one <b>thank-you \/ modest response<\/b>.\n          <\/p>\n\n          <div class=\"qa\">\n            <div class=\"q\" id=\"discQ\">Click <b>Next question<\/b> to begin.<\/div>\n            <textarea id=\"discA\" class=\"textarea\" rows=\"4\" placeholder=\"Write your answer here...\"><\/textarea>\n            <div class=\"row\">\n              <button class=\"btn\" id=\"discCheck\" type=\"button\">Check my language<\/button>\n              <button class=\"btn ghost\" id=\"discSpeakQ\" type=\"button\">\ud83d\udd0a Read question<\/button>\n            <\/div>\n            <div class=\"feedback\" id=\"discFb\" aria-live=\"polite\"><\/div>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 5) READING -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"reading\" aria-label=\"Reading comprehension\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>5) Reading \u2014 \u201cBring your parents to work\u201d<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"read-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini\" type=\"button\" id=\"readTextBtn\">\ud83d\udd0a Read the text<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Read the text, then answer the questions. (LinkedIn + 37 million + 80 companies) :contentReference[oaicite:2]{index=2}\n          <\/p>\n\n          <article class=\"reading\" id=\"readingText\">\n            <div class=\"reading-title\">Would you bring your parents to work?<\/div>\n            <div class=\"reading-p\"><b>1<\/b> Bring Your Parents to Work Day is becoming popular in some U.S. companies. People wonder what their parents might say to their boss or co-workers.<\/div>\n            <div class=\"reading-p\"><b>2<\/b> The company where it started, LinkedIn, said many parents don\u2019t understand what their children\u2019s jobs involve. There is already Take Your Child to Work Day, and more than 37 million Americans take part every year.<\/div>\n            <div class=\"reading-p\"><b>3<\/b> LinkedIn argues that employees who feel supported by their family are happier and more productive. Now, more than 80 companies in 18 countries organize an annual event for parents.<\/div>\n            <div class=\"reading-p\"><b>4<\/b> Martin Richards visited the office where his daughter and son-in-law work. He said it was a great chance to see how digital marketing works, meet co-workers, and spend a day with his daughter.<\/div>\n          <\/article>\n\n          <div class=\"grid2\">\n            <div>\n              <h4 class=\"h4\">A) Comprehension<\/h4>\n              <div id=\"readQ\" class=\"stack\"><\/div>\n              <button class=\"btn\" id=\"readCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"readFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n\n            <div>\n              <h4 class=\"h4\">B) Relative clause spotter<\/h4>\n              <div class=\"note\">\n                Find and type <b>one<\/b> sentence from the text that includes <b>where<\/b> or <b>who<\/b> or <b>that<\/b>.\n              <\/div>\n              <textarea id=\"readClause\" class=\"textarea\" rows=\"3\" placeholder=\"Type your sentence here...\"><\/textarea>\n              <button class=\"btn\" id=\"readClauseCheck\" type=\"button\">Check<\/button>\n              <div class=\"feedback\" id=\"readClauseFb\" aria-live=\"polite\"><\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 6) LISTENING -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"listening\" aria-label=\"Listening comprehension\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>6) Listening \u2014 \u201cThanks a million!\u201d (Learning Curve)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"list-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini\" type=\"button\" id=\"listenPlay\">\u25b6\ufe0f Play listening (TTS)<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"listenStop\">\u23f9 Stop<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Click <b>Play listening<\/b>. Listen and complete the gaps about <b>thanking<\/b> and <b>responding modestly<\/b>.\n            (Key phrases: <i>Thanks a lot \/ Thanks so much \/ Thanks a million \/ It isn\u2019t a problem \/ You\u2019re welcome \/ I had help<\/i>.) :contentReference[oaicite:3]{index=3} :contentReference[oaicite:4]{index=4}\n          <\/p>\n\n          <div id=\"listenGaps\" class=\"stack\"><\/div>\n          <button class=\"btn\" id=\"listenCheck\" type=\"button\">Check<\/button>\n          <div class=\"feedback\" id=\"listenFb\" aria-live=\"polite\"><\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 7) PROBLEM-SOLVING -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"problemsolving\" aria-label=\"Problem-solving tasks\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>7) Problem-solving (Real-life relationships)<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini\" type=\"button\" data-say=\"prob-instr\">\ud83d\udd0a Read instructions<\/button>\n              <button class=\"btn mini ghost\" type=\"button\" id=\"probReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n\n          <p class=\"muted\">\n            Choose the best response. Then write <b>one<\/b> sentence using a <b>relative clause<\/b> or a <b>modest reply<\/b>.\n          <\/p>\n\n          <div id=\"probSet\" class=\"stack\"><\/div>\n          <button class=\"btn\" id=\"probCheck\" type=\"button\">Check<\/button>\n          <div class=\"feedback\" id=\"probFb\" aria-live=\"polite\"><\/div>\n        <\/div>\n      <\/section>\n\n      <!-- ===================== -->\n      <!-- \u2705 8) PROGRESS -->\n      <!-- ===================== -->\n      <section class=\"view\" data-view=\"progress\" aria-label=\"Progress tracking\">\n        <div class=\"card\">\n          <div class=\"card-h\">\n            <h3>Progress<\/h3>\n            <div class=\"card-actions\">\n              <button class=\"btn mini ghost\" type=\"button\" id=\"progressReset\">Clear progress<\/button>\n            <\/div>\n          <\/div>\n\n          <div class=\"progress-grid\">\n            <div class=\"pbox\">\n              <div class=\"pnum\" id=\"pDone\">0<\/div>\n              <div class=\"muted\">Activities completed<\/div>\n            <\/div>\n            <div class=\"pbox\">\n              <div class=\"pnum\" id=\"pScore\">0%<\/div>\n              <div class=\"muted\">Average score<\/div>\n            <\/div>\n            <div class=\"pbox\">\n              <div class=\"pnum\" id=\"pVocab\">0<\/div>\n              <div class=\"muted\">Vocab used (detected)<\/div>\n            <\/div>\n          <\/div>\n\n          <div class=\"note\">\n            Completion is saved in your browser (local storage). If you change device\/browser, progress resets.\n          <\/div>\n\n          <h4 class=\"h4\">Vocabulary Bank (Unit 12)<\/h4>\n          <div class=\"bank\" id=\"vocabBank\"><\/div>\n        <\/div>\n      <\/section>\n\n    <\/main>\n  <\/section>\n\n  <style>\n    \/* ===== WP-SAFE STYLES (scoped) ===== *\/\n    #icte-u12 *{ box-sizing:border-box; }\n    #icte-u12{\n      --green:#28a745;\n      --dark:#132018;\n      --card:#ffffff;\n      --muted:#6b7280;\n      --line:#e5e7eb;\n      --shadow:0 8px 24px rgba(17,24,39,.08);\n      --radius:16px;\n      font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;\n      color:#111827;\n    }\n    #icte-u12 .icte-menu{\n      width:100%;\n      background:var(--green);\n      padding:10px 12px;\n      text-align:center;\n      overflow-x:auto;\n      white-space:nowrap;\n      position:sticky;\n      top:0;\n      z-index:999;\n      box-shadow:0 2px 10px rgba(0,0,0,.12);\n      border-radius:12px;\n      margin-bottom:12px;\n    }\n    #icte-u12 .icte-menu a{\n      display:inline-block;\n      color:#fff;\n      text-decoration:none;\n      font-weight:700;\n      padding:8px 10px;\n      border-radius:999px;\n      margin:0 3px;\n      opacity:.92;\n      transition:.15s;\n    }\n    #icte-u12 .icte-menu a:hover{ opacity:1; background:rgba(255,255,255,.14); }\n    #icte-u12 .icte-menu a.is-current{ background:#fff; color:var(--dark); opacity:1; }\n\n    #icte-u12 .icte-shell{ max-width:1100px; margin:0 auto; }\n    #icte-u12 .icte-hero{\n      display:grid;\n      grid-template-columns: 1.2fr .8fr;\n      gap:14px;\n      background:linear-gradient(135deg,#e9fff0, #ffffff);\n      border:1px solid var(--line);\n      border-radius:var(--radius);\n      padding:16px;\n      box-shadow:var(--shadow);\n      margin-bottom:14px;\n    }\n    @media (max-width: 920px){ #icte-u12 .icte-hero{ grid-template-columns:1fr; } }\n\n    #icte-u12 h2{ margin:0 0 6px 0; font-size:22px; }\n    #icte-u12 .muted{ color:var(--muted); }\n\n    #icte-u12 .icte-hero__controls{\n      border-left:1px dashed var(--line);\n      padding-left:14px;\n    }\n    @media (max-width: 920px){\n      #icte-u12 .icte-hero__controls{ border-left:none; padding-left:0; border-top:1px dashed var(--line); padding-top:12px; }\n    }\n\n    #icte-u12 .icte-row{ display:flex; gap:8px; flex-wrap:wrap; }\n    #icte-u12 .icte-label{ display:block; font-size:12px; font-weight:800; margin-top:10px; }\n    #icte-u12 .icte-select{\n      width:100%;\n      padding:10px 10px;\n      border:1px solid var(--line);\n      border-radius:12px;\n      background:#fff;\n      outline:none;\n      margin-top:6px;\n    }\n\n    #icte-u12 .icte-pill{\n      display:flex; align-items:center; gap:8px;\n      padding:10px 12px;\n      border:1px solid var(--line);\n      border-radius:999px;\n      background:#fff;\n      margin-bottom:10px;\n      font-weight:800;\n    }\n    #icte-u12 .dot{\n      width:10px; height:10px; border-radius:50%;\n      background:#9ca3af;\n      box-shadow:0 0 0 4px rgba(156,163,175,.18);\n    }\n    #icte-u12 .dot.on{\n      background:#22c55e;\n      box-shadow:0 0 0 4px rgba(34,197,94,.18);\n    }\n\n    #icte-u12 .btn{\n      border:none;\n      padding:10px 12px;\n      border-radius:12px;\n      background:var(--green);\n      color:#fff;\n      font-weight:800;\n      cursor:pointer;\n      transition:.15s;\n    }\n    #icte-u12 .btn:hover{ filter:brightness(.95); transform:translateY(-1px); }\n    #icte-u12 .btn:active{ transform:translateY(0); }\n    #icte-u12 .btn.ghost{\n      background:#fff;\n      color:#111827;\n      border:1px solid var(--line);\n    }\n    #icte-u12 .btn.mini{ padding:8px 10px; border-radius:10px; font-size:13px; }\n    #icte-u12 .icte-small{ font-size:12px; }\n\n    #icte-u12 .card{\n      background:var(--card);\n      border:1px solid var(--line);\n      border-radius:var(--radius);\n      padding:14px;\n      box-shadow:var(--shadow);\n      margin-bottom:14px;\n    }\n    #icte-u12 .card-h{\n      display:flex; gap:10px; align-items:flex-start; justify-content:space-between;\n      border-bottom:1px solid var(--line);\n      padding-bottom:10px;\n      margin-bottom:10px;\n    }\n    #icte-u12 .card-h h3{ margin:0; font-size:18px; }\n    #icte-u12 .card-actions{ display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end; }\n\n    #icte-u12 .view{ display:none; }\n    #icte-u12 .view.is-active{ display:block; }\n\n    #icte-u12 .chat{\n      background:#0b1220;\n      color:#e5e7eb;\n      border-radius:14px;\n      padding:12px;\n      min-height:220px;\n      max-height:420px;\n      overflow:auto;\n      border:1px solid rgba(255,255,255,.08);\n    }\n    #icte-u12 .msg{ margin:10px 0; display:flex; gap:10px; align-items:flex-start; }\n    #icte-u12 .who{\n      min-width:72px;\n      font-weight:900;\n      font-size:12px;\n      color:#93c5fd;\n      text-transform:uppercase;\n      letter-spacing:.06em;\n    }\n    #icte-u12 .bubble{\n      flex:1;\n      background:rgba(255,255,255,.06);\n      padding:10px 10px;\n      border-radius:12px;\n      line-height:1.45;\n      border:1px solid rgba(255,255,255,.06);\n    }\n    #icte-u12 .msg.user .who{ color:#86efac; }\n    #icte-u12 .msg.user .bubble{ background:rgba(34,197,94,.10); border-color:rgba(34,197,94,.18); }\n\n    #icte-u12 .chatbar{\n      margin-top:10px;\n      display:flex;\n      gap:8px;\n      align-items:center;\n    }\n    #icte-u12 .input{\n      flex:1;\n      padding:12px 12px;\n      border:1px solid var(--line);\n      border-radius:12px;\n      outline:none;\n    }\n    #icte-u12 .textarea{\n      width:100%;\n      padding:12px;\n      border:1px solid var(--line);\n      border-radius:12px;\n      outline:none;\n      resize:vertical;\n    }\n\n    #icte-u12 .grid2{\n      display:grid;\n      grid-template-columns:1fr 1fr;\n      gap:14px;\n      margin-top:10px;\n    }\n    @media (max-width: 920px){ #icte-u12 .grid2{ grid-template-columns:1fr; } }\n\n    #icte-u12 .stack{ display:flex; flex-direction:column; gap:10px; }\n    #icte-u12 .h4{ margin:0 0 6px 0; font-size:15px; }\n    #icte-u12 .qitem{\n      padding:10px;\n      border:1px solid var(--line);\n      border-radius:14px;\n      background:#fafafa;\n    }\n    #icte-u12 .qtext{ font-weight:800; margin-bottom:8px; }\n    #icte-u12 .row{ display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }\n\n    #icte-u12 .feedback{\n      margin-top:10px;\n      padding:10px 12px;\n      border-radius:14px;\n      border:1px solid var(--line);\n      background:#f9fafb;\n      font-weight:700;\n      display:none;\n      white-space:pre-line;\n    }\n    #icte-u12 .feedback.ok{ display:block; border-color:rgba(34,197,94,.35); background:#ecfdf5; }\n    #icte-u12 .feedback.bad{ display:block; border-color:rgba(239,68,68,.35); background:#fef2f2; }\n\n    #icte-u12 .note{\n      background:#eff6ff;\n      border:1px solid rgba(59,130,246,.22);\n      padding:10px 12px;\n      border-radius:14px;\n      margin:10px 0;\n    }\n\n    #icte-u12 .reading{\n      border:1px solid var(--line);\n      border-radius:14px;\n      padding:12px;\n      background:#fff;\n      margin-top:10px;\n    }\n    #icte-u12 .reading-title{ font-weight:900; margin-bottom:8px; }\n    #icte-u12 .reading-p{ padding:8px 0; border-top:1px dashed var(--line); }\n    #icte-u12 .reading-p:first-of-type{ border-top:none; }\n\n    #icte-u12 .qa .q{\n      padding:12px;\n      border-radius:14px;\n      border:1px solid var(--line);\n      background:#fff;\n      font-weight:900;\n    }\n\n    #icte-u12 .progress-grid{\n      display:grid;\n      grid-template-columns:repeat(3,1fr);\n      gap:12px;\n      margin-top:10px;\n      margin-bottom:10px;\n    }\n    @media (max-width: 920px){ #icte-u12 .progress-grid{ grid-template-columns:1fr; } }\n    #icte-u12 .pbox{\n      border:1px solid var(--line);\n      border-radius:16px;\n      background:#fff;\n      padding:12px;\n      text-align:center;\n      box-shadow:var(--shadow);\n    }\n    #icte-u12 .pnum{ font-size:28px; font-weight:1000; }\n\n    #icte-u12 .bank{\n      border:1px solid var(--line);\n      border-radius:14px;\n      padding:12px;\n      background:#fff;\n      display:flex;\n      flex-wrap:wrap;\n      gap:8px;\n    }\n    #icte-u12 .tag{\n      border:1px solid var(--line);\n      background:#f9fafb;\n      padding:6px 10px;\n      border-radius:999px;\n      font-weight:800;\n      font-size:13px;\n    }\n  <\/style>\n\n  <script>\n    (function(){\n      const root = document.getElementById('icte-u12');\n      if(!root) return;\n\n      \/* =========================\n         Helpers\n      ========================= *\/\n      const qs = (sel, el=root) => el.querySelector(sel);\n      const qsa = (sel, el=root) => Array.from(el.querySelectorAll(sel));\n      const clamp = (n,min,max)=>Math.max(min,Math.min(max,n));\n      const norm = (s)=> (s||\"\").toString().trim();\n      const lower = (s)=> norm(s).toLowerCase();\n      const esc = (s)=> (s||\"\").replace(\/[&<>\"']\/g, m=>({ \"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#039;\" }[m]));\n      const shuffle = (arr)=> arr.map(v=>({v, r:Math.random()})).sort((a,b)=>a.r-b.r).map(o=>o.v);\n\n      \/* =========================\n         Navigation\n      ========================= *\/\n      const navLinks = qsa('.icte-menu a');\n      const views = qsa('.view');\n      function showView(name){\n        views.forEach(v=> v.classList.toggle('is-active', v.getAttribute('data-view')===name));\n        navLinks.forEach(a=> a.classList.toggle('is-current', a.getAttribute('data-view')===name));\n        window.scrollTo({top: root.offsetTop - 10, behavior:'smooth'});\n      }\n      navLinks.forEach(a=>{\n        a.addEventListener('click', (e)=>{\n          e.preventDefault();\n          const v = a.getAttribute('data-view');\n          if(v) showView(v);\n        });\n      });\n\n      \/* =========================\n         Speech (TTS + ASR)\n      ========================= *\/\n      const micDot = qs('#icteMicDot');\n      const micStatus = qs('#icteMicStatus');\n      const voiceSel = qs('#icteVoiceSelect');\n      const btnStartVoice = qs('#icteStartVoice');\n      const btnStopVoice = qs('#icteStopVoice');\n\n      let chosenVoice = null;\n      let recognition = null;\n      let listening = false;\n      let lastPromptSpoken = \"\";\n\n      function loadVoices(){\n        if(!window.speechSynthesis) return;\n        const all = speechSynthesis.getVoices() || [];\n        let list = all.filter(v => (v.lang||\"\").toLowerCase().startsWith(\"en\"));\n        if(list.length === 0) list = all;\n\n        voiceSel.innerHTML = \"\";\n        list.forEach((v,i)=>{\n          const opt = document.createElement('option');\n          opt.value = String(i);\n          opt.textContent = `${v.name} (${v.lang})`;\n          voiceSel.appendChild(opt);\n        });\n\n        chosenVoice = list[0] || null;\n        voiceSel.onchange = ()=>{\n          const idx = parseInt(voiceSel.value,10);\n          chosenVoice = list[idx] || chosenVoice;\n        };\n      }\n      if(window.speechSynthesis){\n        loadVoices();\n        speechSynthesis.onvoiceschanged = loadVoices;\n      }\n\n      function speak(text){\n        const t = norm(text);\n        if(!t || !window.speechSynthesis) return;\n        speechSynthesis.cancel();\n        const u = new SpeechSynthesisUtterance(t);\n        if(chosenVoice) u.voice = chosenVoice;\n        u.rate = 1.02; u.pitch = 1.0; u.volume = 1.0;\n        speechSynthesis.speak(u);\n      }\n      function stopSpeak(){ if(window.speechSynthesis) speechSynthesis.cancel(); }\n\n      function setMicUI(on){\n        listening = on;\n        micDot.classList.toggle('on', on);\n        micStatus.textContent = on ? \"Mic: Listening\u2026\" : \"Mic: Off\";\n      }\n\n      function initRecognition(){\n        const SR = window.SpeechRecognition || window.webkitSpeechRecognition;\n        if(!SR) return null;\n        const r = new SR();\n        r.lang = 'en-US';\n        r.continuous = true;\n        r.interimResults = false;\n        r.maxAlternatives = 1;\n        return r;\n      }\n\n      function startListening(){\n        if(listening) return;\n        recognition = recognition || initRecognition();\n        if(!recognition){\n          alert(\"Speech Recognition is not available in this browser. Use Chrome\/Edge, or type your answers.\");\n          return;\n        }\n        recognition.onresult = (e)=>{\n          const res = e.results[e.results.length - 1];\n          const transcript = res && res[0] ? res[0].transcript : \"\";\n          handleVoiceTranscript(transcript);\n        };\n        recognition.onerror = ()=> setMicUI(false);\n        recognition.onend = ()=>{\n          if(listening){ try{ recognition.start(); }catch(_){ } }\n        };\n        setMicUI(true);\n        try{ recognition.start(); }catch(_){ }\n      }\n      function stopListening(){\n        setMicUI(false);\n        try{ recognition && recognition.stop(); }catch(_){ }\n      }\n      btnStartVoice.addEventListener('click', startListening);\n      btnStopVoice.addEventListener('click', stopListening);\n\n      \/* =========================\n         Progress\n      ========================= *\/\n      const LS_KEY = \"icte_u12_progress_v1\";\n      const progress = JSON.parse(localStorage.getItem(LS_KEY) || \"{}\");\n\n      function saveProgress(){ localStorage.setItem(LS_KEY, JSON.stringify(progress)); renderProgress(); }\n      function markDone(key, scorePct){\n        progress[key] = { done:true, score: clamp(scorePct,0,100), ts: Date.now() };\n        saveProgress();\n      }\n      function resetProgress(){ localStorage.removeItem(LS_KEY); location.reload(); }\n      qs('#progressReset').addEventListener('click', resetProgress);\n\n      \/* =========================\n         Content: Vocabulary bank (Unit 12)\n         (relationships list in overview) :contentReference[oaicite:5]{index=5}\n      ========================= *\/\n      const vocabRelationshipsCore = [\n        {word:\"boss\", def:\"someone who manages you at work\"},\n        {word:\"in-laws\", def:\"your husband\u2019s\/wife\u2019s mother and father\"},\n        {word:\"employee\", def:\"someone who works for you \/ a worker\"},\n        {word:\"relative\", def:\"someone in your family\"},\n        {word:\"colleague\", def:\"someone who works with you\"},\n        {word:\"neighbor\", def:\"someone who lives near you\"},\n        {word:\"roommate\", def:\"someone who shares an apartment with you\"},\n        {word:\"business partner\", def:\"someone who owns a company with you\"}\n      ];\n\n      \/\/ extra relationship words from Unit overview (B1 personal relationships)\n      const vocabRelationshipsMore = [\n        {word:\"bride\", def:\"a woman who is getting married\"},\n        {word:\"brother-in-law\", def:\"your spouse\u2019s brother (or your sibling\u2019s husband)\"},\n        {word:\"classmate\", def:\"someone who is\/was in the same class as you\"},\n        {word:\"cousin\", def:\"your aunt or uncle\u2019s child\"},\n        {word:\"employer\", def:\"a person\/company that employs people\"},\n        {word:\"enemy\", def:\"a person who is against you\"},\n        {word:\"ex-husband\", def:\"a man you were married to before\"},\n        {word:\"girlfriend\", def:\"a female romantic partner\"},\n        {word:\"groom\", def:\"a man who is getting married\"},\n        {word:\"only child\", def:\"a child with no brothers or sisters\"},\n        {word:\"single parent\", def:\"a parent raising a child alone\"},\n        {word:\"stepsister\", def:\"your step-parent\u2019s daughter\"},\n        {word:\"stranger\", def:\"a person you don\u2019t know\"},\n        {word:\"twin\", def:\"a sibling born at the same time as you\"}\n      ];\n\n      const vocabRelVerbs = [\n        {word:\"ask (someone) out\", def:\"invite someone on a date\"},\n        {word:\"become friends\", def:\"start being friends\"},\n        {word:\"break up\", def:\"end a relationship\"},\n        {word:\"fall in love\", def:\"start loving someone romantically\"},\n        {word:\"get back together\", def:\"start a relationship again\"},\n        {word:\"get married\", def:\"become husband and wife\"},\n        {word:\"get along (well)\", def:\"have a friendly relationship\"},\n        {word:\"get to know\", def:\"learn more about a person\"},\n        {word:\"go on a date\", def:\"meet someone socially\/romantically\"},\n        {word:\"go out (together)\", def:\"be in a relationship\"},\n        {word:\"have (something) in common\", def:\"share interests\/experiences\"},\n        {word:\"introduce\", def:\"tell people each other\u2019s names\"},\n        {word:\"stay in touch\", def:\"keep contact (messages\/calls)\"}\n      ];\n\n      const vocabAll = [...vocabRelationshipsCore, ...vocabRelationshipsMore, ...vocabRelVerbs];\n\n      \/\/ render bank\n      const bank = qs('#vocabBank');\n      bank.innerHTML = vocabAll.map(v=>`<span class=\"tag\" title=\"${esc(v.def)}\">${esc(v.word)}<\/span>`).join(\"\");\n\n      function renderProgress(){\n        const items = Object.values(progress).filter(p=>p && p.done);\n        const done = items.length;\n        const avg = done ? Math.round(items.reduce((s,p)=>s+(p.score||0),0)\/done) : 0;\n\n        qs('#pDone').textContent = String(done);\n        qs('#pScore').textContent = String(avg) + \"%\";\n\n        const used = new Set();\n        const txt = (progress._vocabUsedText||\"\");\n        vocabAll.forEach(w=>{\n          if(lower(txt).includes(lower(w.word))) used.add(w.word);\n        });\n        qs('#pVocab').textContent = String(used.size);\n      }\n\n      \/* =========================\n         Instruction TTS map\n      ========================= *\/\n      const SAY = {\n        \"conv-instr\":\n          \"Conversation. Answer using defining relative clauses with who, that, or where. Include relationship vocabulary like colleague, in laws, or roommate. You can also use approximate quantities like about, roughly, or at least.\",\n        \"vocab-instr\":\n          \"Vocabulary. Match relationship words and relationship verbs to meanings. Then complete the sentences using the same words.\",\n        \"gram-instr\":\n          \"Grammar. Part A: choose who, that, or where. Part B: choose an approximate quantity expression like about, around, roughly, nearly, or at least.\",\n        \"disc-instr\":\n          \"Discussion. Include two vocabulary items, one defining relative clause, and one approximate quantity or a thank you expression.\",\n        \"read-instr\":\n          \"Reading. Read about Bring Your Parents to Work Day and answer questions about the key facts and details.\",\n        \"list-instr\":\n          \"Listening. Listen for thank you phrases and modest responses such as Thanks a lot, Thanks a million, It isn't a problem, and You're welcome.\",\n        \"prob-instr\":\n          \"Problem-solving. Choose the best response and write one sentence using a relative clause or responding modestly.\"\n      };\n      qsa('[data-say]').forEach(btn=>{\n        btn.addEventListener('click', ()=>{\n          const k = btn.getAttribute('data-say');\n          if(SAY[k]) speak(SAY[k]);\n        });\n      });\n\n      \/* =========================\n         1) Conversation engine\n      ========================= *\/\n      const convChat = qs('#convChat');\n      const convText = qs('#convText');\n      const convSend = qs('#convSend');\n      const convHear = qs('#convHear');\n      const convReset = qs('#convReset');\n\n      let convStep = 0;\n\n      const convSteps = [\n        {\n          bot: \"Hi! Unit 12. Tell me about a colleague or classmate who you like. Use a sentence with WHO.\",\n          check: (a)=> \/\\bwho\\b\/i.test(a) && a.length >= 12,\n          tips: \"Example: I have a colleague who always helps me.\"\n        },\n        {\n          bot: \"Now describe a place you like (a caf\u00e9, office, park). Use WHERE.\",\n          check: (a)=> \/\\bwhere\\b\/i.test(a) && a.length >= 10,\n          tips: \"Example: There\u2019s a caf\u00e9 where my friends meet.\"\n        },\n        {\n          bot: \"Define a thing you use every day (phone, laptop, app). Use THAT.\",\n          check: (a)=> \/\\bthat\\b\/i.test(a) && a.length >= 10,\n          tips: \"Example: A phone is something that I use to stay in touch.\"\n        },\n        {\n          bot: \"Relationships: Name one person who is your in-laws \/ roommate \/ neighbor \/ relative, and say one fact.\",\n          check: (a)=> \/(in-laws|roommate|neighbor|relative)\/i.test(a) && (\/\\bwho\\b\/i.test(a) || \/\\bthat\\b\/i.test(a)),\n          tips: \"Try to include who\/that: My roommate is someone who studies at night.\"\n        },\n        {\n          bot: \"Time: Use an approximate quantity. How many hours do you sleep on a normal day? Use about \/ roughly \/ around.\",\n          check: (a)=> \/(about|roughly|around)\/i.test(a) && \/\\b(hour|hours)\\b\/i.test(a),\n          tips: \"Example: I sleep about eight hours.\"\n        },\n        {\n          bot: \"Last one: Thank me for something, then respond modestly as if you were me (two short lines).\",\n          check: (a)=> \/(thanks|thank you)\/i.test(a) && \/(you'?re welcome|no problem|it isn'?t a problem|it was nothing)\/i.test(a),\n          tips: \"Example: Thanks so much! \/ You're welcome. It isn't a problem.\"\n        }\n      ];\n\n      function addMsg(who, text){\n        const div = document.createElement('div');\n        div.className = 'msg ' + (who==='You' ? 'user' : 'bot');\n        div.innerHTML = `<div class=\"who\">${esc(who)}<\/div><div class=\"bubble\">${esc(text)}<\/div>`;\n        convChat.appendChild(div);\n        convChat.scrollTop = convChat.scrollHeight;\n      }\n\n      function botAsk(){\n        const step = convSteps[convStep];\n        if(!step){\n          addMsg(\"Bot\",\"Great work! You finished Unit 12 conversation. Try other sections.\");\n          speak(\"Great work! You finished Unit 12 conversation. Try other sections.\");\n          markDone(\"conversation\", 100);\n          return;\n        }\n        addMsg(\"Bot\", step.bot);\n        lastPromptSpoken = step.bot;\n        speak(step.bot);\n      }\n\n      function scoreAnswer(a){\n        const step = convSteps[convStep];\n        if(!step) return {ok:true, msg:\"\"};\n        const ok = step.check(norm(a));\n        const msg = ok ? \"\u2705 Good. Nice use of the target language.\" : \"\u26a0\ufe0f Try again. \" + step.tips;\n        return {ok, msg};\n      }\n\n      function handleConversationInput(text){\n        const a = norm(text);\n        if(!a) return;\n        addMsg(\"You\", a);\n\n        progress._vocabUsedText = (progress._vocabUsedText||\"\") + \" \" + a;\n        saveProgress();\n\n        const {ok, msg} = scoreAnswer(a);\n        addMsg(\"Bot\", msg);\n        speak(msg);\n\n        if(ok){\n          convStep++;\n          setTimeout(botAsk, 450);\n        }else{\n          setTimeout(()=> speak(\"Please try again. \" + convSteps[convStep].bot), 450);\n        }\n      }\n\n      convSend.addEventListener('click', ()=> { handleConversationInput(convText.value); convText.value=\"\"; });\n      convText.addEventListener('keydown', (e)=>{\n        if(e.key === \"Enter\"){ e.preventDefault(); handleConversationInput(convText.value); convText.value=\"\"; }\n      });\n      convHear.addEventListener('click', ()=> speak(lastPromptSpoken || \"No question yet.\"));\n      convReset.addEventListener('click', ()=>{\n        convChat.innerHTML = \"\";\n        convStep = 0;\n        addMsg(\"Bot\",\"Ready! Start Voice (optional) and answer. Let\u2019s begin.\");\n        botAsk();\n      });\n\n      addMsg(\"Bot\",\"Ready! Start Voice (optional) and answer. Let\u2019s begin.\");\n      botAsk();\n\n      \/* =========================\n         Route voice transcripts\n      ========================= *\/\n      function activeViewName(){\n        const v = qs('.view.is-active');\n        return v ? v.getAttribute('data-view') : \"conversation\";\n      }\n\n      function handleVoiceTranscript(t){\n        const text = norm(t);\n        if(!text) return;\n\n        const v = activeViewName();\n        if(v === \"conversation\"){ handleConversationInput(text); return; }\n        if(v === \"discussion\"){\n          const ta = qs('#discA');\n          ta.value = (ta.value ? (ta.value + \" \") : \"\") + text;\n          speak(\"I heard: \" + text);\n          return;\n        }\n        const input = qs('.view.is-active input.input');\n        if(input){ input.value = text; speak(\"I heard: \" + text); return; }\n        speak(\"I heard: \" + text);\n      }\n\n      \/* =========================\n         2) Vocabulary matching + use\n      ========================= *\/\n      const vocabMatch = qs('#vocabMatch');\n      const vocabFb = qs('#vocabFb');\n      const vocabUse = qs('#vocabUse');\n      const vocabUseFb = qs('#vocabUseFb');\n\n      const matchSet = shuffle([\n        ...vocabRelationshipsCore.slice(0,8),\n        ...vocabRelVerbs.slice(0,6)\n      ]);\n\n      function renderVocabMatching(){\n        const defs = shuffle(matchSet.map(x=>x.def));\n        vocabMatch.innerHTML = matchSet.map((x,i)=>{\n          const options = ['<option value=\"\">Choose meaning\u2026<\/option>']\n            .concat(defs.map(d=>`<option value=\"${esc(d)}\">${esc(d)}<\/option>`))\n            .join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${i+1}) <b>${esc(x.word)}<\/b><\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(x.def)}\">${options}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderVocabMatching();\n\n      qs('#vocabCheck').addEventListener('click', ()=>{\n        const sels = qsa('#vocabMatch select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        vocabFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        vocabFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"vocab_match\", pct);\n      });\n\n      const useItems = [\n        {sent:\"My ____ is the person who manages me at work.\", ans:\"boss\"},\n        {sent:\"My ____ are my husband\u2019s\/wife\u2019s parents.\", ans:\"in-laws\"},\n        {sent:\"I share an apartment with my ____.\", ans:\"roommate\"},\n        {sent:\"I often ____ with my colleague after work.\", ans:\"go on a date\"},\n        {sent:\"They broke up, but later they ____.\", ans:\"get back together\"},\n        {sent:\"If you move abroad, it\u2019s important to ____ with friends.\", ans:\"stay in touch\"}\n      ];\n\n      function renderVocabUse(){\n        const bank2 = shuffle(useItems.map(x=>x.ans));\n        vocabUse.innerHTML = useItems.map((x,i)=>{\n          const opts = ['<option value=\"\">Choose\u2026<\/option>']\n            .concat(bank2.map(w=>`<option value=\"${esc(w)}\">${esc(w)}<\/option>`)).join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${i+1}) ${esc(x.sent)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(x.ans)}\">${opts}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderVocabUse();\n\n      qs('#vocabUseCheck').addEventListener('click', ()=>{\n        const sels = qsa('#vocabUse select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        vocabUseFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        vocabUseFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"vocab_use\", pct);\n      });\n\n      qs('#vocabReset').addEventListener('click', ()=>{\n        renderVocabMatching();\n        renderVocabUse();\n        vocabFb.style.display=\"none\";\n        vocabUseFb.style.display=\"none\";\n      });\n\n      \/* =========================\n         3) Grammar \u2014 Relative clauses + quantities\n      ========================= *\/\n      const relQuiz = qs('#relQuiz');\n      const relFb = qs('#relFb');\n      const qtyQuiz = qs('#qtyQuiz');\n      const qtyFb = qs('#qtyFb');\n\n      const relItems = [\n        {q:\"LinkedIn is a company ____ started Bring Your Parents to Work Day.\", ans:\"that\", opts:[\"who\",\"that\",\"where\"]},\n        {q:\"A colleague is someone ____ works with you.\", ans:\"who\", opts:[\"who\",\"that\",\"where\"]},\n        {q:\"That\u2019s the office ____ my sister works.\", ans:\"where\", opts:[\"who\",\"that\",\"where\"]},\n        {q:\"A roommate is a person ____ shares an apartment with you.\", ans:\"who\", opts:[\"who\",\"that\",\"where\"]},\n        {q:\"A remote control is something ____ you use to turn on the TV.\", ans:\"that\", opts:[\"who\",\"that\",\"where\"]}\n      ];\n\n      function renderRelQuiz(){\n        relQuiz.innerHTML = relItems.map((it,i)=>{\n          const options = ['<option value=\"\">Choose\u2026<\/option>']\n            .concat(it.opts.map(o=>`<option value=\"${esc(o)}\">${esc(o)}<\/option>`)).join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${i+1}) ${esc(it.q)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${options}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderRelQuiz();\n\n      qs('#relCheck').addEventListener('click', ()=>{\n        const sels = qsa('#relQuiz select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        relFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        relFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"grammar_relatives\", pct);\n      });\n\n      \/\/ quantities from Unit 12B text (78 years \/ 26 years \/ 11 years \/ around 91,000 hours etc.) :contentReference[oaicite:6]{index=6}\n      const qtyItems = [\n        {q:\"People sleep for ____ eight hours a day.\", ans:\"about\", opts:[\"about\",\"at least\",\"nearly\",\"just over\"]},\n        {q:\"We spend ____ 91,000 hours at work in a lifetime.\", ans:\"around\", opts:[\"around\",\"nearly\",\"at least\",\"just over\"]},\n        {q:\"That\u2019s ____ ten and a half years.\", ans:\"nearly\", opts:[\"nearly\",\"about\",\"at least\",\"just over\"]},\n        {q:\"It leaves you with ____ two years to spend with family and friends.\", ans:\"just over\", opts:[\"just over\",\"at least\",\"nearly\",\"about\"]},\n        {q:\"We spend ____ three and a half years studying.\", ans:\"roughly\", opts:[\"roughly\",\"nearly\",\"just over\",\"at least\"]}\n      ];\n\n      function renderQtyQuiz(){\n        qtyQuiz.innerHTML = qtyItems.map((it,i)=>{\n          const options = ['<option value=\"\">Choose\u2026<\/option>']\n            .concat(it.opts.map(o=>`<option value=\"${esc(o)}\">${esc(o)}<\/option>`)).join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${i+1}) ${esc(it.q)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${options}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderQtyQuiz();\n\n      qs('#qtyCheck').addEventListener('click', ()=>{\n        const sels = qsa('#qtyQuiz select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        qtyFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        qtyFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"grammar_quantities\", pct);\n      });\n\n      qs('#gramReset').addEventListener('click', ()=>{\n        renderRelQuiz();\n        renderQtyQuiz();\n        relFb.style.display=\"none\";\n        qtyFb.style.display=\"none\";\n      });\n\n      \/* =========================\n         4) Discussion\n      ========================= *\/\n      const discQ = qs('#discQ');\n      const discA = qs('#discA');\n      const discFb = qs('#discFb');\n\n      const discQs = [\n        \"Would you bring your parents to work? Explain why. Use one relative clause (who\/that\/where).\",\n        \"Do you think employees who are supported by family are happier and more productive? Give reasons. (Use one approximate quantity word: about\/around\/roughly\/nearly\/at least.)\",\n        \"What relationship is most important to you (friend, cousin, colleague, in-laws)? Describe a person who supports you.\",\n        \"How do you stay in touch with people who live far away? Use: stay in touch, videochat, or message.\",\n        \"Practice polite thanks: Your colleague helps you a lot. What do you say? Then respond modestly.\"\n      ];\n      let discIdx = -1;\n\n      function nextDiscQ(){\n        discIdx = (discIdx + 1) % discQs.length;\n        discQ.textContent = discQs[discIdx];\n        discA.value = \"\";\n        discFb.style.display = \"none\";\n        speak(discQs[discIdx]);\n      }\n      qs('#discNext').addEventListener('click', nextDiscQ);\n      qs('#discSpeakQ').addEventListener('click', ()=> speak(discQs[Math.max(0,discIdx)] || \"Click next question to begin.\"));\n\n      function detectTargets(text){\n        const t = lower(text);\n        const vocabHits = vocabAll.filter(v => t.includes(lower(v.word))).map(v=>v.word);\n        const hasRelClause = \/\\bwho\\b|\\bwhere\\b|\\bthat\\b\/i.test(text);\n        const hasApprox = \/\\babout\\b|\\baround\\b|\\broughly\\b|\\bnearly\\b|\\balmost\\b|\\bat least\\b|\\bjust over\\b\/i.test(text);\n        const hasThanks = \/\\bthanks\\b|\\bthank you\\b|\\byou're welcome\\b|\\bit (isn'?t|wasn'?t) a problem\\b|\\bno problem\\b|\\bit was nothing\\b\/i.test(text);\n        return { vocabHits, hasRelClause, hasApprox, hasThanks };\n      }\n\n      qs('#discCheck').addEventListener('click', ()=>{\n        const ans = norm(discA.value);\n        if(!ans){\n          discFb.className = \"feedback bad\";\n          discFb.textContent = \"Please write or speak an answer first.\";\n          return;\n        }\n\n        progress._vocabUsedText = (progress._vocabUsedText||\"\") + \" \" + ans;\n        saveProgress();\n\n        const {vocabHits, hasRelClause, hasApprox, hasThanks} = detectTargets(ans);\n        const okV = vocabHits.length >= 2;\n        const okG = hasRelClause && (hasApprox || hasThanks);\n\n        let score = 0;\n        if(okV) score += 50;\n        if(okG) score += 50;\n\n        discFb.className = \"feedback \" + (score>=70 ? \"ok\":\"bad\");\n        discFb.textContent =\n          `Detected vocab: ${vocabHits.slice(0,10).join(\", \") || \"none\"}\\n` +\n          `Relative clause: ${hasRelClause ? \"\u2705\" : \"\u26a0\ufe0f add who\/that\/where\"}\\n` +\n          `Approx\/Thanks: ${(hasApprox || hasThanks) ? \"\u2705\" : \"\u26a0\ufe0f add about\/roughly OR a thank-you + modest reply\"}\\n` +\n          `Score: ${score}%`;\n\n        markDone(\"discussion\", score);\n      });\n\n      \/* =========================\n         5) Reading questions\n      ========================= *\/\n      const readQ = qs('#readQ');\n      const readFb = qs('#readFb');\n\n      const readItems = [\n        {q:\"1) Which company introduced Bring Your Parents to Work Day?\", ans:\"LinkedIn\"},\n        {q:\"2) How many Americans take part in Take Your Child to Work Day every year?\", ans:\"more than 37 million\"},\n        {q:\"3) What benefits does the company say the day has?\", ans:\"happier and more productive\"},\n        {q:\"4) How many companies now have a similar day?\", ans:\"more than 80\"},\n        {q:\"5) What does Martin Richards\u2019 daughter do at work?\", ans:\"digital marketing\"}\n      ];\n\n      function renderReadQ(){\n        const options = {\n          \"LinkedIn\":[\"LinkedIn\",\"Google\",\"Amazon\",\"Microsoft\"],\n          \"more than 37 million\":[\"more than 37 million\",\"about 3 million\",\"nearly 80 million\",\"just over 10 million\"],\n          \"happier and more productive\":[\"happier and more productive\",\"richer and more famous\",\"faster and stronger\",\"more creative and athletic\"],\n          \"more than 80\":[\"more than 80\",\"about 18\",\"nearly 40\",\"just over 1000\"],\n          \"digital marketing\":[\"digital marketing\",\"software engineering\",\"teaching\",\"healthcare\"]\n        };\n        readQ.innerHTML = readItems.map((it,i)=>{\n          const opts = ['<option value=\"\">Choose\u2026<\/option>']\n            .concat((options[it.ans]||[it.ans]).map(o=>`<option value=\"${esc(o)}\">${esc(o)}<\/option>`)).join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${esc(it.q)}<\/div>\n              <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${opts}<\/select>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderReadQ();\n\n      qs('#readCheck').addEventListener('click', ()=>{\n        const sels = qsa('#readQ select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        readFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        readFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"reading\", pct);\n      });\n\n      const readClause = qs('#readClause');\n      const readClauseFb = qs('#readClauseFb');\n      qs('#readClauseCheck').addEventListener('click', ()=>{\n        const txt = norm(readClause.value);\n        const ok = \/\\b(where|who|that)\\b\/i.test(txt) && txt.length >= 20;\n        readClauseFb.className = \"feedback \" + (ok ? \"ok\":\"bad\");\n        readClauseFb.textContent = ok ? \"\u2705 Good. You included a defining relative clause.\" : \"\u26a0\ufe0f Please type a longer sentence including who\/that\/where.\";\n        markDone(\"reading_clause\", ok ? 100 : 0);\n      });\n\n      qs('#readTextBtn').addEventListener('click', ()=>{\n        const text = qsa('#readingText .reading-p').map(p=>p.textContent).join(\" \");\n        speak(\"Reading text. \" + text);\n      });\n\n      \/* =========================\n         6) Listening (TTS script + gaps)\n         Based on Learning Curve Unit 12 scripts :contentReference[oaicite:7]{index=7}\n      ========================= *\/\n      const listeningScript =\n        \"Kate says it\u2019s almost nine a.m. at Learning Curve studios in London, and today is Simon\u2019s birthday. \" +\n        \"Kate is organizing a surprise party. She offers Simon tea with milk. Simon says, That\u2019s very kind of you. \" +\n        \"Kate asks Simon to mail a parcel to the post office. Simon agrees. Kate says, Thanks so much, and later, Thanks a million. \" +\n        \"Simon replies that it isn\u2019t a problem. At the party, everyone says Surprise. Simon says, This is so kind of you. \" +\n        \"Penny says, Glad you noticed. Later, Penny says, It was nothing. You\u2019re welcome. Kate says she had help.\";\n\n      const gapItems = [\n        {q:\"1) Kate says it\u2019s almost ____ a.m.\", ans:\"9:00\"},\n        {q:\"2) Today is Simon\u2019s ____.\", ans:\"birthday\"},\n        {q:\"3) Kate offers tea with ____.\", ans:\"milk\"},\n        {q:\"4) Kate asks Simon to mail a ____.\", ans:\"parcel\"},\n        {q:\"5) Simon can stop at the ____ office.\", ans:\"post\"},\n        {q:\"6) Kate says: Thanks so ____.\", ans:\"much\"},\n        {q:\"7) Kate says: Thanks a ____.\", ans:\"million\"},\n        {q:\"8) Simon replies: It isn\u2019t a ____.\", ans:\"problem\"},\n        {q:\"9) Penny says: Glad you ____.\", ans:\"noticed\"},\n        {q:\"10) Kate says: I had ____.\", ans:\"help\"}\n      ];\n\n      const listenGaps = qs('#listenGaps');\n      const listenFb = qs('#listenFb');\n\n      function renderListeningGaps(){\n        const wordBank = shuffle([\"9:00\",\"birthday\",\"milk\",\"parcel\",\"post\",\"much\",\"million\",\"problem\",\"noticed\",\"help\"]);\n        listenGaps.innerHTML =\n          `<div class=\"note\"><b>Word bank:<\/b> ${wordBank.map(w=>`<span class=\"tag\">${esc(w)}<\/span>`).join(\" \")}<\/div>` +\n          gapItems.map((it)=>{\n            const opts = ['<option value=\"\">Choose\u2026<\/option>']\n              .concat(wordBank.map(w=>`<option value=\"${esc(w)}\">${esc(w)}<\/option>`)).join(\"\");\n            return `\n              <div class=\"qitem\">\n                <div class=\"qtext\">${esc(it.q)}<\/div>\n                <select class=\"icte-select\" data-ans=\"${esc(it.ans)}\">${opts}<\/select>\n              <\/div>\n            `;\n          }).join(\"\");\n      }\n      renderListeningGaps();\n\n      qs('#listenPlay').addEventListener('click', ()=> speak(listeningScript));\n      qs('#listenStop').addEventListener('click', stopSpeak);\n\n      qs('#listenCheck').addEventListener('click', ()=>{\n        const sels = qsa('#listenGaps select');\n        let correct = 0;\n        sels.forEach(s=>{\n          const ok = s.value === s.getAttribute('data-ans');\n          s.style.borderColor = ok ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n          if(ok) correct++;\n        });\n        const pct = Math.round((correct \/ sels.length) * 100);\n        listenFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        listenFb.textContent = `Score: ${correct}\/${sels.length} (${pct}%).`;\n        markDone(\"listening\", pct);\n      });\n\n      \/* =========================\n         7) Problem-solving\n         Responding modestly examples :contentReference[oaicite:8]{index=8}\n      ========================= *\/\n      const probSet = qs('#probSet');\n      const probFb = qs('#probFb');\n\n      const problems = [\n        {\n          scenario: \"Scenario 1: Your colleague gives you tea. What is the best response?\",\n          choices: [\n            \"Give me tea now.\",\n            \"That\u2019s very kind of you. Thanks a lot.\",\n            \"I dislike tea where you make it.\"\n          ],\n          correct: 1,\n          followup: \"Write ONE sentence using a modest reply (e.g., It isn\u2019t a problem \/ You\u2019re welcome).\"\n        },\n        {\n          scenario: \"Scenario 2: Describe your roommate using a defining relative clause.\",\n          choices: [\n            \"My roommate is a person who shares an apartment with me.\",\n            \"My roommate is where I live.\",\n            \"My roommate is a thing that I use.\"\n          ],\n          correct: 0,\n          followup: \"Write ONE sentence with who\/that\/where.\"\n        },\n        {\n          scenario: \"Scenario 3: Someone says: \u2018I can\u2019t thank you enough.\u2019 What is the best modest response?\",\n          choices: [\n            \"It\u2019s no problem.\",\n            \"I demand more thanks.\",\n            \"Where is your gift?\"\n          ],\n          correct: 0,\n          followup: \"Write ONE short dialogue line to respond modestly.\"\n        }\n      ];\n\n      function renderProblems(){\n        probSet.innerHTML = problems.map((p,idx)=>{\n          const opts = p.choices.map((c,i)=>`\n            <label class=\"opt\" style=\"display:flex;gap:10px;align-items:flex-start;padding:8px 10px;border:1px solid var(--line);border-radius:12px;background:#fff;\">\n              <input type=\"radio\" name=\"prob_${idx}\" value=\"${i}\">\n              <span>${esc(c)}<\/span>\n            <\/label>\n          `).join(\"\");\n          return `\n            <div class=\"qitem\">\n              <div class=\"qtext\">${idx+1}) ${esc(p.scenario)}<\/div>\n              <div class=\"stack\" style=\"gap:8px;margin-top:8px\">${opts}<\/div>\n              <div class=\"muted icte-small\" style=\"margin-top:8px\">${esc(p.followup)}<\/div>\n              <textarea class=\"textarea\" rows=\"2\" data-followup=\"${idx}\" placeholder=\"Write your sentence here...\"><\/textarea>\n            <\/div>\n          `;\n        }).join(\"\");\n      }\n      renderProblems();\n\n      function okFollowup(idx, txt){\n        const t = txt.trim();\n        if(idx === 0) return \/(you'?re welcome|no problem|it isn'?t a problem|it was nothing)\/i.test(t);\n        if(idx === 1) return \/\\b(who|that|where)\\b\/i.test(t) && t.length >= 12;\n        return \/(you'?re welcome|no problem|it isn'?t a problem|it was nothing|glad you noticed)\/i.test(t);\n      }\n\n      qs('#probCheck').addEventListener('click', ()=>{\n        let score = 0;\n        const total = problems.length * 2;\n\n        problems.forEach((p,idx)=>{\n          const sel = qs(`input[name=\"prob_${idx}\"]:checked`);\n          const okChoice = sel && parseInt(sel.value,10) === p.correct;\n          if(okChoice) score++;\n\n          const ta = qs(`textarea[data-followup=\"${idx}\"]`);\n          const txt = norm(ta.value);\n          const okSentence = okFollowup(idx, txt);\n          if(okSentence) score++;\n          ta.style.borderColor = okSentence ? \"rgba(34,197,94,.6)\" : \"rgba(239,68,68,.6)\";\n        });\n\n        const pct = Math.round((score \/ total) * 100);\n        probFb.className = \"feedback \" + (pct>=70 ? \"ok\":\"bad\");\n        probFb.textContent =\n          `Score: ${score}\/${total} (${pct}%).\\nTip: Follow-up must include a modest reply OR a defining relative clause.`;\n        markDone(\"problemsolving\", pct);\n      });\n\n      qs('#probReset').addEventListener('click', ()=>{\n        renderProblems();\n        probFb.style.display=\"none\";\n      });\n\n      \/* =========================\n         Final init\n      ========================= *\/\n      renderProgress();\n\n    })();\n  <\/script>\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Conversation Vocabulary Grammar Discussion Reading Listening Problem-solving Progress Unit 12 \u2014 People and relationships Practice defining relative clauses (who \/<\/p>\n","protected":false},"author":1,"featured_media":737,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_layout":"default_layout","footnotes":""},"categories":[37],"tags":[],"class_list":["post-738","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-b1"],"_links":{"self":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/738","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=738"}],"version-history":[{"count":1,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/738\/revisions"}],"predecessor-version":[{"id":739,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/738\/revisions\/739"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media\/737"}],"wp:attachment":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media?parent=738"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/categories?post=738"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/tags?post=738"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}