{"id":137,"date":"2026-04-16T03:44:48","date_gmt":"2026-04-16T03:44:48","guid":{"rendered":"https:\/\/allenglish4u.com\/dictation\/"},"modified":"2026-07-05T02:44:43","modified_gmt":"2026-07-05T02:44:43","slug":"dictation","status":"publish","type":"page","link":"https:\/\/allenglish4u.com\/vi\/dictation\/","title":{"rendered":"Dictation Practice \u2014 All English 4U"},"content":{"rendered":"\n<style>\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Fraunces:opsz,wght@9..144,700&display=swap');\n\/* AE4U: escape theme constrained wrapper -> full-bleed design *\/\n.entry-content,.wp-block-post-content,.is-layout-constrained{max-width:none !important;width:auto !important;margin-left:0 !important;margin-right:0 !important;padding-left:0 !important;padding-right:0 !important;}\nbody.entry-content>*,body.wp-block-post-content>*{max-width:none !important;}\nbody.entry-content.wp-block-post-title,body.wp-block-post-title{display:none !important;}\n\n\/* ============ TOKENS ============ *\/\n:root{\n  --teal:#0D9488; --cyan:#06B6D4;\n  --accent-a:#0D9488; --accent-b:#06B6D4;\n  --light:#F0F7FF; --light-2:#F8FAFF; --white:#FFFFFF;\n  --text:#0F172A; --muted:#475569; --subtle:#94A3B8; --border:#E2E8F0;\n  --dark:#050E20; --dark-2:#0A1628; --dark-3:#0D2352;\n  --r6:6px; --r10:10px; --r16:16px; --r18:18px; --r22:22px; --r32:32px;\n  --sh-card:0 2px 8px rgba(0,0,0,.06);\n  --sh-lg:0 12px 40px rgba(0,0,0,.12);\n  --sh-glow:0 8px 24px rgba(13,148,136,.32);\n  --t-fast:160ms ease;\n  --t-mid:280ms cubic-bezier(.4,0,.2,1);\n  --t-spring:400ms cubic-bezier(.34,1.56,.64,1);\n  --anim-mult:1;\n  --maxw:1200px;\n  --sp-sec:clamp(64px,9vw,128px);\n}\n*{box-sizing:border-box;margin:0;padding:0}\nhtml{scroll-behavior:smooth}\nbody{\n  font-family:'Plus Jakarta Sans',system-ui,sans-serif;\n  color:var(--text); background:var(--light-2);\n  -webkit-font-smoothing:antialiased; line-height:1.6; font-size:16px; overflow-x:hidden;\n}\n.serif{font-family:'Fraunces',Georgia,serif;font-weight:700;line-height:1.05;text-wrap:balance}\nh1,h2,h3{text-wrap:balance}\na{color:inherit;text-decoration:none}\nimg{display:block;max-width:100%}\n.wrap{max-width:var(--maxw);margin:0 auto;padding:0 28px}\n:focus-visible{outline:2px solid var(--accent-b);outline-offset:2px;border-radius:4px}\n.btn:focus-visible,.icon-btn:focus-visible,.gear:focus-visible{outline:2px solid var(--accent-b);outline-offset:2px}\n.navlinks a:focus-visible,.fcol a:focus-visible,.soc:focus-visible{outline:2px solid var(--accent-b);outline-offset:3px}\n.grad-text{\n  background:linear-gradient(110deg,var(--accent-a),var(--accent-b));\n  -webkit-background-clip:text;background-clip:text;color:transparent;\n}\n.grad-bg{background:linear-gradient(110deg,var(--accent-a),var(--accent-b))}\nsection{position:relative}\n\n\/* ============ BUTTONS ============ *\/\n.btn{\n  display:inline-flex;align-items:center;gap:9px;font-weight:700;font-size:15px;\n  padding:14px 26px;border-radius:999px;border:none;cursor:pointer;\n  transition:transform var(--t-spring),box-shadow var(--t-mid),background var(--t-fast);\n  white-space:nowrap;font-family:inherit;\n}\n.btn:active{transform:scale(.97)}\n.btn-grad{color:#fff;background:linear-gradient(110deg,var(--accent-a),var(--accent-b));box-shadow:var(--sh-glow)}\n.btn-grad:hover{transform:translateY(-2px) scale(1.02);box-shadow:0 14px 34px rgba(6,182,212,.42)}\n.btn-ghost{background:rgba(255,255,255,.06);color:#fff;border:1.5px solid rgba(255,255,255,.22)}\n.btn-ghost:hover{background:rgba(255,255,255,.13);transform:translateY(-2px)}\n.btn-light{background:#fff;color:var(--text);border:1.5px solid var(--border);box-shadow:var(--sh-card)}\n.btn-light:hover{transform:translateY(-2px);box-shadow:var(--sh-lg);border-color:var(--accent-b)}\n.btn-red{background:#FF0000;color:#fff;box-shadow:0 8px 24px rgba(255,0,0,.28)}\n.btn-red:hover{transform:translateY(-2px) scale(1.02);background:#e60000}\n\n\/* ============ HEADER ============ *\/\nheader{\n  position:fixed;top:0;left:0;right:0;z-index:100;\n  transition:background var(--t-mid),box-shadow var(--t-mid),border-color var(--t-mid);\n  border-bottom:1px solid transparent;\n}\nheader.scrolled{\n  background:rgba(255,255,255,.82);backdrop-filter:blur(18px) saturate(160%);\n  -webkit-backdrop-filter:blur(18px) saturate(160%);\n  border-bottom:1px solid var(--border);box-shadow:0 1px 0 rgba(255,255,255,.5),0 6px 20px rgba(15,23,42,.05);\n}\n.nav{display:flex;align-items:center;gap:18px;height:72px}\n.brand{display:flex;align-items:center;gap:11px;font-weight:800;font-size:17px;letter-spacing:-.02em}\n.brand.b-name{white-space:nowrap}\n.brand img{width:40px;height:40px;border-radius:11px;object-fit:cover;box-shadow:var(--sh-card)}\n.brand.b-name{color:#fff;transition:color var(--t-mid)}\nheader.scrolled.brand.b-name{color:var(--text)}\n.navlinks{display:flex;align-items:center;gap:2px;margin-left:18px}\n.navlinks a{\n  font-size:14.5px;font-weight:600;padding:9px 13px;border-radius:var(--r10);\n  color:rgba(255,255,255,.78);position:relative;transition:color var(--t-fast),background var(--t-fast);\n}\n.navlinks a:hover{color:#fff;background:rgba(255,255,255,.08)}\nheader.scrolled.navlinks a{color:var(--muted)}\nheader.scrolled.navlinks a:hover{color:var(--text);background:var(--light)}\n.navlinks a.active{color:#fff;font-weight:700}\nheader.scrolled.navlinks a.active{color:var(--teal)}\n.navlinks a.active::after{\n  content:\"\";position:absolute;left:13px;right:13px;bottom:2px;height:2.5px;border-radius:2px;\n  background:linear-gradient(90deg,var(--accent-a),var(--accent-b));\n}\n.nav-right{margin-left:auto;display:flex;align-items:center;gap:12px}\n.icon-btn{\n  width:40px;height:40px;display:grid;place-items:center;border-radius:50%;cursor:pointer;\n  background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.16);color:#fff;transition:all var(--t-fast);\n}\nheader.scrolled.icon-btn{background:var(--light);border-color:var(--border);color:var(--muted)}\n.icon-btn:hover{transform:scale(1.08)}\n.hamburger{display:none}\n.start-pill{padding:11px 20px;font-size:14px}\n\n\/* mobile menu *\/\n.mobile-menu{\n  position:fixed;inset:0 0 0 auto;width:min(82vw,340px);z-index:120;\n  background:var(--dark-2);transform:translateX(100%);transition:transform var(--t-mid);\n  padding:90px 26px 30px;display:flex;flex-direction:column;gap:6px;box-shadow:-20px 0 60px rgba(0,0,0,.5);\n}\n.mobile-menu.open{transform:translateX(0)}\n.mobile-menu a{color:rgba(255,255,255,.85);font-weight:600;font-size:17px;padding:14px 12px;border-radius:var(--r10)}\n.mobile-menu a:hover{background:rgba(255,255,255,.06)}\n.mobile-menu a.active{color:var(--cyan)}\n.scrim{position:fixed;inset:0;background:rgba(5,14,32,.55);z-index:110;opacity:0;pointer-events:none;transition:opacity var(--t-mid);backdrop-filter:blur(2px)}\n.scrim.open{opacity:1;pointer-events:auto}\n\n\/* ============ HERO ============ *\/\n.hero{\n  position:relative;overflow:hidden;padding:150px 0 110px;\n  background:radial-gradient(120% 90% at 78% 18%,#0D2352 0%,#081435 42%,#050E20 100%);\n  color:#fff;\n}\n.hero::before{\n  content:\"\";position:absolute;width:760px;height:760px;right:-120px;top:-80px;border-radius:50%;\n  background:radial-gradient(circle,rgba(13,148,136,.42),rgba(6,182,212,.16) 42%,transparent 70%);\n  filter:blur(8px);pointer-events:none;z-index:0;\n}\n.hero::after{\n  content:\"\";position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.5;\n  background-image:radial-gradient(rgba(255,255,255,.05) 1px,transparent 1px);\n  background-size:34px 34px;mask-image:radial-gradient(70% 60% at 30% 40%,#000,transparent 80%);\n}\n.hero-grid{\n  position:relative;z-index:2;display:grid;grid-template-columns:1.05fr.95fr;gap:30px;align-items:center;\n}\n.eyebrow{\n  display:inline-flex;align-items:center;gap:9px;font-size:12.5px;font-weight:700;letter-spacing:.12em;\n  text-transform:uppercase;color:#8FEAF5;padding:7px 15px;border-radius:999px;\n  background:rgba(6,182,212,.1);border:1px solid rgba(6,182,212,.28);margin-bottom:24px;\n}\n.eyebrow.dot{width:7px;height:7px;border-radius:50%;background:var(--cyan);box-shadow:0 0 12px var(--cyan);animation:pulse 2s infinite}\n@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.4)}}\n.hero h1{font-size:clamp(44px,6vw,82px);line-height:1.04;letter-spacing:-.025em;margin-bottom:30px}\n.hero h1 .grad-text{display:inline-block;padding-bottom:.06em}\n.hero.sub{font-size:clamp(16px,1.5vw,19px);line-height:1.6;color:rgba(226,240,255,.88);max-width:56ch;margin-bottom:30px;font-weight:400}\n.chips{display:flex;flex-wrap:wrap;gap:11px;margin-bottom:32px}\n.chip{\n  display:inline-flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;\n  padding:9px 15px;border-radius:999px;background:rgba(255,255,255,.05);\n  border:1px solid rgba(255,255,255,.12);color:rgba(226,240,255,.92);transition:all var(--t-fast);\n}\n.chip:hover{background:rgba(6,182,212,.12);border-color:rgba(6,182,212,.4);transform:translateY(-2px)}\n.chip b{color:#fff;font-weight:800}\n.chip.ic{width:16px;height:16px;color:var(--cyan)}\n.hero-cta{display:flex;flex-wrap:wrap;gap:14px}\n.hero-3d-wrap{position:relative;height:520px;display:flex;align-items:center;justify-content:center}\n#hero3d{width:100%;height:100%;display:block}\n.hero-3d-glow{\n  position:absolute;width:70%;height:70%;left:15%;top:15%;border-radius:50%;z-index:-1;\n  background:radial-gradient(circle,rgba(6,182,212,.28),transparent 65%);filter:blur(30px);\n  animation:breathe 6s ease-in-out infinite;\n}\n@keyframes breathe{0%,100%{transform:scale(1);opacity:.8}50%{transform:scale(1.12);opacity:1}}\n\n\/* ============ SECTION SHELL ============ *\/\n.sec{padding:var(--sp-sec) 0;background:var(--light-2)}\n.sec.alt{background:var(--light)}\n#b1{box-shadow:inset 0 38px 46px -46px rgba(5,14,32,.55)}\n.sec-head{max-width:680px;margin-bottom:48px}\n.kick{\n  display:inline-flex;align-items:center;gap:9px;font-size:12px;font-weight:800;letter-spacing:.12em;\n  text-transform:uppercase;color:var(--teal);margin-bottom:16px;\n}\n.kick.line{width:26px;height:2px;background:linear-gradient(90deg,var(--accent-a),var(--accent-b));border-radius:2px}\n.sec h2{font-size:clamp(30px,3.6vw,46px);letter-spacing:-.02em;line-height:1.06;margin-bottom:16px}\n.sec h2.serif{font-weight:700}\n.sec-head p{font-size:17px;color:var(--muted);max-width:62ch}\n.level-badge{\n  display:inline-flex;align-items:center;gap:8px;font-size:12px;font-weight:800;letter-spacing:.08em;\n  padding:6px 13px;border-radius:999px;text-transform:uppercase;\n}\n.bd-live{background:rgba(13,148,136,.12);color:#0B7A70;border:1px solid rgba(13,148,136,.28)}\n.bd-soon{background:rgba(148,163,184,.16);color:#475569;border:1px solid var(--border)}\n.bd-prod{background:rgba(99,102,241,.1);color:#4F46E5;border:1px solid rgba(99,102,241,.24)}\n.live-dot{width:7px;height:7px;border-radius:50%;background:var(--teal);box-shadow:0 0 0 0 rgba(13,148,136,.5);animation:ring 1.8s infinite}\n@keyframes ring{0%{box-shadow:0 0 0 0 rgba(13,148,136,.5)}70%{box-shadow:0 0 0 8px rgba(13,148,136,0)}100%{box-shadow:0 0 0 0 rgba(13,148,136,0)}}\n\n\/* ============ TOPIC CARDS ============ *\/\n.topic-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:20px}\n.tcard{\n  position:relative;display:flex;flex-direction:column;min-height:188px;\n  background:#fff;border:1px solid var(--border);border-radius:var(--r18);\n  padding:24px;transition:transform var(--t-spring),box-shadow var(--t-mid),border-color var(--t-mid);\n  box-shadow:var(--sh-card);overflow:hidden;\n}\n.tcard::before{\n  content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;\n  background:linear-gradient(180deg,var(--accent-a),var(--accent-b));opacity:0;transition:opacity var(--t-mid);\n}\n.tcard.live::before{opacity:1}\n.tcard.live:hover{transform:translateY(-4px);box-shadow:var(--sh-lg);border-color:rgba(13,148,136,.4)}\n.tcard.locked{background:var(--light-2)}\n.tcard.prod{background:repeating-linear-gradient(135deg,var(--light-2),var(--light-2) 10px,#EEF4FC 10px,#EEF4FC 20px)}\n.tnum{\n  font-family:'Fraunces',serif;font-weight:700;font-size:15px;width:42px;height:42px;border-radius:13px;\n  display:grid;place-items:center;color:#fff;background:linear-gradient(135deg,var(--accent-a),var(--accent-b));\n  box-shadow:var(--sh-glow);flex-shrink:0;\n}\n.tcard.locked.tnum{background:#E2E8F0;color:var(--subtle);box-shadow:none}\n.tcard-top{display:flex;align-items:center;gap:14px;margin-bottom:18px}\n.tstat{margin-left:auto}\n.tcard h3{font-size:19px;font-weight:700;letter-spacing:-.01em;margin-bottom:8px}\n.tcard.locked h3{color:var(--muted)}\n.tags{display:flex;flex-wrap:wrap;gap:7px;margin:14px 0 18px}\n.tag{\n  display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:700;\n  padding:5px 10px;border-radius:7px;background:var(--light);color:var(--muted);border:1px solid var(--border);\n}\n.tag.vid{color:#dc2626;background:rgba(220,38,38,.07);border-color:rgba(220,38,38,.18)}\n.tag.fill{color:var(--teal);background:rgba(13,148,136,.08);border-color:rgba(13,148,136,.2)}\n.tcard.play-row{display:flex;align-items:center;gap:10px;font-size:14px;font-weight:700;color:var(--teal);margin-top:auto}\n.tcard.play-row.pico{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;background:linear-gradient(135deg,var(--accent-a),var(--accent-b));color:#fff;transition:transform var(--t-spring)}\n.tcard.live:hover.play-row.pico{transform:scale(1.12) rotate(8deg)}\n.mini-stat{font-size:12.5px;font-weight:600;color:var(--muted);display:flex;align-items:center;gap:6px}\n\n\/* ============ COMING SOON BLOCK ============ *\/\n.cs-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px}\n.cs-card{\n  background:#fff;border:1px solid var(--border);border-radius:var(--r32);padding:36px;\n  box-shadow:var(--sh-card);position:relative;overflow:hidden;transition:transform var(--t-mid),box-shadow var(--t-mid);\n}\n.cs-card:hover{transform:translateY(-4px);box-shadow:var(--sh-lg)}\n.cs-card.glow{position:absolute;width:240px;height:240px;right:-60px;top:-60px;border-radius:50%;background:radial-gradient(circle,rgba(6,182,212,.12),transparent 70%)}\n.cs-card h3{font-size:26px;font-family:'Fraunces',serif;font-weight:700;margin:16px 0 6px}\n.cs-card.lvl-tag{font-size:13px;font-weight:700;color:var(--muted);letter-spacing:.04em;text-transform:uppercase}\n.cs-card p{color:var(--muted);font-size:15.5px;margin:14px 0 22px;position:relative;z-index:1}\n.pillrow{display:flex;flex-wrap:wrap;gap:9px;margin-bottom:26px;position:relative;z-index:1}\n.spill{\n  font-size:13px;font-weight:600;padding:8px 14px;border-radius:999px;background:var(--light);\n  border:1px solid var(--border);color:var(--muted);transition:all var(--t-fast);\n}\n.spill:hover{border-color:var(--accent-b);color:var(--teal);transform:translateY(-2px)}\n.spill.more{background:rgba(13,148,136,.08);color:var(--teal);border-color:rgba(13,148,136,.22)}\n\n\/* ============ DEMO ============ *\/\n.demo-sec{padding:var(--sp-sec) 0;background:radial-gradient(120% 80% at 50% 0%,#0A1628,#050E20);color:#fff;overflow:hidden;position:relative}\n.demo-sec.kick{color:#7DE3F0}\n.demo-sec.kick.line{background:linear-gradient(90deg,var(--accent-a),var(--accent-b))}\n.demo-sec h2{color:#fff}\n.demo-sec.sec-head p{color:rgba(226,240,255,.78)}\n.demo-card{\n  max-width:760px;margin:0 auto;background:linear-gradient(180deg,rgba(13,35,82,.7),rgba(10,22,40,.7));\n  border:1px solid rgba(6,182,212,.22);border-radius:var(--r32);padding:38px;\n  box-shadow:0 30px 80px rgba(0,0,0,.45),inset 0 1px 0 rgba(255,255,255,.06);backdrop-filter:blur(10px);\n}\n.player{display:flex;align-items:center;gap:20px;margin-bottom:30px}\n.player-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:12px}\n.bigplay{\n  width:72px;height:72px;border-radius:50%;flex-shrink:0;border:none;cursor:pointer;color:#fff;\n  background:linear-gradient(135deg,var(--accent-a),var(--accent-b));box-shadow:0 10px 30px rgba(6,182,212,.45);\n  display:grid;place-items:center;transition:transform var(--t-spring);position:relative;\n}\n.bigplay:hover{transform:scale(1.07)}\n.bigplay.playing{animation:playpulse 1.6s ease-in-out infinite}\n@keyframes playpulse{0%,100%{box-shadow:0 10px 30px rgba(6,182,212,.45)}50%{box-shadow:0 10px 44px rgba(6,182,212,.8)}}\n#wave{width:100%;height:60px;border-radius:var(--r10);display:block}\n.prow{display:flex;align-items:center;gap:13px}\n.ptime{font-size:12.5px;font-weight:700;font-variant-numeric:tabular-nums;color:rgba(226,240,255,.8);min-width:34px}\n.ptime.end{text-align:right}\n.ptrack{\n  flex:1;height:6px;border-radius:999px;background:rgba(255,255,255,.14);position:relative;cursor:pointer;\n}\n.pfill{\n  position:absolute;left:0;top:0;bottom:0;width:0%;border-radius:999px;\n  background:linear-gradient(90deg,var(--accent-a),var(--accent-b));transition:width.12s linear;\n}\n.pfill::after{\n  content:\"\";position:absolute;right:-6px;top:50%;width:14px;height:14px;border-radius:50%;\n  transform:translateY(-50%);background:#fff;box-shadow:0 2px 6px rgba(6,182,212,.6);\n}\n.dline{font-size:clamp(19px,2.4vw,26px);line-height:1.7;font-weight:500;margin-bottom:8px;letter-spacing:-.01em}\n.blank-in{\n  display:inline-block;width:150px;font-family:inherit;font-size:inherit;font-weight:700;color:#fff;text-align:center;\n  background:rgba(6,182,212,.08);border:none;border-bottom:2.5px solid var(--cyan);padding:2px 8px 4px;margin:0 4px;\n  outline:none;transition:all var(--t-fast);border-radius:6px 6px 0 0;\n}\n.blank-in::placeholder{color:rgba(125,227,240,.5);font-weight:500}\n.blank-in:focus{background:rgba(6,182,212,.16)}\n.blank-in.correct{color:#34D399;border-color:#34D399;background:rgba(52,211,153,.12)}\n.blank-in.wrong{color:#FB7185;border-color:#FB7185;background:rgba(251,113,133,.12);animation:shake.4s}\n@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-5px)}75%{transform:translateX(5px)}}\n.dhint{font-size:14.5px;color:rgba(226,240,255,.78);margin-bottom:24px;min-height:22px;transition:all var(--t-fast)}\n.dhint.ok{color:#34D399;font-weight:700}\n.dhint.no{color:#FB7185;font-weight:700}\n.demo-actions{display:flex;flex-wrap:wrap;gap:12px;align-items:center}\n.demo-actions.btn{padding:12px 22px;font-size:14px}\n.demo-meta{margin-left:auto;font-size:13px;white-space:nowrap;color:rgba(226,240,255,.68);display:flex;align-items:center;gap:7px}\n\n\/* ============ FEATURES ============ *\/\n.feat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px}\n.feat{\n  background:#fff;border:1px solid var(--border);border-radius:var(--r18);padding:32px;box-shadow:var(--sh-card);\n  transition:transform var(--t-spring),box-shadow var(--t-mid);\n}\n.feat:hover{transform:translateY(-4px);box-shadow:var(--sh-lg)}\n.feat.ficon{\n  width:54px;height:54px;border-radius:16px;display:grid;place-items:center;margin-bottom:20px;color:#fff;\n  background:linear-gradient(135deg,var(--accent-a),var(--accent-b));box-shadow:var(--sh-glow);\n}\n.feat h3{font-size:19px;font-weight:700;margin-bottom:9px;letter-spacing:-.01em}\n.feat p{color:var(--muted);font-size:15.5px;line-height:1.6}\n.free-banner{\n  margin-top:26px;display:flex;align-items:center;justify-content:center;gap:14px;\n  background:linear-gradient(110deg,var(--accent-a),var(--accent-b));color:#fff;border-radius:var(--r22);\n  padding:26px;font-weight:700;font-size:20px;box-shadow:var(--sh-glow);text-align:center;flex-wrap:wrap;\n}\n.free-banner.big{font-family:'Fraunces',serif;font-size:30px}\n\n\/* ============ YOUTUBE BAND ============ *\/\n.yt-sec{padding:var(--sp-sec) 0;background:var(--dark-2);color:#fff}\n.yt-head{text-align:center;max-width:620px;margin:0 auto 44px}\n.yt-head h2{color:#fff;font-size:clamp(28px,3.4vw,42px);margin-bottom:14px}\n.yt-head p{color:rgba(226,240,255,.7);font-size:17px;margin-bottom:24px}\n.yt-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px;max-width:880px;margin:0 auto}\n.vcard{\n  background:var(--dark-3);border:1px solid rgba(255,255,255,.08);border-radius:var(--r18);overflow:hidden;\n  cursor:pointer;transition:transform var(--t-spring),box-shadow var(--t-mid);\n}\n.vcard:hover{transform:translateY(-4px);box-shadow:0 20px 50px rgba(0,0,0,.4)}\n.vthumb{aspect-ratio:16\/9;position:relative;display:grid;place-items:center;overflow:hidden;\n  background:radial-gradient(circle at 50% 50%,#0D2352,#081435)}\n.vthumb.wbars{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:5px;opacity:.5}\n.vthumb.wbars span{width:5px;border-radius:3px;background:linear-gradient(180deg,var(--accent-a),var(--accent-b));animation:vb 1.4s ease-in-out infinite}\n.vplay{width:62px;height:62px;border-radius:50%;background:#FF0000;display:grid;place-items:center;color:#fff;z-index:2;box-shadow:0 8px 24px rgba(255,0,0,.4);transition:transform var(--t-spring)}\n.vcard:hover.vplay{transform:scale(1.12)}\n.vinfo{padding:18px 20px}\n.vinfo h4{font-size:16px;font-weight:700;margin-bottom:5px}\n.vinfo span{font-size:13px;color:rgba(226,240,255,.7);display:flex;align-items:center;gap:6px}\n@keyframes vb{0%,100%{height:18px}50%{height:54px}}\n\n\/* ============ FOOTER ============ *\/\nfooter{background:var(--dark);color:#fff;padding:72px 0 30px}\n.foot-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:40px;padding-bottom:48px;border-bottom:1px solid rgba(255,255,255,.08)}\n.foot-brand.brand{margin-bottom:18px}\n.foot-brand.brand.b-name{color:#fff}\n.foot-brand p{color:rgba(226,240,255,.72);font-size:15px;line-height:1.6;max-width:300px;margin-bottom:22px}\n.socials{display:flex;gap:11px}\n.soc{width:42px;height:42px;border-radius:12px;display:grid;place-items:center;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);color:rgba(255,255,255,.8);transition:all var(--t-fast)}\n.soc:hover{background:linear-gradient(135deg,var(--accent-a),var(--accent-b));color:#fff;transform:translateY(-3px);border-color:transparent}\n.fcol h5{font-size:13px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:#7DE3F0;margin-bottom:18px}\n.fcol a{display:block;color:rgba(226,240,255,.75);font-size:15px;padding:7px 0;transition:color var(--t-fast)}\n.fcol a:hover{color:#fff}\n.foot-bot{display:flex;justify-content:space-between;align-items:center;padding-top:26px;flex-wrap:wrap;gap:12px}\n.foot-bot p{color:rgba(226,240,255,.62);font-size:14px}\n.foot-bot.pill-free{font-size:12.5px;font-weight:700;color:#7DE3F0;background:rgba(6,182,212,.1);border:1px solid rgba(6,182,212,.25);padding:6px 14px;border-radius:999px}\n\n\/* ============ REVEAL ============ *\/\n.reveal{opacity:0;transform:translateY(28px);transition:opacity.7s cubic-bezier(.16,1,.3,1),transform.7s cubic-bezier(.16,1,.3,1)}\n.reveal.in{opacity:1;transform:none}\n.reveal.d1{transition-delay:.08s}.reveal.d2{transition-delay:.16s}.reveal.d3{transition-delay:.24s}.reveal.d4{transition-delay:.32s}.reveal.d5{transition-delay:.4s}.reveal.d6{transition-delay:.48s}\n\n\/* ============ TWEAK PANEL ============ *\/\n.gear{\n  position:fixed;bottom:24px;right:24px;z-index:200;width:54px;height:54px;border-radius:50%;border:none;cursor:pointer;\n  background:linear-gradient(135deg,var(--accent-a),var(--accent-b));color:#fff;display:grid;place-items:center;\n  box-shadow:var(--sh-glow);transition:transform var(--t-spring);\n}\n.gear:hover{transform:rotate(45deg) scale(1.08)}\n.gear svg{transition:transform.6s}\n.tweakpanel{\n  position:fixed;bottom:90px;right:24px;z-index:200;width:300px;background:#fff;border:1px solid var(--border);\n  border-radius:var(--r22);box-shadow:0 24px 70px rgba(15,23,42,.22);padding:22px;\n  transform:translateY(16px) scale(.96);opacity:0;pointer-events:none;transform-origin:bottom right;\n  transition:transform var(--t-spring),opacity var(--t-mid);\n}\n.tweakpanel.open{transform:none;opacity:1;pointer-events:auto}\n.tp-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px}\n.tp-head h4{font-size:16px;font-weight:800;display:flex;align-items:center;gap:8px}\n.tp-close{width:28px;height:28px;border-radius:8px;border:none;background:var(--light);cursor:pointer;color:var(--muted);display:grid;place-items:center;transition:all var(--t-fast)}\n.tp-close:hover{background:var(--border)}\n.tp-row{margin-bottom:18px}\n.tp-row label{display:flex;justify-content:space-between;font-size:13px;font-weight:700;color:var(--text);margin-bottom:9px}\n.tp-row label span{color:var(--teal);font-weight:600}\n.tp-row input[type=range]{width:100%;-webkit-appearance:none;height:6px;border-radius:999px;background:var(--border);outline:none}\n.tp-row input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:linear-gradient(135deg,var(--accent-a),var(--accent-b));cursor:pointer;box-shadow:0 2px 6px rgba(13,148,136,.4)}\n.tp-row input[type=range]::-moz-range-thumb{width:18px;height:18px;border:none;border-radius:50%;background:var(--teal);cursor:pointer}\n.swatches{display:flex;gap:8px}\n.sw{flex:1;height:34px;border-radius:10px;cursor:pointer;border:2px solid transparent;transition:all var(--t-fast)}\n.sw.active{border-color:var(--text);transform:scale(1.05)}\n.tp-toggle{display:flex;align-items:center;justify-content:space-between}\n.toggle{width:46px;height:26px;border-radius:999px;background:var(--border);position:relative;cursor:pointer;transition:background var(--t-fast);border:none;flex-shrink:0}\n.toggle::after{content:\"\";position:absolute;width:20px;height:20px;border-radius:50%;background:#fff;top:3px;left:3px;transition:transform var(--t-spring);box-shadow:0 1px 4px rgba(0,0,0,.2)}\n.toggle.on{background:linear-gradient(135deg,var(--accent-a),var(--accent-b))}\n.toggle.on::after{transform:translateX(20px)}\n\n\/* ============ RESPONSIVE ============ *\/\n@media(max-width:980px){\n  .hero-grid{grid-template-columns:1fr;gap:0}\n  .hero-3d-wrap{height:340px;order:-1;margin-bottom:10px}\n  .cs-grid,.feat-grid,.yt-grid,.foot-grid{grid-template-columns:1fr}\n  .foot-grid{gap:34px}\n  .feat-grid{grid-template-columns:1fr}\n}\n@media(max-width:860px){\n  .navlinks,.start-pill.lbl{display:none}\n  .hamburger{display:grid}\n  .search-btn{display:none}\n  .nav{height:64px}\n  .icon-btn{width:44px;height:44px}\n  .hero{padding:120px 0 80px}\n}\n@media(max-width:620px){\n  .wrap{padding:0 20px}\n  .demo-card,.cs-card{padding:26px}\n  .player{flex-direction:column;align-items:stretch;gap:18px}\n  .bigplay{align-self:center}\n  .demo-actions{gap:10px}\n  .demo-meta{margin-left:0;width:100%;justify-content:flex-start}\n  .free-banner{flex-direction:column;font-size:17px}\n  .topic-grid{grid-template-columns:1fr}\n  .feat-grid{grid-template-columns:1fr}\n  .tweakpanel{width:calc(100vw - 40px);right:20px}\n}\n@media(prefers-reduced-motion:reduce){\n  *{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}\n  html{scroll-behavior:auto}\n  .reveal{opacity:1;transform:none}\n}\n<\/style>\n\n\n<!-- ============ HEADER ============ -->\n<header id=\"hdr\">\n  <div class=\"wrap nav\">\n    <a href=\"#\" class=\"brand\">\n      <img decoding=\"async\" src=\"https:\/\/allenglish4u.com\/wp-content\/uploads\/2026\/04\/Transparent-background-MacBook-Pro-cua-Hang.png\" alt=\"All English 4U\" onerror=\"this.style.background='linear-gradient(135deg,#0D9488,#06B6D4)';this.removeAttribute('src')\" \/>\n      <span class=\"b-name\">All English 4U<\/span>\n    <\/a>\n    <nav class=\"navlinks\">\n      <a href=\"\/grammar\/\">Grammar<\/a>\n      <a href=\"\/ielts\/\">IELTS<\/a>\n      <a href=\"\/toefl\/\">TOEFL<\/a>\n      <a href=\"\/cambridge\/\">Cambridge<\/a>\n      <a href=\"\/celpip\/\">CELPIP<\/a>\n      <a href=\"\/dictation\/\" class=\"active\">Dictation<\/a>\n      <a href=\"\/contact\/\">Contact<\/a>\n    <\/nav>\n    <div class=\"nav-right\">\n      <button class=\"icon-btn search-btn\" aria-label=\"Search\">\n        <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"\/><path d=\"m21 21-4.3-4.3\"\/><\/svg>\n      <\/button>\n      <button class=\"btn btn-grad start-pill\"><span class=\"lbl\">Start Free<\/span><svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"><path d=\"M5 12h14M13 6l6 6-6 6\"\/><\/svg><\/button>\n      <button class=\"icon-btn hamburger\" id=\"hamb\" aria-label=\"Menu\">\n        <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\"><path d=\"M4 7h16M4 12h16M4 17h16\"\/><\/svg>\n      <\/button>\n    <\/div>\n  <\/div>\n<\/header>\n\n<div class=\"scrim\" id=\"scrim\"><\/div>\n<nav class=\"mobile-menu\" id=\"mobileMenu\">\n  <a href=\"\/grammar\/\">Grammar<\/a><a href=\"\/ielts\/\">IELTS<\/a><a href=\"\/toefl\/\">TOEFL<\/a><a href=\"\/cambridge\/\">Cambridge<\/a>\n  <a href=\"\/celpip\/\">CELPIP<\/a>\n  <a href=\"\/dictation\/\" class=\"active\">Dictation<\/a><a href=\"\/contact\/\">Contact<\/a>\n<\/nav>\n\n<!-- ============ HERO ============ -->\n<main id=\"main\">\n<section class=\"hero\" id=\"top\">\n  <div class=\"wrap hero-grid\">\n    <div class=\"hero-copy\">\n      <div class=\"eyebrow reveal\"><span class=\"dot\"><\/span>English Dictation Practice<\/div>\n      <h1 class=\"serif reveal d1\">Dictation <span class=\"grad-text\">Lessons<\/span><\/h1>\n      <p class=\"sub reveal d2\">Real-world topics, authentic listening passages. Hear it, understand it, write it. Build spelling accuracy and listening focus \u2014 B1, B2, and C1 levels.<\/p>\n      <div class=\"chips reveal d3\">\n        <span class=\"chip\"><svg class=\"ic\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M9 18V5l12-2v13\"\/><circle cx=\"6\" cy=\"18\" r=\"3\"\/><circle cx=\"18\" cy=\"16\" r=\"3\"\/><\/svg><b>21<\/b> Total Lessons<\/span>\n        <span class=\"chip\"><svg class=\"ic\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m9 12 2 2 4-4\"\/><circle cx=\"12\" cy=\"12\" r=\"9\"\/><\/svg><b>4<\/b> Available Now<\/span>\n        <span class=\"chip\"><svg class=\"ic\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 12h4l3-9 4 18 3-9h4\"\/><\/svg><b>3<\/b> CEFR Levels<\/span>\n        <span class=\"chip\"><svg class=\"ic\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 20h9M3 20h2M16.5 3.5a2.1 2.1 0 0 1 3 3L8 18l-4 1 1-4Z\"\/><\/svg>Fill-in-the-Blank<\/span>\n      <\/div>\n      <div class=\"hero-cta reveal d4\">\n        <button class=\"btn btn-grad\" onclick=\"document.getElementById('b1').scrollIntoView()\">\n          <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"\/><\/svg>Start B1 Topic 1<\/button>\n        <a href=\"#\" class=\"btn btn-ghost\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M21.6 7.2a2.7 2.7 0 0 0-1.9-1.9C18 4.8 12 4.8 12 4.8s-6 0-7.7.5A2.7 2.7 0 0 0 2.4 7.2 28 28 0 0 0 2 12a28 28 0 0 0 .4 4.8 2.7 2.7 0 0 0 1.9 1.9c1.7.5 7.7.5 7.7.5s6 0 7.7-.5a2.7 2.7 0 0 0 1.9-1.9A28 28 0 0 0 22 12a28 28 0 0 0-.4-4.8zM10 15V9l5 3z\"\/><\/svg>Watch on YouTube<\/a>\n      <\/div>\n    <\/div>\n    <div class=\"hero-3d-wrap reveal d2\">\n      <div class=\"hero-3d-glow\"><\/div>\n      <canvas id=\"hero3d\"><\/canvas>\n    <\/div>\n  <\/div>\n<\/section>\n\n<!-- ============ B1 SECTION ============ -->\n<section class=\"sec\" id=\"b1\">\n  <div class=\"wrap\">\n    <div class=\"sec-head reveal\">\n      <div class=\"kick\"><span class=\"line\"><\/span>Live Now<\/div>\n      <div style=\"display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:16px\">\n        <h2 class=\"serif\">B1 \u2014 Intermediate<\/h2>\n        <span class=\"level-badge bd-live\"><span class=\"live-dot\"><\/span>B1 Intermediate<\/span>\n      <\/div>\n      <p>Listen, understand, and write \u2014 real topics at an intermediate level. Build your spelling accuracy and listening comprehension.<\/p>\n    <\/div>\n    <div class=\"topic-grid\">\n      <!-- Topic 1 -->\n      <a href=\"\/dictation\/dictation-b1-the-most-useful-inventions\/\" class=\"tcard live reveal d1\" style=\"text-decoration:none;color:inherit\">\n        <div class=\"tcard-top\"><div class=\"tnum\">01<\/div><span class=\"tstat level-badge bd-live\"><span class=\"live-dot\"><\/span>Live<\/span><\/div>\n        <h3>The Most Useful Inventions<\/h3>\n        <div class=\"tags\"><span class=\"tag vid\"><svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"\/><\/svg>Video<\/span><span class=\"tag fill\">Fill-in<\/span><\/div>\n        <div class=\"play-row\"><span class=\"pico\"><svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"\/><\/svg><\/span>Start lesson<\/div>\n      <\/a>\n      <!-- Topic 2 -->\n      <a href=\"\/dictation\/dictation-b1-allergies\/\" class=\"tcard live reveal d2\" style=\"text-decoration:none;color:inherit\">\n        <div class=\"tcard-top\"><div class=\"tnum\">02<\/div><span class=\"tstat level-badge bd-live\"><span class=\"live-dot\"><\/span>Live<\/span><\/div>\n        <h3>Allergies<\/h3>\n        <div class=\"tags\"><span class=\"tag vid\"><svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"\/><\/svg>Video<\/span><span class=\"tag fill\">Fill-in<\/span><\/div>\n        <div class=\"play-row\"><span class=\"pico\"><svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"\/><\/svg><\/span>Start lesson<\/div>\n      <\/a>\n      <!-- Topic 3 -->\n      <div class=\"tcard locked reveal d3\">\n        <div class=\"tcard-top\"><div class=\"tnum\">03<\/div><span class=\"tstat level-badge bd-soon\">Soon<\/span><\/div>\n        <h3>Planet Earth<\/h3>\n        <div class=\"tags\"><span class=\"tag\">Coming soon<\/span><\/div>\n        <div class=\"mini-stat\" style=\"margin-top:6px\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"4\" y=\"11\" width=\"16\" height=\"10\" rx=\"2\"\/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"\/><\/svg>In the pipeline<\/div>\n      <\/div>\n      <!-- Topic 4 -->\n      <div class=\"tcard locked reveal d4\">\n        <div class=\"tcard-top\"><div class=\"tnum\">04<\/div><span class=\"tstat level-badge bd-soon\">Soon<\/span><\/div>\n        <h3>Long Life<\/h3>\n        <div class=\"tags\"><span class=\"tag\">Coming soon<\/span><\/div>\n        <div class=\"mini-stat\" style=\"margin-top:6px\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"4\" y=\"11\" width=\"16\" height=\"10\" rx=\"2\"\/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"\/><\/svg>In the pipeline<\/div>\n      <\/div>\n      <!-- Topics 5-7 -->\n      <div class=\"tcard locked prod reveal d1\">\n        <div class=\"tcard-top\"><div class=\"tnum\">05<\/div><span class=\"tstat level-badge bd-prod\">In Production<\/span><\/div>\n        <h3>Topic 5<\/h3>\n        <div class=\"tags\"><span class=\"tag\">Being recorded<\/span><\/div>\n      <\/div>\n      <div class=\"tcard locked prod reveal d2\">\n        <div class=\"tcard-top\"><div class=\"tnum\">06<\/div><span class=\"tstat level-badge bd-prod\">In Production<\/span><\/div>\n        <h3>Topic 6<\/h3>\n        <div class=\"tags\"><span class=\"tag\">Being recorded<\/span><\/div>\n      <\/div>\n      <div class=\"tcard locked prod reveal d3\">\n        <div class=\"tcard-top\"><div class=\"tnum\">07<\/div><span class=\"tstat level-badge bd-prod\">In Production<\/span><\/div>\n        <h3>Topic 7<\/h3>\n        <div class=\"tags\"><span class=\"tag\">Being recorded<\/span><\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>\n\n<!-- ============ B2 \/ C1 SECTION ============ -->\n<section class=\"sec alt\">\n  <div class=\"wrap\">\n    <div class=\"sec-head reveal\">\n      <div class=\"kick\"><span class=\"line\"><\/span>On the Roadmap<\/div>\n      <h2 class=\"serif\">More levels, coming soon<\/h2>\n      <p>The B1 library is live and growing. B2 and C1 are in production \u2014 get notified the moment each level goes live.<\/p>\n    <\/div>\n    <div class=\"cs-grid\">\n      <div class=\"cs-card reveal d1\">\n        <div class=\"glow\"><\/div>\n        <span class=\"level-badge bd-soon\">Coming Soon<\/span>\n        <h3>B2 \u2014 Upper Intermediate<\/h3>\n        <span class=\"lvl-tag\">8 topics<\/span>\n        <p>More complex sentences, richer vocabulary. 8 topics with richer vocabulary and faster natural speech.<\/p>\n        <div class=\"pillrow\">\n          <span class=\"spill\">Environment<\/span><span class=\"spill\">Technology<\/span><span class=\"spill\">Psychology<\/span><span class=\"spill\">Global Issues<\/span><span class=\"spill more\">+4 more topics<\/span>\n        <\/div>\n        <button class=\"btn btn-light\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9\"\/><path d=\"M13.7 21a2 2 0 0 1-3.4 0\"\/><\/svg>Notify Me<\/button>\n      <\/div>\n      <div class=\"cs-card reveal d2\">\n        <div class=\"glow\"><\/div>\n        <span class=\"level-badge bd-soon\">Coming Soon<\/span>\n        <h3>C1 \u2014 Advanced<\/h3>\n        <span class=\"lvl-tag\">6 topics<\/span>\n        <p>Advanced-level passages \u2014 academic texts, news excerpts, and professional English.<\/p>\n        <div class=\"pillrow\">\n          <span class=\"spill\">Academic English<\/span><span class=\"spill\">Journalism<\/span><span class=\"spill\">Culture &amp; Society<\/span><span class=\"spill more\">+3 more topics<\/span>\n        <\/div>\n        <button class=\"btn btn-light\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9\"\/><path d=\"M13.7 21a2 2 0 0 1-3.4 0\"\/><\/svg>Notify Me<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>\n\n<!-- ============ INTERACTIVE DEMO ============ -->\n<section class=\"demo-sec\">\n  <div class=\"wrap\">\n    <div class=\"sec-head reveal\" style=\"text-align:center;margin:0 auto 44px\">\n      <div class=\"kick\" style=\"justify-content:center\"><span class=\"line\"><\/span>Interactive Demo<span class=\"line\"><\/span><\/div>\n      <h2 class=\"serif\">Try a dictation line<\/h2>\n      <p style=\"margin:0 auto\">Press play, listen to the waveform, and type the missing word. This is exactly how every lesson works.<\/p>\n    <\/div>\n    <div class=\"demo-card reveal d1\">\n      <div class=\"player\">\n        <button class=\"bigplay\" id=\"bigplay\" aria-label=\"Play passage\">\n          <svg id=\"ppicon\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"\/><\/svg>\n        <\/button>\n        <div class=\"player-body\">\n          <canvas id=\"wave\"><\/canvas>\n          <div class=\"prow\">\n            <span class=\"ptime\" id=\"curTime\">0:00<\/span>\n            <div class=\"ptrack\" id=\"ptrack\" role=\"slider\" aria-label=\"Playback position\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\" tabindex=\"0\"><div class=\"pfill\" id=\"pfill\"><\/div><\/div>\n            <span class=\"ptime end\" id=\"durTime\">0:08<\/span>\n          <\/div>\n        <\/div>\n      <\/div>\n      <p class=\"dline\">\u201cThe wheel is often called the most useful\n        <input class=\"blank-in\" id=\"blank\" placeholder=\"?????\" autocomplete=\"off\" spellcheck=\"false\" aria-label=\"Type the missing word\" \/> ever made.\u201d<\/p>\n      <p class=\"dhint\" id=\"dhint\">Listen carefully, then type the word you hear.<\/p>\n      <div class=\"demo-actions\">\n        <button class=\"btn btn-grad\" id=\"checkBtn\">Check answer<\/button>\n        <button class=\"btn btn-ghost\" id=\"hintBtn\" style=\"color:#fff\">Hint<\/button>\n        <button class=\"btn btn-ghost\" id=\"resetBtn\" style=\"color:#fff\">Reset<\/button>\n        <span class=\"demo-meta\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"9\"\/><path d=\"M12 7v5l3 2\"\/><\/svg>B1 \u00b7 Topic 1<\/span>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>\n\n<!-- ============ HOW IT WORKS ============ -->\n<section class=\"sec\">\n  <div class=\"wrap\">\n    <div class=\"sec-head reveal\" style=\"text-align:center;margin:0 auto 44px\">\n      <div class=\"kick\" style=\"justify-content:center\"><span class=\"line\"><\/span>The Method<span class=\"line\"><\/span><\/div>\n      <h2 class=\"serif\">How dictation works<\/h2>\n      <p style=\"margin:0 auto\">Three simple steps train your ear and your spelling at the same time.<\/p>\n    <\/div>\n    <div class=\"feat-grid\">\n      <div class=\"feat reveal d1\">\n        <div class=\"ficon\"><svg width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 14v-4a9 9 0 0 1 18 0v4\"\/><path d=\"M21 16a3 3 0 0 1-3 3h-1v-6h1a3 3 0 0 1 3 3zM3 16a3 3 0 0 0 3 3h1v-6H6a3 3 0 0 0-3 3z\"\/><\/svg><\/div>\n        <h3>Hear authentic passages<\/h3>\n        <p>Listen to real-world topics spoken at a natural pace. Every lesson uses genuine, useful English \u2014 not robotic textbook lines.<\/p>\n      <\/div>\n      <div class=\"feat reveal d2\">\n        <div class=\"ficon\"><svg width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 20h9M3 20h2M16.5 3.5a2.1 2.1 0 0 1 3 3L8 18l-4 1 1-4Z\"\/><\/svg><\/div>\n        <h3>Type what you hear<\/h3>\n        <p>Fill in the blanks as you listen. Active recall forces you to process sounds, spelling, and meaning all at once.<\/p>\n      <\/div>\n      <div class=\"feat reveal d3\">\n        <div class=\"ficon\"><svg width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m9 12 2 2 4-4\"\/><circle cx=\"12\" cy=\"12\" r=\"9\"\/><\/svg><\/div>\n        <h3>Instant feedback<\/h3>\n        <p>Get immediate correct\/incorrect feedback with the answer revealed \u2014 so every line builds your spelling and listening together.<\/p>\n      <\/div>\n    <\/div>\n    <div class=\"free-banner reveal d2\">\n      <svg width=\"34\" height=\"34\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1-1.1a5.5 5.5 0 0 0-7.8 7.8l1.1 1L12 21l7.7-7.6 1.1-1a5.5 5.5 0 0 0 0-7.8z\"\/><\/svg>\n      <span><span class=\"big\">100% free<\/span>. No account, no paywall, no catch.<\/span>\n    <\/div>\n  <\/div>\n<\/section>\n\n<!-- ============ YOUTUBE BAND ============ -->\n<section class=\"yt-sec\">\n  <div class=\"wrap\">\n    <div class=\"yt-head reveal\">\n      <h2 class=\"serif\">Watch free dictation lessons on YouTube<\/h2>\n      <p>Every lesson is a full video with audio, captions, and answers. Subscribe so you never miss a new topic.<\/p>\n      <a href=\"#\" class=\"btn btn-red\"><svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M21.6 7.2a2.7 2.7 0 0 0-1.9-1.9C18 4.8 12 4.8 12 4.8s-6 0-7.7.5A2.7 2.7 0 0 0 2.4 7.2 28 28 0 0 0 2 12a28 28 0 0 0 .4 4.8 2.7 2.7 0 0 0 1.9 1.9c1.7.5 7.7.5 7.7.5s6 0 7.7-.5a2.7 2.7 0 0 0 1.9-1.9A28 28 0 0 0 22 12a28 28 0 0 0-.4-4.8zM10 15V9l5 3z\"\/><\/svg>Subscribe<\/a>\n    <\/div>\n    <div class=\"yt-grid\">\n      <div class=\"vcard reveal d1\">\n        <div class=\"vthumb\"><div class=\"wbars\" id=\"wbar1\"><\/div><div class=\"vplay\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"\/><\/svg><\/div><\/div>\n        <div class=\"vinfo\"><h4>The Most Useful Inventions<\/h4><span><svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"9\"\/><path d=\"M12 7v5l3 2\"\/><\/svg>B1 dictation \u00b7 Fill-in-the-blank<\/span><\/div>\n      <\/div>\n      <div class=\"vcard reveal d2\">\n        <div class=\"vthumb\"><div class=\"wbars\" id=\"wbar2\"><\/div><div class=\"vplay\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"\/><\/svg><\/div><\/div>\n        <div class=\"vinfo\"><h4>Allergies \u2014 B1 dictation<\/h4><span><svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"9\"\/><path d=\"M12 7v5l3 2\"\/><\/svg>B1 dictation \u00b7 Fill-in-the-blank<\/span><\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>\n\n<\/main>\n\n<!-- ============ FOOTER ============ -->\n\n\n<!-- ============ TWEAK PANEL ============ -->\n<button class=\"gear\" id=\"gear\" aria-label=\"Customize\">\n  <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"3\"\/><path d=\"M19.4 15a1.6 1.6 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.6 1.6 0 0 0-1.8-.3 1.6 1.6 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.6 1.6 0 0 0-1-1.5 1.6 1.6 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.6 1.6 0 0 0 .3-1.8 1.6 1.6 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.6 1.6 0 0 0 1.5-1 1.6 1.6 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.6 1.6 0 0 0 1.8.3H9a1.6 1.6 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.6 1.6 0 0 0 1 1.5 1.6 1.6 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.6 1.6 0 0 0-.3 1.8V9a1.6 1.6 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.6 1.6 0 0 0-1.5 1z\"\/><\/svg>\n<\/button>\n<div class=\"tweakpanel\" id=\"tweakpanel\">\n  <div class=\"tp-head\">\n    <h4><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--teal)\" stroke-width=\"2.2\"><path d=\"m15 4 6 6M13 6 4 15v5h5l9-9\"\/><\/svg>Customize<\/h4>\n    <button class=\"tp-close\" id=\"tpClose\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\"><path d=\"M6 6l12 12M18 6 6 18\"\/><\/svg><\/button>\n  <\/div>\n  <div class=\"tp-row\">\n    <label>Accent <span id=\"hueVal\">Teal \u2192 Cyan<\/span><\/label>\n    <div class=\"swatches\" id=\"swatches\">\n      <div class=\"sw active\" data-a=\"#0D9488\" data-b=\"#06B6D4\" style=\"background:linear-gradient(135deg,#0D9488,#06B6D4)\"><\/div>\n      <div class=\"sw\" data-a=\"#0EA5A5\" data-b=\"#22D3EE\" style=\"background:linear-gradient(135deg,#0EA5A5,#22D3EE)\"><\/div>\n      <div class=\"sw\" data-a=\"#0891B2\" data-b=\"#38BDF8\" style=\"background:linear-gradient(135deg,#0891B2,#38BDF8)\"><\/div>\n      <div class=\"sw\" data-a=\"#059669\" data-b=\"#06B6D4\" style=\"background:linear-gradient(135deg,#059669,#06B6D4)\"><\/div>\n    <\/div>\n  <\/div>\n  <div class=\"tp-row\">\n    <label>Animation speed <span id=\"spdVal\">1.0\u00d7<\/span><\/label>\n    <input type=\"range\" id=\"spd\" min=\"0\" max=\"2\" step=\"0.1\" value=\"1\" \/>\n  <\/div>\n  <div class=\"tp-row\">\n    <label>3D \/ waveform intensity <span id=\"intVal\">100%<\/span><\/label>\n    <input type=\"range\" id=\"intensity\" min=\"0.2\" max=\"1.6\" step=\"0.1\" value=\"1\" \/>\n  <\/div>\n  <div class=\"tp-row tp-toggle\">\n    <label style=\"margin:0\">Reduce motion<\/label>\n    <button class=\"toggle\" id=\"rmToggle\" aria-label=\"Reduce motion\"><\/button>\n  <\/div>\n<\/div>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/three.js\/r128\/three.min.js\"><\/script>\n<script>\n\/* ============================================================\n   All English 4U \u2014 Dictation landing page\n   ============================================================ *\/\n(function(){\n  'use strict';\n  const $ = (s,el)=> (el||document).querySelector(s);\n  const $$ = (s,el)=> Array.from((el||document).querySelectorAll(s));\n  const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n  const isMobile = window.matchMedia('(max-width: 860px)').matches;\n\n  \/\/ global tweak state\n  const STATE = { speed:1, intensity:1, reduce:prefersReduced };\n\n  \/* ---------- HEADER scroll ---------- *\/\n  const hdr = $('#hdr');\n  const onScroll = ()=>{ hdr.classList.toggle('scrolled', window.scrollY > 40); };\n  onScroll(); window.addEventListener('scroll', onScroll, {passive:true});\n\n  \/* ---------- MOBILE menu ---------- *\/\n  const mm = $('#mobileMenu'), scrim = $('#scrim'), hamb = $('#hamb');\n  const toggleMenu = (open)=>{ mm.classList.toggle('open',open); scrim.classList.toggle('open',open); };\n  hamb.addEventListener('click', ()=> toggleMenu(!mm.classList.contains('open')));\n  scrim.addEventListener('click', ()=> toggleMenu(false));\n  $$('#mobileMenu a').forEach(a=> a.addEventListener('click', ()=> toggleMenu(false)));\n\n  \/* ---------- SCROLL REVEAL ---------- *\/\n  const io = new IntersectionObserver((ents)=>{\n    ents.forEach(e=>{ if(e.isIntersecting){ e.target.classList.add('in'); io.unobserve(e.target); } });\n  }, {threshold:0.12, rootMargin:'0px 0px -8% 0px'});\n  $$('.reveal').forEach(el=> io.observe(el));\n\n  \/* ---------- YOUTUBE thumbnail bars ---------- *\/\n  function fillBars(id, n){\n    const host = $('#'+id); if(!host) return;\n    let html='';\n    for(let i=0;i<n;i++){ html += `<span style=\"animation-delay:${(i*0.07).toFixed(2)}s\"><\/span>`; }\n    host.innerHTML = html;\n  }\n  fillBars('wbar1', 26); fillBars('wbar2', 26);\n\n  \/* ============================================================\n     INTERACTIVE DEMO \u2014 animated waveform + dictation check\n     ============================================================ *\/\n  const ANSWER = 'invention';\n  const blank = $('#blank'), hint = $('#dhint');\n  const bigplay = $('#bigplay'), ppicon = $('#ppicon');\n  let playing = false;\n\n  \/\/ waveform canvas\n  const wave = $('#wave');\n  const wctx = wave.getContext('2d');\n  let wPhase = 0, waveRAF = null, waveLevel = 0;\n  function sizeWave(){\n    const r = wave.getBoundingClientRect();\n    const dpr = Math.min(window.devicePixelRatio||1, 2);\n    wave.width = Math.max(2, r.width*dpr); wave.height = Math.max(2, r.height*dpr);\n    wctx.setTransform(dpr,0,0,dpr,0,0);\n  }\n  function accentCols(){\n    const cs = getComputedStyle(document.documentElement);\n    return [cs.getPropertyValue('--accent-a').trim()||'#0D9488', cs.getPropertyValue('--accent-b').trim()||'#06B6D4'];\n  }\n  function drawWave(){\n    const r = wave.getBoundingClientRect(); const W=r.width, H=r.height;\n    wctx.clearRect(0,0,W,H);\n    const [ca,cb] = accentCols();\n    const bars = Math.max(28, Math.floor(W\/9));\n    const bw = W\/bars;\n    const mid = H\/2;\n    \/\/ target level eases toward playing state\n    const target = playing ? 1 : 0.18;\n    waveLevel += (target - waveLevel)*0.08;\n    for(let i=0;i<bars;i++){\n      const x = i*bw + bw*0.5;\n      const t = i\/bars;\n      \/\/ layered sines for organic motion\n      const env = Math.sin(t*Math.PI); \/\/ taper ends\n      const s = Math.sin(t*9 + wPhase) * 0.5 + Math.sin(t*17 - wPhase*1.6) * 0.3 + Math.sin(t*4 + wPhase*0.7)*0.4;\n      let h = (Math.abs(s)*0.6 + 0.12) * env * H * 0.82 * waveLevel + 3;\n      h = Math.max(3, h);\n      const g = wctx.createLinearGradient(0, mid-h\/2, 0, mid+h\/2);\n      g.addColorStop(0, ca); g.addColorStop(1, cb);\n      wctx.fillStyle = g;\n      wctx.globalAlpha = 0.55 + 0.45*waveLevel;\n      const bwR = Math.min(bw*0.42, 3);\n      roundRect(wctx, x-bw*0.3, mid-h\/2, bw*0.6, h, bwR);\n      wctx.fill();\n    }\n    wctx.globalAlpha = 1;\n    const inc = (playing?0.09:0.025) * STATE.speed * (STATE.reduce?0:1);\n    wPhase += inc;\n    waveRAF = requestAnimationFrame(drawWave);\n  }\n  function roundRect(ctx,x,y,w,h,r){\n    r = Math.min(r, w\/2, h\/2);\n    ctx.beginPath();\n    ctx.moveTo(x+r,y); ctx.arcTo(x+w,y,x+w,y+h,r); ctx.arcTo(x+w,y+h,x,y+h,r);\n    ctx.arcTo(x,y+h,x,y,r); ctx.arcTo(x,y,x+w,y,r); ctx.closePath();\n  }\n  sizeWave(); drawWave();\n  window.addEventListener('resize', ()=>{ sizeWave(); });\n\n  \/\/ simulate playback with progress bar + timestamps\n  const TOTAL = 8.0; \/\/ seconds (simulated)\n  const pfill = $('#pfill'), curTime = $('#curTime'), durTime = $('#durTime'), ptrack = $('#ptrack');\n  let progress = 0, progRAF = null, lastTS = 0;\n  function fmt(s){ s=Math.max(0,Math.min(TOTAL,s)); const m=Math.floor(s\/60), sec=Math.floor(s%60); return m+':'+String(sec).padStart(2,'0'); }\n  if(durTime) durTime.textContent = fmt(TOTAL);\n  function paintProgress(){\n    const pct = (progress\/TOTAL)*100;\n    if(pfill) pfill.style.width = pct.toFixed(1)+'%';\n    if(curTime) curTime.textContent = fmt(progress);\n    if(ptrack) ptrack.setAttribute('aria-valuenow', Math.round(pct));\n  }\n  function stopPlay(){\n    playing=false; bigplay.classList.remove('playing');\n    ppicon.innerHTML = '<path d=\"M8 5v14l11-7z\"\/>';\n    if(progRAF){ cancelAnimationFrame(progRAF); progRAF=null; }\n  }\n  function progLoop(ts){\n    if(!playing) return;\n    if(!lastTS) lastTS = ts;\n    const dt = (ts-lastTS)\/1000; lastTS = ts;\n    progress += dt * (STATE.reduce?2:1) * Math.max(0.4, STATE.speed);\n    if(progress >= TOTAL){\n      progress = TOTAL; paintProgress(); stopPlay();\n      hint.innerHTML = 'Finished. Type the word you heard, then press <b>Check answer<\/b>.';\n      return;\n    }\n    paintProgress();\n    progRAF = requestAnimationFrame(progLoop);\n  }\n  bigplay.addEventListener('click', ()=>{\n    playing = !playing;\n    bigplay.classList.toggle('playing', playing);\n    bigplay.setAttribute('aria-label', playing ? 'Pause passage' : 'Play passage');\n    ppicon.innerHTML = playing\n      ? '<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"\/>'\n      : '<path d=\"M8 5v14l11-7z\"\/>';\n    if(playing){\n      hint.innerHTML = 'Playing\u2026 listen for the missing word.';\n      if(progress >= TOTAL) progress = 0;\n      lastTS = 0; progRAF = requestAnimationFrame(progLoop);\n    } else {\n      if(progRAF){ cancelAnimationFrame(progRAF); progRAF=null; }\n      hint.innerHTML = 'Paused. Type the word you heard, then press Check.';\n    }\n  });\n  \/\/ seek\n  function seekTo(clientX){\n    const r = ptrack.getBoundingClientRect();\n    progress = Math.max(0, Math.min(1, (clientX-r.left)\/r.width)) * TOTAL;\n    paintProgress();\n  }\n  if(ptrack){\n    ptrack.addEventListener('click', e=> seekTo(e.clientX));\n    ptrack.addEventListener('keydown', e=>{\n      if(e.key==='ArrowRight'){ progress=Math.min(TOTAL,progress+0.5); paintProgress(); e.preventDefault(); }\n      if(e.key==='ArrowLeft'){ progress=Math.max(0,progress-0.5); paintProgress(); e.preventDefault(); }\n    });\n  }\n\n  \/\/ check answer\n  function normalize(s){ return (s||'').trim().toLowerCase().replace(\/[^a-z]\/g,''); }\n  function check(){\n    const val = normalize(blank.value);\n    blank.classList.remove('correct','wrong');\n    if(!val){ hint.innerHTML = '<span class=\"no\">Type a word first<\/span> \u2014 press play to listen again.'; return; }\n    if(val === ANSWER){\n      blank.classList.add('correct');\n      blank.value = 'invention';\n      hint.innerHTML = '<span class=\"ok\">\u2713 Correct!<\/span> The word was <b>\u201cinvention\u201d<\/b>. Nicely heard.';\n    } else {\n      blank.classList.add('wrong');\n      hint.innerHTML = '<span class=\"no\">\u2717 Not quite.<\/span> Listen again, or use a hint.';\n    }\n  }\n  $('#checkBtn').addEventListener('click', check);\n  blank.addEventListener('keydown', e=>{ if(e.key==='Enter') check(); });\n  blank.addEventListener('input', ()=> blank.classList.remove('correct','wrong'));\n\n  \/\/ hint reveals first letters\n  $('#hintBtn').addEventListener('click', ()=>{\n    hint.innerHTML = 'Hint: it starts with <b>\u201cinv\u2026\u201d<\/b> and means something newly created.';\n    blank.focus();\n  });\n  \/\/ reset\n  $('#resetBtn').addEventListener('click', ()=>{\n    blank.value=''; blank.classList.remove('correct','wrong');\n    hint.innerHTML = 'Listen carefully, then type the word you hear.';\n    stopPlay(); progress = 0; paintProgress();\n    blank.focus();\n  });\n\n  \/* ============================================================\n     THREE.JS \u2014 transparent 3D audio waveform ribbon\n     ============================================================ *\/\n  function initHero3D(){\n    const canvas = $('#hero3d');\n    if(!canvas || typeof THREE === 'undefined') return;\n\n    const renderer = new THREE.WebGLRenderer({canvas, alpha:true, antialias:true, powerPreference:'high-performance'});\n    renderer.setClearColor(0x000000, 0); \/\/ fully transparent\n    renderer.setPixelRatio(Math.min(window.devicePixelRatio||1, 2));\n\n    const scene = new THREE.Scene();\n    const camera = new THREE.PerspectiveCamera(42, 1, 0.1, 100);\n    camera.position.set(0, 1.6, 13);\n    camera.lookAt(0, 0.2, 0);\n\n    function resize(){\n      const r = canvas.getBoundingClientRect();\n      const w = Math.max(2, r.width), h = Math.max(2, r.height);\n      renderer.setSize(w, h, false);\n      camera.aspect = w\/h; camera.updateProjectionMatrix();\n    }\n\n    \/\/ ---- lights ----\n    scene.add(new THREE.AmbientLight(0x335577, 0.9));\n    const key = new THREE.DirectionalLight(0x9beaf5, 1.5); key.position.set(4,6,8); scene.add(key);\n    const teal = new THREE.PointLight(0x0D9488, 2.2, 40); teal.position.set(-6,2,6); scene.add(teal);\n    const cyan = new THREE.PointLight(0x06B6D4, 2.0, 40); cyan.position.set(6,-1,5); scene.add(cyan);\n\n    \/\/ ---- material colors (updatable by tweaks) ----\n    let colA = new THREE.Color('#0D9488'), colB = new THREE.Color('#06B6D4');\n\n    \/\/ ---- waveform: grid of rounded bars ----\n    const group = new THREE.Group();\n    scene.add(group);\n    const COLS = isMobile ? 22 : 34;\n    const ROWS = isMobile ? 3 : 4;\n    const bars = [];\n    const barGeo = new THREE.BoxGeometry(0.26, 1, 0.26);\n    \/\/ round-ish via small scale; box is fine for glossy look\n    const spacingX = 0.42, spacingZ = 0.55;\n    for(let r=0;r<ROWS;r++){\n      for(let c=0;c<COLS;c++){\n        const mix = c\/(COLS-1);\n        const col = colA.clone().lerp(colB, mix);\n        const mat = new THREE.MeshStandardMaterial({\n          color: col, emissive: col.clone().multiplyScalar(0.35),\n          metalness:0.55, roughness:0.22\n        });\n        const m = new THREE.Mesh(barGeo, mat);\n        m.position.x = (c-(COLS-1)\/2)*spacingX;\n        m.position.z = (r-(ROWS-1)\/2)*spacingZ - 0.3;\n        m.position.y = 0;\n        m.userData = {c, r, mix, mat, baseCol:col.clone()};\n        group.add(m); bars.push(m);\n      }\n    }\n    group.rotation.x = -0.18;\n    group.position.y = 0.1;\n\n    \/\/ ---- floating headphones (friendly companion) ----\n    const phones = new THREE.Group();\n    const bandMat = new THREE.MeshStandardMaterial({color:'#06B6D4', emissive:'#06B6D4', emissiveIntensity:0.25, metalness:0.6, roughness:0.3});\n    const band = new THREE.Mesh(new THREE.TorusGeometry(1.05, 0.12, 16, 60, Math.PI), bandMat);\n    band.rotation.z = Math.PI; band.position.y = 0.2; phones.add(band);\n    const cupGeo = (typeof THREE.CapsuleGeometry === 'function') ? new THREE.CapsuleGeometry(0.34,0.3,8,16) : new THREE.CylinderGeometry(0.34,0.34,0.6,20);\n    [-1,1].forEach(s=>{\n      const cup = new THREE.Mesh(cupGeo, bandMat.clone());\n      cup.position.set(1.05*s, -0.65, 0); cup.rotation.z = Math.PI\/2; phones.add(cup);\n    });\n    phones.scale.setScalar(0.95);\n    phones.position.set(isMobile?0:5.4, 2.6, -1.5);\n    phones.rotation.set(0.1,-0.3,0.12);\n    scene.add(phones);\n\n    \/\/ ---- particles ----\n    const pCount = isMobile ? 60 : 130;\n    const pGeo = new THREE.BufferGeometry();\n    const pPos = new Float32Array(pCount*3);\n    const pSpeed = new Float32Array(pCount);\n    for(let i=0;i<pCount;i++){\n      pPos[i*3]   = (Math.random()-0.5)*20;\n      pPos[i*3+1] = (Math.random()-0.5)*12;\n      pPos[i*3+2] = (Math.random()-0.5)*8 - 2;\n      pSpeed[i]   = 0.2 + Math.random()*0.6;\n    }\n    pGeo.setAttribute('position', new THREE.BufferAttribute(pPos,3));\n    const pMat = new THREE.PointsMaterial({color:0x7DE3F0, size:0.075, transparent:true, opacity:0.7, blending:THREE.AdditiveBlending, depthWrite:false});\n    const particles = new THREE.Points(pGeo, pMat);\n    scene.add(particles);\n\n    \/\/ ---- mouse ----\n    const mouse = {x:0,y:0,tx:0,ty:0};\n    window.addEventListener('pointermove', (e)=>{\n      mouse.tx = (e.clientX\/window.innerWidth - 0.5);\n      mouse.ty = (e.clientY\/window.innerHeight - 0.5);\n    });\n\n    function updateColors(a,b){\n      colA = new THREE.Color(a); colB = new THREE.Color(b);\n      bars.forEach(m=>{\n        const col = colA.clone().lerp(colB, m.userData.mix);\n        m.userData.baseCol = col.clone();\n        m.userData.mat.color.copy(col);\n        m.userData.mat.emissive.copy(col).multiplyScalar(0.35);\n      });\n      bandMat.color.set(b); bandMat.emissive.set(b);\n      teal.color.set(a); cyan.color.set(b);\n    }\n    window.__hero3dColors = updateColors;\n\n    \/\/ ---- animation ----\n    let t = 0; let raf=null; let running=true;\n    const clock = new THREE.Clock();\n    function frame(){\n      if(!running) return;\n      raf = requestAnimationFrame(frame);\n      const dt = Math.min(clock.getDelta(), 0.05);\n      const amp = STATE.intensity;\n      t += dt * (STATE.reduce?0:1) * STATE.speed;\n\n      \/\/ ease mouse\n      mouse.x += (mouse.tx - mouse.x)*0.05;\n      mouse.y += (mouse.ty - mouse.y)*0.05;\n\n      bars.forEach(m=>{\n        const {c,r} = m.userData;\n        const phase = c*0.35 + r*0.6;\n        const wv = Math.sin(t*2.2 + phase) * 0.5 + Math.sin(t*1.3 + c*0.5 - r*0.3)*0.4;\n        \/\/ mouse ripple\n        const mInf = Math.sin(t*2 + c*0.3 + mouse.x*4) * mouse.x * 0.8;\n        const hgt = (1.4 + (wv+mInf)*1.7) * amp;\n        m.scale.y = Math.max(0.18, hgt);\n        m.position.y = 0.1;\n        \/\/ emissive crest glow\n        const crest = Math.max(0, (wv+0.4));\n        m.userData.mat.emissiveIntensity = 0.25 + crest*0.9*amp;\n      });\n\n      group.rotation.y = mouse.x*0.35;\n      group.rotation.x = -0.18 + mouse.y*0.12;\n      group.position.y = 0.1 + Math.sin(t*0.8)*0.12;\n\n      phones.rotation.y = -0.3 + Math.sin(t*0.7)*0.18;\n      phones.position.y = 2.6 + Math.sin(t*0.9+1)*0.22;\n\n      \/\/ particles drift up\n      const pos = pGeo.attributes.position.array;\n      for(let i=0;i<pCount;i++){\n        pos[i*3+1] += pSpeed[i]*dt*(STATE.reduce?0:1);\n        if(pos[i*3+1] > 6.5) pos[i*3+1] = -6.5;\n      }\n      pGeo.attributes.position.needsUpdate = true;\n      particles.rotation.y = t*0.02;\n\n      camera.position.x += (mouse.x*1.6 - camera.position.x)*0.04;\n      camera.lookAt(0,0.2,0);\n\n      renderer.render(scene, camera);\n    }\n\n    function renderStatic(){\n      \/\/ pretty static frame for reduced-motion\n      bars.forEach(m=>{\n        const {c,r} = m.userData;\n        const wv = Math.sin(c*0.55 + r*0.5)*0.5 + Math.sin(c*0.3)*0.4;\n        m.scale.y = Math.max(0.2, (1.4 + wv*1.5)*STATE.intensity);\n        m.userData.mat.emissiveIntensity = 0.3 + Math.max(0,wv)*0.5;\n      });\n      renderer.render(scene, camera);\n    }\n\n    resize();\n    window.addEventListener('resize', resize);\n\n    \/\/ pause when offscreen\n    const heroIO = new IntersectionObserver((e)=>{\n      const vis = e[0].isIntersecting;\n      if(vis && !STATE.reduce){ if(!running){ running=true; clock.start(); frame(); } }\n      else { running=false; if(raf) cancelAnimationFrame(raf); }\n    }, {threshold:0.02});\n    heroIO.observe(canvas);\n\n    \/\/ expose control for reduce-motion tweak\n    window.__hero3dSetReduce = (red)=>{\n      if(red){ running=false; if(raf) cancelAnimationFrame(raf); renderStatic(); }\n      else { if(!running){ running=true; clock.start(); frame(); } }\n    };\n\n    if(STATE.reduce){ renderStatic(); }\n    else { frame(); }\n\n    \/\/ dispose on unload to free GPU resources\n    window.addEventListener('pagehide', ()=>{\n      running=false; if(raf) cancelAnimationFrame(raf);\n      try{\n        barGeo.dispose(); bars.forEach(m=> m.userData.mat.dispose());\n        pGeo.dispose(); pMat.dispose(); bandMat.dispose();\n        renderer.dispose();\n      }catch(e){}\n    }, {once:true});\n  }\n\n  \/\/ lazy-init hero 3D when near viewport\n  const heroCanvas = $('#hero3d');\n  if(heroCanvas){\n    if('IntersectionObserver' in window){\n      const initIO = new IntersectionObserver((e,obs)=>{\n        if(e[0].isIntersecting){ initHero3D(); obs.disconnect(); }\n      }, {rootMargin:'200px'});\n      initIO.observe(heroCanvas);\n    } else { initHero3D(); }\n  }\n\n  \/* ============================================================\n     TWEAK PANEL\n     ============================================================ *\/\n  const gear = $('#gear'), panel = $('#tweakpanel'), tpClose = $('#tpClose');\n  gear.addEventListener('click', ()=> panel.classList.toggle('open'));\n  tpClose.addEventListener('click', ()=> panel.classList.remove('open'));\n  document.addEventListener('click', (e)=>{\n    if(panel.classList.contains('open') && !panel.contains(e.target) && e.target!==gear && !gear.contains(e.target)){\n      panel.classList.remove('open');\n    }\n  });\n\n  \/\/ accent swatches\n  const root = document.documentElement;\n  $$('#swatches.sw').forEach(sw=>{\n    sw.addEventListener('click', ()=>{\n      $$('#swatches.sw').forEach(s=> s.classList.remove('active'));\n      sw.classList.add('active');\n      const a = sw.dataset.a, b = sw.dataset.b;\n      root.style.setProperty('--accent-a', a);\n      root.style.setProperty('--accent-b', b);\n      root.style.setProperty('--teal', a);\n      root.style.setProperty('--cyan', b);\n      \/\/ glow shadow tint\n      const rgb = hexToRgb(a);\n      root.style.setProperty('--sh-glow', `0 8px 24px rgba(${rgb.r},${rgb.g},${rgb.b},.32)`);\n      if(window.__hero3dColors) window.__hero3dColors(a,b);\n    });\n  });\n  function hexToRgb(h){\n    h = h.replace('#',''); const n = parseInt(h,16);\n    return {r:(n>>16)&255, g:(n>>8)&255, b:n&255};\n  }\n\n  \/\/ animation speed\n  const spd = $('#spd'), spdVal = $('#spdVal');\n  spd.addEventListener('input', ()=>{\n    STATE.speed = parseFloat(spd.value);\n    spdVal.textContent = STATE.speed.toFixed(1)+'\u00d7';\n    root.style.setProperty('--anim-mult', STATE.speed || 0.001);\n  });\n\n  \/\/ intensity\n  const intensity = $('#intensity'), intVal = $('#intVal');\n  intensity.addEventListener('input', ()=>{\n    STATE.intensity = parseFloat(intensity.value);\n    intVal.textContent = Math.round(STATE.intensity*100)+'%';\n  });\n\n  \/\/ reduce motion toggle\n  const rmToggle = $('#rmToggle');\n  if(STATE.reduce) rmToggle.classList.add('on');\n  rmToggle.addEventListener('click', ()=>{\n    STATE.reduce = !STATE.reduce;\n    rmToggle.classList.toggle('on', STATE.reduce);\n    document.documentElement.classList.toggle('rm', STATE.reduce);\n    if(window.__hero3dSetReduce) window.__hero3dSetReduce(STATE.reduce);\n  });\n\n})();\n\n<\/script>\n\n","protected":false},"excerpt":{"rendered":"<p>All English 4U Grammar IELTS TOEFL Cambridge CELPIP Dictation Contact Start Free GrammarIELTSTOEFLCambridge CELPIP DictationContact English Dictation Practice Dictation Lessons Real-world topics, authentic listening passages. Hear it, understand it, write it. Build spelling accuracy and listening focus \u2014 B1, B2, and C1 levels. 21 Total Lessons 4 Available Now 3 CEFR Levels Fill-in-the-Blank Start B1 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-with-title","meta":{"footnotes":""},"class_list":["post-137","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/allenglish4u.com\/vi\/wp-json\/wp\/v2\/pages\/137","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/allenglish4u.com\/vi\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/allenglish4u.com\/vi\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/allenglish4u.com\/vi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/allenglish4u.com\/vi\/wp-json\/wp\/v2\/comments?post=137"}],"version-history":[{"count":23,"href":"https:\/\/allenglish4u.com\/vi\/wp-json\/wp\/v2\/pages\/137\/revisions"}],"predecessor-version":[{"id":5974,"href":"https:\/\/allenglish4u.com\/vi\/wp-json\/wp\/v2\/pages\/137\/revisions\/5974"}],"wp:attachment":[{"href":"https:\/\/allenglish4u.com\/vi\/wp-json\/wp\/v2\/media?parent=137"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}