1<!DOCTYPE html> 2<html lang="en"> 3<head> 4<meta charset="UTF-8" /> 5<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" /> 6<title data-i18n="meta.title">Lomia â Learn a language by living inside stories</title> 7<meta name="description" data-i18n-meta="meta.desc" content="Lomia turns anything you read into spoken story episodes â then listens as you say each line back, and brings the words you stumble on right back to you." /> 8<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> 9 10<link rel="preconnect" href="https://fonts.googleapis.com" /> 11<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 12<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin /> 13<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;0,9..144,600;0,9..144,700;1,9..144,500;1,9..144,600&family=Manrope:wght@300;400;500;600;700;800&family=Noto+Serif+SC:wght@400;600;700&family=Noto+Sans+SC:wght@300;400;500;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" /> 14<!-- éé¹ææ¥· (LXGW WenKai Screen) â warm kaiti for Chinese, per Sage1.0 --> 15<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lxgw-wenkai-screen-web/style.css" /> 16 17<style> 18/* ============================================================ 19 FABLE · bilingual landing â warm editorial Apple 20 ============================================================ */ 21:root{ 22 --paper:#f6f3ec; --paper-pure:#fffdf9; 23 --night:#0d0b09; --night-2:#16120e; 24 --ink:#15110c; --ink-soft:#3a342b; --mute:#6f6657; --faint:#a59a87; 25 --cream:#efe7d8; --cream-mute:#a79c89; 26 --ember:#df5a36; --ember-bright:#f06a44; --ember-soft:#f1a98e; --ember-glow:rgba(223,90,54,.16); 27 --line:rgba(21,17,12,.10); --line-strong:rgba(21,17,12,.18); --line-cream:rgba(239,231,216,.14); 28 --r-sm:14px; --r:22px; --r-lg:32px; --r-xl:42px; 29 --shadow-soft:0 2px 6px rgba(21,17,12,.04), 0 18px 50px -20px rgba(21,17,12,.18); 30 --shadow-lift:0 4px 12px rgba(21,17,12,.06), 0 40px 90px -30px rgba(21,17,12,.32); 31 --shadow-ember:0 18px 50px -16px rgba(223,90,54,.5); 32 --max:1180px; --ease:cubic-bezier(.22,1,.36,1); --ease-soft:cubic-bezier(.4,0,.2,1); 33 --font-display:"Fraunces", "Cormorant Garamond", Georgia, serif; 34 --font-sans:"Manrope", -apple-system, BlinkMacSystemFont, sans-serif; 35 --font-mono:"JetBrains Mono", ui-monospace, "SF Mono", monospace; 36 --tracking-display:-.02em; --tracking-h2:-.018em; --display-lh:1.05; --body-lh:1.6; 37 --display-wght:600; 38} 39/* ---- Chinese typographic overrides (éé¹ææ¥·, per Sage1.0) ---- */ 40html[lang="zh"]{ 41 --font-display:"LXGW WenKai Screen", "Noto Serif SC", "STKaiti", "Kaiti SC", serif; 42 --font-sans:"LXGW WenKai Screen", "Noto Sans SC", -apple-system, "PingFang SC", sans-serif; 43 --tracking-display:0em; --tracking-h2:0em; --display-lh:1.12; --body-lh:1.85; 44 --display-wght:700; 45} 46html[lang="zh"] .serif,html[lang="zh"] .serif-i,html[lang="zh"] em.acc{font-style:normal} 47html[lang="zh"] .lead{letter-spacing:0} 48html[lang="zh"] body{letter-spacing:0} 49html[lang="zh"] .display{font-size:clamp(2.3rem,5.6vw,5.4rem)} 50html[lang="zh"] .h2{font-size:clamp(1.85rem,4vw,3.5rem)} 51html[lang="zh"] .eyebrow,html[lang="zh"] .marquee-cap,html[lang="zh"] .foot-col h5,html[lang="zh"] .tag,html[lang="zh"] .cl{letter-spacing:.14em} 52 53*,*::before,*::after{box-sizing:border-box;margin:0;padding:0} 54html{scroll-behavior:smooth;-webkit-text-size-adjust:100%} 55@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}} 56body{font-family:var(--font-sans);background:var(--paper);color:var(--ink);line-height:var(--body-lh);font-weight:400;letter-spacing:-.01em;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow-x:hidden} 57.grain{position:fixed;inset:0;z-index:9999;pointer-events:none;opacity:.04;mix-blend-mode:multiply;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")} 58::selection{background:var(--ember);color:#fff} 59a{color:inherit;text-decoration:none} 60img{max-width:100%;display:block} 61.wrap{max-width:var(--max);margin-inline:auto;
61padding-inline:clamp(20px,5vw,40px)} 62 63/* Typography */ 64.eyebrow{font-family:var(--font-mono);font-size:.7rem;font-weight:500;letter-spacing:.32em;text-transform:uppercase;color:var(--ember);display:inline-flex;align-items:center;gap:.7em} 65.eyebrow::before{content:"";width:26px;height:1px;background:var(--ember);opacity:.6} 66.serif{font-family:var(--font-display);font-weight:400} 67.serif-i{font-family:var(--font-display);font-style:italic;font-weight:400} 68em.acc{font-family:var(--font-display);font-style:italic;font-weight:400;color:var(--ember)} 69h1,h2,h3{font-weight:var(--display-wght);letter-spacing:var(--tracking-h2);line-height:1.04} 70.display,.h2,.cta .big,.feat-copy h3{font-family:var(--font-display)} 71.display{font-size:clamp(2.5rem,6vw,5.5rem);line-height:var(--display-lh);letter-spacing:var(--tracking-display);font-weight:var(--display-wght)} 72.h2{font-size:clamp(2rem,4.3vw,3.8rem);letter-spacing:var(--tracking-h2);line-height:1.08} 73.lead{font-size:clamp(1.08rem,1.5vw,1.42rem);line-height:1.6;color:var(--mute);font-weight:400;max-width:42ch;letter-spacing:-.012em} 74 75/* Buttons */ 76.btn{display:inline-flex;align-items:center;gap:.55em;font-family:var(--font-sans);font-size:.98rem;font-weight:600;letter-spacing:-.01em;padding:.92em 1.6em;border-radius:999px;cursor:pointer;border:1px solid transparent;transition:transform .4s var(--ease),box-shadow .4s var(--ease),background .3s var(--ease-soft),color .3s var(--ease-soft);white-space:nowrap} 77.btn-primary{background:var(--ember);color:#fff;box-shadow:var(--shadow-ember)} 78.btn-primary:hover{background:var(--ember-bright);transform:translateY(-2px);box-shadow:0 24px 60px -16px rgba(223,90,54,.62)} 79.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line-strong)} 80.btn-ghost:hover{border-color:var(--ink);transform:translateY(-2px)} 81.btn-ghost .arr{transition:transform .4s var(--ease)} 82.btn-ghost:hover .arr{transform:translateY(3px)} 83.on-dark .btn-ghost{color:var(--cream);border-color:var(--line-cream)} 84.on-dark .btn-ghost:hover{border-color:var(--cream)} 85 86/* Lang toggle */ 87.lang-toggle{display:inline-flex;border:1px solid var(--line-strong);border-radius:999px;padding:3px;gap:2px;flex:none} 88.lang-toggle button{font-family:var(--font-mono);font-size:.74rem;font-weight:500;border:none;background:none;color:var(--mute);padding:.34em .72em;border-radius:999px;cursor:pointer;transition:background .25s,color .25s;letter-spacing:.04em} 89.lang-toggle button.active{background:var(--ink);color:var(--paper)} 90 91/* Nav */ 92.nav{position:fixed;top:0;left:0;right:0;z-index:100;transition:background .4s var(--ease-soft),backdrop-filter .4s,border-color .4s,padding .4s var(--ease);border-bottom:1px solid transparent} 93.nav-inner{max-width:var(--max);margin-inline:auto;padding:20px clamp(20px,5vw,40px);display:flex;align-items:center;justify-content:space-between;gap:24px} 94.nav.scrolled{background:rgba(246,243,236,.72);backdrop-filter:saturate(180%) blur(20px);-webkit-backdrop-filter:saturate(180%) blur(20px);border-color:var(--line)} 95.nav.scrolled .nav-inner{padding-block:13px} 96.brand{display:flex;align-items:center;gap:.6em;font-size:1.5rem} 97.brand .mark{width:30px;height:30px;flex:none} 98.brand b{font-family:"Fraunces","Cormorant Garamond",serif;font-weight:600;font-size:1.72rem;letter-spacing:.005em} 99.nav-links{display:flex;align-items:center;gap:32px} 100.nav-links a.lnk{font-size:.92rem;font-weight:500;color:var(--ink-soft);transition:color .25s} 101.nav-links a.lnk:hover{color:var(--ember)} 102.nav-cta{display:flex;align-items:center;gap:12px} 103@media (max-width:880px){.nav-links .lnk{display:none}} 104 105/* Hero */ 106.hero{position:relative;padding:clamp(140px,18vh,210px) 0 clamp(60px,8vh,110px);overflow:hidden} 107.hero-bg{position:absolute;inset:0;z-index:0;pointer-events:none} 108.hero-bg::before{content:"";position:absolute;inset:-10%;background:radial-gradient(60% 50% at 78% 8%,var(--ember-glow),transparent 60%),radial-gradient(50% 45% at 12% 30%,rgba(223,142,54,.10),transparent 60%)} 109.hero-grid{position:relative;z-index:1;display:grid;grid-template-columns:1.06fr .94fr;gap:clamp(30px,5vw,72px);align-items:center} 110.hero-copy{max-width:660px} 111.hero h1{margin:.32em 0 .5em} 112.hero h1 .l1{display:block;color:var(--ink)} 113.hero h1 .l2{display:block;color:var(--ember)} 114.hero .lead{max-width:42ch;margin-bottom:2.1em} 115.hero-cta{display:flex;align-items:center;gap:16px;flex-wrap:wrap} 116.hero-note{margin-top:1.5em;font-size:.84rem;color:var(--faint);display:flex;align-items:center;gap:.6em} 117.hero-note .dot{width:6px;height:6px;border-radius:50%;background:#3aa06a;box-shadow:0 0 0 4px rgba(58,160,106,.16);flex:none} 118.rise{opacity:0;transform:translateY(22px)} 119.js .hero .rise{animation:rise 1s var(--ease) forwards}
120.js .hero .rise.d1{animation-delay:.05s}.js .hero .rise.d2{animation-delay:.16s}.js .hero .rise.d3{animation-delay:.27s}.js .hero .rise.d4{animation-delay:.38s}.js .hero .rise.d5{animation-delay:.5s} 121@keyframes rise{to{opacity:1;transform:none}} 122 123/* Device mockup */ 124.device{position:relative;z-index:1;justify-self:center;width:min(360px,86vw);background:linear-gradient(180deg,#fffefb,#f3eee3);border:1px solid var(--line);border-radius:var(--r-xl);padding:18px;box-shadow:var(--shadow-lift);will-change:transform} 125.js .device{animation:float 7s ease-in-out infinite} 126@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-14px)}} 127.dev-top{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 16px} 128.dev-top .scene{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.12em;text-transform:uppercase;color:var(--faint)} 129.score-ring{--v:92;width:46px;height:46px;border-radius:50%;display:grid;place-items:center;background:conic-gradient(var(--ember) calc(var(--v)*1%),rgba(21,17,12,.08) 0);position:relative} 130.score-ring::before{content:"";position:absolute;inset:5px;border-radius:50%;background:#fffefb} 131.score-ring b{position:relative;font-family:var(--font-mono);font-size:.92rem;font-weight:500;color:var(--ink)} 132.bubble{background:#fff;border:1px solid var(--line);border-radius:18px 18px 18px 6px;padding:12px 15px;font-size:.86rem;color:var(--mute);margin-bottom:12px;max-width:84%;font-family:"Manrope",sans-serif} 133.line-card{background:#fff;border:1px solid var(--line-strong);border-radius:18px;padding:16px 16px 14px;box-shadow:0 10px 30px -18px rgba(21,17,12,.4)} 134.line-card .who{font-family:var(--font-mono);font-size:.6rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ember);margin-bottom:9px} 135.line-card .txt{font-family:"Manrope",sans-serif;font-size:1.06rem;line-height:1.45;letter-spacing:-.02em;color:var(--ink);font-weight:500} 136.line-card .txt .w-now{color:var(--ember)} 137.line-card .txt .w-miss{color:var(--faint);text-decoration:underline wavy var(--ember-soft) 1.5px;text-underline-offset:4px} 138.wave{display:flex;align-items:center;gap:3px;height:34px;margin:15px 2px 13px} 139.wave i{flex:1;background:linear-gradient(180deg,var(--ember-soft),var(--ember));border-radius:3px;height:30%;opacity:.85} 140.js .wave i{animation:wv 1.4s var(--ease-soft) infinite} 141@keyframes wv{0%,100%{height:22%}50%{height:90%}} 142.metrics{display:grid;grid-template-columns:1fr 1fr;gap:9px 16px;margin:4px 2px 14px} 143.metric .ml{display:flex;justify-content:space-between;font-size:.66rem;color:var(--mute);margin-bottom:5px} 144.metric .ml b{font-family:var(--font-mono);font-weight:500;color:var(--ink)} 145.metric .bar{height:4px;border-radius:3px;background:rgba(21,17,12,.08);overflow:hidden} 146.metric .bar span{display:block;height:100%;border-radius:3px;background:var(--ember)} 147.metric.jade .bar span{background:#3aa06a} 148.dev-actions{display:flex;align-items:center;justify-content:center;gap:14px;padding:6px 0 4px} 149.rec{width:58px;height:58px;border-radius:50%;background:var(--ember);border:none;cursor:pointer;display:grid;place-items:center;box-shadow:0 12px 30px -8px rgba(223,90,54,.6);position:relative} 150.rec::after{content:"";position:absolute;inset:-7px;border-radius:50%;border:2px solid var(--ember);opacity:.4} 151.js .rec::after{animation:pulse 2.2s ease-out infinite} 152@keyframes pulse{0%{transform:scale(.9);opacity:.5}100%{transform:scale(1.5);opacity:0}} 153.rec span{width:18px;height:18px;border-radius:5px;background:#fff} 154.ghost-btn{width:46px;height:46px;border-radius:50%;border:1px solid var(--line-strong);background:#fff;display:grid;place-items:center;color:var(--ink-soft)} 155 156/* Marquee */ 157.marquee{border-block:1px solid var(--line);padding:34px 0;overflow:hidden;background:var(--paper-pure)} 158.marquee .row{display:flex;gap:60px;width:max-content;align-items:center} 159.js .marquee .row{animation:slide 40s linear infinite} 160.marquee:hover .row{animation-play-state:paused} 161@keyframes slide{to{transform:translateX(-50%)}} 162.marquee .lbl{font-family:var(--font-display);font-size:clamp(1.4rem,3vw,2.3rem);color:var(--faint);white-space:nowrap} 163.marquee .lbl em{font-style:italic;color:var(--ink-soft)} 164html[lang="zh"] .marquee .lbl em{font-style:normal;color:var(--ember)} 165.marquee .sep{width:7px;height:7px;border-radius:50%;background:var(--ember-soft);flex:none} 166.marquee-cap{text-align:center;font-family:var(--font-mono);font-size:.7rem;letter-spacing:.28em;text-transform:uppercase;color:var(--faint);padding-bottom:26px} 167 168/* Sections */ 169section{position:relative} 170.sec{padding:clamp(80px,12vh,150px) 0} 171.sec-head{max-width:820px;margin-bottom:clamp(48px,7vh,86px)} 172.sec-head .h2{margin:.35em 0 .4em} 173.sec-head p{font-size:clamp(1.05rem,1.4vw,1.3rem);color:var(--mute);max-width:56ch;line-height:1.55} 174.dark{background:radial-gradient(120% 80% at 50% -10%,var(--night-2),var(--night));color:var(--cream)} 175.dark .h2,.dark .display{color:var(--cream)} 176.dark .sec-head p,.dark .lead{color:var(--cream-mute)} 177.dark .eyebrow{color:var(--ember-soft)}.dark .eyebrow::before{background:var(--ember-soft)} 178 179/* Who-it's-for */ 180.who{text-align:center;background:var(--paper-pure)}
180 181.who .wrap{max-width:900px} 182.who .eyebrow{justify-content:center} 183.who .h2{margin:.4em 0 .55em;font-size:clamp(2.3rem,6vw,5rem)} 184.who p{font-size:clamp(1.1rem,1.6vw,1.45rem);color:var(--mute);max-width:50ch;margin-inline:auto;line-height:1.6} 185.who .rule{width:1px;height:60px;background:linear-gradient(var(--ember),transparent);margin:0 auto clamp(36px,5vh,60px)} 186 187/* Steps */ 188.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(20px,3vw,40px)} 189.step{padding-top:30px;border-top:1px solid var(--line)} 190.dark .step{border-color:var(--line-cream)} 191.step .no{font-family:var(--font-display);font-style:italic;font-size:2.6rem;color:var(--ember);line-height:1;margin-bottom:.4em} 192html[lang="zh"] .step .no{font-style:normal} 193.step h3{font-size:1.5rem;letter-spacing:-.025em;margin-bottom:.5em;font-weight:600} 194.step p{color:var(--mute);font-size:1rem;line-height:1.65;max-width:36ch} 195.dark .step p{color:var(--cream-mute)} 196 197/* Science cards */ 198.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:18px} 199.card{background:var(--paper-pure);border:1px solid var(--line);border-radius:var(--r-lg);padding:34px 30px 36px;transition:transform .5s var(--ease),box-shadow .5s var(--ease),border-color .5s} 200.dark .card{background:rgba(239,231,216,.035);border-color:var(--line-cream)} 201.card:hover{transform:translateY(-6px);box-shadow:var(--shadow-soft);border-color:var(--line-strong)} 202.card .ic{width:46px;height:46px;border-radius:13px;display:grid;place-items:center;background:var(--ember-glow);color:var(--ember);margin-bottom:22px} 203.card h3{font-size:1.32rem;letter-spacing:-.025em;margin-bottom:.5em;font-weight:600} 204.card p{color:var(--mute);font-size:.97rem;line-height:1.62} 205.dark .card p{color:var(--cream-mute)} 206.card .tag{margin-top:18px;font-family:var(--font-mono);font-size:.66rem;letter-spacing:.16em;text-transform:uppercase;color:var(--faint)} 207 208/* Feature rows */ 209.feat{display:grid;grid-template-columns:1fr 1fr;gap:clamp(36px,6vw,96px);align-items:center;padding:clamp(50px,8vh,96px) 0} 210.feat:nth-child(even) .feat-media{order:-1} 211.feat-copy h3{font-size:clamp(1.7rem,3vw,2.7rem);letter-spacing:-.035em;line-height:1.05;margin-bottom:.5em} 212html[lang="zh"] .feat-copy h3{letter-spacing:-.01em;line-height:1.2} 213.feat-copy p{color:var(--mute);font-size:1.08rem;line-height:1.65;max-width:42ch} 214.feat-media{aspect-ratio:4/3;border-radius:var(--r-lg);border:1px solid var(--line);overflow:hidden;position:relative;box-shadow:var(--shadow-soft);background:var(--paper-pure)} 215.viz{position:absolute;inset:0;display:grid;place-items:center;padding:30px} 216.viz-1{background:linear-gradient(135deg,#fffdf9,#efe7d8)} 217.paper-chip{background:#fff;border:1px solid var(--line);border-radius:14px;padding:18px 20px;box-shadow:var(--shadow-soft);transform:rotate(-3deg);font-size:.82rem;color:var(--mute);max-width:78%} 218.paper-chip .arrow{display:block;text-align:center;color:var(--ember);font-size:1.4rem;margin:10px 0} 219.scene-chip{background:#fff;border:1px solid var(--line-strong);border-radius:14px;padding:14px 16px;box-shadow:var(--shadow-lift);transform:rotate(2deg);margin-top:-44px;margin-left:30%} 220.scene-chip .who{font-family:var(--font-mono);font-size:.56rem;letter-spacing:.16em;text-transform:uppercase;color:var(--ember)} 221.scene-chip .t{font-size:.92rem;color:var(--ink);font-weight:500;margin-top:4px} 222.viz-2{background:radial-gradient(100% 100% at 30% 20%,#16120e,#0d0b09)} 223.queue{display:flex;flex-direction:column;gap:11px;width:78%} 224.q-row{display:flex;align-items:center;gap:12px;background:rgba(239,231,216,.05);border:1px solid var(--line-cream);border-radius:12px;padding:11px 14px} 225.q-row .d{width:8px;height:8px;border-radius:50%;background:var(--ember);flex:none} 226.q-row .d.s{background:#3aa06a} 227.q-row .tx{font-size:.8rem;color:var(--cream);flex:1;font-family:"Manrope",sans-serif} 228.q-row .due{font-family:var(--font-mono);font-size:.64rem;color:var(--cream-mute);white-space:nowrap} 229.viz-3{background:linear-gradient(135deg,#fffdf9,#f1e9da)} 230.compare-bars{display:flex;gap:18px;align-items:flex-end;width:80%;justify-content:center} 231.compare-bars .col{flex:1;text-align:center} 232.compare-bars .stack{height:120px;
232display:flex;align-items:flex-end;gap:4px;justify-content:center} 233.compare-bars .stack i{width:6px;border-radius:3px;background:var(--ember-soft)} 234.compare-bars .col.now .stack i{background:var(--ember)} 235.compare-bars .cl{font-family:var(--font-mono);font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;color:var(--mute);margin-top:10px} 236 237/* Comparison */ 238.compare-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;align-items:stretch} 239.cmp{background:var(--paper-pure);border:1px solid var(--line);border-radius:var(--r-lg);padding:32px 28px 34px;display:flex;flex-direction:column} 240.cmp.featured{border-color:var(--ember);box-shadow:var(--shadow-ember);position:relative} 241.cmp.featured::before{content:attr(data-badge);position:absolute;top:-12px;left:28px;background:var(--ember);color:#fff;font-family:var(--font-mono);font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;padding:5px 11px;border-radius:999px} 242.cmp h4{font-size:1.18rem;font-weight:700;letter-spacing:-.02em;margin-bottom:1.2em;color:var(--ink-soft)} 243.cmp.featured h4{color:var(--ember)} 244.cmp ul{list-style:none;display:flex;flex-direction:column;gap:16px;flex:1} 245.cmp li{display:flex;gap:11px;font-size:.95rem;line-height:1.5;color:var(--mute)} 246.cmp li .ck{flex:none;width:18px;height:18px;margin-top:2px;color:var(--faint)} 247.cmp.featured li{color:var(--ink-soft)} 248.cmp.featured li .ck{color:var(--ember)} 249.cmp li .lab{display:block;font-family:var(--font-mono);font-size:.58rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);margin-bottom:3px} 250html[lang="zh"] .cmp li .lab{letter-spacing:.1em} 251 252/* Pull quote */ 253.quote{text-align:center;background:var(--paper)} 254.quote .wrap{max-width:1000px} 255.quote blockquote{font-family:var(--font-display);font-style:italic;font-size:clamp(1.9rem,4.6vw,3.6rem);line-height:1.22;letter-spacing:-.02em;color:var(--ink)} 256html[lang="zh"] .quote blockquote{font-style:normal;line-height:1.4;letter-spacing:0} 257.quote blockquote em{color:var(--ember);font-style:italic} 258html[lang="zh"] .quote blockquote em{font-style:normal} 259.quote .qmark{font-family:var(--font-display);font-size:5rem;color:var(--ember-soft);line-height:.5;margin-bottom:.2em;display:block} 260.quote .attr{margin-top:1.6em;font-family:var(--font-mono);font-size:.74rem;letter-spacing:.2em;text-transform:uppercase;color:var(--faint)} 261 262/* Stats */ 263.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:24px} 264.stat{padding:26px 0;border-top:1px solid var(--line-cream)} 265.stat .n{font-family:var(--font-display);font-size:clamp(2.6rem,5vw,4rem);line-height:1;color:var(--cream);letter-spacing:-.02em} 266.stat .n em{font-style:italic;color:var(--ember-soft)} 267.stat .l{margin-top:.6em;font-size:.9rem;color:var(--cream-mute);max-width:26ch;line-height:1.5} 268 269/* FAQ */ 270.faq-list{max-width:820px;border-top:1px solid var(--line)} 271.faq-item{border-bottom:1px solid var(--line)} 272.faq-q{width:100%;background:none;border:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:26px 4px;text-align:left;font-family:var(--font-sans);font-size:clamp(1.05rem,1.6vw,1.3rem);font-weight:600;color:var(--ink);letter-spacing:-.02em} 273html[lang="zh"] .faq-q{letter-spacing:0} 274.faq-q .pm{flex:none;width:24px;height:24px;position:relative;transition:transform .4s var(--ease)} 275.faq-q .pm::before,.faq-q .pm::after{content:"";position:absolute;background:var(--ember);border-radius:2px;top:50%;left:50%;transform:translate(-50%,-50%)} 276.faq-q .pm::before{width:15px;height:2px} 277.faq-q .pm::after{width:2px;height:15px;transition:transform .4s var(--ease)} 278.faq-item.open .pm{transform:rotate(180deg)} 279.faq-item.open .pm::after{transform:translate(-50%,-50%) scaleY(0)} 280.faq-a{display:grid;grid-template-rows:0fr;transition:grid-template-rows .5s var(--ease)} 281.faq-item.open .faq-a{grid-template-rows:1fr} 282.faq-a>div{overflow:hidden} 283.faq-a p{padding:0 4px 28px;max-width:62ch;color:var(--mute);font-size:1.02rem;line-height:1.65} 284 285/* CTA */ 286.cta{padding:clamp(110px,18vh,200px) 0;text-align:center;position:relative;overflow:hidden} 287.cta-bg{position:absolute;inset:0;background:radial-gradient(60% 70% at 50% 30%,var(--ember-glow),transparent 70%);z-index:0} 288.cta .inner{position:relative;z-index:1} 289.cta .big{font-size:clamp(2.2rem,5vw,4.6rem);letter-spacing:-.025em;line-height:1.08;margin-bottom:.5em} 290html[lang="zh"] .cta .big{letter-spacing:-.01em;line-height:1.12} 291.cta .big em{font-family:var(--font-display);font-style:italic;font-weight:400;color:var(--ember)} 292html[lang="zh"] .cta .big em{font-style:normal} 293.cta .lead{margin:0 auto 2em;text-align:center;max-width:46ch} 294.cta .hero-cta{justify-content:center} 295 296/* Footer */ 297footer{background:var(--night);color:var(--cream-mute);padding:70px 0 50px;border-top:1px solid var(--line-cream)} 298.foot{display:flex;justify-content:space-between;gap:40px;flex-wrap:wrap;align-items:flex-start} 299.foot .brand{color:var(--cream);font-size:1.3rem} 300.foot p.tg{max-width:32ch;font-size:.92rem;margin-top:1em;line-height:1.6} 301.foot-cols{display:flex;gap:64px;flex-wrap:wrap} 302.foot-col h5{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:var(--faint);margin-bottom:1.1em} 303.foot-col a{display:block;font-size:.92rem;margin-bottom:.7em;color:var(--cream-mute);transition:color .2s} 304.foot-col a:hover{color:var(--ember-soft)} 305.foot-base{margin-top:54px;padding-top:26px;border-top:1px solid var(--line-cream);display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;font-size:.8rem;color:var(--faint)} 306 307/* Reveal */ 308.reveal{opacity:0;transform:translateY(28px);transition:opacity 1s var(--ease),transform 1s var(--ease)} 309.reveal.in{opacity:1;transform:none}
310.reveal.d1{transition-delay:.08s}.reveal.d2{transition-delay:.16s}.reveal.d3{transition-delay:.24s} 311html:not(.js) .reveal{opacity:1;transform:none} 312@media (prefers-reduced-motion:reduce){ 313 .reveal{opacity:1!important;transform:none!important;transition:none} 314 .js .hero .rise{animation:none;opacity:1;transform:none} 315 .js .device,.js .wave i,.js .rec::after,.js .marquee .row{animation:none} 316} 317 318/* Responsive */ 319@media (max-width:900px){ 320 .hero-grid{grid-template-columns:1fr;text-align:center} 321 .hero-copy{max-width:none;margin-inline:auto} 322 .hero .lead{margin-inline:auto} 323 .hero-cta,.hero-note{justify-content:center} 324 .device{margin-top:50px} 325 .steps,.cards,.stats,.compare-grid{grid-template-columns:1fr} 326 .feat{grid-template-columns:1fr;gap:32px} 327 .feat:nth-child(even) .feat-media{order:0} 328 .stats{gap:0} 329} 330@media (max-width:560px){ 331 .nav-cta .btn-ghost{display:none} 332 .marquee .lbl{font-size:1.5rem} 333 .lang-toggle button{padding:.3em .6em} 334} 335 336/* ============================================================ 337 Added motion layer 338 ============================================================ */ 339.scroll-progress{position:fixed;top:0;left:0;height:2px;width:0;background:linear-gradient(90deg,var(--ember),var(--ember-bright));z-index:200;transition:width .1s linear;pointer-events:none} 340.nav-links a.lnk{position:relative} 341.nav-links a.lnk::after{content:"";position:absolute;left:0;right:0;bottom:-5px;height:1.5px;background:var(--ember);transform:scaleX(0);transform-origin:left;transition:transform .35s var(--ease)} 342.nav-links a.lnk:hover::after{transform:scaleX(1)} 343.btn-primary{will-change:transform} 344.card{position:relative;overflow:hidden} 345.card::after{content:"";position:absolute;inset:0;border-radius:inherit;background:radial-gradient(240px circle at var(--mx,50%) var(--my,50%),var(--ember-glow),transparent 62%);opacity:0;transition:opacity .45s var(--ease);pointer-events:none} 346.card:hover::after{opacity:1} 347.cta-bg{background:radial-gradient(42% 52% at 28% 32%,var(--ember-glow),transparent 70%),radial-gradient(40% 50% at 72% 62%,rgba(223,142,54,.13),transparent 70%)} 348@media (prefers-reduced-motion:no-preference){.cta-bg{animation:mesh 18s ease-in-out infinite alternate}} 349@keyframes mesh{0%{background-position:0% 0%,100% 100%}100%{background-position:34% 22%,66% 78%}} 350.hero-bg{will-change:transform} 351 352/* ============================================================ 353 Auth modal (Supabase) + checkout (Dodo) 354 ============================================================ */ 355.auth-overlay{position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(13,11,9,.5);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);opacity:0;transition:opacity .35s var(--ease)} 356.auth-overlay.open{opacity:1} 357.auth-overlay[hidden]{display:none} 358.auth-card{width:min(420px,100%);background:var(--paper-pure);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-lift);padding:clamp(26px,4vw,40px);position:relative;transform:translateY(12px) scale(.98);transition:transform .4s var(--ease)} 359.auth-overlay.open .auth-card{transform:none} 360.auth-close{position:absolute;top:14px;right:16px;width:34px;height:34px;border:none;background:none;font-size:1.5rem;line-height:1;color:var(--mute);cursor:pointer;border-radius:50%;transition:background .2s,color .2s} 361.auth-close:hover{background:var(--paper);color:var(--ink)} 362.auth-brand{font-family:var(--font-display);font-weight:600;font-size:1.5rem;color:var(--ink);margin-bottom:4px} 363.auth-tabs{display:flex;gap:4px;background:var(--paper);border-radius:999px;padding:4px;margin:18px 0 22px} 364.auth-tabs button{flex:1;border:none;background:none;font-family:var(--font-sans);font-size:.9rem;font-weight:600;color:var(--mute);padding:.6em;border-radius:999px;cursor:pointer;transition:background .25s,color .25s} 365.auth-tabs button.active{background:var(--ink);color:var(--paper)} 366.auth-field{margin-bottom:14px} 367.auth-field label{display:block;font-family:var(--font-mono);font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);margin-bottom:7px} 368.auth-field input{width:100%;font-family:var(--font-sans);font-size:1rem;color:var(--ink);background:var(--paper);border:1px solid var(--line-strong);border-radius:12px;padding:.85em 1em;transition:border-color .25s,box-shadow .25s} 369.auth-field input:focus{outline:none;border-color:var(--ember);box-shadow:0 0 0 3px var(--ember-glow)} 370.auth-card .btn{width:100%;justify-content:center;margin-top:6px} 371.auth-msg{font-size:.86rem;line-height:1.5;margin-top:14px;min-height:1.2em;color:var(--mute)} 372.auth-msg.error{color:var(--ember)} 373.auth-msg.ok{color:#3a8a5e} 374.auth-foot{margin-top:16px;font-size:.78rem;color:var(--faint);text-align:center;line-height:1.5} 375.auth-acct .auth-email{font-family:var(--font-mono);font-size:.9rem;color:var(--ink);background:var(--paper);border-radius:10px;padding:.7em 1em;margin:14px 0 18px;word-break:break-all} 376.auth-acct .sub-note{font-size:.82rem;color:var(--mute);margin:14px 0 0;line-height:1.55} 377</style> 378</head> 379<body> 380<div class="grain" aria-hidden="true"></div> 381<div class="scroll-progress" id="sprog" aria-hidden="true"></div> 382 383<!-- NAV --> 384<nav class="nav" id="nav"> 385 <div class="nav-inner"> 386 <a class="brand" href="#top" data-i18n-aria="nav.brandAria" aria-label="Lomia home"> 387 <svg class="mark" viewBox="0 0 32 32" fill="none" aria-hidden="true"> 388 <path d="M6 25V8.5C6 7 7 6 8.5 6H22c2 0 3.5 1.6 3.5 3.6 0 1.9-1.4 3.4-3.3 3.4" stroke="#df5a36" stroke-width="2.1" stroke-linecap="round"/> 389 <path d="M6 16h13.5c2.2 0 3.9 1.6 3.9 3.7 0 2.1-1.7 3.8-3.9 3.8H9.5" stroke="#df5a36" stroke-width="2.1" stroke-linecap="round"/> 390 <circle cx="24.5" cy="25" r="2.4" fill="#df5a36"/> 391 </svg> 392 <b>Lomia</b> 393 </a> 394 <div class="nav-links"> 395 <a class="lnk" href="#how" data-i18n="nav.how">How it works</a> 396 <a class="lnk" href="#science" data-i18n="nav.why">Why it works</a> 397 <a class="lnk" href="#compare" data-i18n="nav.features">Features</a> 398 <a class="lnk" href="#faq" data-i18n="nav.faq">FAQ</a> 399 </div> 400 <div class="nav-cta"> 401 <div class="lang-toggle" role="group" aria-label="Language"> 402 <button type="button" data-lang="en">EN</button> 403 <button type="button" data-lang="zh">ä¸</button> 404 </div> 405 <a class="btn btn-ghost" href="#cta" data-i18n="nav.signin">Sign in</a> 406 <a class="btn btn-primary" href="#cta" data-i18n="nav.start">Start free</a> 407 </div> 408 </div> 409</nav> 410 411<!-- HERO --> 412<header class="hero" id="top">
413 <div class="hero-bg"></div> 414 <div class="wrap hero-grid"> 415 <div class="hero-copy"> 416 <div class="hero-yan rise d1" id="yanHero" aria-hidden="true" style="width:62px;margin:0 0 18px"></div> 417 <span class="eyebrow rise d1" data-i18n="hero.eyebrow">Language, out loud</span> 418 <h1 class="display rise d2" data-i18n="hero.h1"><span class="l1">Don't just read</span><span class="l1">a language.</span><span class="l2"><em class="acc">Live it out loud.</em></span></h1> 419 <p class="lead rise d3" data-i18n="hero.lead">Lomia turns anything you read into spoken story episodes â then listens as you say each line back, and brings the words you stumble on right back to you.</p> 420 <div class="hero-cta rise d4"> 421 <a class="btn btn-primary" href="#cta" data-i18n="hero.cta1">Start with a story</a> 422 <a class="btn btn-ghost" href="#how" data-i18n="hero.cta2">See how it works <span class="arr">â</span></a> 423 </div> 424 <div class="hero-note rise d5"><span class="dot"></span> <span data-i18n="hero.note">No account needed to try · Works with any text you bring</span></div> 425 </div> 426 427 <div class="device rise d4" id="device" aria-hidden="true"> 428 <div class="dev-top"> 429 <span class="scene" data-i18n="device.scene">Aesop · Tortoise & Hare · 3</span> 430 <div class="score-ring" style="--v:92"><b>92</b></div> 431 </div> 432 <div class="bubble">âSlow and steady â is that really how you win?â</div> 433 <div class="line-card"> 434 <div class="who" data-i18n="device.you">You · say it back</div> 435 <div class="txt">The tortoise <span class="w-now">plodded</span> on, slow <span class="w-miss">and</span> steady.</div> 436 <div class="wave"> 437 <i style="animation-delay:0s"></i>
437<i style="animation-delay:.08s"></i><i style="animation-delay:.16s"></i><i style="animation-delay:.24s"></i><i style="animation-delay:.32s"></i><i style="animation-delay:.4s"></i><i style="animation-delay:.48s"></i><i style="animation-delay:.56s"></i><i style="animation-delay:.64s"></i><i style="animation-delay:.72s"></i><i style="animation-delay:.6s"></i><i style="animation-delay:.5s"></i><i style="animation-delay:.4s"></i><i style="animation-delay:.3s"></i><i style="animation-delay:.2s"></i> 438 </div> 439 <div class="metrics"> 440 <div class="metric"><div class="ml"><span data-i18n="metric.accuracy">Accuracy</span><b>96</b></div><div class="bar"><span style="width:96%"></span></div></div> 441 <div class="metric jade"><div class="ml"><span data-i18n="metric.fluency">Fluency</span><b>90</b></div><div class="bar"><span style="width:90%"></span></div></div> 442 <div class="metric"><div class="ml"><span data-i18n="metric.completeness">Completeness</span><b>88</b></div><div class="bar"><span style="width:88%"></span></div></div> 443 <div class="metric jade"><div class="ml"><span data-i18n="metric.prosody">Prosody</span><b>94</b></div><div class="bar"><span style="width:94%"></span></div></div> 444 </div> 445 </div> 446 <div class="dev-actions"> 447 <div class="ghost-btn">âº</div> 448 <button class="rec" data-i18n-aria="device.recAria" aria-label="Record"><span></span></button> 449 <div class="ghost-btn">â¶</div> 450 </div> 451 </div> 452 </div> 453</header> 454 455<!-- MARQUEE --> 456<div class="marquee"> 457 <div class="marquee-cap" data-i18n="marquee.cap">Bring anything you actually read</div> 458 <div class="row" id="marquee-row" aria-hidden="true"></div> 459</div> 460 461<!-- WHO --> 462<section class="sec who"> 463 <div class="wrap"> 464 <div class="rule reveal" aria-hidden="true"></div> 465 <span class="eyebrow reveal" data-i18n="who.eyebrow">Sound familiar?</span> 466 <h2 class="h2 reveal d1" data-i18n="who.h2">You can read it.<br>You just can't <em class="acc">say</em> it.</h2> 467 <p class="reveal d2" data-i18n="who.p">You've passed the exams. You understand the films. But the moment you need to speak, the words don't come. Lomia is built for exactly that gap â between knowing a language and living inside it.</p> 468 </div> 469</section> 470 471<!-- HOW --> 472<section class="sec" id="how" style="background:var(--paper)"> 473 <div class="wrap"> 474 <div class="sec-head reveal"> 475 <span class="eyebrow" data-i18n="how.eyebrow">How it works</span> 476 <h2 class="h2" data-i18n="how.h2">Three steps from<br>a page to your voice.</h2> 477 <p data-i18n="how.p">No decks of flashcards. No grammar drills. Just the loop that actually builds spoken language â listen, say it back, and hear what to fix.</p> 478 </div> 479 <div class="steps"> 480 <div class="step reveal d1"><div class="no">01</div><h3 data-i18n="how.s1t">Paste anything</h3><p data-i18n="how.s1p">An article, a chapter, a transcript, or a fable. The language you actually want to speak â not a textbook's idea of it.</p></div> 481 <div class="step reveal d2"><div class="no">02</div><h3 data-i18n="how.s2t">It becomes a story</h3><p data-i18n="how.s2p">Lomia rewrites it into short, two-voice scenes pitched at your level â natural lines worth saying out loud.</p></div> 482 <div class="step reveal d3"><div class="no">03</div><h3 data-i18n="how.s3t">Shadow it</h3><p data-i18n="how.s3p">Speak each line over a native voice. Hear yourself instantly, and see exactly which words and rhythms to chase.</p></div> 483 </div> 484 </div> 485</section> 486 487<!-- DIAGNOSIS (dark) --> 488<section class="sec dark on-dark"> 489 <div class="wrap"> 490 <div class="sec-head reveal" style="margin-inline:auto;text-align:center"> 491 <span class="eyebrow" style="justify-content:center" data-i18n="diag.eyebrow">Your voice, measured</span> 492 <h2 class="h2" data-i18n="diag.h2">Not a grade. A diagnosis.</h2> 493 <p style="margin-inline:auto" data-i18n="diag.p">Every take is broken into the things that actually make you understood â so a low score always comes with a reason, and a way to fix it.</p> 494 </div> 495 <div class="cards"> 496 <div class="card reveal d1"> 497 <div class="ic"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M12 3v18M7 8v8M17 7v10M3 11v2M21 10v4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg></div> 498 <h3 data-i18n="diag.c1t">Words & sounds</h3> 499 <p data-i18n="diag.c1p">Edit-distance alignment matches what you said to the line â so one extra word never red-marks the rest. The sounds Mandarin speakers find hardest get singled out, gently.</p> 500 <div class="tag" data-i18n="diag.c1tag">Accuracy · Completeness</div> 501 </div> 502 <div class="card reveal d2"> 503 <div class="ic"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M4 18c3-8 5-12 8-12s5 4 8 12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
503<path d="M3 21h18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg></div> 504 <h3 data-i18n="diag.c2t">Rhythm & melody</h3> 505 <p data-i18n="diag.c2p">Lomia scores your pace, pauses and pitch against the original. Because being understood is mostly prosody â the music of a sentence â not perfect phonemes.</p> 506 <div class="tag" data-i18n="diag.c2tag">Fluency · Prosody</div> 507 </div> 508 <div class="card reveal d3"> 509 <div class="ic"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M21 12a9 9 0 1 1-3-6.7" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M21 4v5h-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div> 510 <h3 data-i18n="diag.c3t">The words come back</h3> 511 <p data-i18n="diag.c3p">Every line you stumble on becomes a memory the app tracks â and resurfaces right before you'd forget it, on a schedule tuned to your own curve.</p> 512 <div class="tag" data-i18n="diag.c3tag">Spaced review</div> 513 </div> 514 </div> 515 </div> 516</section> 517 518<!-- SCIENCE / FEATURES --> 519<section class="sec" id="science" style="background:var(--paper)"> 520 <div class="wrap"> 521 <div class="sec-head reveal"> 522 <span class="eyebrow" data-i18n="ev.eyebrow">Built on the evidence</span> 523 <h2 class="h2" data-i18n="ev.h2">Designed around how<br>language actually sticks.</h2> 524 <p data-i18n="ev.p">Every choice in Lomia traces to second-language research â comprehensible input, spaced retrieval, and the things shadowing is proven to train.</p> 525 </div> 526 </div> 527 <div class="wrap" id="features"> 528 <div class="feat reveal"> 529 <div class="feat-copy"><h3 data-i18n="f1t">Any text becomes <em class="acc">a scene.</em></h3><p data-i18n="f1p">Paste a paragraph and watch it turn into a short conversation between two voices â rewritten to your level, never above it. The sweet spot, just past what you already know, where new language takes hold.</p></div> 530 <div class="feat-media"><div class="viz viz-1"><div style="width:100%"><div class="paper-chip" data-i18n="f1viz1">âThe annual report showed a marked decline in regional output, attributable toâ¦â<span class="arrow">â</span></div><div class="scene-chip"><div class="who" data-i18n="f1viz2">Role A · curious</div><div class="t">âSo⦠the numbers dropped. Why?â</div></div></div></div></div> 531 </div> 532 <div class="feat reveal"> 533 <div class="feat-copy"><h3 data-i18n="f2t">The words <em class="acc">come back.</em></h3><p data-i18n="f2p">No streaks to protect, no guilt for a missed day. Lomia simply remembers the lines and words you struggled with, and quietly puts them in front of you again at exactly the right moment.</p></div> 534 <div class="feat-media"><div class="viz viz-2"><div class="queue"> 535 <div class="q-row"><span class="d"></span><span class="tx">âplodded on, slow and steadyâ</span><span class="due" data-i18n="due.now">due now</span></div> 536 <div class="q-row"><span class="d"></span><span class="tx">âattributable to a shortfallâ</span><span class="due" data-i18n="due.d2">in 2d</span></div> 537 <div class="q-row"><span class="d s"></span><span class="tx">âthe door was still openâ</span><span class="due" data-i18n="due.d9">in 9d</span></div> 538 <div class="q-row"><span class="d s"></span><span class="tx">âwhether or not it matteredâ</span><span class="due" data-i18n="due.d21">in 21d</span></div> 539 </div></div></div> 540 </div> 541 <div class="feat reveal"> 542 <div class="feat-copy"><h3 data-i18n="f3t">Hear your <em class="acc">past self.</em></h3><p data-i18n="f3p">Lomia keeps your takes. A month in, set today's voice beside the one from week one on the same line â the kind of progress you can actually hear, not just a number going up.</p></div> 543 <div class="feat-media"><div class="viz viz-3"><div class="compare-bars"> 544 <div class="col then"><div class="stack"><i style="height:30%"></i><i style="height:55%"></i><i style="height:22%"></i><i style="height:60%"></i><i style="height:18%"></i><i style="height:45%"></i></div><div class="cl" data-i18n="cmp.then">4 weeks ago</div></div> 545 <div class="col now"><div class="stack"><i style="height:62%"></i><i style="height:90%"></i><i style="height:70%"></i><i style="height:96%"></i><i style="height:58%"></i><i style="height:84%"></i></div><div class="cl" data-i18n="cmp.now">today</div></div> 546 </div></div></div> 547 </div> 548 </div> 549</section> 550 551<!-- COMPARISON --> 552<section class="sec" id="compare" style="background:var(--paper-pure)"> 553 <div class="wrap"> 554 <div class="sec-head reveal">
555 <span class="eyebrow" data-i18n="cm.eyebrow">Why not justâ¦</span> 556 <h2 class="h2" data-i18n="cm.h2">Three ways to study.<br>Only one makes you <em class="acc">speak.</em></h2> 557 </div> 558 <div class="compare-grid"> 559 <div class="cmp reveal d1"> 560 <h4 data-i18n="cm.aT">Flashcard apps</h4> 561 <ul> 562 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/></svg><span><span class="lab" data-i18n="cm.r1">You do</span><span data-i18n="cm.a1">Memorize words in isolation</span></span></li> 563 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/></svg><span><span class="lab" data-i18n="cm.r2">Measured by</span><span data-i18n="cm.a2">Tapping that you recognize it</span></span></li> 564 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/></svg><span><span class="lab" data-i18n="cm.r3">You walk away</span><span data-i18n="cm.a3">Able to recognize â not produce</span></span></li> 565 </ul> 566 </div> 567 <div class="cmp reveal d2"> 568 <h4 data-i18n="cm.bT">Streak apps</h4> 569 <ul> 570 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/></svg><span><span class="lab" data-i18n="cm.r1">You do</span><span data-i18n="cm.b1">Protect a daily streak</span></span></li> 571 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/></svg><span><span class="lab" data-i18n="cm.r2">Measured by</span><span data-i18n="cm.b2">Logging in, day after day</span></span></li> 572 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/></svg><span><span class="lab" data-i18n="cm.r3">You walk away</span><span data-i18n="cm.b3">A habit of tapping â and guilt</span></span></li> 573 </ul> 574 </div> 575 <div class="cmp featured reveal d3" data-badge="Lomia" data-i18n-badge="cm.badge"> 576 <h4 data-i18n="cm.cT">Lomia</h4> 577 <ul> 578 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><path d="M5 13l4 4L19 7" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg><span><span class="lab" data-i18n="cm.r1">You do</span><span data-i18n="cm.c1">Speak real sentences out loud</span></span></li> 579 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><path d="M5 13l4 4L19 7" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg><span><span class="lab" data-i18n="cm.r2">Measured by</span><span data-i18n="cm.c2">Four dimensions of being understood</span></span></li> 580 <li><svg class="ck" width="18" height="18" viewBox="0 0 24 24" fill="none"><path d="M5 13l4 4L19 7" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg><span><span class="lab" data-i18n="cm.r3">You walk away</span><span data-i18n="cm.c3">Actually able to speak â nothing to break</span></span></li> 581 </ul> 582 </div> 583 </div> 584 </div> 585</section> 586 587<!-- QUOTE --> 588<section class="sec quote"> 589 <div class="wrap"> 590 <span class="qmark reveal" aria-hidden="true">â</span> 591 <blockquote class="reveal d1" data-i18n="quote.text">A language you can't speak isn't yours yet.<br>It's time to make it <em>yours</em> â out loud.</blockquote> 592 <div class="attr reveal d2" data-i18n="quote.attr">â The idea behind Lomia</div> 593 </div> 594</section> 595 596<!-- STATS (dark) --> 597<section class="sec dark on-dark"> 598 <div class="wrap"> 599 <div class="sec-head reveal" style="max-width:700px"> 600 <span class="eyebrow" data-i18n="st.eyebrow">For the quietly fluent</span> 601 <h2 class="h2" data-i18n="st.h2">You've studied for years.<br>Time to be heard.</h2> 602 </div> 603 <div class="stats"> 604 <div class="stat reveal d1"><div class="n"><span data-count="4">4</span><em>Ã</em></div><div class="l" data-i18n="st.l1">dimensions scored on every line, not one opaque grade</div></div> 605 <div class="stat reveal d1"><div class="n"><em>â</em></div><div class="l" data-i18n="st.l2">sources â any text you bring becomes practice</div></div> 606 <div class="stat reveal d2"><div class="n">0</div><div class="l" data-i18n="st.l3">streaks, hearts, or guilt â progress, not pressure</div></div> 607 <div class="stat reveal d3"><div class="n">1<em>:</em>1</div><div class="l" data-i18n="st.l4">your voice against a native line, every single time</div></div> 608 </div> 609 </div> 610</section> 611 612<!-- FAQ --> 613<section class="sec" id="faq" style="background:var(--paper)"> 614 <div class="wrap"> 615 <div class="sec-head reveal"><span class="eyebrow" data-i18n="faq.eyebrow">Questions</span><h2 class="h2" data-i18n="faq.h2">Good to know.</h2></div> 616 <div class="faq-list reveal d1"> 617 <div class="faq-item"><button class="faq-q" aria-expanded="false"><span data-i18n="faq.q1">
617What can I put into Lomia?</span><span class="pm" aria-hidden="true"></span></button><div class="faq-a"><div><p data-i18n="faq.a1">Anything you read in your target language â an article, a book chapter, a podcast transcript, song lyrics, even a work email. Lomia turns it into short spoken scenes at your level.</p></div></div></div> 618 <div class="faq-item"><button class="faq-q" aria-expanded="false"><span data-i18n="faq.q2">Do I need a microphone?</span><span class="pm" aria-hidden="true"></span></button><div class="faq-a"><div><p data-i18n="faq.a2">Yes â speaking is the whole point. Lomia listens to each line you say and shows you exactly what to improve, then brings the hard ones back later.</p></div></div></div> 619 <div class="faq-item"><button class="faq-q" aria-expanded="false"><span data-i18n="faq.q3">Is this like Duolingo?</span><span class="pm" aria-hidden="true"></span></button><div class="faq-a"><div><p data-i18n="faq.a3">No. There are no streaks to lose and no guilt for a missed day. Lomia measures whether you can be understood, and resurfaces the words you struggle with on a schedule tuned to your own memory.</p></div></div></div> 620 <div class="faq-item"><button class="faq-q" aria-expanded="false"><span data-i18n="faq.q4">Which languages?</span><span class="pm" aria-hidden="true"></span></button><div class="faq-a"><div><p data-i18n="faq.a4">Lomia starts with English for Mandarin speakers â the gap we know best â with more language pairs on the way.</p></div></div></div> 621 <div class="faq-item"><button class="faq-q" aria-expanded="false"><span data-i18n="faq.q5">How fast can I start?</span><span class="pm" aria-hidden="true"></span></button><div class="faq-a"><div><p data-i18n="faq.a5">Under a minute. Paste a page, pick a voice, and you're speaking your first line.</p></div></div></div> 622 </div> 623 </div> 624</section> 625 626<!-- CTA --> 627<section class="cta" id="cta"> 628 <div class="cta-bg" aria-hidden="true"></div> 629 <div class="wrap inner"> 630 <h2 class="big reveal" data-i18n="cta.h2">Open a book.<br><em>Start a conversation.</em></h2> 631 <p class="lead reveal d1" data-i18n="cta.lead">Bring a page you've always meant to understand. In a minute, you'll be speaking it.</p> 632 <div class="hero-cta reveal d2"> 633 <a class="btn btn-primary" href="#top" data-i18n="cta.b1">Start with a story</a> 634 <a class="btn btn-ghost" href="#how" data-i18n="cta.b2">How it works <span class="arr">â</span></a> 635 </div> 636 </div> 637</section> 638 639<!-- FOOTER --> 640<footer> 641 <div class="wrap foot"> 642 <div> 643 <a class="brand" href="#top"> 644 <svg class="mark" viewBox="0 0 32 32" fill="none" aria-hidden="true"><path d="M6 25V8.5C6 7 7 6 8.5 6H22c2 0 3.5 1.6 3.5 3.6 0 1.9-1.4 3.4-3.3 3.4" stroke="#efe7d8" stroke-width="2.1" stroke-linecap="round"/><path d="M6 16h13.5c2.2 0 3.9 1.6 3.9 3.7 0 2.1-1.7 3.8-3.9 3.8H9.5" stroke="#efe7d8" stroke-width="2.1" stroke-linecap="round"/><circle cx="24.5" cy="25" r="2.4" fill="#df5a36"/></svg> 645 <b style="font-family:'Fraunces','Cormorant Garamond',serif;font-weight:600;font-size:1.55rem">Lomia</b> 646 </a> 647 <p class="tg" data-i18n="footer.tg">For people who learned a language for years â and still don't speak it.</p> 648 </div> 649 <div class="foot-cols"> 650 <div class="foot-col"><h5 data-i18n="footer.c1">Product</h5><a href="#how" data-i18n="nav.how">How it works</a><a href="#science" data-i18n="footer.science">The science</a><a href="#compare" data-i18n="nav.features">Features</a><a href="#cta" data-i18n="nav.start">Start free</a></div> 651 <div class="foot-col"><h5 data-i18n="footer.c2">Stories</h5><a href="#" data-i18n="footer.s1">Aesop's fables</a><a href="#" data-i18n="footer.s2">Bring your own</a><a href="#" data-i18n="footer.s3">News & articles</a><a href="#" data-i18n="footer.s4">Transcripts</a></div> 652 <div class="foot-col"><h5 data-i18n="footer.c3">Company</h5><a href="#" data-i18n="footer.co1">About</a><a href="#" data-i18n="footer.co2">Privacy</a><a href="#" data-i18n="footer.co3">Contact</a></div> 653 </div> 654 </div> 655 <div class="wrap foot-base"><span data-i18n="footer.base1">© 2026 Lomia. Speak the story.</span><span data-i18n="footer.base2">Made for the quietly fluent.</span></div> 656</footer> 657 658<!-- ============ AUTH MODAL (Supabase) ============ --> 659<div class="auth-overlay" id="authOverlay" hidden> 660 <div class="auth-card" role="dialog" aria-modal="true" aria-label="Lomia account"> 661 <button class="auth-close" id="authClose" aria-label="Close">×</button> 662 <div class="auth-brand">Lomia</div> 663 664 <!-- sign in / sign up --> 665 <div id="authForm"> 666 <div class="auth-tabs"> 667 <button type="button" data-mode="signup" class="active" data-i18n="auth.tabSignup">Create account</button> 668 <button type="button" data-mode="signin" data-i18n="auth.tabSignin">Sign in</button> 669 </div> 670 <form id="authFormEl"> 671 <div class="auth-field"> 672 <label data-i18n="auth.emailLabel">Email</label> 673 <input id="authEmail" type="email" autocomplete="email" required placeholder="[email protected]" /> 674 </div> 675 <div class="auth-field"> 676 <label data-i18n="auth.passLabel">Password</label> 677 <input id="authPass" type="password" autocomplete="current-password" required minlength="6" placeholder="â¢â¢â¢â¢â¢â¢â¢â¢" /> 678 </div> 679 <button class="btn btn-primary" id="authSubmit" type="submit" data-i18n="auth.submitSignup">Create account</button> 680 </form> 681 <p class="auth-msg" id="authMsg" role="status"></p> 682 <p class="auth-foot" data-i18n="auth.foot">No spam â just your spoken-language practice.</p> 683 </div> 684 685 <!-- signed-in account --> 686 <div id="authAccount" class="auth-acct" hidden> 687 <h3 style="font-family:var(--font-display);font-weight:600;font-size:1.5rem;margin-top:8px" data-i18n="auth.welcome">You're in.</h3> 688 <div class="auth-email" id="acctEmail"></div> 689 <a class="btn btn-primary" href="/app.html" data-i18n="auth.enter">Start practising â</a> 690 <button class="btn btn-ghost" id="subscribeBtn" data-i18n="auth.subscribe" style="margin-top:10px">Go premium</button> 691 <p class="sub-note" id="subNote" data-i18n="auth.subNote">Unlock every voice, every story, and unlimited shadowing.</p> 692 <button class="btn btn-ghost" id="signOutBtn" style="margin-top:14px" data-i18n="auth.signout">Sign out</button> 693 </div> 694 </div> 695</div> 696
697<script> 698document.documentElement.classList.add('js'); 699 700/* Heal stale ShadowPlay PWA service worker / caches from older lomia.ai builds */ 701if ('serviceWorker' in navigator) { 702 navigator.serviceWorker.getRegistrations().then((rs) => rs.forEach((r) => r.unregister())).catch(() => {}); 703} 704if (self.caches) { 705 caches.keys().then((ks) => ks.forEach((k) => caches.delete(k))).catch(() => {}); 706} 707 708/* ---------- i18n ---------- */ 709const I18N = { 710 en: { 711 "meta.title":"Lomia â Learn a language by living inside stories", 712 "meta.desc":"Lomia turns anything you read into spoken story episodes â then listens as you say each line back, and brings the words you stumble on right back to you.", 713 "nav.brandAria":"Lomia home","nav.how":"How it works","nav.why":"Why it works","nav.features":"Features","nav.faq":"FAQ","nav.signin":"Sign in","nav.start":"Start free", 714 "hero.eyebrow":"Language, out loud", 715 "hero.h1":'<span class="l1">Don\'t just read</span><span class="l1">a language.</span><span class="l2"><em class="acc">Live it out loud.</em></span>', 716 "hero.lead":"Lomia turns anything you read into spoken story episodes â then listens as you say each line back, and brings the words you stumble on right back to you.", 717 "hero.cta1":"Start with a story","hero.cta2":'See how it works <span class="arr">â</span>', 718 "hero.note":"No account needed to try · Works with any text you bring", 719 "device.scene":"Aesop · Tortoise & Hare · 3","device.you":"You · say it back","device.recAria":"Record", 720 "metric.accuracy":"Accuracy","metric.fluency":"Fluency","metric.completeness":"Completeness","metric.prosody":"Prosody", 721 "marquee.cap":"Bring anything you actually read", 722 "marquee.row":'<span class="lbl">An <em>article</em></span><span class="sep"></span><span class="lbl">A novel <em>chapter</em></span><span class="sep"></span><span class="lbl">A podcast <em>transcript</em></span><span class="sep"></span><span class="lbl">An Aesop <em>fable</em></span><span class="sep"></span><span class="lbl">The <em>news</em></span><span class="sep"></span><span class="lbl">Song <em>lyrics</em></span><span class="sep"></span><span class="lbl">A work <em>email</em></span><span class="sep"></span>', 723 "who.eyebrow":"Sound familiar?", 724 "who.h2":'You can read it.<br>You just can\'t <em class="acc">say</em> it.', 725 "who.p":"You've passed the exams. You understand the films. But the moment you need to speak, the words don't come. Lomia is built for exactly that gap â between knowing a language and living inside it.", 726 "how.eyebrow":"How it works","how.h2":"Three steps from<br>a page to your voice.","how.p":"No decks of flashcards. No grammar drills. Just the loop that actually builds spoken language â listen, say it back, and hear what to fix.", 727 "how.s1t":"Paste anything","how.s1p":"An article, a chapter, a transcript, or a fable. The language you actually want to speak â not a textbook's idea of it.", 728 "how.s2t":"It becomes a story","how.s2p":"Lomia rewrites it into short, two-voice scenes pitched at your level â natural lines worth saying out loud.", 729 "how.s3t":"Shadow it","how.s3p":"Speak each line over a native voice. Hear yourself instantly, and see exactly which words and rhythms to chase.", 730 "diag.eyebrow":"Your voice, measured","diag.h2":"Not a grade. A diagnosis.","diag.p":"Every take is broken into the things that actually make you understood â so a low score always comes with a reason, and a way to fix it.", 731 "diag.c1t":"Words & sounds","diag.c1p":"Edit-distance alignment matches what you said to the line â so one extra word never red-marks the rest. The sounds Mandarin speakers find hardest get singled out, gently.","diag.c1tag":"Accuracy · Completeness", 732 "diag.c2t":"Rhythm & melody","diag.c2p":"Lomia scores your pace, pauses and pitch against the original. Because being understood is mostly prosody â the music of a sentence â not perfect phonemes.","diag.c2tag":"Fluency · Prosody", 733 "diag.c3t":"The words come back","diag.c3p":"Every line you stumble on becomes a memory the app tracks â and resurfaces right before you'd forget it, on a schedule tuned to your own curve.","diag.c3tag":"Spaced review", 734 "ev.eyebrow":"Built on the evidence","ev.h2":"Designed around how<br>language actually sticks.","ev.p":"Every choice in Lomia traces to
734second-language research â comprehensible input, spaced retrieval, and the things shadowing is proven to train.", 735 "f1t":'Any text becomes <em class="acc">a scene.</em>',"f1p":"Paste a paragraph and watch it turn into a short conversation between two voices â rewritten to your level, never above it. The sweet spot, just past what you already know, where new language takes hold.", 736 "f1viz1":'âThe annual report showed a marked decline in regional output, attributable toâ¦â<span class="arrow">â</span>',"f1viz2":"Role A · curious", 737 "f2t":'The words <em class="acc">come back.</em>',"f2p":"No streaks to protect, no guilt for a missed day. Lomia simply remembers the lines and words you struggled with, and quietly puts them in front of you again at exactly the right moment.", 738 "due.now":"due now","due.d2":"in 2d","due.d9":"in 9d","due.d21":"in 21d", 739 "f3t":'Hear your <em class="acc">past self.</em>',"f3p":"Lomia keeps your takes. A month in, set today's voice beside the one from week one on the same line â the kind of progress you can actually hear, not just a number going up.", 740 "cmp.then":"4 weeks ago","cmp.now":"today", 741 "cm.eyebrow":"Why not justâ¦","cm.h2":'Three ways to study.<br>Only one makes you <em class="acc">speak.</em>', 742 "cm.r1":"You do","cm.r2":"Measured by","cm.r3":"You walk away","cm.badge":"Lomia", 743 "cm.aT":"Flashcard apps","cm.a1":"Memorize words in isolation","cm.a2":"Tapping that you recognize it","cm.a3":"Able to recognize â not produce", 744 "cm.bT":"Streak apps","cm.b1":"Protect a daily streak","cm.b2":"Logging in, day after day","cm.b3":"A habit of tapping â and guilt", 745 "cm.cT":"Lomia","cm.c1":"Speak real sentences out loud","cm.c2":"Four dimensions of being understood","cm.c3":"Actually able to speak â nothing to break", 746 "quote.text":'A language you can\'t speak isn\'t yours yet.<br>It\'s time to make it <em>yours</em> â out loud.',"quote.attr":"â The idea behind Lomia", 747 "st.eyebrow":"For the quietly fluent","st.h2":"You've studied for years.<br>Time to be heard.", 748 "st.l1":"dimensions scored on every line, not one opaque grade","st.l2":"sources â any text you bring becomes practice","st.l3":"streaks, hearts, or guilt â progress, not pressure","st.l4":"your voice against a native line, every single time", 749 "faq.eyebrow":"Questions","faq.h2":"Good to know.", 750 "faq.q1":"What can I put into Lomia?","faq.a1":"Anything you read in your target language â an article, a book chapter, a podcast transcript, song lyrics, even a work email. Lomia turns it into short spoken scenes at your level.", 751 "faq.q2":"Do I need a microphone?","faq.a2":"Yes â speaking is the whole point. Lomia listens to each line you say and shows you exactly what to improve, then brings the hard ones back later.", 752 "faq.q3":"Is this like Duolingo?","faq.a3":"No. There are no streaks to lose and no guilt for a missed day. Lomia measures whether you can be understood, and resurfaces the words you struggle with on a schedule tuned to your own memory.", 753 "faq.q4":"Which languages?","faq.a4":"Lomia starts with English for Mandarin speakers â the gap we know best â with more language pairs on the way.", 754 "faq.q5":"How fast can I start?","faq.a5":"Under a minute. Paste a page, pick a voice, and you're speaking your first line.", 755 "cta.h2":"Open a book.<br><em>Start a conversation.</em>","cta.lead":"Bring a page you've always meant to understand. In a minute, you'll be speaking it.","cta.b1":"Start with a story","cta.b2":'How it works <span class="arr">â</span>', 756 "footer.tg":"For people who learned a language for years â and still don't speak it.", 757 "footer.c1":"Product","footer.science":"The science","footer.c2":"Stories","footer.s1":"Aesop's fables","footer.s2":"Bring your own","footer.s3":"News & articles","footer.s4":"Transcripts","footer.c3":"Company","footer.co1":"About","footer.co2":"Privacy","footer.co3":"Contact", 758 "footer.base1":"© 2026 Lomia. Speak the story.","footer.base2":"Made for the quietly fluent.", 759 "auth.tabSignup":"Create account","auth.tabSignin":"Sign in", 760 "auth.emailLabel":"Email","auth.passLabel":"Password", 761 "auth.submitSignup":"Create account","auth.submitSignin":"Sign in", 762 "auth.foot":"No spam â just your spoken-language practice.", 763 "auth.welcome":"You're in.","auth.enter":"Start practising â","auth.subscribe":"Go premium","auth.signout":"Sign out", 764 "auth.subNote":"Unlock every voice, every story, and unlimited shadowing.", 765 "auth.notConfigured":"Sign-in isn't switched on yet â check back soon.", 766 "auth.checkEmail":"Check your inbox to confirm your email, then sign in.", 767 "auth.signedIn":"Signed in.","auth.working":"One momentâ¦","auth.payOff":"Payments aren't enabled yet." 768 }, 769 zh: { 770 "meta.title":"Lomia ââ èµ°è¿æ äºé,å¦ä¼ä¸é¨è¯è¨", 771 "meta.desc":"Lomia æä½ 读å°ç任使å,åæå¯ä»¥å¼å£è·è¯»çæ äºåºæ¯ââåå¬ä½ ä¸å¥å¥è¯´åæ¥,å¹¶æä½ å¡å£³çè¯,å¨ä½ å¿«è¦å¿è®°æ¶éæ°å¸¦åä½ é¢åã", 772 "nav.brandAria":"Lomia é¦é¡µ","nav.how":"å¦ä½è¿ä½","nav.why":"ä¸ºä½ææ","nav.features":"åè½","nav.faq":"常è§é®é¢","nav.signin":"ç»å½","nav.start":"å è´¹å¼å§", 773 "hero.eyebrow":"让è¯è¨,å¼å£è¯´åºæ¥", 774 "hero.h1":'<span class="l1">
774å«åªæ¯è¯»æ</span><span class="l1">ä¸é¨è¯è¨ã</span><span class="l2"><em class="acc">æå®,å¤§å£°è¯´åºæ¥ã</em></span>', 775 "hero.lead":"Lomia æä½ 读å°ç任使å,åæå¯ä»¥å¼å£è·è¯»çæ äºåºæ¯ââåå¬ä½ ä¸å¥å¥è¯´åæ¥,å¹¶æä½ å¡å£³çè¯,å¨ä½ å¿«è¦å¿è®°æ¶éæ°å¸¦åä½ é¢åã", 776 "hero.cta1":"ä»ä¸ä¸ªæ äºå¼å§","hero.cta2":'çç宿ä¹è¿ä½ <span class="arr">â</span>', 777 "hero.note":"æ éæ³¨åå³å¯ä½éª · 任使æ¬é½è½åæç»ä¹ ", 778 "device.scene":"ä¼ç´¢ · é¾å èµè· · 3","device.you":"ä½ Â· è·ç说","device.recAria":"å½é³", 779 "metric.accuracy":"å确度","metric.fluency":"æµå©åº¦","metric.completeness":"宿´åº¦","metric.prosody":"éµå¾", 780 "marquee.cap":"带æ¥ä»»ä½ä½ çæ£ä¼è¯»çä¸è¥¿", 781 "marquee.row":'<span class="lbl">ä¸ç¯<em>æç« </em></span><span class="sep"></span><span class="lbl">ä¸ä¸ª<em>ç« è</em></span><span class="sep"></span><span class="lbl">䏿®µ<em>æå®¢æå稿</em></span><span class="sep"></span><span class="lbl">ä¸å<em>ä¼ç´¢å¯è¨</em></span><span class="sep"></span><span class="lbl">ä»å¤©ç<em>æ°é»</em></span><span class="sep"></span><span class="lbl">䏿®µ<em>æè¯</em></span><span class="sep"></span><span class="lbl">ä¸å°<em>å·¥ä½é®ä»¶</em></span><span class="sep"></span>', 782 "who.eyebrow":"æ¯ä¸æ¯å¾çæ?", 783 "who.h2":'ä½ è½è¯»æ,<br>å´å§ç»<em class="acc">说ä¸åºå£</em>ã', 784 "who.p":"èè¯ä½ è¿äº,çµå½±ä½ çæäºãå¯çè¦å¼å£çé£ä¸å»,è¯å´å¡å¨å´è¾¹åºä¸æ¥ãLomia æ£æ¯ä¸ºè¿é鸿æ²èçââå¨âç徿âåâ说å¾åºâä¹é´ã", 785 "how.eyebrow":"å¦ä½è¿ä½","how.h2":"ä»ä¸é¡µæå,å°ä½ ç声é³,<br>åªè¦ä¸æ¥ã","how.p":"æ²¡æææ²çåè¯å¡,没æè¯æ³æç»ãåªæçæ£è½ç»åºå£è¯ç循ç¯ââå¬,è¯´åæ¥,å¬è§èªå·±åªéè¦æ¹ã", 786 "how.s1t":"ç²è´´ä»»ä½æå","how.s1p":"ä¸ç¯æç« ãä¸ä¸ªç« èã䏿®µè®¿è°,æä¸åå¯è¨ãä½ çæ£æ³è¯´åºå£çè¯è¨,è䏿¯æç§ä¹¦éçæ ·åã", 787 "how.s2t":"å®åæä¸ä¸ªæ äº","how.s2p":"Lomia æå®æ¹åæä¸¤ä¸ªè§è²çç®çåºæ¯,è´´çä½ çæ°´å¹³ââå¼å¾å¤§å£°è¯´åºæ¥çèªç¶å¥åã", 788 "how.s3t":"è·ç说","how.s3p":"卿¯è¯è ç声é³ä¹ä¸è·è¯»æ¯ä¸å¥ã峿¶å¬è§èªå·±,çæ¸ 该追åªä¸ªè¯ãåªæ®µèå¥ã", 789 "diag.eyebrow":"ä½ ç声é³,被éå","diag.h2":"䏿¯ä¸ä¸ªåæ°,èæ¯ä¸ä»½è¯æã","diag.p":"æ¯ä¸æ¬¡å¼å£é½ä¼è¢«æè§£æçæ£è®©ä½ âè¢«å¬æâçè¦ç´ ââæä»¥ä½åæ»æåå ,乿»ææ¹æ³ã", 790 "diag.c1t":"è¯ä¸é³","diag.c1p":"ç¼è¾è·ç¦»å¯¹é½ä¼æä½ 说çååå¥éè¯é åââå¤è¯´ä¸ä¸ªè¯,åé¢çä¹ä¸ä¼å被è¿ç´¯æ 红ãä¸å½å¦ä¹ è æé¾çé£äºé³,ä¼è¢«æ¸©æå°åç¬ç¹åºæ¥ã","diag.c1tag":"å确度 · 宿´åº¦", 791 "diag.c2t":"èå¥ä¸éµå¾","diag.c2p":"Lomia æä½ çè¯éãåé¡¿åé³é«ä¸åå£°ç¸æ¯ãå 为âè¢«å¬æâé ç夿¯éµå¾ââä¸å¥è¯çæå¾,èéå®ç¾çé³ç´ ã","diag.c2tag":"æµå©åº¦ · éµå¾", 792 "diag.c3t":"è¯ä¼åæ¥","diag.c3p":"æ¯ä¸ä¸ªä½ å¡ä½çå¥å,é½ä¼è¢«è®°ä¸,å¹¶å¨ä½ å¿«è¦å¿è®°ä¹åãæä½ èªå·±çéå¿æ²çº¿éæ°åºç°ã","diag.c3tag":"é´éå¤ä¹ ", 793 "ev.eyebrow":"建ç«å¨è¯æ®ä¹ä¸","ev.h2":"å´ç»è¯è¨<br>
793çæ£è¢«è®°ä½çæ¹å¼æ¥è®¾è®¡ã","ev.p":"Lomia çæ¯ä¸ä¸ªéæ©é½è½è¿½æº¯å°äºè¯ä¹ å¾ç ç©¶ââå¯çè§£è¾å ¥ãé´éæå,以åè·è¯»è¢«è¯æè½ç»æçä¸è¥¿ã", 794 "f1t":'任使å,<em class="acc">齿ä¸å¹ã</em>',"f1p":"ç²è¿ä¸æ®µè¯,çå®åæä¸¤ä¸ªå£°é³ä¹é´çç®ç对è¯ââæ¹åå°ä½ çæ°´å¹³,ç»ä¸è¶ 纲ãå°±å¨ä½ å·²ç¥çè¾¹ç¼åè¿ä¸æ¥,è¯è¨æå®¹æå¨é£éææ ¹ã", 795 "f1viz1":'â年度æ¥åæ¾ç¤ºè¯¥å°åºäº§åºææ¾ä¸æ»,åå å¯å½ç»ä¸ºâ¦â¦â<span class="arrow">â</span>',"f1viz2":"è§è² A · 好å¥", 796 "f2t":'é£äºè¯,<em class="acc">ä¼åæ¥ã</em>',"f2p":"没æè¦å®æ¤çè¿è,没æç¼ºå¸çæ§çãLomia åªæ¯è®°ä½ä½ æ£æè¿çå¥ååè¯,卿°å¥½çæ¶å»,ææéæ°æ¾å°ä½ ç¼åã", 797 "due.now":"ç°å¨å°æ","due.d2":"2 天å","due.d9":"9 天å","due.d21":"21 天å", 798 "f3t":'å¬è§<em class="acc">è¿å»çèªå·±ã</em>',"f3p":"Lomia ä¿çä½ çæ¯ä¸æ¬¡å½é³ãä¸ä¸ªæå,æä»å¤©ç声é³å第ä¸å¨çåä¸å¥è¯å¹¶æââè¿ç§è¿æ¥,ä½ å¬å¾è§,èä¸åªæ¯ä¸ä¸ªå¾ä¸èµ°çæ°åã", 799 "cmp.then":"åå¨å","cmp.now":"ä»å¤©", 800 "cm.eyebrow":"为ä»ä¹ä¸ç´æ¥ç¨â¦â¦","cm.h2":'ä¸ç§å¦ä¹ æ¹å¼ã<br>åªæä¸ç§,è®©ä½ <em class="acc">å¼å£ã</em>', 801 "cm.r1":"ä½ åä»ä¹","cm.r2":"æä¹è¡¡é","cm.r3":"ä½ æç»å¾å°","cm.badge":"Lomia", 802 "cm.aT":"åè¯å¡ App","cm.a1":"å¤ç«å°èåè¯","cm.a2":"ç¿»å¡çã认å¾åº","cm.a3":"认å¾åºââå´è¯´ä¸åº", 803 "cm.bT":"æå¡ App","cm.b1":"å®ä½æ¯æ¥è¿è","cm.b2":"æ¥å¤ä¸æ¥å°ç»å½","cm.b3":"æå¡çä¹ æ¯ââåæ§ç", 804 "cm.cT":"Lomia","cm.c1":"大声说åºçå®çå¥å","cm.c2":"å个âè¢«å¬æâç维度","cm.c3":"çæ£è½å¼å£ââæ²¡ä»ä¹å¯æç", 805 "quote.text":'ä¸é¨ä½ 说ä¸åºå£çè¯è¨,è¿ä¸ç®æ¯ä½ çã<br>æ¯æ¶å让å®<em>å±äºä½ </em>äºââ大声å°ã',"quote.attr":"ââ Lomia çåå¿", 806 "st.eyebrow":"åç»âæ²é»ççç»è â","st.h2":"ä½ å·²ç»å¦äºå¾å¤å¹´ã<br>æ¯æ¶å,被å¬è§äºã", 807 "st.l1":"æ¯å¥è¯è¢«è¯ç维度,èéä¸ä¸ªå«ç³çåæ°","st.l2":"æ¥æºââä½ å¸¦æ¥ç任使å齿¯ç»ä¹ ","st.l3":"没æè¿èãä½åãæ§çââæ¯è¿æ¥,䏿¯åå","st.l4":"ä½ ç声é³å¯¹ä¸å¥æ¯è¯å声,æ¯ä¸æ¬¡", 808 "faq.eyebrow":"常è§é®é¢","faq.h2":"å äºè§£ä¸ä¸ã", 809 "faq.q1":"æå¯ä»¥æ¾ä»ä¹è¿ Lomia?","faq.a1":"ä»»ä½ä½ å¨ç®æ è¯é读å°çä¸è¥¿ââæç« ã书çç« èãæå®¢æå稿ãæè¯,çè³ä¸å°å·¥ä½é®ä»¶ãLomia 伿å®åæè´´åä½ æ°´å¹³çç®çå£è¯åºæ¯ã", 810 "faq.q2":"éè¦éº¦å é£å?","faq.a2":"éè¦ââå¼å£ææ¯å ³é®ãLomia ä¼å¬ä½ è¯´çæ¯ä¸å¥,æ¸ æ¥åè¯ä½ 该æ¹ä»ä¹,åå¨ä¹åæé¾çé£äºéæ°å¸¦åæ¥ã", 811 "faq.q3":"è¿åå¤é»å½ä¸æ ·å?","faq.a3":"ä¸ä¸æ ·ã没æä¼æçè¿è,乿²¡æç¼ºå¸çæ§çãLomia è¡¡éçæ¯ä½ è½å¦è¢«å¬æ,å¹¶æä½ èªå·±çè®°å¿æ²çº¿,æä½ æ£æçè¯éæ°å¸¦åæ¥ã", 812 "faq.q4":"æ¯æåªäºè¯è¨?","faq.a4":"Lomia ä»â䏿æ¯è¯è å¦è±è¯âèµ·æ¥ââè¿æ¯æä»¬æäºè§£ç鸿æ²ââæ´å¤è¯è¨ç»åå¨è·¯ä¸ã", 813 "faq.q5":"å¤å¿«è½å¼å§?","faq.a5":"ä¸å°ä¸åéãç²è´´ä¸é¡µæå,éä¸ä¸ªå£°é³,ä½ å°±è½è¯´åºç¬¬ä¸å¥ã", 814 "cta.h2":"æå¼ä¸æ¬ä¹¦,<br><em>å¼å¯ä¸æ®µå¯¹è¯ã</em>","cta.lead":"带æ¥ä¸é¡µä½ ä¸ç´æ³è¯»æçæåãä¸åéå ,ä½ å°±ä¼å¼å£è¯´å®ã","cta.b1":"ä»ä¸ä¸ªæ äºå¼å§","cta.b2":'å®å¦ä½è¿ä½ <span class="arr">â</span>', 815 "footer.tg":"åç»é£äºââå¦äºä¸é¨è¯è¨å¾å¤å¹´,å´ä¾ç¶å¼ä¸äºå£ç人ã", 816 "footer.c1":"产å","footer.science":"ç§å¦ä¾æ®","footer.c2":"æ äº","footer.s1":"ä¼ç´¢å¯è¨","footer.s2":"带æ¥ä½ èªå·±ç","footer.s3":"æ°é»ä¸æç« ","footer.s4":"è®¿è°æå稿","footer.c3":"å ¬å¸","footer.co1":"å ³äº","footer.co2":"éç§","footer.co3":"èç³»", 817 "footer.base1":"© 2026 Lomia. ææ äº,è¯´åºæ¥ã","footer.base2":"åç»æ²é»ççç»è ã", 818 "auth.tabSignup":"注å","auth.tabSignin":"ç»å½", 819 "auth.emailLabel":"é®ç®±","auth.passLabel":"å¯ç ", 820 "auth.submitSignup":"å建账æ·","auth.submitSignin":"ç»å½", 821 "auth.foot":"ä¸ååå¾é®ä»¶ââåªä¸ºä½ çå£è¯ç»ä¹ ã", 822 "auth.welcome":"ä½ å·²ç»å½ã","auth.enter":"å¼å§ç»ä¹ â","auth.subscribe":"å级ä¼å","auth.signout":"éåºç»å½", 823 "auth.subNote":"è§£éå ¨é¨å£°é³ãå ¨é¨æ äºä¸æ éè·è¯»ã", 824 "auth.notConfigured":"ç»å½åè½å°æªå¼å¯,æ¬è¯·æå¾ ã", 825 "auth.checkEmail":"è¯·æ¥æ¶é®ç®±ç¡®è®¤é®ä»¶,确认åå³å¯ç»å½ã", 826 "auth.signedIn":"å·²ç»å½ã","auth.working":"请ç¨åâ¦â¦","auth.payOff":"æ¯ä»å°æªå¼å¯ã" 827 } 828}; 829 830function applyLang(lang){ 831 const dict = I18N[lang] || I18N.en; 832 document.documentElement.lang = lang; 833 document.querySelectorAll('[data-i18n]').forEach(el=>{ 834 const v = dict[el.getAttribute('data-i18n')]; 835 if (v != null) el.innerHTML = v; 836 }); 837 document.querySelectorAll('[data-i18n-aria]').forEach(el=>{ 838 const v = dict[el.getAttribute('data-i18n-aria')]; 839 if (v != null) el.setAttribute('aria-label', v); 840 }); 841 document.querySelectorAll('[data-i18n-badge]').forEach(el=>{ 842 const v = dict[el.getAttribute('data-i18n-badge')]; 843 if (v != null) el.setAttribute('data-badge', v); 844 }); 845 const metaEl = document.querySelector('[data-i18n-meta]'); 846 if (metaEl && dict['meta.desc']) metaEl.setAttribute('content', dict['meta.desc']); 847 if (dict['meta.title']) document.title = dict['meta.title']; 848 // marquee (duplicated for seamless loop)
849 const row = document.getElementById('marquee-row'); 850 if (row && dict['marquee.row']) row.innerHTML = dict['marquee.row'] + dict['marquee.row']; 851 // toggle active state 852 document.querySelectorAll('.lang-toggle button').forEach(b=>b.classList.toggle('active', b.dataset.lang===lang)); 853 try { localStorage.setItem('fable.lang', lang); } catch(e){} 854} 855 856const saved = (()=>{ try { return localStorage.getItem('fable.lang'); } catch(e){ return null; } })(); 857const initial = saved || ((navigator.language||'en').toLowerCase().startsWith('zh') ? 'zh' : 'en'); 858applyLang(initial); 859document.querySelectorAll('.lang-toggle button').forEach(b=>b.addEventListener('click', ()=>applyLang(b.dataset.lang))); 860 861/* ---------- nav ---------- */ 862const nav = document.getElementById('nav'); 863const onScroll = ()=>nav.classList.toggle('scrolled', window.scrollY>24); 864onScroll(); window.addEventListener('scroll', onScroll, {passive:true}); 865 866/* ---------- reveal + count-up ---------- */ 867const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; 868function countUp(el){ 869 const target = +el.dataset.count; 870 if (reduce){ el.textContent = target; return; } 871 const dur = 1100; let start = null; 872 function step(ts){ if(start===null) start=ts; const p=Math.min(1,(ts-start)/dur); 873 el.textContent = Math.round(p*target); if(p<1) requestAnimationFrame(step); } 874 requestAnimationFrame(step); 875} 876if (!reduce && 'IntersectionObserver' in window){ 877 const io = new IntersectionObserver((entries)=>{ 878 entries.forEach(e=>{ if(e.isIntersecting){ 879 e.target.classList.add('in'); 880 e.target.querySelectorAll && e.target.querySelectorAll('[data-count]').forEach(countUp); 881 io.unobserve(e.target); 882 }}); 883 }, {threshold:0.16, rootMargin:'0px 0px -8% 0px'}); 884 document.querySelectorAll('.reveal').forEach(el=>io.observe(el)); 885} else { 886 document.querySelectorAll('.reveal').forEach(el=>el.classList.add('in')); 887 document.querySelectorAll('[data-count]').forEach(el=>el.textContent=el.dataset.count); 888} 889 890/* ---------- FAQ accordion ---------- */ 891document.querySelectorAll('.faq-item').forEach(item=>{ 892 const q = item.querySelector('.faq-q'); 893 q.addEventListener('click', ()=>{ 894 const open = item.classList.toggle('open'); 895 q.setAttribute('aria-expanded', open ? 'true' : 'false'); 896 }); 897}); 898 899/* ---------- device tilt ---------- */ 900const device = document.getElementById('device'); 901if (device && !reduce && window.matchMedia('(pointer:fine)').matches){ 902 const hero = device.closest('.hero'); 903 hero.addEventListener('mousemove', (ev)=>{ 904 const r = hero.getBoundingClientRect(); 905 const x = (ev.clientX-r.left)/r.width-0.5, y=(ev.clientY-r.top)/r.height-0.5; 906 device.style.transform = `perspective(1000px) rotateY(${x*5}deg) rotateX(${-y*5}deg)`; 907 }); 908 hero.addEventListener('mouseleave', ()=>{ device.style.transform=''; }); 909} 910 911/* ---------- scroll progress ---------- */ 912const sprog = document.getElementById('sprog'); 913function progress(){ 914 const h = document.documentElement; 915 const max = h.scrollHeight - h.clientHeight; 916 sprog.style.width = (max>0 ? (h.scrollTop/max*100) : 0) + '%'; 917} 918window.addEventListener('scroll', progress, {passive:true}); progress(); 919 920/* ---------- hero background parallax ---------- */ 921const heroBg = document.querySelector('.hero-bg'); 922if (heroBg && !reduce){ 923 window.addEventListener('scroll', ()=>{ heroBg.style.transform = `translateY(${window.scrollY*0.22}px)`; }, {passive:true}); 924} 925 926/* ---------- magnetic primary buttons ---------- */ 927if (!reduce && window.matchMedia('(pointer:fine)').matches){ 928 document.querySelectorAll('.btn-primary').forEach(btn=>{ 929 btn.addEventListener('pointermove', e=>{ 930 const r = btn.getBoundingClientRect(); 931 const x = e.clientX - r.left - r.width/2, y = e.clientY - r.top - r.height/2; 932 btn.style.transform = `translate(${x*0.18}px, ${y*0.3}px)`; 933 }); 934 btn.addEventListener('pointerleave', ()=>{ btn.style.transform=''; }); 935 }); 936} 937 938/* ---------- card cursor spotlight ---------- */ 939if (!reduce && window.matchMedia('(pointer:fine)').matches){ 940 document.querySelectorAll('.card').forEach(c=>{ 941 c.addEventListener('pointermove', e=>{ 942 const r = c.getBoundingClientRect(); 943 c.style.setProperty('--mx', (e.clientX-r.left)+'px'); 944 c.style.setProperty('--my', (e.clientY-r.top)+'px'); 945 }); 946 }); 947} 948 949/* ---------- Auth (Supabase) + checkout (Dodo) ---------- */ 950(function(){
951 const overlay = document.getElementById('authOverlay'); 952 const formView = document.getElementById('authForm'); 953 const acctView = document.getElementById('authAccount'); 954 const msg = document.getElementById('authMsg'); 955 const submitBtn = document.getElementById('authSubmit'); 956 const tabs = document.querySelectorAll('.auth-tabs button'); 957 const emailIn = document.getElementById('authEmail'); 958 const passIn = document.getElementById('authPass'); 959 let mode = 'signup', sb = null, cfg = null, started = false; 960 961 const lang = () => document.documentElement.lang || 'en'; 962 const t = (k) => (I18N[lang()] && I18N[lang()][k]) || I18N.en[k] || k; 963 const setMsg = (text, cls) => { msg.textContent = text || ''; msg.className = 'auth-msg' + (cls ? ' ' + cls : ''); }; 964 965 function updateAuthMode(){ 966 tabs.forEach(b => b.classList.toggle('active', b.dataset.mode === mode)); 967 submitBtn.textContent = mode === 'signup' ? t('auth.submitSignup') : t('auth.submitSignin'); 968 passIn.setAttribute('autocomplete', mode === 'signup' ? 'new-password' : 'current-password'); 969 } 970 971 async function ensureClient(){ 972 if (started) return sb; 973 started = true; 974 try { cfg = await (await fetch('/api/config')).json(); } catch (e) { cfg = {}; } 975 if (cfg && cfg.supabaseUrl && cfg.supabaseAnonKey){ 976 try { 977 const mod = await import('https://esm.sh/@supabase/supabase-js@2'); 978 sb = mod.createClient(cfg.supabaseUrl, cfg.supabaseAnonKey, { auth: { persistSession: true, autoRefreshToken: true } }); 979 const { data } = await sb.auth.getSession(); 980 if (data && data.session) showAccount(data.session.user); 981 } catch (e) { sb = null; } 982 } 983 return sb; 984 } 985 986 function showForm(){ acctView.hidden = true; formView.hidden = false; } 987 function showAccount(user){ 988 formView.hidden = true; acctView.hidden = false; 989 document.getElementById('acctEmail').textContent = user.email || ''; 990 if (cfg && !cfg.payments){ 991 const sbtn = document.getElementById('subscribeBtn'); 992 sbtn.disabled = true; sbtn.style.opacity = '.5'; 993 document.getElementById('subNote').textContent = t('auth.payOff'); 994 } 995 } 996 997 async function openAuth(m){ 998 mode = m || 'signup'; 999 overlay.hidden = false; 1000 requestAnimationFrame(() => overlay.classList.add('open')); 1001 setMsg(''); updateAuthMode(); 1002 await ensureClient(); 1003 if (!sb){ showForm(); setMsg(t('auth.notConfigured'), 'error'); submitBtn.disabled = true; } 1004 else { submitBtn.disabled = false; } 1005 setTimeout(() => emailIn && emailIn.focus(), 80); 1006 } 1007 function closeAuth(){ overlay.classList.remove('open'); setTimeout(() => { overlay.hidden = true; }, 300); } 1008 1009 document.querySelectorAll('[data-i18n="nav.signin"]').forEach(el => el.addEventListener('click', e => { e.preventDefault(); openAuth('signin'); })); 1010 document.querySelectorAll('[data-i18n="nav.start"],[data-i18n="hero.cta1"],[data-i18n="cta.b1"]').forEach(el => el.addEventListener('click', e => { e.preventDefault(); openAuth('signup'); }));
1011 tabs.forEach(b => b.addEventListener('click', () => { mode = b.dataset.mode; updateAuthMode(); setMsg(''); })); 1012 document.getElementById('authClose').addEventListener('click', closeAuth); 1013 overlay.addEventListener('click', e => { if (e.target === overlay) closeAuth(); }); 1014 document.addEventListener('keydown', e => { if (e.key === 'Escape' && !overlay.hidden) closeAuth(); }); 1015 document.querySelectorAll('.lang-toggle button').forEach(b => b.addEventListener('click', () => setTimeout(updateAuthMode, 0))); 1016 1017 document.getElementById('authFormEl').addEventListener('submit', async (e) => { 1018 e.preventDefault(); 1019 if (!sb){ setMsg(t('auth.notConfigured'), 'error'); return; } 1020 const email = emailIn.value.trim(), password = passIn.value; 1021 if (!email || !password) return; 1022 submitBtn.disabled = true; setMsg(t('auth.working')); 1023 try { 1024 if (mode === 'signup'){ 1025 const { data, error } = await sb.auth.signUp({ email, password }); 1026 if (error) throw error; 1027 if (data.session) { showAccount(data.session.user); setMsg(''); } 1028 else setMsg(t('auth.checkEmail'), 'ok'); 1029 } else { 1030 const { data, error } = await sb.auth.signInWithPassword({ email, password }); 1031 if (error) throw error; 1032 showAccount(data.user); setMsg(''); 1033 } 1034 } catch (err) { setMsg(err.message || 'Error', 'error'); } 1035 finally { submitBtn.disabled = false; } 1036 }); 1037 1038 document.getElementById('subscribeBtn').addEventListener('click', async () => { 1039 if (!cfg || !cfg.payments){ document.getElementById('subNote').textContent = t('auth.payOff'); return; } 1040 const email = document.getElementById('acctEmail').textContent; 1041 const btn = document.getElementById('subscribeBtn'); btn.disabled = true; 1042 try { 1043 const r = await fetch('/api/checkout', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ email }) }); 1044 const j = await r.json(); 1045 if (j.checkout_url) location.href = j.checkout_url; 1046 else { document.getElementById('subNote').textContent = j.error || t('auth.payOff'); btn.disabled = false; } 1047 } catch (e) { btn.disabled = false; } 1048 }); 1049 1050 document.getElementById('signOutBtn').addEventListener('click', async () => { 1051 if (sb) { try { await sb.auth.signOut(); } catch (e) {} } 1052 showForm(); setMsg(''); 1053 }); 1054})(); 1055</script>
vendor: 1 bytes, line 1055
1055
1056<script src="/yan.js"></script>
vendor: 1 bytes, line 1056
1056
1057<script>(function(){ if(window.Yan){ var h=document.getElementById('yanHero'); if(h) Yan.mount(h,{size:62}); } })();</script>
1057 1058</body> 1059</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.