PageSourceSearch

https://xuetong.com/register?goto=/

html xuetong.com collected 2026-10-07 14:28:19 UTC 149,786 bytes, 3,286 lines download raw bytes

1<!DOCTYPE html>
2
3
4<html lang="zh_CN" class="">
5<head>
6  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
7  <meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1">
8  <meta name="renderer" content="webkit">
9  <meta name="viewport"
10    content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
11  <title>注册 - 范士闯数学 · 学通在线 - 范士闯数学|学会,不是学过 - Powered By EduSoho</title>
12      <meta name="keywords"
13          content="
14范士闯数学,学通在线,小学奥数,小学数学,初中数学,数学同步课,中考数学,在线数学课,专题课,做题方法"/>
15    <meta name="description"
16          content="学通在线 xuetong.com · 范士闯数学。小学初中数学视频课:小学数学同步提高、小学奥数专题、初中数学,覆盖一至九年级。年卡 1,499 元/年,新老同价,全站课程畅学。"/>
17    <meta name="format-detection"
18          content=""/>
19    <meta content="ndvJnDVfouGPEfos_GEcVXJ8QLFFfzq-NrBCgFCYR0Q" name="csrf-token"/>
20    <meta content="0" name="is-login"/>
21    <meta content="0" name="wechat_login_bind"/>
22  
23
24  <meta property="qc:admins" content="213630315547676375" />
25      <link rel="icon" href="/files/system/2026/09-17/183851b306d2792570.png?version=26.3.6" type="image/x-icon"/>
26    <link rel="shortcut icon" href="/files/system/2026/09-17/183851b306d2792570.png?version=26.3.6" type="image/x-icon" media="screen"/>
27  
28  
28<script src="/static-dist/libs/agent-web-sdk/1.2.7/agent-sdk.1.2.7.iife.js?version=26.3.6"></script>
28
29
30          <link href="/static-dist/app/css/bootstrap.css?version=26.3.6" rel="stylesheet" />
31<link href="/static-dist/app/css/main.css?version=26.3.6" rel="stylesheet" />
32<link href="/static-dist/app/css/main-v2.css?version=26.3.6" rel="stylesheet" />
33
34
35
36  <link rel="stylesheet" media="screen" href="/static-dist/gracefultheme/css/main.css?version=1.7.15" />
37  
38  </head>
39<body class="es-main-default es-nav-default register" >
40
41  <div class="es-wrap">
42                  <!-- header -->
43<div class="navbar site-navbar one-nav" id="site-navbar"  data-counter-url="/user_remind_counter">
44  <div class="container">
45    <div class="container-gap">
46      <div class="navbar-header clearfix">
47
48        <!-- btn-->
49        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
50          <span class="iconfont  icon-nanrentouxiang"></span>
51        </button>
52
53        <!-- btn-->
54        <div class="menu-btn">
55          <span class="iconfont icon-menu"></span>
56        </div>
57
58        <!-- logo -->
59                  <a class="navbar-brand-logo" href="/"><img src="/files/system/2026/09-17/1838499c1a54682586.png?version=26.3.6"></a>
60        
61                <form class="navbar-form navbar-left hidden-sm hidden-xs clearfix" role="search" action="/search">
62          <div class="form-group">
63            <input type="search" class="form-control" placeholder="请输入感兴趣的课程名" name="q">
64          </div>
65          <button type="submit" class="btn"><span class="iconfont  icon-sousuo1"></span></button>
66        </form>
67
68      </div>
69
70      <div class="navbar-collapse collapse">
71        <ul class="nav navbar-nav navbar-right">
72                        <li><a href="/login?goto=/"> <span class="iconfont icon-login"></span><p>登录</p></a></li>
73            <li><a href="/register?goto=/"> <span class="iconfont icon-zhuce"></span><p>注册</p></a></li>
74                  </ul>
75      </div><!--/.navbar-collapse end -->
76    </div>
77  </div>  <div class="menu-sec">
78    <div class="container">
79      <ul class="nav navbar-nav">
80                <li class="">
81        <a href="/" class=""  >首页 </a>
82              </li>
83                    <li class="">
84        <a href="/course/explore/xiaosx" class=""  >小学数学 </a>
85              </li>
86                    <li class="">
87        <a href="/course/explore/xiaoas" class=""  >小学奥数 </a>
88              </li>
89                    <li class="">
90        <a href="/course/explore/chusx" class=""  >初中数学 </a>
91              </li>
92                    <li class="">
93        <a href="/vip/" class="" target="_blank" >畅学年卡 </a>
94              </li>
95                    <li class="">
96        <a href="/classroom/explore" class=""  >班级 </a>
97              </li>
98                    <li class="">
99        <a href="/article" class="" target="_blank" >黑板报 </a>
100              </li>
101                    <li class="">
102        <a href="/page/liveclass" class=""  >范士闯直播课 </a>
103              </li>
104                    <li class="">
105        <a href="/page/daoxue" class=""  >导学 </a>
106              </li>
107                    <li class="">
108        <a href="/page/gerenxuean" class=""  >个性化学案 </a>
109              </li>
110      </ul>
111    </div>
112  </div>
113</div>          
114          
115      <div id="content-container" class="container">
116          <div class="es-section login-section">
117    <div class="logon-tab clearfix">
118      <a href="/login?goto=/">登录帐号</a>
119      <a class="active">注册帐号</a>
120    </div>
121    <div class="login-main">
122              <input type="hidden" name="register_mode" value="mobile"/>
123        <form id="register-form" method="post" action="">
124            
125                                <div class="form-group mbl">
126              <label class="control-label required"
127                     for="register_mobile">手机号码</label>
128              <div class="controls">
129                <input type="tel" id="register_mobile" name="verifiedMobile" class="form-control input-lg"
130                       data-url="/register/mobile/check"
131                       placeholder="填写你常用的手机号码作为登录帐号"
132                       onkeydown="if(event.keyCode==13) return false;">
133                <p class="help-block"></p>
134              </div>
135            </div>
136          
137          <div class="form-group mbl">
138            <label class="control-label required"
139                   for="register_nickname">用户名</label>
140            <div class="controls">
141              <input type="text" id="register_nickname" name="nickname" required="required"
142                     class="form-control input-lg" data-url="/register/nickname/check"
143                     placeholder="中、英文均可,最长18个英文或9个汉字"
144                     onkeydown="if(event.keyCode==13) return false;">
145              <p class="help-block"></p>
146            </div>
147          </div>
148
149          <div class="form-group mbl">
150            <label class="control-label required"
151                   for="register_password">密码</label>
152            <div class="controls" style="position: relative;">
153              <input type="password" id="register_password" name="password" required="required"
154                     class="form-control input-lg" placeholder="请输入密码"
155                     onkeydown="if(event.keyCode==13) return false;">
156              <p class="help-block">8-32位字符,包含字母、数字、符号任意两种及以上组合成的密码</p>
157              <img src="/static-dist/app/img/open_eye.svg?version=26.3.6" class="open-eye" alt=""
158                   style="position: absolute; right: 10px; top: 8px; cursor: pointer; display: none"/>
159              <img src="/static-dist/app/img/close_eye.svg?version=26.3.6" class="close-eye" alt=""
160                   style="position: absolute; right: 10px; top: 8px; cursor: pointer; display: block"/>
161            </div>
162          </div>
163
164                      <div
165              class="form-group cd-mb32 js-drag-jigsaw">
166                <label class=" control-label  required ">验证码</label>
167<input type="hidden" name="dragCaptchaToken" value="" />
168<div class="drag-section-wrap">
169  <div class="drag-section">
170    <div class="drag-img js-drag-img">
171      <img class="js-jigsaw drag-img__jigsaw">
172      <div class="drag-img__mask js-drag-img-mask infinite-loading"></div>
173    </div>
174
175    <div class="drag-bar">
176      <span class="drag-bar__tip js-drag-bar-tip">拖动左边滑块完成上方拼图</span>
177      <div class="drag-bar__mask js-drag-bar-mask"></div>
178      <div id="drag-btn" class="drag-bar__btn"></div>
179    </div>
180  </div>
181</div>
182            </div>
183                    <div
184            class="form-group mbl email_mobile_msg">
185            <label class="control-label required js-email_mobile_msg-label">短信验证码</label>
186            <div class="controls cd-row">
187              <div class="col-xs-6">
188                <input type="text" maxlength="6" class="form-control input-lg js-email_mobile_msg-input"
189                       data-url="/edu_cloud/sms_check/sms_registration"
190                       onkeydown="if(event.keyCode==13) return false;">
191                <p class="help-block"></p>
192              </div>
193              <div class="col-xs-6">
194                <a href="javascript:;" class="btn btn-default sms-send-btn js-code-send-btn disabled"
195                   data-sms-url="/edu_cloud/sms_send_registration">
196                  <span id="js-time-left"></span>
197                  <span id="js-fetch-btn-text">获取验证码</span>
198                </a>
199              </div>
200            </div>
201          </div>
202
203          
204          <div class="form-group mbl">
205            <div class="controls">
206              <button type="button" id="register-btn" data-submiting-text="正在提交..."
207                      class="btn btn-primary btn-lg btn-block">注册</button>
208            </div>
209          </div>
210
211          
212          <input type="hidden" name="emailToken" value="">
213          <input type="hidden" name="captcha_enabled" value="1"/>
214          <input type="hidden" name="email_enabled" value="closed"/>
215          <input type="hidden" name="_csrf_token" value="ndvJnDVfouGPEfos_GEcVXJ8QLFFfzq-NrBCgFCYR0Q">
216          <input type="hidden" name="registerVisitId" value="">
217          <input type="hidden" name="emailOrMobile" value="">
218        </form>
219
220                  <div class="social-login">
221
222            <span>
223              
224      <a href="/login/bind/qq?_target_path=/&amp;inviteCode=" class="social-icon social-qq">
225      <i class="es-icon es-icon-qq"></i>
226    </a>
227  
228
229
230            </span>
231            <div class="line"></div>
232          </div>
233                  </div>
234  </div>
235      </div>
236
237          
238          <div id="footer-fir" class="hidden-xs">
239  <div class="container clearfix">
240
241          <a class="pull-left" href="/"><img src="/files/system/2026/09-17/1838499c1a54682586.png?version=26.3.6"></a>
242    
243    <div class="pull-right">
244      <ul class="site-footer-links">
245		  		  		  		  		  	</ul>
246
247      <p>
248                          课程内容版权均归<a href="/">范士闯数学</a>所有
249                &nbsp;
250                  <a href=https://beian.miit.gov.cn target="_blank">京ICP备10050476号-1</a>
251              </p>
252      <p class="edusoho">    Powered by <a href="http://www.edusoho.com/" target="_blank">EduSoho v26.3.6</a>
253  ©2014-2026
254</p>
255      <!-- 范士闯数学 · 全站排版与视觉基线(DESIGN.md v1.0 · 2026-09-18 · P1-2 圆角与按钮统一) -->
256<style id="fsc-typography">
257:root{
258  --fsc-green:#0F392B; --fsc-gold:#B8893D; --fsc-leaf:#8EC663;
259  --fsc-cream:#FBF8F2; --fsc-ink:#3C3C3C; --fsc-ink-soft:#6B655C;
260  --fsc-body:16px; --fsc-lh:1.75;
261  --fsc-radius:4px; --fsc-radius-sm:4px; --fsc-radius-pill:999px;
262}
263/* ── A. 长文正文(P0-A 已上线,保留)────────────────────────────── */
264.article-content{max-width:720px;margin:0 auto;font-size:var(--fsc-body)!important;
265  line-height:var(--fsc-lh)!important;color:var(--fsc-ink);text-align:left;}
266.article-content p{line-height:var(--fsc-lh)!important;margin:0 0 1.2em!important;}
267.article-content li{line-height:var(--fsc-lh)!important;}
268.article-content h1,.article-content h2,.article-content h3{color:var(--fsc-green);}
269.article-content a{color:var(--fsc-green);text-decoration:underline;
270  text-underline-offset:3px;}
271.course-item .title a,.es-card .title a{color:var(--fsc-ink);}
272.course-item .title a:hover,.es-card .title a:hover{color:var(--fsc-green);}
273
274/* ── B. 圆角统一为 4px(P1-2)─────────────────────────────────── */
275/* 大白话:把全站按钮 / 卡片 / 输入框的"倒角"统一成一个尺寸,
276   避免有的方、有的圆、有的半圆,看着像几个人分别做的。 */
277/* B1. 卡片类容器(本已多是 4px,收紧残余的 2px/3px/6px) */
278.course-item,.classroom-item,.teacher-item,.es-card,.es-box,.panel,.card,
279.profile-card,.item-list li,.class-item,.coupon-item,.vip-card,.media,
280.list-item,.note-item,.question-item,.comment-item,.package-item{
281  border-radius:var(--fsc-radius)!important;
282}
283/* B2. 按钮:统一 4px(覆盖师资页 2px 与首页 0px) */
284.btn,.btn-primary,.btn-default,.btn-success,.btn-info,.btn-warning,
285.es-btn,button,input[type="submit"],input[type="button"],.ant-btn{
286  border-radius:var(--fsc-radius)!important;
287}
288/* B3. 表单控件 */
289.form-control,input[type="text"],input[type="password"],input[type="email"],
290input[type="tel"],input[type="number"],textarea,select,.input-group,
291.search-input,.search-box{
292  border-radius:var(--fsc-radius)!important;
293}
294/* B4. 标签 / 徽章 / 小圆片 —— 保留胶囊形(本就是设计意图) */
295.label,.badge,.tag,.es-tag,.pill,.chip,.status-tag{
296  border-radius:var(--fsc-radius-pill)!important;
297}
298/* B5. 头像与圆形装饰 —— 保持正圆,不要被上面规则波及 */
299.avatar,.user-avatar,.img-circle,.round,.circle,
300[class*="avatar"] img,.teacher-avatar,.header-avatar{
301  border-radius:50%!important;
302}
303/* B6. 下拉 / 浮层 / 弹窗 */
304.dropdown-menu,.modal,.modal-content,.popover,.tooltip-inner,.es-modal,
305.ant-dropdown,.ant-modal-content,.select-menu,.tip-box{
306  border-radius:var(--fsc-radius)!important;
307}
308/* B7. 图片容器(缩略图统一圆角,与卡片一致) */
309.course-item img,.classroom-item img,.es-card img,.cover,.thumb,
310.thumbnail,.banner-img{
311  border-radius:var(--fsc-radius)!important;
312}
313/* B8. 会员页专项(实测残留:2px/7px/8px/16px 混用) */
314.level-item,.level-item__bg,.time-item,.time-item__btn,
315.title-style__item,.buy__btn,.vip-banner,.vip-box{
316  border-radius:var(--fsc-radius)!important;
317}
318
319/* ── C. 主色收敛(P1-3 · 第一步:只动文字色,不动按钮底色)────────── */
320/* 背景:实测全站用的是 EduSoho 自带亮绿 #02b980,
321   而品牌深绿 #0F392B 只在会员页出现 → 全站品牌感断裂。
322   本步只把「文字类」的绿收敛到品牌深绿,按钮底色留到第二步单独看效果。
323   大白话:先把"字"的颜色换成咱家的绿,按钮的"底色"先别动,稳妥点。 */
324/* C1. 正文内链接 */
325.article-content a,.article-content a:visited{color:var(--fsc-green)!important;}
326/* C2. 文章标签 / 分类小标 */
327.btn-tag,.article-tag,.tag-item,.label-tag{color:var(--fsc-green)!important;}
328/* C3. 导航链接(当前选中态 / 悬停)—— 用品牌绿替代亮绿 */
329.navbar-nav > li > a:hover,.navbar-nav > li > a:focus,
330.navbar-nav > .active > a,.nav-link:hover,.nav-link.active{
331  color:var(--fsc-green)!important;
332}
333/* C4. 面包屑 / 次级导航的文字链接 */
334.breadcrumb a,.breadcrumb-item a,.sub-nav a:hover,.crumb a{
335  color:var(--fsc-green)!important;
336}
337/* C5. 分页页码(数字链接)文字色 */
338.pagination > li > a,.pager > li > a,.page-link,.pagination a{
339  color:var(--fsc-green)!important;
340}
341.pagination > .active > a,.page-item.active .page-link{
342  background-color:var(--fsc-green)!important;
343  border-color:var(--fsc-green)!important;color:#fff!important;
344}
345/* C6. 会员页:把品牌金/深绿已有部分保持,仅统一"勾选"符号色 */
346.level-item .fa-check,.time-item .fa-check,.vip-table .fa-check{
347  color:var(--fsc-gold)!important;
348}
349/* C7. 全局标题文字色(h1-h3 未上榜的部分) */
350h1,h2,h3{color:var(--fsc-green);}
351.page-header h1,.section-title,.block-title,.main-title{color:var(--fsc-green);}
352
353/* ── D. 按钮底色收敛(P1-3 第二步 · 方案 C:深绿底 + 品牌色描边)────── */
354/* 决策:范老师 2026-09-18 拍板「C 用 C」。
355   实测依据(WCAG 对比度):亮绿底+白字 = 2.54(❌ 不及格)
356                            深绿底+白字 = 12.80(✅ 完全及格)
357   → 换成深绿底不只是"统一品牌",是**真的更好读**。
358   描边用亮绿 #8EC663(配深绿 6.34)而非品牌金(配深绿仅 4.07,1px 太弱)。 */
359:root{ --fsc-btn:#0F392B; --fsc-btn-hover:#155C43; --fsc-btn-line:#8EC663; }
360
361/* D1. 主按钮:深绿底 + 亮绿描边 + 白字 */
362.btn-primary,.btn-success,.btn-info,.btn-lg,.btn-sm,
363.es-btn-primary,.buy__btn,.time-item__btn{
364  background-color:var(--fsc-btn)!important;
365  border:1px solid var(--fsc-btn-line)!important;
366  color:#fff!important;
367  box-shadow:0 1px 2px rgba(15,57,43,.18)!important;
368}
369.btn-primary:hover,.btn-success:hover,.btn-info:hover,.es-btn-primary:hover,
370.buy__btn:hover,.time-item__btn:hover,
371.btn-primary:focus,.btn-success:focus,.btn-info:focus{
372  background-color:var(--fsc-btn-hover)!important;
373  border-color:var(--fsc-leaf)!important;
374  color:#fff!important;
375}
376/* D2. 顶部搜索按钮(实测:`<button class="btn"><span class="iconfont icon-sousuo1">`,
377   父元素 `.navbar-form`)→ 深绿底 + 亮绿描边 + 白图标
378   ⚠️ 必须用 :not() 排除客服条,否则会误伤「加微信」唯一通道 */
379.navbar-form .btn,button.btn[type="submit"]:not([class*="consult"]){
380  background-color:var(--fsc-btn)!important;
381  border:1px solid var(--fsc-btn-line)!important;
382  color:#fff!important;
383}
384.navbar-form .btn:hover,button.btn[type="submit"]:not([class*="consult"]):hover{
385  background-color:var(--fsc-btn-hover)!important;
386}
387/* D3. 下拉切换按钮「会员课程」→ 实测是**无边框透明底灰字**的设计,
388   不要给它加边框(加了反而变丑)。只统一圆角,保持原样。 */
389.btn.dropdown-toggle,.dropdown-toggle{
390  border-radius:var(--fsc-radius)!important;
391}
392/* D4. 会员页价格按钮:橙色 #ffa51f 配白字仅 1.97(❌ 严重不及格)
393   → 收敛到品牌深绿,保留金色描边做会员专属区分。
394   ⚠️ 必须避开 .btn-consult-warning(客服条也含 .btn-warning 前缀类名) */
395.btn-warning:not(.btn-consult-warning){
396  background-color:var(--fsc-btn)!important;
397  border:1px solid var(--fsc-gold)!important;
398  color:#fff!important;
399  box-shadow:0 1px 2px rgba(15,57,43,.18)!important;
400}
401.btn-warning:not(.btn-consult-warning):hover{
402  background-color:var(--fsc-btn-hover)!important;
403  border-color:var(--fsc-gold)!important;
404  color:#fff!important;
405}
406/* D5. 🔴🔴 保护条:客服浮动条 = 全站"加微信"唯一通道,绝对不能被覆盖。
407   放在最后 + 显式声明,确保优先级最高。 */
408.btn-consult-warning,.float-consult .btn,
409.float-consult-phone-btn,.float-consult-weixin-btn,.float-consult-email-btn,
410[class*="float-consult"]{
411  background-color:rgb(255,165,31)!important;
412  border:1px solid rgb(238,148,14)!important;
413  color:#fff!important;
414  border-radius:var(--fsc-radius)!important;
415}
416/* D6. 分页当前页(与按钮同色系) */
417.pagination > .active > a,.page-item.active .page-link{
418  background-color:var(--fsc-btn)!important;
419  border-color:var(--fsc-btn)!important;
420}
421
422/* ── E. 导航条深绿化(P1-3 收尾 · 与按钮呼应)────────────────────── */
423/* 实测改前:`.menu-sec` 是 1440×40 横贯全宽的亮绿实心色块(视觉最重的一块),
424   按钮已改深绿后,导航条仍是亮绿会形成明显割裂。
425   配比:深绿底 #0F392B + 米白字 #FBF8F2(对比度 12.08 ✅)。 */
426.menu-sec{
427  background-color:var(--fsc-green)!important;
428  border-color:var(--fsc-green)!important;
429}
430.menu-sec a,.menu-sec .nav-link,.menu-sec li > a{
431  color:var(--fsc-cream)!important;
432}
433.menu-sec a:hover,.menu-sec a:focus,.menu-sec a.active,
434.menu-sec .active > a,.menu-sec .nav-link:hover,.menu-sec .nav-link.active{
435  color:var(--fsc-leaf)!important;
436  background-color:transparent!important;
437}
438/* E2. 「最新 / 最热 / 推荐」筛选条选中态
439   ⚠️ 实测:全站仅 1 个 `a.active`,祖先链 `ul.nav.nav-sort < div.es-filter.pc-es-filter`。
440   用精确祖先限定,绝不用宽泛的 `li > a.active`(会误伤全站列表链接)。 */
441.es-filter .nav-sort > li > a.active,
442.es-filter .nav-sort > li.active > a,
443.pc-es-filter .nav > li > a.active{
444  background-color:var(--fsc-green)!important;
445  color:#fff!important;
446  border-color:var(--fsc-green)!important;
447}
448/* E3. 分类导航(「全部/小学奥数/小学数学/初中数学」)选中态 */
449.cat-nav a.active,.category-list a.active,.nav-tabs > li.active > a{
450  color:var(--fsc-green)!important;
451  border-color:var(--fsc-green)!important;
452}
453/* E4. 顶部主导航(白底那一层)hover 也统一 */
454.navbar-nav > li > a:hover,.navbar-nav li.open > a{
455  color:var(--fsc-green)!important;
456}
457/* E5. 课程卡片悬停浮层(首页 `.mask`,实测 `opacity:0` 鼠标悬停才显示)
458   → 底色收敛到品牌深绿(原本就是深色遮罩的设计意图)。
459   ⚠️ 该浮层内容含教师昵称"土豆",属 IP 问题,另行处理,此处只改底色。 */
460.mask{background-color:rgba(15,57,43,.92)!important;}
461
462/* ── F. 首页区块标题改写(2026-09-18 范老师工单)─────────────────── */
463/* 工单:首页「学通班级」→「班级」;「学通畅学年卡」→「畅学年卡」。
464   背景:实测这两个 `<h2>` 是 **graceful 主题模板写死的**,
465        4 个候选后台入口(/setting/theme、/theme、/block、/sett
465ing/homepage)全 404,
466        `/admin/v2/setting/theme` 里也无对应字段 → **后台改不了**。
467   方案:用 CSS 视觉覆盖(原文 `font-size:0` 隐藏 + `::after` 注入新文字),
468        不改模板、可一键回滚。
469   ⚠️ 已知局限:HTML 里的**真实文字仍是旧的**——屏幕阅读器与搜索引擎读到的还是原文。
470        仅"视觉"变了。对区块标题这种非核心内容可接受。
471   🔴 关键坑:「推荐课程」和「学通班级」**共用 `.es-box.es-course > h2`**!
472        必须用 `:has(> ul.home-class-list)` 精确区分,否则会把「推荐课程」也改成「班级」。 */
473.es-box:has(> ul.home-class-list) > h2{font-size:0!important;}
474.es-box:has(> ul.home-class-list) > h2::after{
475  content:"班级";
476  font-size:24px; color:var(--fsc-green); font-weight:600; line-height:1.2;
477}
478.the-vip-content > h2{font-size:0!important;}
479.the-vip-content > h2::after{
480  content:"畅学年卡";
481  font-size:24px; color:var(--fsc-green); font-weight:600; line-height:1.2;
482}
483
484/* ── G. 文章正文排版修复(2026-09-18 范老师工单「页面排版不行」)───── */
485/* 实测改前(Playwright 读渲染后真实值,article/256):
486     .article-content 容器 = 16px / lh 28px   ← 容器是对的
487     .article-content p    = **13px** / lh 22.75px  ← 🔴 被主题压到 13px
488     .article-content h3   = 18px / **lh 19.8px**   ← 🔴 行高比字号还小,字叠在一起
489   根因:正文是裸 <p> 无内联样式,前台吃 graceful 主题默认样式。
490   大白话:外框穿着 16 码的鞋,里面塞了只 13 码的脚。
491   预演实测:13px→16px / lh 22.75→28 / 小标题 lh 19.8→28.5 / 段距 15.6→19.2px */
492.article-content p,.article-content li,.article-content div{
493  font-size:16px!important; line-height:1.8!important;
494  margin:0 0 1.1em!important; color:var(--fsc-ink)!important;
495}
496.article-content h2{font-size:21px!important; line-height:1.5!important;
497  margin:32px 0 14px!important; color:var(--fsc-green)!important;}
498.article-content h3{font-size:19px!important; line-height:1.5!important;
499  margin:28px 0 12px!important; color:var(--fsc-green)!important;}
500.article-content h4{font-size:17px!important; line-height:1.5!important;
501  margin:22px 0 10px!important; color:var(--fsc-green)!important;}
502.article-content strong,.article-content b{color:var(--fsc-green)!important;}
503.article-content ul,.article-content ol{margin:0 0 1.1em 1.5em!important;padding:0;}
504.article-content ul li,.article-content ol li{margin:0 0 .5em!important;}
505.article-content img{max-width:100%;height:auto;
506  border-radius:var(--fsc-radius)!important;}
507.article-content blockquote{margin:0 0 1.1em!important;padding:12px 16px;
508  border-left:3px solid var(--fsc-leaf);background:var(--fsc-cream);
509  color:var(--fsc-ink-soft)!important;}
510.article-content hr{border:0;border-top:1px solid #e7e0d2;margin:28px 0;}
511
512/* ── H. 文章封面图兜底(2026-09-18 范老师工单「图片显示不正常」)──── */
513/* 实测根因:默认封面 URL `https://www.xuetong.com/assets/img/default/` 返回 **HTTP 404**
514   (返回 6225 字节的 404 页面),166/186 篇文章封面全指向它 →
515   前台渲染成破图,或被压成 **16px 宽的细长条**(截图里竖排文字即此故)。
516   ⚠️ 诚实说明:CSS **无法检测 404**,纯 CSS 只能处理"空 src"和尺寸失控。
517      真正的 404 破图必须靠"给文章补封面图"根治,本段只是安全网。 */
518/* H1. 尺寸兜底:无论有没有图,都别出现 16px 细长条 */
519.article-item img,.media img,.article-item .cover,
520.media-left img,.thumb,.thumbnail{
521  max-width:100%!important;
522  height:auto!important;
523  min-width:0!important;
524  object-fit:cover!important;
525}
526/* H2. 空 src / 无 src 的图直接隐藏,避免破图轮廓 */
527img[src=""],img:not([src]){display:none!important;}
528/* H3. 🔴 实测真实结构(2026-09-18):
529   `div.media > div.media-left > a > img.thumb-img[src="/files/ "]`
530   —— 不只是图破了,**父容器 div.media-left 本身被压成 16px 宽**,
531     于是图片被挤成 16×170 的细长条,链接文字只能竖排换行。
532   → 必须同时撑开 **父容器** 与 **img**,两层一起修,只改 img 没用。 */
533.article-item .media-left,.article-item .media-left a{
534  display:block!important;
535  width:120px!important;min-width:120px!important;max-width:120px!important;
536  height:80px!important;overflow:hidden!important;
537  border-radius:var(--fsc-radius)!important;
538  background-color:var(--fsc-cream);
539}
540.article-item .media-left img,.article-item img.thumb-img{
541  display:block!important;
542  width:120px!important;min-width:120px!important;max-width:120px!important;
543  height:80px!important;min-height:80px!important;max-height:80px!important;
544  object-fit:cover!important;object-position:center!important;
545}
546/* H4. 列表正文列左移,避免被 120px 封面挤压 */
547.article-item .media-body,.article-item .media-right{min-width:0!important;}
548
549/* ── I. 文章页右侧栏瘦身 + 正文加宽(2026-09-18 范老师拍板)───────── */
550/* 实测:正文 `.es-section.article-content` 只有 **720px**(x=167),
551   右侧栏 363px 占满,中间大片空白 → 信息密度极低。
552   右侧栏 4 块真实 class(实测):hot-article(热门焦点) / hot-tag(热门标签) /
553   hot-comments(热门评论) / recommend-article(编辑推荐),四块 **li 条目数全为 0
553**
554   (即"热门评论"当前是空的,"热门标签"是旧站关键词)。
555   决策:只留「热门焦点」(=站内导航,真有用),其余三块隐藏;正文加宽到 840px。 */
556.article-page .hot-tag,.article-page .hot-comments,
557.hot-tag,.hot-comments{display:none!important;}
558/* 正文容器加宽(含列表/详情通用) */
559.es-section.article-content{max-width:840px!important;}
560/* 兼容其它页面上的同款容器 */
561.article-content{max-width:840px!important;}
562/* 右侧栏保持原宽,但顶部对齐,避免留白 */
563.panel.hot-article,.panel.recommend-article{margin-bottom:16px!important;}
564</style>
565
566<!-- FSC LIVE NAV HIGHLIGHT v1 -->
567<style id="fsc-live-nav">
568/* 导航「范士闯直播课」高亮 —— 暖金底块(对齐 DESIGN.md:暖金=成交动作) */
569.es-header-nav a[href="/page/liveclass"],
570.navbar-nav a[href="/page/liveclass"],
571.nav>li>a[href="/page/liveclass"],
572.top-nav a[href="/page/liveclass"]{
573  background:#B8893D!important;
574  color:#FFFFFF!important;
575  font-weight:500!important;
576  border-radius:4px 4px 0 0!important;
577  padding-left:15px!important;
578  padding-right:15px!important;
579}
580.es-header-nav a[href="/page/liveclass"]:hover,
581.navbar-nav a[href="/page/liveclass"]:hover,
582.nav>li>a[href="/page/liveclass"]:hover,
583.top-nav a[href="/page/liveclass"]:hover{
584  background:#9E7433!important;
585  color:#FFFFFF!important;
586}
587.es-header-nav a[href="/page/liveclass"]::before,
588.navbar-nav a[href="/page/liveclass"]::before,
589.nav>li>a[href="/page/liveclass"]::before,
590.top-nav a[href="/page/liveclass"]::before{
591  content:"\25CF";
592  color:#FFE9C4;
593  font-size:9px;
594  margin-right:6px;
595  vertical-align:2px;
596}
597@media(max-width:767px){
598  .es-header-nav a[href="/page/liveclass"]::before,
599  .navbar-nav a[href="/page/liveclass"]::before,
600  .nav>li>a[href="/page/liveclass"]::before,
601  .top-nav a[href="/page/liveclass"]::before{vertical-align:middle;}
602}
603</style>
604
605<!-- FSC DAOXUE NAV HIGHLIGHT v2 -->
606<style id="fsc-daoxue-nav">
607/* 导航「导学」高亮 v2(2026-09-19)—— 墨青实底 + 米白字 + 暖金细边
608   与「范士闯直播课」暖金实底块 同形状 / 同高度 / 同字重,靠色相(青 ↔ 金)区分。
609   v1 曾用米白实底 #FBF8F2:在墨绿导航条上过亮过跳、与金块不成比例 → 改为中间调。
610   对比度:米白字 vs #35786A = 4.90:1(≥4.5 达标) */
611.es-header-nav a[href="/page/daoxue"],
612.navbar-nav a[href="/page/daoxue"],
613.nav>li>a[href="/page/daoxue"],
614.top-nav a[href="/page/daoxue"]{
615  background:#35786A!important;
616  color:#FBF8F2!important;
617  font-weight:500!important;
618  border-radius:4px 4px 0 0!important;
619  box-shadow:inset 0 0 0 1px #B8893D!important;
620  padding-left:15px!important;
621  padding-right:15px!important;
622}
623.es-header-nav a[href="/page/daoxue"]:hover,
624.navbar-nav a[href="/page/daoxue"]:hover,
625.nav>li>a[href="/page/daoxue"]:hover,
626.top-nav a[href="/page/daoxue"]:hover{
627  background:#3E8B7B!important;
628  color:#FFFFFF!important;
629}
630.es-header-nav a[href="/page/daoxue"]::before,
631.navbar-nav a[href="/page/daoxue"]::before,
632.nav>li>a[href="/page/daoxue"]::before,
633.top-nav a[href="/page/daoxue"]::before{
634  content:"\25AA";
635  color:#FBF8F2;
636  font-size:9px;
637  margin-right:6px;
638  vertical-align:2px;
639}
640@media(max-width:767px){
641  .es-header-nav a[href="/page/daoxue"]::before,
642  .navbar-nav a[href="/page/daoxue"]::before,
643  .nav>li>a[href="/page/daoxue"]::before,
644  .top-nav a[href="/page/daoxue"]::before{vertical-align:middle;}
645}
646</style>
647</p></span></button>
648
649<!-- FSC LAZYLOAD FIX v1 · 2026-09-19
650     问题:graceful 主题的图片懒加载用 echo.js(打包在 app/js/main.js 内,window.echo)。
651           echo 的 render() 被 250ms debounce 包住 —— 只在"停止滚动 250ms 后"才跑一次,
652           期间划过的整行卡片永远不换图,src 停在 480×270 纯灰占位图
653           /assets/img/default/lazyload_course.png(实测 rgb(224,224,224))。
654     现状:课程列表页首屏 8/20 真图;触控板连续滑 / 拖滚动条跳到底 → 第 3 行 4 张永久灰框。
655     本段:把 data-echo 交给浏览器原生 loading="lazy" 接管,彻底绕开 echo.js 的 debounce。
656     影响面:全站所有用了 data-echo 的图;只把"灰占位"换成"真图",不改变任何布局。
657     回退:删掉本段(或 xt_site_css.py revert)即恢复原状。 -->
658<script id="fsc-lazyload-fix">
659(function(){
660  if (window.__fscLazyFix) { return; }
661  window.__fscLazyFix = 1;
662  function fix(){
663    var list = document.querySelectorAll('img[data-echo]');
664    for (var i = 0; i < list.length; i++) {
665      var el  = list[i];
666      var src = el.getAttribute('data-echo');
667      if (!src) { continue; }
668      el.setAttribute('loading', 'lazy');
669      el.setAttribute('src', src);
670      el.removeAttribute('data-echo');
671    }
672  }
673  function boot(){ fix(); }
674  if (document.readyState === 'loading') {
675    document.addEventListener('DOMContentLoaded', boot);
676  } else { boot(); }
677  window.addEventListener('load', boot);
678  if (window.MutationObserver && document.body) {
679    new MutationObserver(fix).observe(document.body, {childList: true, subtree: true});
680  }
681})();
682</script>
682
683
684<!-- FSC TEXT FIX v1 · 2026-09-19 (指令卡 003-R1)
685     目的:把 6 处「导航一个名、页面另一个名」和自夸词「精品」清掉。
686
687     A1  班级页页头      「精品班列表」   → 「班级」        (与导航名一致)
688     A2  年卡页浏览器标签「会员专区 - 会员专区」→「畅学年卡」(去重复 + 与导航一致)
689     B2  班级页会员筛选  「会员精品班」   → 「会员班级」
690     B3  班级页免费筛选  「免费精品班」   → 「免费班级」
691     B4  课程页按钮      「查看精品班」   → 「查看班级」
692     B5b 年卡页区块标题  「会员精品班(N)」→「会员班级(N)」
693
694     为什么必须走这里:这 6 处文字全部写死在 graceful 主题服务端模板里,
695           后台没有配置口(12 个候选入口逐字段核过,见指令卡 003 探查报告)。
696           唯一可改通道 = 站点设置 analytics(本段),可一键退回。
697
698     范围与安全性:只改文本节点(text node),不动元素结构、不动链接、不动布局。
699           白名单 4 个精确词组,不具备泛化匹配能力。
700           上线前已核对:166 门课程 + 166 个课程计划 + 10 个班级 + 71 篇文章正文
701           + 站点设置全字段 + 导航名 —— 0 处冲突,不会误伤任何真实内容。
702
703     回退:删掉本段 → xt_site_css.py apply;或直接 xt_site_css.py revert 一键还原。 -->
704<script id="fsc-text-fix">
705(function () {
706  if (window.__fscTextFix) { return; }
707  window.__fscTextFix = 1;
708
709  /* 白名单:只认这 4 个精确词组,改完即止(幂等,重复跑不会二次变形) */
710  var MAP = {
711    '精品班列表': '班级',
712    '查看精品班': '查看班级',
713    '免费精品班': '免费班级',
714    '会员精品班': '会员班级'
715  };
716  var RE = new RegExp(Object.keys(MAP).join('|'), 'g');
717
718  function swap(t) {
719    return t.replace(RE, function (m) { return MAP[m]; });
720  }
721
722  /* 只遍历「含『精品班』三个字的文本节点」,其余一律跳过 —— 便宜且精准 */
723  function walk(root) {
724    if (!root) { return; }
725    var it = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
726      acceptNode: function (n) {
727        var p = n.parentNode;
728        if (!p) { return NodeFilter.FILTER_REJECT; }
729        var tag = p.nodeName;
730        if (tag === 'SCRIPT' || tag === 'STYLE' ||
731            tag === 'NOSCRIPT' || tag === 'TEXTAREA') {
732          return NodeFilter.FILTER_REJECT;
733        }
734        return (n.nodeValue && n.nodeValue.indexOf('精品班') >= 0)
735          ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
736      }
737    }, false);
738    var list = [], n;
739    while ((n = it.nextNode())) { list.push(n); }
740    for (var i = 0; i < list.length; i++) {
741      var v = swap(list[i].nodeValue);
742      if (v !== list[i].nodeValue) { list[i].nodeValue = v; }
743    }
744  }
745
746  /* A2:年卡页浏览器标签。保留站点统一的「 - 站名 - 标语 - Powered By EduSoho」尾巴,
747     只把开头重复的「会员专区 - 会员专区」换成「畅学年卡」。 */
748  function fixTitle() {
749    if (location.pathname.replace(/\/+$/, '') !== '/vip') { return; }
750    var m = document.title.match(/^会员专区(\s*[-–—]\s*会员专区)?(\s*[-–—]\s*[\s\S]*)$/);
751    if (m) { document.title = '畅学年卡' + m[2]; }
752    var og = document.querySelector('meta[property="og:title"]');
753    if (og) {
754      var c = og.getAttribute('content') || '';
755      if (c.indexOf('会员专区') >= 0) {
756        og.setAttribute('content', c.replace(/会员专区/g, '畅学年卡'));
757      }
758    }
759  }
760
761  var timer = null;
762  function run() {
763    clearTimeout(timer);
764    timer = setTimeout(function () { walk(document.body); fixTitle(); }, 60);
765  }
766
767  if (document.readyState === 'loading') {
768    document.addEventListener('DOMContentLoaded', run);
769  } else { run(); }
770  window.addEventListener('load', run);
771
772  /* 兜底:换图/翻页等异步插入的节点也覆盖到。
773     只监听 childList,不监听 characterData —— 否则会被自己的改动触发死循环。 */
774  document.addEventListener('DOMContentLoaded', function () {
775    if (!document.body || !window.MutationObserver) { return; }
776    new MutationObserver(run).observe(document.body, { childList: true, subtree: true });
777    run();
778  });
779})();
780</script>
780
781<!-- 范士闯数学 · 首页首屏优化 fsc-home-firstscreen(指令卡004 · 2026-09-19) -->
782<style id="fsc-home-firstscreen">
783/* ============================================================================
784   范士闯数学 · 学通在线 首页首屏「右轻左重」布局优化
785   指令卡 004 · 2026-09-19 · workbuddy 产出
786   ----------------------------------------------------------------------------
787   作用域:body.homepage(仅首页)· 桌面端 ≥992px
788   原则:  只追加、纯 CSS、不改主题代码、不改后台内容、可一键还原
789   品牌色:深森林绿 #0F392B / 莫兰迪绿 #3A6B55 / 暖金 #B8893D / 米白 #FBF8F2
790   ----------------------------------------------------------------------------
791   【实测定位到的三个真实问题】
792     ① 右栏整体只有 536px 高,左栏 2313px —— 右栏底部往下约 1777px 是空白带
793     ② 「畅学年卡」卡片里图片容器被模板写死为 div.col-md-4.col-xs-6,
794        在 363px 宽的卡片里只剩 117px → 图片被压成 97×127,右侧 235px 全空
795        (这就是「右轻」的根因;原图 1040×584,放大后无损)
796     ③ 「付费课程」Top3 序号是裸露的 #FF5D42 数字,视觉权重弱
797   ============================================================================ */
798
799
800/* ==========================================================================
801   第 1 组 · 两栏等高(为右栏滚动跟随提供高度基础)
802   Bootstrap3 栅格原本靠 float,右列高度只等于自身内容高,无法做长距离吸附。
803   改为 flex 等高(仅首页这一个 .row),左右列宽度按原栅格比例复刻,视觉零变化。
804   ========================================================================== */
805@media (min-width: 992px) {
806
807  body.homepage .es-wrap > .container > .row {
808    display: -webkit-box;
809    display: -ms-flexbox;
810    display: flex;
811    -ms-flex-wrap: nowrap;
812        flex-wrap: nowrap;
813    -webkit-box-align: stretch;
814        -ms-flex-align: stretch;
815            align-items: stretch;
816  }
817
818  /* 左列:749px 内容宽,完全不动 */
819  body.homepage .es-wrap > .container > .row > .main.col-md-8 {
820    -webkit-box-flex: 0;
821        -ms-flex: 0 0 66.666667%;
822            flex: 0 0 66.666667%;
823    width: 66.666667%;
824    max-width: 66.666667%;
825    float: none;
826  }
827
828  /* 右列:387px,拉高到与左列等高,内部改为纵向 flex */
829  body.homepage .es-wrap > .container > .row > .col-md-4 {
830    -webkit-box-flex: 0;
831        -ms-flex: 0 0 33.333333%;
832            flex: 0 0 33.333333%;
833    width: 33.333333%;
834    max-width: 33.333333%;
835    float: none;
836    display: -webkit-box;
837    display: -ms-flexbox;
838    display: flex;
839    -webkit-box-orient: vertical;
840        -ms-flex-direction: column;
841            flex-direction: column;
842  }
843
844
845  /* ======================================================================
846     第 2 组 · 右栏两卡片滚动跟随 —— 根治 1777px 空白带
847     ①「付费课程」吸附在视口顶 20px 处
848     ②「畅学年卡」吸附在 280px 处(=20 + 付费卡片 230 + 30 间距,保持原间距)
849     两者高度合计 536px,视口 900px 内不重叠、不遮内容。
850     整页最大滚动量 1770px < 推走阈值 1954px → 全程吸附,不会被底部推走。
851     ====================================================================== */
852  body.homepage .es-wrap > .container > .row > .col-md-4 > .es-box {
853    position: -webkit-sticky;
854    position: sticky;
855    z-index: 5;
856    -ms-flex-negative: 0;
857        flex-shrink: 0;
858  }
859  body.homepage .es-wrap > .container > .row > .col-md-4 > .es-box:nth-child(1) { top: 20px; }
860  body.homepage .es-wrap > .container > .row > .col-md-4 > .es-box:nth-child(2) { top: 280px; }
861
862
863  /* ======================================================================
864     第 3 组 ·【核心修复】畅学年卡卡片
865     模板把图片容器写死成 col-md-4.col-xs-6(33%),在卡片内只剩 117px。
866     覆盖为 100% 宽 → 图片 97×127 放大到 332×187(原图 1040×584,等比无损)。
867     卡片高度随之 246px → 约 310px,与左侧轮播 365px 形成合理配重。
868     ====================================================================== */
869  body.homepage .the-vip-content li.row > [class*="col-"] {
870    width: 100%;
871    max-width: 100%;
872    float: none;
873    -ms-flex-preferred-size: 100%;
874        flex-basis: 100%;
875  }
876  body.homepage .the-vip-content img.vip-card {
877    width: 100%;
878    height: auto;
879    border-radius: 8px;
880    display: block;
881  }
882
883  /* 卡片高度与内部节奏(不拉伸图片,只补足留白) */
884  body.homepage .row > .col-md-4 > .the-vip-content {
885    min-height: 310px;
886    display: -webkit-box;
887    display: -ms-flexbox;
888    display: flex;
889    -webkit-box-orient: vertical;
890        -ms-flex-direction: column;
891            flex-direction: column;
892  }
893  body.homepage .row > .col-md-4 > .the-vip-content > ul {
894    -webkit-box-flex: 1;
895        -ms-flex: 1 1 auto;
896            flex: 1 1 auto;
897  }
898  body.homepage .the-vip-content li.row {
899    margin-bottom: 30px;
900  }
901
902
903  /* ======================================================================
904     第 4 组 · 付费课程 Top3:序号色块(纯 CSS,无图片、无 HTML 改动)
905     原为 40×40 的 float:left 数字(#FF5D42,24px)。加圆角色块 + 白字,
906     第 1 名用暖金、第 2 名莫兰迪绿、第 3 名深森林绿,形成梯度权重。
907     色块收到 36px,避免与下方「XX人报名」贴得太紧(原 40px 会占满整行高度)。
908     ====================================================================== */
909  body.homepage #kechen-list .num-warn {
910    width: 36px;
911    height: 36px;
912    line-height: 36px;
913    margin: 3px 6px 3px 0;
914    text-align: center;
915    border-radius: 8px;
916    color: #fff !important;
917    font-size: 19px;
918    font-weight: 700;
919    -webkit-box-sizing: border-box;
920            box-sizing: border-box;
921  }
922  body.homepage #kechen-list .course-row-list li:nth-child(1) .num-warn { background: #B8893D; }
923  body.homepage #kechen-list .course-row-list li:nth-child(2) .num-warn { background: #3A6B55; }
924  body.homepage #kechen-list .course-row-list li:nth-child(3) .num-warn { background: #0F392B; }
925
926  /* 课程名加粗一档,报名人数退到次要层级 */
927  body.homepage #kechen-list h3 {
928    font-weight: 600;
929    color: #2B2B2B;
930  }
931}
932
933
934/* ==========================================================================
935   第 5 组 · 加微信浮动条
936   实测:它本就 fixed 贴屏幕右缘、视口垂直居中,从未被空白区遮挡。
937   但宽屏(≥1320px)下页面内容区居中、两侧留白很宽,浮动条孤悬屏幕边缘。
938   → 宽屏时把它对齐到内容区右侧 24px 处(仍在内容区之外,不遮挡任何内容),
939     并加投影让它在米白底上更醒目。窄屏维持原样。
940   注:离开屏幕边缘后,右边直角会显得像被切断 → 改为四角等圆角。
941   ========================================================================== */
942@media (min-width: 1320px) {
943  body.homepage .float-consult {
944    right: auto;
945    left: calc(50% + 580px + 24px);
946    border-radius: 10px;
947    -webkit-filter: drop-shadow(0 6px 16px rgba(15, 57, 43, .22));
948            filter: drop-shadow(0 6px 16px rgba(15, 57, 43, .22));
949  }
950}
951
952@media (min-width: 992px) {
953  body.homepage .float-consult .btn {
954    -webkit-transition: -webkit-transform .18s ease;
955    transition: transform .18s ease;
956  }
957  body.homepage .float-consult .btn:hover {
958    -webkit-transform: translateX(-3px);
959            transform: translateX(-3px);
960  }
961}
962
963/* ============================================================================
964   未触碰清单(有意为之,避免误伤)
965     · 左列轮播 .es-poster:一动没动
966     · 页面总宽 / .container 宽度:一动没动
967     · 移动端 <992px:全部规则在 @media 内,布局与原来完全一致
968     · 年卡价格、权益、按钮文案:一个字没改(属后台内容,CSS 无权也不该改)
969   ============================================================================ */
970
971</style>
972<!-- 范士闯数学 · 文章列表页后台提示条清除 fsc-article-adminbar-hide(指令卡005 · 2026-09-19) -->
973<style id="fsc-article-adminbar-hide">
974/* ============================================================================
975   范士闯数学 · 文章列表页「后台配置提示条」清除
976   指令卡 005 · 2026-09-19 · 纯 CSS,可一键还原
977   ----------------------------------------------------------------------------
978   目标元素(/article 顶部):
979     <div class="alert alert-warning">
980       头条大图轮播功能需先在后台资讯管理页面设置缩略图以及添加头条属性
981       <a class="mls alert-link" href="/admin/v2/article">前往设置</a>
982     </div>
983
984   实测结论(2026-09-19,游客态 vs 管理员态 双份原始 HTML 比对):
985     · 游客态 /article       —— 0 处。前台家长/访客本来就看不到这条提示
986     · 管理员登录态 /article —— 1 处。EduSoho 模板按「当前登录身份」输出
987     · 出现范围:仅 /article 首页;分类页 / 首页 / 课程列表 / 班级广场 / 年卡页 均为 0
988     · 桌面 1140×54 @y=253;手机端 370×76 —— 端到端都要处理
989     · 全页只有这 1 个 .alert,没有成功/错误提示条,不存在误伤对象
990
991   选择器取值理由(三级收口,越靠后越严):
992     body.artcile-list-page                  ← ① 页面级收口:只在这一个页面生效
993     #content-container >                     ← ② 必须是内容容器的「直接子级」
994     .es-tabs.article-list-header +           ← ③ 必须紧跟在「文章列表页签」之后
995     .alert.alert-warning                     ← ④ 且必须是警告型提示条
996     (注:artcile-list-page 是 graceful 主题里本身拼错的类名,照抄原文,不要"修正")
997     分类页的 body 类名是 artcile-cat-page,与本规则天然隔离。
998
999   不会误伤的原因:EduSoho 的 flash 成功/错误提示不会渲染å
999Ϭ
1000   「页签之后、内容容器直接子级」这个位置上。已实测该选择器命中数 = 1,且命中的就是本条。
1001   ========================================================================== */
1002
1003body.artcile-list-page #content-container > .es-tabs.article-list-header + .alert.alert-warning {
1004  display: none !important;
1005}
1006
1007</style>
1008
1009<!-- 范士闯数学 · 浮动咨询条联系方式更新(2026-09-19 · v2全局替换+延迟200ms) -->
1010<script>
1011(function(){
1012  function updateContact(){
1013    var phoneBox=document.getElementById('consult-phone-content');
1014    if(phoneBox){phoneBox.innerHTML=phoneBox.innerHTML.replace(/13167306058/g,'13601275360');}
1015    var emailBox=document.getElementById('consult-email-content');
1016    if(emailBox){emailBox.innerHTML=emailBox.innerHTML.replace(/[email protected]/g,'[email protected]');}
1017  }
1018  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',function(){setTimeout(updateContact,200);});}
1019  else{setTimeout(updateContact,200);}
1020})();
1021</script>
1021
1022<!-- 范士闯数学 · 首页推荐课程卡片HTML标签碎片清理 fsc-course-card-clean(指令卡006 · 2026-09-19) -->
1023<style id="fsc-course-card-clean">
1024/* ======================================================================
1025   学通在线 · 首页「推荐课程」卡片 hover 遮罩里的 HTML 标签碎片清理
1026   指令卡 006 · 2026-09-19 · 范士闯数学
1027   ----------------------------------------------------------------------
1028   现象:鼠标移到首页「推荐课程」卡片上时,深绿色遮罩里出现两行乱码:
1029             <p><span style="color:#E53333;">
1030             <st...
1031   看起来像网站出 bug。
1032   ======================================================================
1033
1034   【根因】这不是课程数据脏 —— 是主题模板里写死的一段文本
1035   ----------------------------------------------------------------------
1036   实测证据链:
1037
1038     ① 首页 6 处文字【完全相同】,都是 38 字符:
1039          <p><span style="color:#E53333;"><st...
1040     ② 这 6 门课后台的字段【各不相同】:
1041          title    6 个值全不同
1042          subtitle 6 个值全不同(19/19/17/24/25/14 字)
1043          summary  6 个值全不同(1297/1335/1008/1633/1687/1024 字)
1044     ③ 这 6 门课的后台页面里搜 `E53333` → 0 次
1045     ④ 课程管理全部子页(base / courses / question / testpaper / files)
1046        搜 `E53333` → 0 次
1047     ⑤ 全站装修页 / 组件页 / 站点设置页搜 `E53333` → 0 次
1048
1049   → 结论:这段文字既不是「课程简介」也不是「课程副标题」,
1050     而是主题模板里写死的一段「已转义的 HTML 源码文本」,
1051     被模板按固定长度(35 字符 + 省略号)截断后当纯文本输出。
1052     后台没有任何字段可以改它,模板文件也不在本站可编辑范围内。
1053
1054   【为什么是转义形态】
1055   HTML 里写的是 `&lt;p&gt;&lt;span style="color:#E53333;"&gt;&lt;st...`
1056   —— 尖括号被转义、但双引号没有。
1057   若是模板引擎自动转义,双引号会一起变成 `&quot;`。
1058   所以这段值是「存进来时就带着 &lt; 实体」的,被原样输出。
1059
1060   ======================================================================
1061   【做法】只隐藏这一个元素:不动模板、不动数据、不动其他页面
1062   ----------------------------------------------------------------------
1063   收口四层(缺一不可):
1064
1065     body.homepage                → 只在首页生效
1066     #content-container           → 只在正文区
1067     .es-box.es-course            → 只在「推荐课程」区块
1068     li.es-course-list            → 只在该区块的课程卡片
1069     .mask > a > p                → 只在该卡片 hover 遮罩里的那一行
1070
1071   实测:`li.es-course-list` 在首页正好命中 6 个(就是这 6 张卡片),
1072        `.mask > a > p` 正好命中 6 处(就是这 6 行碎屑)。无误伤对象。
1073
1074   ⚠️ 注意别写裸 `.es-box.es-course > h2` 之类 —— 「学通班级」区块
1075      与「推荐课程」共用 `.es-box.es-course` 这个类名,宽泛选择器会串味。
1076      本段用 `li.es-course-list` 收口,已实测不命中班级卡片。
1077
1078   ======================================================================
1079   【可见性说明】这条很重要,决定了问题的真实严重程度
1080   ----------------------------------------------------------------------
1081   `.mask` 的样式是 position:absolute + opacity:0,只有鼠标悬停到卡片上
1082   才 opacity:1 显示。
1083
1084     · 桌面端:鼠标移上去才看得到(已实拍确认,确实难看)
1085     · 手机 / 平板:没有 hover 状态,永远看不到
1086
1087   所以它是「鼠标悬停才露出的瑕疵」,不是页面一打开就有的硬伤。
1088
1089   ======================================================================
1090   【影响面】已全站扫描 11 个页面,只有首页这 6 处
1091   ----------------------------------------------------------------------
1092     首页                6 处  ❗ <-- 唯一
1093     课程列表 /course/explore   0 处 ✅
1094     年卡页 /vip                0 处 ✅
1095     班级广场 /classroom/explore 0 处 ✅
1096     搜索页                     0 处 ✅
1097     6 门课详情页(各 1 个)     0 处 ✅
1098   ====================================================================== */
1099
1100body.homepage #content-container .es-box.es-course li.es-course-list .mask > a > p {
1101  display: none !important;
1102}
1103
1104/* ----------------------------------------------------------------------
1105   隐藏后遮罩内容垂直居中:
1106   原来那行碎屑高 95px,占掉遮罩近一半高度。去掉后若不居中,
1107   头像+名称+标题会全部挤在遮罩顶部,上方留一大块空。
1108   实测遮罩高 227px、内层 <a> 高 187px,改 flex 居中后层次更稳。
1109   ---------------------------------------------------------------------- */
1110body.homepage #content-container .es-box.es-course li.es-course-list .mask > a {
1111  display: -webkit-flex;
1112  display: flex;
1113  -webkit-flex-direction: column;
1114          flex-direction: column;
1115  -webkit-justify-content: center;
1116          justify-content: center;
1117  height: 100%;
1118  -webkit-box-sizing: border-box;
1119          box-sizing: border-box;
1120}
1121
1122</style>
1123</span></p></a></p></span>
1124<!-- 范士闯数学 · 全站 SEO 补全:页面主标题 H1(指令卡 P2-1 · 2026-09-19)
1125
1126     背景:全站核心页面 <h1> 数量为 0 —— 搜索引擎拿不到页面主标题,
1127           屏幕阅读器也没有标题锚点来定位正文。
1128     做法:按页面类型,动态插入 1 个「视觉隐藏」的 <h1>(sr-only):
1129           位置在 body 首位、尺寸 1x1、绝对定位不占布局,视觉上完全看不见。
1130     约束:① 每页恰好 1 个(脚本先检测已有 H1,有则跳过)
1131           ② 课程/商品页标题从页面 DOM 实际读取,读不到不插入(宁缺毋滥)
1132           ③ 文章详情页模板自带 H1 → 自动跳过,不重复添加
1133           ④ 只走注入通道,不改主题模板
1134
1135     ⚠️ 已知局限:本段是 JS,对「不执行 JS 的传统爬虫」不可见;
1136        对 Google/Bing(会执行 JS)、屏幕阅读器完全有效。
1137     回退:删除本段(id=fsc-seo-h1)即可,页面立即恢复原样。
1138-->
1139<script id="fsc-seo-h1">
1140(function () {
1141  if (window.__fscSeoH1) return;
1142  window.__fscSeoH1 = 1;
1143
1144  function pickTitle() {
1145    var p = location.pathname;
1146    var b = (document.body && document.body.className) || '';
1147    if (p === '/' || /\bhomepage\b/.test(b)) return '范士闯数学 · 学通在线';
1148    if (p === '/course/explore') return '课程列表';
1149    if (/^\/(?:course|goods\/show)\/\d+/.test(p)) {
1150      var el = document.querySelector('.detail-right__title');
1151      if (el) {
1152        var s = (el.textContent || '').replace(/\s+/g, ' ').trim();
1153        if (s) return s;
1154      }
1155      var dt = (document.title || '').split(' - ')[0].replace(/\s+/g, ' ').trim();
1156      return dt || null;
1157    }
1158    if (p === '/vip' || p === '/vip/') return '畅学年卡';
1159    if (p === '/article' || p === '/article/') return '黑板报';
1160    if (p === '/classroom/explore') return '班级';
1161    return null;
1162  }
1163
1164  function insert(t) {
1165    var st = document.createElement('style');
1166    st.id = 'fsc-seo-h1-style';
1167    st.textContent = '.fsc-seo-h1{position:absolute!important;width:1px;height:1px;'
1168      + 'padding:0!important;margin:-1px!important;overflow:hidden!important;'
1169      + 'clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important;}';
1170    document.head.appendChild(st);
1171    var h = document.createElement('h1');
1172    h.className = 'fsc-seo-h1';
1173    h.id = 'fscSeoH1';
1174    h.textContent = t;
1175    document.body.insertBefore(h, document.body.firstChild);
1176  }
1177
1178  var tries = 20;
1179  function attempt() {
1180    if (document.querySelector('h1')) return;
1181    var t = pickTitle();
1182    if (t) { insert(t); return; }
1183    if (tries-- > 0) setTimeout(attempt, 300);
1184  }
1185
1186  if (document.readyState === 'loading') {
1187    document.addEventListener('DOMContentLoaded', attempt);
1188  } else {
1189    attempt();
1190  }
1191})();
1192</script>
1192
1193<!-- 范士闯数学 · 全站 SEO 补全:图片 alt 属性(指令卡 P2-2 · 2026-09-19)
1194
1195     背景:全站唯一「完全无 alt 属性」的图片只有三类 ——
1196           ① 站点 Logo(页头 + 页脚,每页各 1 个)
1197           ② 页脚微信二维码(扫描添加好友)
1198           ③ 详情页「分享」二维码(JS 动态生成)
1199           课程封面 / 轮播图 / 文章缩略图的 alt 早已齐全,装饰图也已用 alt="" 正确处理。
1200
1201     做法:只给「完全没有 alt 属性」的图片补 alt;已有 alt(含空 alt="")一律不动。
1202     原则:宁缺毋滥 —— 只处理能高置信识别的三类,其余保持原样,绝不编造描述。
1203           空 alt="" 是合法且正确的(装饰图),所以不主动添加。
1204
1205     识别判据(2026-09-19 实测确定,均已收紧避免误伤):
1206       · Logo      :src 含 /files/system/ 且位于 .navbar-brand-logo / #footer-fir 内
1207                     (⚠️ 不能只用 src 前缀 —— 轮播图也在 /files/system/ 下)
1208       · 页脚二维码:img.qrcode
1209       · 分享二维码:src 含 /qrcode
1210
1211     回退:删除本段(id=fsc-seo-alt)即可,图片立即恢复原样。
1212-->
1213<script id="fsc-seo-alt">
1214(function () {
1215  if (window.__fscSeoAlt) return;
1216  window.__fscSeoAlt = 1;
1217
1218  function fix() {
1219    var imgs = document.querySelectorAll('img:not([alt])');
1220    var n = 0;
1221    for (var i = 0; i < imgs.length; i++) {
1222      var im = imgs[i];
1223      var src = im.getAttribute('src') || '';
1224      var cls = (im.className || '').toString();
1225      var alt = null;
1226      var near = im.closest('.navbar-brand-logo, .navbar-brand, #footer-fir, .es-footer');
1227      if (src.indexOf('/files/system/') >= 0 && near) {
1228        alt = '范士闯数学';
1229      } else if (cls.indexOf('qrcode') >= 0) {
1230        alt = '扫码添加范士闯数学为微信好友';
1231      } else if (src.indexOf('/qrcode') >= 0) {
1232        alt = '扫码用手机打开本页面';
1233      }
1234      if (alt !== null) {
1235        im.setAttribute('alt', alt);
1236        n++;
1237      }
1238    }
1239    return n;
1240  }
1241
1242  function attempt() { fix(); }
1243  if (document.readyState === 'loading') {
1244    document.addEventListener('DOMContentLoaded', attempt);
1245  } else {
1246    attempt();
1247  }
1248  setTimeout(fix, 1200);
1249  setTimeout(fix, 3000);
1250})();
1251</script>
1251
1252<!-- FSC:P2-3:BEGIN -->
1253<!-- 范士闯数学 · 文章日期补全年份(指令卡 P2-3 · 2026-09-19)
1254
1255     问题:文章列表页 / 分类页 / 详情页的日期徽章只显示「日 + 月」(如 18 / 09月),
1256           不显示年份。跨年后家长无法判断文章属于哪一年,搜索引擎也拿不到完整发布日期。
1257     做法:在日期圆圈(.date)内、月份下方补一行小字年份(如「2026年」)。
1258     年份来源:本站官方 API `GET /api/articles` 的 publishedTime 字段 —— 真实数据,
1259               不从页面推断、不硬编码。快照日期:2026-09-19(71 篇,全部为 2026 年)。
1260
1261     🔑 自更新机制(无需每年维护):
1262        ① 优先用内置映射表(快照)—— 当前文章 100% 命中,零网络请求、零延迟;
1263        ② 若页面上出现映射表里没有的文章(例如将来新增的 2027 年文章),
1264           自动请求同源官方 API `/api/articles?limit=500` 补齐,
1265           结果存入 sessionStorage(同一浏览会话内只请求一次);
1266        ③ 接口不可用时静默跳过,绝不猜年份 —— 找不到年份的文章保持原样。
1267
1268     影响范围:仅在文章页生效(body.artcile-list-page / artcile-cat-page / article-detail-page)。
1269     回退:删除本段(id=fsc-article-date-year)即可,页面立即恢复原样。
1270-->
1271<style id="fsc-article-date-year-css">
1272/* 日期徽章原为固定 45x45 的灰圆,内含「日 / 月」两行。
1273   本段:把圆放到 50x50,让第三行「年」装得下,并统一三行行高。
1274
1275   ⚠️ 详情页还要压掉一个历史遗留:早前的正文排版段(fsc-typography)里有一条
1276      `.article-content p / li / div` 的规则,强设 font-size:16px、line-height:1.8、
1277      margin:0 0 1.1em(均为 !important)。而详情页的日期徽章正好落在 .article-content
1278      内 → 徽章里的 div 被放大成 16px / 行高 28.8px / 下边距 17.6px,
1279      实测徽章内容溢出 35px,「月」被挤出圆圈(历史遗留视觉缺陷)。
1280      本段用更高特异性 + !important 把那三项压回原位,顺带修复该缺陷。
1281      ⚠️ 下面所有声明必须带 !important,否则会被上述 !important 规则压过。
1282
1283   实测(2026-09-19,Playwright 真浏览器):
1284     列表/分类页:徽章 45x45 → 50x50,.article-metas 高 54px 不变,页面高度 Δ0
1285     详情页    :徽章 45x45(内容溢出 35px) → 50x50(溢出 0),页面高度 Δ0
1286     三页 0 溢出、0 裁剪、0 JS 报错、横向无溢出 */
1287body.artcile-list-page   .article-metas .date,
1288body.artcile-cat-page    .article-metas .date,
1289body.article-detail-page .article-metas .date {
1290  width: 50px !important;
1291  height: 50px !important;
1292  min-height: 50px !important;
1293  padding: 0 0 2px !important;
1294  margin: 0 !important;
1295  box-sizing: border-box;
1296  overflow: hidden;
1297  line-height: 1.1 !important;
1298}
1299body.artcile-list-page   .article-metas .date .day,
1300body.artcile-cat-page    .article-metas .date .day,
1301body.article-detail-page .article-metas .date .day {
1302  font-size: 15px !important;
1303  line-height: 1.1 !important;
1304  padding: 3px 0 0 !important;
1305  margin: 0 !important;
1306}
1307body.artcile-list-page   .article-metas .date .month,
1308body.artcile-cat-page    .article-metas .date .month,
1309body.article-detail-page .article-metas .date .month {
1310  font-size: 12px !important;
1311  line-height: 1.1 !important;
1312  padding: 0 !important;
1313  margin: 0 !important;
1314}
1315body.artcile-list-page   .article-metas .date .fsc-art-year,
1316body.artcile-cat-page    .article-metas .date .fsc-art-year,
1317body.article-detail-page .article-metas .date .fsc-art-year {
1318  font-size: 10px !important;
1319  line-height: 1.15 !important;
1320  font-weight: 400 !important;
1321  color: #999 !important;
1322  letter-spacing: .2px !important;
1323  white-space: nowrap !important;
1324  padding: 0 !important;
1325  margin: 0 !important;
1326}
1327</style>
1328<script id="fsc-article-date-year">
1329(function () {
1330  if (window.__fscArtYear) return;
1331  window.__fscArtYear = 1;
1332
1333  /* ── 内置年份映射:文章ID -> 发布年份 ──
1334     数据来源:GET /api/articles(EduSoho 官方 API)的 publishedTime
1335     快照日期:2026-09-19    共 71 篇 */
1336  var YG = {
1337    "2026": "234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 258"
1338      + " 259 260 261 262 263 264 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283"
1339      + " 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306"
1340  };
1341
1342  var YM = {};
1343  for (var y in YG) {
1344    var ids = String(YG[y]).split(/\s+/);
1345    for (var i = 0; i < ids.length; i++) { if (ids[i]) YM[ids[i]] = y; }
1346  }
1347
1348  var API = '/api/articles?limit=500';
1349  var CACHE = 'fscArtYearV1';
1350  var TTL = 6 * 3600 * 1000;   /* 会话缓存 6 小时 */
1351
1352  /* 找某个日期元素对应的文章ID:列表/分类页走 article-item 里的链接,详情页走 URL
1353     注意:article-item 里第一个 /article/ 链接往往是分类链接(/article/category/xxx),
1354     所以必须遍历所有链接、只认 /article/ 后跟纯数字的 */
1355  function idOf(el) {
1356    var box = el.closest ? el.closest('article.article-item') : null;
1357    if (box) {
1358      var as = box.querySelectorAll('a[href*="/article/"]');
1359      for (var k = 0; k < as.length; k++) {
1360        var m = (as[k].getAttribute('href') || '').match(/\/article\/(\d+)(?:[\/?#]|$)/);
1361        if (m) return m[1];
1362      }
1363    }
1364    var m2 = (location.pathname || '').match(/^\/article\/(\d+)(?:[\/?#]|$)/);
1365    return m2 ? m2[1] : null;
1366  }
1367
1368  function paint(el, y) {
1369    if (el.querySelector('.fsc-art-year')) return;
1370    var d = document.createElement('div');
1371    d.className = 'fsc-art-year';
1372    d.textContent = y + 'å¹´';
1373    el.appendChild(d);
1374  }
1375
1376  /* 遍历页面所有日期徽章;返回「映射表里还没有的」文章ID */
1377  function pass() {
1378    var els = document.querySelectorAll('.article-metas .date');
1379    var need = [];
1380    for (var i = 0; i < els.length; i++) {
1381      var el = els[i];
1382      if (el.querySelector('.fsc-art-year')) continue;
1383      var id = idOf(el);
1384      if (!id) continue;
1385      var y = YM[id];
1386      if (y) paint(el, y); else need.push(id);
1387    }
1388    return need;
1389  }
1390
1391  function merge(o) {
1392    for (var k in o) { if (o[k] && !YM[k]) YM[k] = o[k]; }
1393  }
1394
1395  function cacheRead() {
1396    try { return JSON.parse(sessionStorage.getItem(CACHE) || 'null'); } catch (e) { return null; }
1397  }
1398  function cacheWrite(m) {
1399    try { sessionStorage.setItem(CACHE, JSON.stringify({ t: Date.now(), m: m })); } catch (e) {}
1400  }
1401
1402  function refresh() {
1403    if (window.__fscArtYearBusy) return;
1404    window.__fscArtYearBusy = 1;
1405    try {
1406      fetch(API, { credentials: 'same-origin',
1407                    headers: { 'Accept': 'application/vnd.edusoho.v2+json' } })
1408        .then(function (r) { return r.ok ? r.json() : null; })
1409        .then(function (j) {
1410          if (!j || !j.data) return;
1411          var m = {}, d = j.data;
1412          for (var i = 0; i < d.length; i++) {
1413            var t = String(d[i].publishedTime || '');
1414            if (t.length >= 4) m[String(d[i].id)] = t.slice(0, 4);
1415          }
1416          merge(m);
1417          cacheWrite(m);
1418          pass();
1419        })
1420        .catch(function () {});
1421    } catch (e) {}
1422  }
1423
1424  function run() {
1425    var need = pass();
1426    if (!need.length) return;                       /* 内置表全命中:不发任何请求 */
1427    var c = cacheRead();                            /* 看会话缓存 */
1428    if (c && c.t && (Date.now() - c.t) < TTL && c.m) {
1429      merge(c.m);
1430      if (!pass().length) return;
1431    }
1432    refresh();                                      /* 仍缺 → 拉一次官方 API */
1433  }
1434
1435  if (document.readyState === 'loading') {
1436    document.addEventListener('DOMContentLoaded', run);
1437  } else {
1438    run();
1439  }
1440})();
1441</script>
1441
1442<!-- FSC:P2-3:END -->
1443<!-- FSC:P3-1:BEGIN -->
1444<!-- ══════════════════════════════════════════════════════════════════════════
1445     范士闯数学 · 学通在线 | 年卡落地页(P3-1)
1446     制作:2026-09-19 | 段ID:fsc-vip-landing | 作用页:/vip/ 与 /vip/(仅电脑版主题)
1447     ──────────────────────────────────────────────────────────────────────
1448     · 只在 /vip/ 生效;其他页面不执行任何逻辑
1449     · 不清空任何 EduSoho 容器:新建 .vip-landing 插在 .container 之前,
1450       再把原生区块搬进来;只对 .vip-banner / .es-wrap > .container 做 display:none
1451     · 原生保留:.vip-level(会员卡)、.vip-opening-time(开通/续费入口)、
1452                 .vip-filer(会员课程166 + 会员班级10 实时列表)、#vipDetailInfo 及 3 个 input
1453     · 全幅出血不用 100vw,避免横向溢出;CSS 全部带 .vip-landing 前缀,不污染全站
1454     · 回退:python xt_inject.py vip revert   (或删掉 <style>/
1454<script> 两个 fsc-vip-landing* 标签)
1455     ══════════════════════════════════════════════════════════════════════ -->
1456<style id="fsc-vip-landing-css">
1457  .vip-landing, .vip-landing * {
1458    box-sizing: border-box !important
1459  }
1460  .vip-landing :where(.hero, .hero *, .section, .section *, .final-cta, .final-cta *) {
1461    margin: 0 !important; padding: 0 !important
1462  }
1463  .vip-landing {
1464    font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif !important; background: #FBF8F2 !important; color: #1a1a1a !important; line-height: 1.7 !important
1465  }
1466  .vip-landing .vip-inner {
1467    max-width: 960px !important; margin: 0 auto !important; padding: 0 20px !important
1468  }
1469  .vip-landing .hero {
1470    background: linear-gradient(135deg, #0F392B 0%, #1a5c42 100%) !important; color: #FBF8F2 !important; padding: 60px 0 50px !important; text-align: center !important; position: relative !important; overflow: hidden !important
1471  }
1472  .vip-landing .hero::before {
1473    content: '' !important; position: absolute !important; top: -50% !important; right: -20% !important; width: 500px !important; height: 500px !important; background: radial-gradient(circle, rgba(184,137,61,0.15) 0%, transparent 70%) !important; border-radius: 50% !important
1474  }
1475  .vip-landing .hero-tag {
1476    display: inline-block !important; background: rgba(184,137,61,0.2) !important; border: 1px solid #B8893D !important; color: #B8893D !important; padding: 6px 18px !important; border-radius: 20px !important; font-size: 14px !important; margin-bottom: 20px !important; letter-spacing: 2px !important
1477  }
1478  .vip-landing .hero .vip-hero-title {
1479    font-size: 42px !important; font-weight: 700 !important; margin-bottom: 12px !important; letter-spacing: 1px !important
1480  }
1481  .vip-landing .hero-sub {
1482    font-size: 18px !important; color: rgba(251,248,242,0.8) !important; margin-bottom: 30px !important
1483  }
1484  .vip-landing .hero-price {
1485    margin-bottom: 30px !important
1486  }
1487  .vip-landing .hero-price .num {
1488    font-size: 56px !important; font-weight: 700 !important; color: #B8893D !important
1489  }
1490  .vip-landing .hero-price .unit {
1491    font-size: 20px !important; color: rgba(251,248,242,0.7) !important; margin-left: 8px !important
1492  }
1493  .vip-landing .hero-price .per-day {
1494    font-size: 14px !important; color: rgba(251,248,242,0.6) !important; margin-top: 6px !important
1495  }
1496  .vip-landing .hero-cta {
1497    display: inline-block !important; background: #B8893D !important; color: #fff !important; padding: 16px 48px !important; border-radius: 8px !important; font-size: 18px !important; font-weight: 600 !important; text-decoration: none !important; transition: all 0.3s !important; box-shadow: 0 4px 20px rgba(184,137,61,0.4) !important
1498  }
1499  .vip-landing .hero-cta:hover {
1500    background: #c99a4e !important; transform: translateY(-2px) !important
1501  }
1502  .vip-landing .hero-note {
1503    margin-top: 16px !important; font-size: 13px !important; color: rgba(251,248,242,0.5) !important
1504  }
1505  .vip-landing .section {
1506    padding: 50px 0 !important
1507  }
1508  .vip-landing .section-title {
1509    text-align: center !important; font-size: 28px !important; font-weight: 700 !important; color: #0F392B !important; margin-bottom: 8px !important
1510  }
1511  .vip-landing .section-desc {
1512    text-align: center !important; color: #666 !important; font-size: 15px !important; margin-bottom: 36px !important
1513  }
1514  .vip-landing .divider {
1515    width: 50px !important; height: 3px !important; background: #B8893D !important; margin: 0 auto 30px !important; border-radius: 2px !important
1516  }
1517  .vip-landing .benefits-grid {
1518    display: grid !important; grid-template-columns: repeat(2, 1fr) !important; gap: 20px !important
1519  }
1520  .vip-landing .benefit-card {
1521    background: #fff !important; border-radius: 12px !important; padding: 28px 24px !important; box-shadow: 0 2px 12px rgba(15,57,43,0.06) !important; border-left: 4px solid #B8893D !important; transition: transform 0.3s !important
1522  }
1523  .vip-landing .benefit-card:hover {
1524    transform: translateY(-4px) !important
1525  }
1526  .vip-landing .benefit-icon {
1527    width: 48px !important; height: 48px !important; background: linear-gradient(135deg, #0F392B, #1a5c42) !important; border-radius: 10px !important; display: flex !important; align-items: center !important; justify-content: center !important; font-size: 24px !important; margin-bottom: 14px !important
1528  }
1529  .vip-landing .benefit-title {
1530    font-size: 18px !important; font-weight: 600 !important; color: #0F392B !important; margin-bottom: 8px !important
1531  }
1532  .vip-landing .benefit-desc {
1533    font-size: 14px !important; color: #666 !important; line-height: 1.7 !important
1534  }
1535  .vip-landing .benefit-highlight {
1536    color: #B8893D !important; font-weight: 600 !important
1537  }
1538  .vip-landing .compare-section {
1539    background: #fff !important
1540  }
1541  .vip-landing .compare-table {
1542    width: 100% !important; border-collapse: collapse !important; background: #fff !important; border-radius: 12px !important; overflow: hidden !important; box-shadow: 0 2px 12px rgba(15,57,43,0.06) !important
1543  }
1544  .vip-landing .compare-table th {
1545    background: #0F392B !important; color: #FBF8F2 !important; padding: 14px 16px !important; font-size: 15px !important; font-weight: 600 !important; text-align: left !important
1546  }
1547  .vip-landing .compare-table td {
1548    padding: 14px 16px !important; border-bottom: 1px solid #f0ece3 !important; font-size: 14px !important
1549  }
1550  .vip-landing .compare-table tr:last-child td {
1551    border-bottom: none !important
1552  }
1553  .vip-landing .compare-table tr:hover {
1554    background: #faf7f0 !important
1555  }
1556  .vip-landing .compare-table .vip-price {
1557    color: #B8893D !important; font-weight: 700 !important
1558  }
1559  .vip-landing .compare-table .save-tag {
1560    display: inline-block !important; background: #e8f5e9 !important; color: #2e7d32 !important; padding: 2px 10px !important; border-radius: 10px !important; font-size: 12px !important; font-weight: 600 !important
1561  }
1562  .vip-landing .compare-note {
1563    text-align: center !important; margin-top: 20px !important; font-size: 14px !important; color: #888 !important
1564  }
1565  .vip-landing .audience-grid {
1566    display: grid !important; grid-template-columns: repeat(3, 1fr) !important; gap: 20px !important
1567  }
1568  .vip-landing .audience-card {
1569    background: #fff !important; border-radius: 12px !important; padding: 30px 24px !important; text-align: center !important; box-shadow: 0 2px 12px rgba(15,57,43,0.06) !important; transition: transform 0.3s !important
1570  }
1571  .vip-landing .audience-card:hover {
1572    transform: translateY(-4px) !important
1573  }
1574  .vip-landing .audience-num {
1575    width: 40px !important; height: 40px !important; background: #B8893D !important; color: #fff !important; border-radius: 50% !important; display: flex !important; align-items: center !important; justify-content: center !important; font-size: 18px !important; font-weight: 700 !important; margin: 0 auto 16px !important
1576  }
1577  .vip-landing .audience-title {
1578    font-size: 17px !important; font-weight: 600 !important; color: #0F392B !important; margin-bottom: 10px !important
1579  }
1580  .vip-landing .audience-desc {
1581    font-size: 13px !important; color: #666 !important; line-height: 1.7 !important
1582  }
1583  .vip-landing .choice-section {
1584    background: #fff !important
1585  }
1586  .vip-landing .choice-grid {
1587    display: grid !important; grid-template-columns: repeat(3, 1fr) !important; gap: 20px !important
1588  }
1589  .vip-landing .choice-card {
1590    border-radius: 12px !important; padding: 28px 24px !important; text-align: center !important; border: 2px solid #e8e2d5 !important; transition: all 0.3s !important
1591  }
1592  .vip-landing .choice-card.recommended {
1593    border-color: #B8893D !important; background: linear-gradient(180deg, #fffbf3 0%, #fff 100%) !important; position: relative !important
1594  }
1595  .vip-landing .choice-card.recommended::before {
1596    content: '推荐' !important; position: absolute !important; top: -12px !important; left: 50% !important; transform: translateX(-50%) !important; background: #B8893D !important; color: #fff !important; padding: 4px 16px !important; border-radius: 10px !important; font-size: 12px !important; font-weight: 600 !important
1597  }
1598  .vip-landing .choice-title {
1599    font-size: 18px !important; font-weight: 600 !important; color: #0F392B !important; margin-bottom: 8px !important
1600  }
1601  .vip-landing .choice-price {
1602    font-size: 28px !important; font-weight: 700 !important; color: #B8893D !important; margin-bottom: 12px !important
1603  }
1604  .vip-landing .choice-price small {
1605    font-size: 14px !important; color: #999 !important; font-weight: 400 !important
1606  }
1607  .vip-landing .choice-desc {
1608    font-size: 13px !important; color: #666 !important; line-height: 1.7 !important
1609  }
1610  .vip-landing .faq-list {
1611    max-width: 760px !important; margin: 0 auto !important
1612  }
1613  .vip-landing .faq-item {
1614    background: #fff !important; border-radius: 10px !important; margin-bottom: 12px !important; overflow: hidden !important; box-shadow: 0 2px 8px rgba(15,57,43,0.04) !important
1615  }
1616  .vip-landing .faq-q {
1617    padding: 18px 24px !important; font-size: 15px !important; font-weight: 600 !important; color: #0F392B !important; cursor: pointer !important; display: flex !important; justify-content: space-between !important; align-items: center !important
1618  }
1619  .vip-landing .faq-q::after {
1620    content: '+' !important; font-size: 20px !important; color: #B8893D !important; font-weight: 400 !important
1621  }
1622  .vip-landing .faq-a {
1623    padding: 0 24px 18px !important; font-size: 14px !important; color: #666 !important; line-height: 1.8 !important; display: none !important
1624  }
1625  .vip-landing .faq-item.open .faq-a {
1626    display: block !important
1627  }
1628  .vip-landing .faq-item.open .faq-q::after {
1629    content: '−' !important
1630  }
1631  .vip-landing .final-cta {
1632    background: linear-gradient(135deg, #0F392B 0%, #1a5c42 100%) !important; color: #FBF8F2 !important; padding: 50px 0 !important; text-align: center !important
1633  }
1634  .vip-landing .final-cta h2 {
1635    font-size: 28px !important; margin-bottom: 12px !important
1636  }
1637  .vip-landing .final-cta p {
1638    color: rgba(251,248,242,0.7) !important; margin-bottom: 24px !important; font-size: 15px !important
1639  }
1640  .vip-landing .final-cta .contact {
1641    font-size: 18px !important; color: #B8893D !important; font-weight: 600 !important; margin-bottom: 8px !important
1642  }
1643  .vip-landing .final-cta .contact small {
1644    display: block !important; font-size: 13px !important; color: rgba(251,248,242,0.5) !important; font-weight: 400 !important; margin-top: 4px !important
1645  }
1646@media (max-width: 768px){
1647  .vip-landing .hero .vip-hero-title {
1648    font-size: 28px !important
1649  }
1650  .vip-landing .hero-sub {
1651    font-size: 15px !important
1652  }
1653  .vip-landing .hero-price .num {
1654    font-size: 42px !important
1655  }
1656  .vip-landing .section-title {
1657    font-size: 22px !important
1658  }
1659  .vip-landing .benefits-grid {
1660    grid-template-columns: 1fr !important
1661  }
1662  .vip-landing .audience-grid {
1663    grid-template-columns: 1fr !important
1664  }
1665  .vip-landing .choice-grid {
1666    grid-template-columns: 1fr !important
1667  }
1668  .vip-landing .compare-table {
1669    font-size: 12px !important
1670  }
1671  .vip-landing .compare-table th,
1672  .vip-landing .compare-table td {
1673    padding: 10px 8px !important
1674  }
1675  .vip-landing .hero-cta {
1676    padding: 14px 36px !important; font-size: 16px !important
1677  }
1678}
1679
1680  /* ═══ 本站适配(设计稿之外,P3-1 新增)═══ */
1681
1682  /* ① 会员卡(.vip-level 克隆):去 EduSoho 波浪背景,收成正常卡片尺寸居中 */
1683  .vip-landing .vip-native {
1684    background: #FBF8F2 !important;
1685    padding: 0 20px !important;
1686  }
1687  .vip-landing .vip-wallet {
1688    width: 100% !important;
1689    max-width: 420px !important;
1690    margin: 0 auto !important;
1691    padding-top: 36px !important;
1692  }
1693  .vip-landing .vip-level {
1694    background: none !important;
1695    background-image: none !important;
1696    height: auto !important;
1697    min-height: 0 !important;
1698    width: 100% !important;
1699    padding: 0 !important;
1700    text-align: center !important;
1701  }
1702  /* ⚠️ swiper-container/-wrapper 必须给「显式」高度:实测 height:auto 时整条链路会塌成 0
1703     (slide 有高度、父级却算 0,属性链在 swiper 自有 CSS 下不传递) */
1704  .vip-landing .vip-level .swiper-container,
1705  .vip-landing .vip-level .swiper-wrapper {
1706    width: 100% !important;
1707    max-width: 420px !important;
1708    height: 218px !important;
1709    min-height: 218px !important;
1710    display: block !important;
1711    margin: 0 auto !important;
1712    overflow: visible !important;
1713  }
1714  .vip-landing .vip-level .swiper-slide,
1715  .vip-landing .vip-level .level-item {
1716    width: 100% !important;
1717    max-width: 420px !important;
1718    height: 218px !important;
1719    min-height: 218px !important;
1720    display: block !important;
1721    margin: 0 auto !important;
1722  }
1723  .vip-landing .vip-level .level-item__bg {
1724    width: 100% !important;
1725    height: 100% !important;
1726    object-fit: cover !important;
1727    display: block !important;
1728  }
1729  .vip-landing .vip-level .vip-level-btn { display: none !important; }
1730
1731  /* ② 开通 / 续费(.vip-opening-time):收成尾屏里的一行次要入口 */
1732  .vip-landing .vip-open-inline {
1733    margin-top: 22px !important;
1734  }
1735  .vip-landing .vip-opening-time {
1736    width: auto !important;
1737    height: auto !important;
1738    display: inline-block !important;
1739  }
1740  .vip-landing .vip-opening-time .time-item {
1741    width: auto !important;
1742    height: auto !important;
1743    min-width: 0 !important;
1744    background: rgba(255, 255, 255, 0.08) !important;
1745    border: 1px solid rgba(184, 137, 61, 0.45) !important;
1746    border-radius: 8px !important;
1747    padding: 12px 22px !important;
1748    display: inline-flex !important;
1749    align-items: center !important;
1750    gap: 14px !important;
1751  }
1752  .vip-landing .vip-opening-time .time-item__price,
1753  .vip-landing .vip-opening-time .time-item__duration {
1754    color: #FBF8F2 !important;
1755    font-size: 14px !important;
1756    margin: 0 !important;
1757    padding: 0 !important;
1758  }
1759  .vip-landing .vip-opening-time .buy__btn {
1760    background: transparent !important;
1761    color: #D9B87C !important;
1762    border: 1px solid #B8893D !important;
1763    border-radius: 6px !important;
1764    font-size: 14px !important;
1765    padding: 6px 16px !important;
1766    height: auto !important;
1767    line-height: 1.5 !important;
1768  }
1769  .vip-landing .vip-opening-time a { text-decoration: none !important; }
1770
1771  /* ③ 会员课程 / 会员班级(.vip-filer):保持原生 1140 布局,只补品牌留白 */
1772  .vip-landing .vip-filer {
1773    background: #FFFFFF !important;
1774    padding: 8px 0 46px !important;
1775  }
1776  .vip-landing .vip-filer .es-piece { padding-top: 26px !important; }
1777  .vip-landing .vip-filer .es-piece:first-child {
1778    border-bottom: 1px solid #F0ECE3 !important;
1779    padding-bottom: 32px !important;
1780  }
1781  .vip-landing .vip-filer img {
1782    border-radius: 8px !important;
1783    object-fit: cover !important;
1784  }
1785  .vip-landing .vip-filer .title,
1786  .vip-landing .vip-filer h3,
1787  .vip-landing .vip-filer h4 {
1788    color: #0F392B !important;
1789    font-weight: 700 !important;
1790  }
1791
1792  /* ④ EduSoho 顶栏:游客(只显示「请登录后查看会员状态」)隐藏;已登录用户保留,
1793        收成深绿细条 —— 这样会员状态信息万一有内容也不会被抹掉(未经实测,保守处理) */
1794  html.fsc-vip-guest .vip-banner { display: none !important; }
1795  html.fsc-vip-loggedin .vip-banner {
1796    display: block !important;
1797    background: #0F392B !important;
1798    background-image: none !important;
1799    height: auto !important;
1800    min-height: 0 !important;
1801    padding: 12px 0 !important;
1802    text-align: center !important;
1803  }
1804  html.fsc-vip-loggedin .vip-banner * {
1805    color: #FBF8F2 !important;
1806    font-size: 14px !important;
1807    line-height: 1.8 !important;
1808    margin: 0 auto !important;
1809  }
1810  html.fsc-vip-loggedin .vip-banner img { display: none !important; }
1811
1812  /* ⑤ 只在我方 JS 成功接管后才隐藏主体容器(JS 失败则原页照常显示,安全兜底) */
1813  html.fsc-vip-on .es-wrap > .container { display: none !important; }
1814
1815
1816  /* ═══ 本站自有类(P3-1 新增)═══ */
1817  .vip-landing .vip-pinpoint { padding: 34px 0 0 !important; }
1818  .vip-landing .vip-pinpoint-box {
1819    background: #FBF1DE !important;
1820    border-left: 4px solid #B8893D !important;
1821    border-radius: 0 8px 8px 0 !important;
1822    padding: 16px 20px !important;
1823  }
1824  .vip-landing .vip-pinpoint-box p {
1825    margin: 0 !important;
1826    font-size: 14px !important;
1827    line-height: 1.9 !important;
1828    color: #6B6252 !important;
1829  }
1830  .vip-landing .vip-pinpoint-box strong { color: #8E672A !important; }
1831  .vip-landing .vip-hero-title {
1832    font-size: 42px !important;
1833    font-weight: 700 !important;
1834    color: #FBF8F2 !important;
1835    margin-bottom: 12px !important;
1836    letter-spacing: 1px !important;
1837    line-height: 1.25 !important;
1838  }
1839  .vip-landing .compare-table tr.row-total td {
1840    background: #FAF7F0 !important;
1841    font-weight: 600 !important;
1842  }
1843  .vip-landing .audience-note {
1844    text-align: center !important;
1845    margin-top: 24px !important;
1846    color: #888 !important;
1847    font-size: 14px !important;
1848    line-height: 1.9 !important;
1849  }
1850  .vip-landing .vip-native-section { background: #FFFFFF !important; padding-bottom: 0 !important; }
1851  @media (max-width: 768px) {
1852    .vip-landing .vip-hero-title { font-size: 28px !important; }
1853    .vip-landing .vip-pinpoint { padding: 26px 0 0 !important; }
1854  }
1855
1856</style>
1857<script id="fsc-vip-landing">
1858(function () {
1859  'use strict';
1860  var P = location.pathname;
1861  if (P !== '/vip' && P !== '/vip/' && P.indexOf('/vip/') !== 0) return;
1862  if (document.getElementById('fscVipLanding')) return;      // 幂等
1863
1864  var HTML = `
1865<div class="vip-landing" id="fscVipLanding">
1866
1867  <!-- ① 首屏 -->
1868  <section class="hero">
1869    <div class="vip-inner">
1870      <div class="hero-tag">范士闯数学 · 学通在线</div>
1871      <div class="vip-hero-title">畅学年卡</div>
1872      <p class="hero-sub">一年 365 天,全站 166 门数学课 + 10 个打包班,全部随便学</p>
1873      <div class="hero-price">
1874        <span class="num">&yen;1,499</span>
1875        <span class="unit">/ å¹´</span>
1876        <div class="per-day">不分新老学员,统一价 &middot; 折合每天约 &yen;4.1</div>
1877      </div>
1878      <a href="#vipContact" class="hero-cta">立即咨询开通</a>
1879      <div class="hero-note">本站已暂停在线支付,联系范老师微信 / 转账后立即开通</div>
1880    </div>
1881  </section>
1882
1883  <!-- ② 会员卡(EduSoho 原生 .vip-level 克隆挂载点) -->
1884  <div class="vip-native" id="fscVipLevel"></div>
1885
1886  <!-- ③ 请先看这一句(007 反制文案,设计稿缺失,此处补回) -->
1887  <section class="section vip-pinpoint">
1888    <div class="vip-inner">
1889      <div class="vip-pinpoint-box">
1890        <p><strong>请先看这一句:</strong>本页下方「会员课程」与「会员班级」两个区块里的<strong>全部课程和班级,都已经包含在年卡内,不需要再单独付费</strong>。卡片上的「立即加入」按钮是页面模板自带的,<strong>不代表年卡之外还要加钱</strong>。<br>
1891        (年卡具体包含哪些班级,以本页「会员班级」区块列出的为准)</p>
1892      </div>
1893    </div>
1894  </section>
1895
1896  <!-- ④ 这张卡包含什么 -->
1897  <section class="section">
1898    <div class="vip-inner">
1899      <h2 class="section-title">这张卡包含什么</h2>
1900      <div class="divider"></div>
1901      <div class="benefits-grid">
1902        <div class="benefit-card">
1903          <div class="benefit-icon">&#128218;</div>
1904          <div class="benefit-title">全站 166 门数学课</div>
1905          <div class="benefit-desc">
1906            小学奥数 <span class="benefit-highlight">65 门</span> &middot; 小学数学 <span class="benefit-highlight">57 门</span> &middot; 初中数学 <span class="benefit-highlight">44 门</span><br>
1907            其中 10 门免费试听课,不用买就能看
1908          </div>
1909        </div>
1910        <div class="benefit-card">
1911          <div class="benefit-icon">&#127979;</div>
1912          <div class="benefit-title">10 个打包班</div>
1913          <div class="benefit-desc">
1914            一~六年级 &middot; 初一 &middot; 初二「全年班」&yen;799;<br>
1915            小学奥数 &middot; 思维全程班 &yen;1,299;初三 &middot; 中考全程班 &yen;1,299<br>
1916            单买要 &yen;799~&yen;1,299,年卡全部包含
1917          </div>
1918        </div>
1919        <div class="benefit-card">
1920          <div class="benefit-icon">&#128260;</div>
1921          <div class="benefit-title">反复看,不限次数</div>
1922          <div class="benefit-desc">
1923            一年内同一节课看 1 遍还是 20 遍都一样<br>
1924            不限时长、不额外计费<br>
1925            预习、复习、考前冲刺,随时翻出来看
1926          </div>
1927        </div>
1928        <div class="benefit-card">
1929          <div class="benefit-icon">&#10024;</div>
1930          <div class="benefit-title">新课上线自动包含</div>
1931          <div class="benefit-desc">
1932            年卡期内新上线的课程不用再买<br>
1933            也不用补差价<br>
1934            升年级后接着看,不用再买新课
1935          </div>
1936        </div>
1937      </div>
1938    </div>
1939  </section>
1940
1941  <!-- ⑤ 买几门就回本 -->
1942  <section class="section compare-section">
1943    <div class="vip-inner">
1944      <h2 class="section-title">买几门就回本?</h2>
1945      <p class="section-desc">您不需要用到 166 门。按下面这张表算:买 &yen;399 档 4 门、&yen;299 档 6 门,年卡就已经比单买便宜;如果只买 &yen;129 的奥数专题,要买到 12 门才回本</p>
1946      <div class="divider"></div>
1947      <table class="compare-table">
1948        <thead>
1949          <tr>
1950            <th>
1950您要买的课</th>
1951            <th>单买合计</th>
1952            <th>年卡</th>
1953            <th>结果</th>
1954          </tr>
1955        </thead>
1956        <tbody>
1957          <tr>
1958            <td>&yen;129 档奥数专题 &times; 12 门</td>
1959            <td>&yen;1,548</td>
1960            <td class="vip-price">&yen;1,499</td>
1961            <td><span class="save-tag">省 &yen;49</span></td>
1962          </tr>
1963          <tr>
1964            <td>&yen;199 档课程 &times; 8 门</td>
1965            <td>&yen;1,592</td>
1966            <td class="vip-price">&yen;1,499</td>
1967            <td><span class="save-tag">省 &yen;93</span></td>
1968          </tr>
1969          <tr>
1970            <td>&yen;299 档课程 &times; 6 门</td>
1971            <td>&yen;1,794</td>
1972            <td class="vip-price">&yen;1,499</td>
1973            <td><span class="save-tag">省 &yen;295</span></td>
1974          </tr>
1975          <tr>
1976            <td>&yen;399 档课程 &times; 4 门</td>
1977            <td>&yen;1,596</td>
1978            <td class="vip-price">&yen;1,499</td>
1979            <td><span class="save-tag">省 &yen;97</span></td>
1980          </tr>
1981          <tr>
1982            <td>两个年级的「全年班」(&yen;799 &times; 2)</td>
1983            <td>&yen;1,598</td>
1984            <td class="vip-price">&yen;1,499</td>
1985            <td><span class="save-tag">省 &yen;99</span></td>
1986          </tr>
1987          <tr>
1988            <td>「小学奥数 &middot; 思维全程班」单买(11 门)</td>
1989            <td>&yen;4,389</td>
1990            <td class="vip-price">&yen;1,499</td>
1991            <td><span class="save-tag">省 &yen;2,890</span></td>
1992          </tr>
1993          <tr class="row-total">
1994            <td>站内 166 门课全部逐一单买</td>
1995            <td>&yen;40,324</td>
1996            <td class="vip-price">&yen;1,499</td>
1997            <td><span class="save-tag">省 &yen;38,825</span></td>
1998          </tr>
1999        </tbody>
2000      </table>
2001      <p class="compare-note">一张年卡 = 全站 166 门 + 10 个班,一年内全部学完也还是这个价</p>
2002    </div>
2003  </section>
2004
2005  <!-- ⑥ 单课、报班、年卡怎么选 -->
2006  <section class="section choice-section">
2007    <div class="vip-inner">
2008      <h2 class="section-title">单课、报班、年卡,怎么选</h2>
2009      <div class="divider"></div>
2010      <div class="choice-grid">
2011        <div class="choice-card">
2012          <div class="choice-title">单买一门课</div>
2013          <div class="choice-price">&yen;129<small> 起(付费课最低 &yen;129)</small></div>
2014          <div class="choice-desc">只想补一块。比如孩子分数应用题弱,就单买一个专题。</div>
2015        </div>
2016        <div class="choice-card">
2017          <div class="choice-title">报一个班</div>
2018          <div class="choice-price">&yen;799<small> èµ·</small></div>
2019          <div class="choice-desc">想跟着课本走一学年。一个班把一学期要用的几门课按顺序打包好,不用自己挑,比单买省 20%~70%。</div>
2020        </div>
2021        <div class="choice-card recommended">
2022          <div class="choice-title">开通年卡</div>
2023          <div class="choice-price">&yen;1,499<small> / å¹´</small></div>
2024          <div class="choice-desc">想全站随便学。上面两类里的全部课程和全部班级都含在里面,包括以后新上线的课,不用再买。</div>
2025        </div>
2026      </div>
2027    </div>
2028  </section>
2029
2030  <!-- ⑦ 这张卡适合谁 -->
2031  <section class="section">
2032    <div class="vip-inner">
2033      <h2 class="section-title">这张卡适合谁</h2>
2034      <div class="divider"></div>
2035      <div class="audience-grid">
2036        <div class="audience-card">
2037          <div class="audience-num">1</div>
2038          <div class="audience-title">一~六年级 / 初一初二</div>
2039          <div class="audience-desc">这一年的预习、同步提高、奥数专题全都用得上;升年级后接着看,不用再买新课。</div>
2040        </div>
2041        <div class="audience-card">
2042          <div class="audience-num">2</div>
2043          <div class="audience-title">校内成绩 + 奥数思维</div>
2044          <div class="audience-desc">这两条线本来要买两套课,年卡一次覆盖 166 门。两条腿走路,不偏科。</div>
2045        </div>
2046        <div class="audience-card">
2047          <div class="audience-num">3</div>
2048          <div class="audience-title">初三备考中考</div>
2049          <div class="audience-desc">中考专题复习、压轴题精讲都在内,考前反复看不用额外付费。哪里薄弱翻哪里。</div>
2050        </div>
2051      </div>
2052      <p class="audience-note">
2053        也说句实话:如果孩子只打算补某一个专题、买一门课就够,那单买更合适,不必开年卡。<br>
2054        年卡划算的前提,是这一年里买得够多 —— 具体买到几门才回本,看上面那张表。
2055      </p>
2056    </div>
2057  </section>
2058
2059  <!-- ⑧ 常见问题 -->
2060  <section class="section compare-section">
2061    <div class="vip-inner">
2062      <h2 class="section-title">常见问题</h2>
2063      <div class="divider"></div>
2064      <div class="faq-list">
2065        <div class="faq-item">
2066          <div class="faq-q">Q1 年卡是一年还是永久?</div>
2067          <div class="faq-a">一年。从开通当天开始算,365 天内有效。</div>
2068        </div>
2069        <div class="faq-item">
2070          <div class="faq-q">Q2 新学员和老学员价格一样吗?</div>
2071          <div class="faq-a">一样。&yen;1,499 / 年,不分新老学员,统一价,没有「老学员专享」这种说法。</div>
2072        </div>
2073        <div class="faq-item">
2074          <div class="faq-q">Q3 开通后,新上线的课还要另外付费吗?</div>
2075          <div class="faq-a">不用。年卡有效期内新上线的课程自动包含,不需要补差价,也不需要重新购买。</div>
2076        </div>
2077        <div class="faq-item">
2078          <div class="faq-q">Q4 一节课能反复看吗?</div>
2079          <div class="faq-a">可以。年卡期内不限次数、不限时长,同一节课看多少遍都行。</div>
2080        </div>
2081        <div class="faq-item">
2082          <div class="faq-q">Q5 已经报了「年级全年班」,还要买年卡吗?</div>
2083          <div class="faq-a">不用重复买,二选一即可:想跟着课本走一学年 → 报「年级全年班」&yen;799,够用;想全站随便学(含奥数和其他年级) → 开年卡 &yen;1,499,10 个班也都含在里面。</div>
2084        </div>
2085        <div class="faq-item">
2086          <div class="faq-q">Q6 年卡里的课,和单独买的课内容有区别吗?</div>
2087          <div class="faq-a">没有区别。同一门课、同样的课时、同样的讲义,年卡只是把它变成「一年内不限次数免费学」。</div>
2088        </div>
2089        <div class="faq-item">
2090          <div class="faq-q">Q7 怎么付款开通?</div>
2091          <div class="faq-a">联系范老师 18310750509(微信同电话),微信 / 银行转账均可,收到后立即为您开通,全程几分钟。</div>
2092        </div>
2093      </div>
2094    </div>
2095  </section>
2096
2097  <!-- ⑨ 会员课程 / 会员班级(EduSoho 原生 .vip-filer 挂载点,放在 section 之外
2098        —— 避免被落地页的 margin/padding 归零规则拍平原生排版) -->
2099  <section class="section vip-native-section">
2100    <div class="vip-inner">
2101      <h2 class="section-title">年卡里具体有哪些课和班</h2>
2102      <p class="section-desc">下面是本站年卡当前包含的全部课程与班级(实时数据)</p>
2103      <div class="divider"></div>
2104    </div>
2105  </section>
2106  <div id="fscVipFiler"></div>
2107
2108  <!-- ⑩ 尾屏 CTA -->
2109  <section class="final-cta" id="vipContact">
2110    <div class="vip-inner">
2111      <h2>立即开通年卡 &middot; &yen;1,499 / 年</h2>
2112      <p>全站 166 门课 + 10 个班,一年随便学</p>
2113      <div class="contact">
2114        范老师:183-1075-0509(微信同电话)
2115        <small>微信 / 银行转账均可,收到后立即开通,全程几分钟</small>
2116      </div>
2117      <div class="vip-open-inline" id="fscVipOpen"></div>
2118    </div>
2119  </section>
2120
2121</div>
2122`;
2123
2124  function ready(fn) {
2125    if (document.readyState === 'loading') {
2126      document.addEventListener('DOMContentLoaded', fn);
2127    } else { fn(); }
2128  }
2129
2130  function build() {
2131    var wrap = document.querySelector('.es-wrap');
2132    var container = document.querySelector('.es-wrap > .container');
2133    if (!wrap || !container) return;
2134
2135    // ── 1. 先取原生节点(.vip-filer / .vip-opening-time 搬真节点;
2136    //       .vip-level 用克隆,避免 swiper 尺寸计算被搬移打乱)
2137    var lvl   = document.querySelector('.vip-level');
2138    var open  = document.querySelector('.vip-opening-time');
2139    var filer = document.querySelector('.vip-filer');
2140
2141    // ── 2. 建落地页(此时先不上 class,隐藏逻辑最后一步才生效)
2142    var land = document.createElement('div');
2143    land.innerHTML = HTML;
2144    var root = land.firstElementChild;
2145    if (!root) return;
2146
2147    // ── 3. 原生节点搬进落地页
2148    try {
2149      var lvlBox = root.querySelector('#fscVipLevel');
2150      if (lvl && lvlBox) {
2151        var w = document.createElement('div');
2152        w.className = 'vip-wallet';
2153        var lvClone = lvl.cloneNode(true);
2154        // 🔴 swiper 在 wrapper / slide 上写了行内样式(padding:0 380px、width:380px 等),
2155        //    行内样式会压过普通 CSS 规则 → 克隆后必须剥掉,否则卡片被锁成 380 宽、高度塌成 0
2156        try {
2157          var rm = ['.swiper-container', '.swiper-wrapper', '.swiper-slide'];
2158          for (var ri = 0; ri < rm.length; ri++) {
2159            var es = lvClone.querySelectorAll(rm[ri]);
2160            for (var ei = 0; ei < es.length; ei++) es[ei].removeAttribute('style');
2161          }
2162        } catch (e2) { /* 剥样式失败不致命,CSS 仍可兜底 */ }
2163        w.appendChild(lvClone);
2164        lvlBox.appendChild(w);
2165      }
2166      var filerBox = root.querySelector('#fscVipFiler');
2167      if (filer && filerBox) { filerBox.appendChild(filer); }
2168
2169      var openBox = root.querySelector('#fscVipOpen');
2170      if (open && openBox) { openBox.appendChild(open); }
2171    } catch (e) { /* 搬移失败不影响落地页主体 */ }
2172
2173    // ── 4. 插到 .container 之前(导航栏 / .vip-banner 之后)
2174    container.parentNode.insertBefore(root, container);
2175
2176    // ── 5. 全部就位后才隐藏原生区块(失败时原页照常æ
2176˜¾ç¤ºï¼‰
2177    var banner = document.querySelector('.vip-banner');
2178    var isGuest = !banner || /请登录后查看会员状态/.test(banner.textContent || '');
2179    document.documentElement.classList.add(isGuest ? 'fsc-vip-guest' : 'fsc-vip-loggedin');
2180    document.documentElement.classList.add('fsc-vip-on');
2181
2182    // ── 6. FAQ 折叠(事件委托,插完再绑也无所谓)
2183    root.addEventListener('click', function (ev) {
2184      var q = ev.target.closest ? ev.target.closest('.faq-q') : null;
2185      if (!q || !root.contains(q)) return;
2186      var item = q.parentElement;
2187      if (item) item.classList.toggle('open');
2188    });
2189    // 首条默认展开,让访客一眼看到有一个可交互的问答
2190    var first = root.querySelector('.faq-item');
2191    if (first) first.classList.add('open');
2192  }
2193
2194  ready(function () {
2195    try { build(); } catch (e) {
2196      var de = document.documentElement;
2197      de.classList.remove('fsc-vip-on');
2198      de.classList.remove('fsc-vip-guest');
2199      de.classList.remove('fsc-vip-loggedin');
2200      if (window.console && console.warn) console.warn('[fsc-vip-landing]', e);
2201    }
2202  });
2203})();
2204
2205</script>
2205
2206<!-- FSC:P3-1:END -->
2207</script>
2207</style>
2208<!-- FSC:P2-7-classroom:BEGIN -->
2209<!-- 范士闯数学 · 班级广场「手机端横向溢出」修复(指令卡 P2-7 任务2 · 2026-09-19)
2210
2211     问题:375px 手机端访问 /classroom/explore,整页可横向滚动 10px
2212           (documentElement.scrollWidth = 385,视口 375),左侧内容被推出屏幕 10px。
2213
2214     根因(实测,非猜测):
2215       Bootstrap 的 `.row { margin-left:-10px; margin-right:-10px }` 是「负边距抵消外层
2216       padding」的写法,要求外层容器有 10px 左右的 padding 来抵消。但本页 `.container`
2217       在 ≤768px 时 padding 为 **0**(computed 实测 pl=0 / pr=0),负边距无处抵消
2218       → `.class-list-mobile.row` 变成 x=-10、宽 395(= 375 + 10 + 10)→ 右侧溢出 10px。
2219
2220       (卡面原假设是「.container 的移动端 padding:10px 与 row 负边距叠加」,
2221         方向对但细节反了:container 的 padding 是 0,不是 10px。)
2222
2223     做法:把该行的负边距归零(消除 20px 虚增宽度),同时把它的行内 padding
2224           由 12px 调为 2px 作为补偿 —— 使卡片几何与修复前**逐像素完全一致**:
2225
2226             修复前:row x=-10 + ml/pad → 卡片 x=14,宽 347
2227             修复后:row x=  0 + pad 2 → 卡片 x=14,宽 347(实测一致)
2228             横向溢出:10px → 0px
2229
2230           → 纯消除溢出,视觉零变化(唯一变化是那条看不见的滚动条没了)。
2231
2232     范围控制(三重收窄,确保不误伤其他页):
2233       ① 仅 body.classroom-list-page —— 该 class 只出现在 /classroom/explore
2234       ② 仅 @media (max-width:768px) —— 桌面端(实测本来就没有溢出)完全不介入
2235       ③ 选择器带 .class-list-mobile —— 只命中班级广场的移动列表行
2236
2237     回退:删除本段(成对标记 FSC:P2-7-classroom)
2238-->
2239<style id="fsc-classroom-overflow-fix">
2240@media (max-width: 768px) {
2241  body.classroom-list-page .class-list-mobile.row {
2242    margin-left: 0 !important;
2243    margin-right: 0 !important;
2244    padding-left: 2px !important;
2245    padding-right: 2px !important;
2246  }
2247}
2248</style>
2249<!-- FSC:P2-7-classroom:END -->
2250</head></script>
2250
2251<!-- FSC:P3-5:BEGIN -->
2252<!-- 范士闯数学 · SEO 结构化数据(JSON-LD)· 段ID fsc-seo-schema · 卡 P3-5 · 2026-09-19 -->
2253<script id="fsc-seo-schema">
2254/* ============================================================================
2255   范士闯数学 · SEO 结构化数据(JSON-LD)  ·  段ID: fsc-seo-schema  ·  卡: P3-5
2256   上线日期: 2026-09-19(v2 修订同日)
2257   ----------------------------------------------------------------------------
2258   作用:
2259     ① Organization    —— 全站
2260     ② Course          —— 课程详情页(标题/价格/简介从 DOM 动态读取)
2261     ③ Article         —— 文章详情页(标题/日期/摘要从 DOM 动态读取)
2262     ④ BreadcrumbList  —— 内容页(优先读页面已有面包屑,缺失则按路径推导)
2263   设计约束:
2264     · 不硬编码任何业务数值(价格、课程数、日期一律现读)
2265     · 幂等:已注入过即跳过(防重复)
2266     · 每个 schema 独立 try/catch,单个失败不影响其余
2267     · 纯新增 
2267<script type="application/ld+json"> 到 <head>,不改动页面任何视觉/结构
2268   ★执行时机(实测教训):
2269     注入段在 <head>,执行时正文尚未渲染,且本站部分元素是「渐进式渲染」——
2270     例如文章页 <div class="date"> 在 DOMContentLoaded 当刻只有「日/月」两个子元素,
2271     年份要等其它脚本(P2-3 段)在 ~4.5s 后补入。因此 ready() 必须校验
2272     「内容完整」而不是「元素存在」,否则会把残缺值写进结构化数据。
2273     最多重试 25 次 × 400ms ≈ 10 秒;仍不完整时走官方 API 兜底 / 宁缺勿错。
2274   回退:python xt_inject.py p35seo revert
2275   ============================================================================ */
2276(function () {
2277  'use strict';
2278  if (window.__fscSeoSchema) { return; }        /* 幂等 */
2279  window.__fscSeoSchema = true;
2280
2281  var SITE = 'https://www.xuetong.com';
2282  var path = location.pathname;
2283  var url = SITE + path + location.search;
2284  var isCourse = /^\/(goods\/show\/\d+|course\/\d+)/.test(path);
2285  var isArticle = /^\/article\/\d+/.test(path);
2286
2287  function t(sel) {
2288    var e = document.querySelector(sel);
2289    return e ? (e.innerText || e.textContent || '').replace(/\s+/g, ' ').trim() : '';
2290  }
2291  function el(sel) { return document.querySelector(sel); }
2292  function num(s) {
2293    var m = (s || '').replace(/,/g, '').match(/\d+(?:\.\d+)?/);
2294    return m ? m[0] : '';
2295  }
2296  function put(id, obj) {
2297    try {
2298      var old = document.getElementById(id);
2299      if (old && old.parentNode) { old.parentNode.removeChild(old); }
2300      var s = document.createElement('script');
2301      s.type = 'application/ld+json';
2302      s.id = id;
2303      s.textContent = JSON.stringify(obj);
2304      (document.head || document.documentElement).appendChild(s);
2305    } catch (e) { /* 静默:结构化数据是锦上添花,绝不因此抛错 */ }
2306  }
2307
2308  /* ---------- ① Organization(全站) ---------- */
2309  function org() {
2310    put('fsc-ld-org', {
2311      '@context': 'https://schema.org',
2312      '@type': 'Organization',
2313      name: '范士闯数学',
2314      alternateName: '学通在线',
2315      url: SITE + '/',
2316      logo: 'https://www.xuetong.com/files/system/2026/09-17/1838499c1a54682586.png',
2317      description: '专注中小学数学教育,录播课 + 打包班 + 直播课,覆盖小学到初中全学段。',
2318      telephone: '+86-183-1075-0509',
2319      email: '[email protected]',
2320      address: { '@type': 'PostalAddress', addressCountry: 'CN' },
2321      sameAs: []
2322    });
2323  }
2324
2325  /* ---------- ② Course(课程详情页) ---------- */
2326  function courseSchema() {
2327    var cName = t('h1') || document.title.split('-')[0].trim();
2328    /* 价格:优先详情区,其次从简介 meta 行里抓「价格:¥199」 */
2329    var cPrice = num(t('.detail-right__price__price') || t('.detail-right__price__num'));
2330    if (cPrice === '') {
2331      var mP = t('#info-left-1').match(/价格[::]?\s*¥?\s*([\d.]+)/);
2332      if (mP) { cPrice = mP[1]; }
2333    }
2334    /* 简介:优先取「学什么」段,去掉「简介」抬头与顶部 meta 行 */
2335    var cFull = t('#info-left-1').replace(/▍/g, ' ');
2336    var mS = cFull.match(/学什么\s*([\s\S]{8,320}?)(?:怎么用|$)/);
2337    var cDesc = (mS ? mS[1] : cFull).replace(/^简介\s*/, '').replace(/\s+/g, ' ').trim();
2338    if (cDesc.length > 300) { cDesc = cDesc.slice(0, 297) + '…'; }
2339    var cover = '';
2340    var imgs = document.querySelectorAll('img');
2341    for (var i = 0; i < imgs.length; i++) {
2342      if (/\/files\/course\//.test(imgs[i].src || '')) { cover = imgs[i].src; break; }
2343    }
2344    var course = {
2345      '@context': 'https://schema.org',
2346      '@type': 'Course',
2347      name: cName,
2348      description: cDesc || cName,
2349      provider: { '@type': 'Organization', name: '范士闯数学', url: SITE + '/' }
2350    };
2351    if (cover) { course.image = cover; }
2352    if (cPrice !== '') {
2353      course.offers = {
2354        '@type': 'Offer',
2355        price: cPrice,
2356        priceCurrency: 'CNY',
2357        availability: 'https://schema.org/InStock',
2358        url: url
2359      };
2360    }
2361    course.audience = { '@type': 'EducationalAudience', educationalRole: 'student' };
2362    course.inLanguage = 'zh-CN';
2363    put('fsc-ld-course', course);
2364  }
2365
2366  /* ---------- ③ Article(文章详情页) ---------- */
2367  function dateEl() {
2368    return el('.article-metas .date') || el('.date') || el('[class*="date"]') || el('time');
2369  }
2370  function dateText() {
2371    var d = dateEl();
2372    return d ? (d.textContent || d.innerText || '') : '';
2373  }
2374  /* 解析日期:兼容「18 09月 2026年」「2026年09月18日」「2026-09-18T10:00:00+08:00」
2375     forceYear:DOM 里拿不到年份时由官方 API 传入真实年份
2376     无年份 → 返回 ''(绝不猜) */
2377  function parseDate(s, forceYear) {
2378    s = String(s || '').replace(/\s+/g, ' ').trim();
2379    var y = forceYear
2380         || (s.match(/(20\d\d)\s*å¹´/) || [])[1]
2381         || (s.match(/(20\d\d)[-\/.]/) || [])[1]
2382         || (s.match(/\b(20\d\d)\b/) || [])[1] || '';
2383    if (!y) { return ''; }
2384    var mo = (s.match(/(\d{1,2})\s*月/) || [])[1]
2385          || (s.match(/[-\/.](\d{1,2})[-\/.]/) || [])[1] || '';
2386    var dd = (s.match(/(\d{1,2})\s*日/) || [])[1]
2387          || (s.match(/^(\d{1,2})(?:\s|$)/) || [])[1]
2388          || (s.match(/[-\/.](\d{1,2})(?:[T\s]|$)/) || [])[1] || '';
2389    var out = y;
2390    if (mo) { out += '-' + ('0' + mo).slice(-2); }
2391    if (mo && dd) { out += '-' + ('0' + dd).slice(-2); }
2392    return out;
2393  }
2394  /* 摘要:明确候选链,避开页面顶部登录提示(旧版 [class*="article"] p 曾命中 <p>登录</p>) */
2395  function articleDesc() {
2396    var sels = ['.js-article-text', '.article-text', '.es-article-content',
2397                '[class*="article-content"]', '#detail-content .article-text'];
2398    for (var i = 0; i < sels.length; i++) {
2399      var e = el(sels[i]);
2400      if (!e) { continue; }
2401      var tx = (e.innerText || e.textContent || '').replace(/\s+/g, ' ').trim();
2402      if (tx.length >= 60) { return tx.slice(0, 200); }
2403    }
2404    var md = String((document.querySelector('meta[name="description"]') || {}).content || '')
2405             .replace(/\s+/g, ' ').trim();
2406    return md.slice(0, 200);
2407  }
2408  /* 官方 API 兜底:仅当 DOM 里等不到年份时才请求;结果存 sessionStorage,一次会话只请求一次 */
2409  function apiYear(id, cb) {
2410    var C = 'fscSeoPubV1';
2411    try {
2412      var c = JSON.parse(sessionStorage.getItem(C) || 'null');
2413      if (c && c.t && (Date.now() - c.t) < 6 * 3600 * 1000 && c.m && c.m[id]) { cb(c.m[id]); return; }
2414    } catch (e) {}
2415    try {
2416      fetch('/api/articles?limit=500', {
2417        credentials: 'same-origin',
2418        headers: { 'Accept': 'application/vnd.edusoho.v2+json' }
2419      }).then(function (r) { return r.ok ? r.json() : null; })
2420        .then(function (j) {
2421          if (!j || !j.data) { cb(''); return; }
2422          var m = {}, i;
2423          for (i = 0; i < j.data.length; i++) {
2424            var p = String(j.data[i].publishedTime || '');
2425            if (p.length >= 4) { m[String(j.data[i].id)] = p.slice(0, 4); }
2426          }
2427          try { sessionStorage.setItem(C, JSON.stringify({ t: Date.now(), m: m })); } catch (e2) {}
2428          cb(m[id] || '');
2429        })
2430        .catch(function () { cb(''); });
2431    } catch (e) { cb(''); }
2432  }
2433  function articleSchema(allowApi) {
2434    var aTitle = t('h1') || document.title.split('-')[0].trim();
2435    var dtxt = dateText();
2436    var aDate = parseDate(dtxt);
2437    var art = {
2438      '@context': 'https://schema.org',
2439      '@type': 'Article',
2440      headline: aTitle,
2441      author: { '@type': 'Person', name: '范士闯' },
2442      publisher: {
2443        '@type': 'Organization',
2444        name: '范士闯数学',
2445        logo: { '@type': 'ImageObject', url: 'https://www.xuetong.com/files/system/2026/09-17/1838499c1a54682586.png' }
2446      },
2447      mainEntityOfPage: { '@type': 'WebPage', '@id': url },
2448      inLanguage: 'zh-CN'
2449    };
2450    var body = articleDesc();
2451    if (body) { art.description = body; }
2452    if (aDate) { art.datePublished = aDate; }
2453    put('fsc-ld-article', art);
2454
2455    /* DOM 等不到年份 → 官方 API 兜底(拿到真实年份后与 DOM 的月/日拼完整) */
2456    if (!aDate && allowApi) {
2457      var mId = (path.match(/^\/article\/(\d+)/) || [])[1];
2458      if (mId) {
2459        apiYear(mId, function (y) {
2460          if (!y) { return; }
2461          var full = parseDate(dtxt, y);
2462          if (!full) { return; }
2463          art.datePublished = full;
2464          put('fsc-ld-article', art);
2465        });
2466      }
2467    }
2468  }
2469
2470  /* ---------- ④ BreadcrumbList(内容页) ---------- */
2471  function breadcrumbSchema() {
2472    if (/^\/(goods\/show\/|course\/|article\/|page\/|course\/explore|classroom|vip)/.test(path)) {
2473      var items = [{ '@type': 'ListItem', position: 1, name: '首页', item: SITE + '/' }];
2474      var pos = 2;
2475
2476      /* 优先:页面已有面包屑;按「去空格」归一化后去重(原页面 a/span 混排会重复) */
2477      var crumbEl = el('.breadcrumb') || el('[class*="breadcrumb"]') || el('[class*="crumb"]');
2478      var names = [], seen = {};
2479      if (crumbEl) {
2480        var kids = crumbEl.querySelectorAll('a, span, li');
2481        for (var k = 0; k < kids.length; k++) {
2482          var tx = (kids[k].innerText || '').replace(/\s+/g, '').trim().replace(/^\/|\/$/g, '');
2483          if (!tx || tx.length > 30 || /^[\/>»·•]+$/.test(tx)) { continue; }
2484          if (seen[tx]) { continue; }
2485          seen[tx] = 1;
2486          names.push(tx);
2487        }
2488      }
2489      /* 面包屑缺失 → 按路径推导 */
2490      if (!names.length) {
2491        var seg = path.split('/').filter(Boolean);
2492        if (seg[0] === 'page') {
2493          names.push(t('h1') || '页面');
2494        } else {
2495          var NAMEMAP = { goods: '课程详情', course: '课程', article: '黑板报',
2496                          classroom: '班级', explore: '全部', vip: '畅学年卡' };
2497          for (var j = 0; j < seg.length; j++) {
2498            var nm = NAMEMAP[seg[j]];
2499            if (nm === undefined) { nm = seg[j]; }
2500            if (nm && !seen[nm]) { seen[nm] = 1; names.push(nm); }
2501          }
2502        }
2503      }
2504      for (var n = 0; n < names.length && pos <= 6; n++) {
2505        if (names[n] === '首页') { continue; }
2506        var li = { '@type': 'ListItem', position: pos, name: names[n] };
2507        /* 只给末级真实 URL(中间层没有真 URL 时宁可不给,避免编造) */
2508        if (n === names.length - 1) { li.item = SITE + path; }
2509        items.push(li);
2510        pos++;
2511      }
2512      if (items.length > 1) {
2513        put('fsc-ld-breadcrumb', {
2514          '@context': 'https://schema.org',
2515          '@type': 'BreadcrumbList',
2516          itemListElement: items
2517        });
2518      }
2519    }
2520  }
2521
2522  function runAll(allowApi) {
2523    try { org(); } catch (e) {}
2524    try { if (isCourse) { courseSchema(); } } catch (e) {}
2525    try { if (isArticle) { articleSchema(allowApi); } } catch (e) {}
2526    try { breadcrumbSchema(); } catch (e) {}
2527  }
2528
2529  /* ---------- 执行时机:等「内容完整」而不是「元素存在」 ---------- */
2530  var MAX_TRY = 25;                       /* 25 × 400ms ≈ 10 秒 */
2531  function ready() {
2532    if (isCourse) {
2533      /* 课程页实测:h1 / #info-left-1 / 价格 在 DOMContentLoaded 前后同时就绪;
2534         仍加内容门槛,防未来改版导致读到半成品 */
2535      var info = t('#info-left-1');
2536      return t('h1').length > 0 && (info.length >= 80 || t('.detail-right__price__price').length > 0);
2537    }
2538    if (isArticle) {
2539      /* ★关键:必须有 4 位年份才算完整(年份由别段在 ~4.5s 补入) */
2540      return t('h1').length > 0 && /20\d\d/.test(dateText());
2541    }
2542    return true;
2543  }
2544  function boot(tries) {
2545    tries = tries || 0;
2546    /* 第一遍先落 Organization(不依赖正文),保证任何情况下都有产出 */
2547    try { org(); } catch (e) {}
2548    if (ready()) { runAll(false); return; }
2549    if (tries >= MAX_TRY) { runAll(true); return; }   /* 等不到了:文章页走 API 兜底 */
2550    setTimeout(function () { boot(tries + 1); }, 400);
2551  }
2552  if (document.readyState === 'loading') {
2553    document.addEventListener('DOMContentLoaded', function () { boot(0); });
2554  } else {
2555    boot(0);
2556  }
2557})();
2558</script>
2558
2559<!-- FSC:P3-5:END -->
2560</head></div>
2561<!-- FSC:P3-4:BEGIN -->
2562<!-- 范士闯数学 · 首页重新设计(P3-4)· 段ID fsc-home-redesign-css / fsc-home-redesign · 2026-09-19 -->
2563<style id="fsc-home-redesign-css">
2564/* ============================================================================
2565   范士闯数学 · 首页重新设计(指令卡 P3-4 · 2026-09-19)
2566   段ID: fsc-home-redesign-css
2567   ----------------------------------------------------------------------------
2568   全部规则以 body.homepage + .fsc-hrd 双重限定:
2569     · body.homepage  → 只在首页生效,其它页面零影响
2570     · .fsc-hrd 前缀  → 不与 EduSoho 主题的通用类(.container/.btn/h1…)冲突
2571   原 #content-container 不删除,仅在 body 加上 .fsc-hrd-on 后隐藏(回退只需去掉这个类)。
2572   回退:python xt_inject.py p34home revert
2573   ============================================================================ */
2574.fsc-hrd,
2575.fsc-hrd * { box-sizing: border-box; }
2576.fsc-hrd {
2577  font-family: inherit;
2578  background: var(--fsc-cream, #FBF8F2);
2579  color: #1a1a1a;
2580  line-height: 1.7;
2581}
2582body.homepage.fsc-hrd-on #content-container { display: none !important; }
2583
2584.fsc-hrd .hrd-in { max-width: 1140px; margin: 0 auto; padding: 0 20px; }
2585.fsc-hrd img { max-width: 100%; border: 0; }
2586.fsc-hrd a { text-decoration: none; }
2587
2588/* ── 1 首屏 Hero ── */
2589.fsc-hrd .hrd-hero {
2590  background: linear-gradient(135deg, #0F392B 0%, #1a5c42 50%, #0F392B 100%);
2591  color: #FBF8F2; padding: 64px 0; position: relative; overflow: hidden;
2592}
2593.fsc-hrd .hrd-hero::before {
2594  content: ''; position: absolute; top: -100px; right: -100px;
2595  width: 400px; height: 400px; border-radius: 50%;
2596  background: radial-gradient(circle, rgba(184,137,61,.2) 0%, transparent 70%);
2597}
2598.fsc-hrd .hrd-hero-grid {
2599  display: grid; grid-template-columns: 1.2fr 1fr; gap: 50px;
2600  align-items: center; position: relative; z-index: 2;
2601}
2602.fsc-hrd .hrd-tag {
2603  display: inline-block; border: 1px solid #B8893D; color: #B8893D;
2604  background: rgba(184,137,61,.2); border-radius: 20px;
2605  padding: 6px 16px; font-size: 13px; letter-spacing: 1px; margin-bottom: 20px;
2606}
2607/* ★ Hero 主标题用 <h2 class="hrd-h1">(不是 h1):
2608   P2-1 段(fsc-seo-h1)已在每页注入 1 个视觉隐藏的 h1 承载页面主标题,
2609   此处再用 h1 会造成「同页两个 h1」。改用 h2 + 同款样式,视觉效果完全一致,
2610   同时保住全站「每页恰好 1 个 h1」的 SEO 约定。
2611   另注:fsc-typography 段有全局 `h1,h2,h3{color:var(--fsc-green)}`,
2612   因此深色底上的标题必须显式写 color,否则会变成深绿看不清。 */
2613.fsc-hrd .hrd-hero .hrd-h1 {
2614  font-size: 42px; font-weight: 800; line-height: 1.3;
2615  margin: 0 0 16px; color: #FBF8F2; padding: 0; border: 0;
2616}
2617.fsc-hrd .hrd-hero .hrd-h1 .gold { color: #B8893D; }
2618/* 品牌金色强调词。必须写成显式规则:站点全局有 `h1,h2,h3{color:var(--fsc-green)}`,
2619   深色底上的强调字若不显式指定,会继承到深绿而几乎看不见。 */
2620.fsc-hrd .gold { color: #B8893D; }
2621.fsc-hrd .hrd-sub {
2622  font-size: 17px; line-height: 1.8; margin: 0 0 28px;
2623  color: rgba(251,248,242,.8);
2624}
2625.fsc-hrd .hrd-ctas { display: flex; gap: 16px; margin-bottom: 30px; flex-wrap: wrap; }
2626.fsc-hrd .hrd-btn-1,
2627.fsc-hrd .hrd-btn-2 {
2628  display: inline-block; padding: 14px 32px; border-radius: 8px;
2629  font-size: 16px; font-weight: 600; transition: all .3s; line-height: 1.2;
2630}
2631.fsc-hrd .hrd-btn-1 {
2632  background: #B8893D; color: #fff;
2633  box-shadow: 0 4px 16px rgba(184,137,61,.4);
2634}
2635.fsc-hrd .hrd-btn-1:hover { background: #c99a4e; color: #fff; transform: translateY(-2px); }
2636.fsc-hrd .hrd-btn-2 {
2637  color: #FBF8F2; border: 1.5px solid rgba(251,248,242,.4);
2638}
2639.fsc-hrd .hrd-btn-2:hover { border-color: #B8893D; color: #B8893D; }
2640.fsc-hrd .hrd-stats {
2641  display: flex; gap: 40px; padding-top: 24px;
2642  border-top: 1px solid rgba(251,248,242,.15);
2643}
2644.fsc-hrd .hrd-num { font-size: 28px; font-weight: 700; color: #B8893D; }
2645.fsc-hrd .hrd-lab { font-size: 13px; color: rgba(251,248,242,.6); }
2646.fsc-hrd .hrd-hero-card {
2647  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.15);
2648  border-radius: 16px; padding: 30px; text-align: center;
2649  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
2650}
2651.fsc-hrd .hrd-hc-title { font-size: 18px; font-weight: 600; margin-bottom: 8px; }
2652.fsc-hrd .hrd-hc-price { font-size: 42px; font-weight: 800; color: #B8893D; margin: 10px 0; }
2653.fsc-hrd .hrd-hc-price small { font-size: 16px; font-weight: 400; color: rgba(251,248,242,.6); }
2654.fsc-hrd .hrd-hc-desc { font-size: 13px; color: rgba(251,248,242,.7); margin-bottom: 16px; }
2655.fsc-hrd .hrd-hc-list { text-align: left; font-size: 13px; line-height: 2;
2656  color: rgba(251,248,242,.8); margin: 0; padding: 0; list-style: none; }
2657.fsc-hrd .hrd-hc-list li { list-style: none; padding-left: 20px; position: relative; }
2658.fsc-hrd .hrd-hc-list li::before {
2659  content: '\2713'; position: absolute; left: 0; color: #B8893D; font-weight: 700;
2660}
2661.fsc-hrd .hrd-hc-btn {
2662  display: inline-block; margin-top: 18px; padding: 10px 24px; border-radius: 8px;
2663  background: #B8893D; color: #fff; font-size: 14px; font-weight: 600;
2664}
2665.fsc-hrd .hrd-hc-btn:hover { background: #c99a4e; color: #fff; }
2666
2667/* ── 通用区块 ── */
2668.fsc-hrd .hrd-sec { padding: 58px 0; }
2669.fsc-hrd .hrd-head { text-align: center; margin-bottom: 38px; }
2670.fsc-hrd .hrd-sec-tag {
2671  display: inline-block; color: #B8893D; font-size: 13px;
2672  font-weight: 600; letter-spacing: 2px; margin-bottom: 8px;
2673}
2674.fsc-hrd .hrd-sec-title {
2675  font-size: 30px; font-weight: 700; color: #0F392B;
2676  margin: 0 0 10px; padding: 0; border: 0; line-height: 1.35;
2677}
2678.fsc-hrd .hrd-sec-desc { font-size: 15px; color: #888; margin: 0; }
2679
2680/* ── 2 核心产品三入口 ── */
2681.fsc-hrd .hrd-products { background: #fff; }
2682.fsc-hrd .hrd-pgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
2683.fsc-hrd .hrd-pcard {
2684  background: #FBF8F2; border-radius: 16px; padding: 32px 28px; text-align: center;
2685  border: 2px solid transparent; transition: all .3s;
2686}
2687.fsc-hrd .hrd-pcard:hover {
2688  transform: translateY(-6px); border-color: #B8893D;
2689  box-shadow: 0 12px 32px rgba(15,57,43,.12);
2690}
2691.fsc-hrd .hrd-picon {
2692  width: 64px; height: 64px; border-radius: 16px; margin: 0 auto 18px;
2693  display: flex; align-items: center; justify-content: center; font-size: 28px;
2694  background: linear-gradient(135deg, #0F392B, #1a5c42); color: #FBF8F2;
2695}
2696.fsc-hrd .hrd-pcard:nth-child(2) .hrd-picon { background: linear-gradient(135deg, #B8893D, #d4a84f); }
2697.fsc-hrd .hrd-pcard:nth-child(3) .hrd-picon { background: linear-gradient(135deg, #3A6B55, #4a8068); }
2698.fsc-hrd .hrd-pname { font-size: 20px; font-weight: 700; color: #0F392B; margin-bottom: 8px; }
2699.fsc-hrd .hrd-pdesc { font-size: 14px; color: #666; margin-bottom: 16px; line-height: 1.7; }
2700.fsc-hrd .hrd-pprice { font-size: 22px; font-weight: 700; color: #B8893D; }
2701.fsc-hrd .hrd-pprice small { font-size: 13px; font-weight: 400; color: #999; }
2702
2703/* ── 3 精选课程(动态)── */
2704.fsc-hrd .hrd-courses { background: #FBF8F2; }
2705.fsc-hrd .hrd-cgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
2706.fsc-hrd .hrd-ccard {
2707  background: #fff; border-radius: 12px; overflow: hidden;
2708  box-shadow: 0 2px 12px rgba(15,57,43,.06); transition: all .3s; display: block;
2709}
2710.fsc-hrd .hrd-ccard:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(15,57,43,.12); }
2711.fsc-hrd .hrd-ccover { position: relative; background: #eef1ee; }
2712.fsc-hrd .hrd-ccover img { display: block; width: 100%; height: 168px; object-fit: cover; }
2713.fsc-hrd .hrd-badge {
2714  position: absolute; top: 12px; right: 12px; background: rgba(255,255,255,.92);
2715  color: #0F392B; padding: 4px 10px; border-radius: 10px;
2716  font-size: 11px; font-weight: 600;
2717}
2718.fsc-hrd .hrd-cinfo { padding: 16px 18px; }
2719.fsc-hrd .hrd-ctitle {
2720  font-size: 15px; font-weight: 600; color: #1a1a1a; line-height: 1.45;
2721  margin: 0 0 10px; min-height: 43px;
2722}
2723.fsc-hrd .hrd-cmeta {
2724  display: flex; justify-content: space-between; align-items: center;
2725  font-size: 13px; color: #888;
2726}
2727.fsc-hrd .hrd-cnum { color: #B8893D; font-weight: 600; }
2728
2729/* ── 4 学通班级(动态)── */
2730.fsc-hrd .hrd-classes { background: #fff; }
2731.fsc-hrd .hrd-clgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
2732.fsc-hrd .hrd-clcard {
2733  display: block; background: #FBF8F2; border-radius: 12px; overflow: hidden;
2734  border: 1px solid #ece6da; transition: all .3s;
2735}
2736.fsc-hrd .hrd-clcard:hover { transform: translateY(-4px); border-color: #B8893D;
2737  box-shadow: 0 8px 24px rgba(15,57,43,.1); }
2738.fsc-hrd .hrd-clcover { display: block; width: 100%; height: 150px; object-fit: cover; background: #eef1ee; }
2739.fsc-hrd .hrd-clinfo { padding: 16px 18px; }
2740.fsc-hrd .hrd-cltitle {
2741  font-size: 15px; font-weight: 600; color: #1a1a1a; line-height: 1.45; margin: 0 0 10px;
2742}
2743.fsc-hrd .hrd-clmeta { font-size: 12.5px; color: #888; display: flex; gap: 14px; flex-wrap: wrap; }
2744
2745/* ── 5 直播课介绍 ── */
2746.fsc-hrd .hrd-live {
2747  background: linear-gradient(135deg, #0F392B 0%, #1a5c42 100%); color: #FBF8F2;
2748}
2749.fsc-hrd .hrd-live-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 50px; align-items: center; }
2750.fsc-hrd .hrd-live h2 {
2751  font-size: 32px; font-weight: 700; margin: 0 0 16px; color: #FBF8F2; padding: 0; border: 0;
2752}
2753.fsc-hrd .hrd-live h2 .gold { color: #B8893D; }
2754.fsc-hrd .hrd-ldesc { font-size: 16px; line-height: 1.8; color: rgba(251,248,242,.8); margin: 0 0 24px; }
2755.fsc-hrd .hrd-lfeats { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 26px; }
2756.fsc-hrd .hrd-lfeat { display: flex; gap: 10px; align-items: flex-start; }
2757.fsc-hrd .hrd-lfico {
2758  flex-shrink: 0; width: 24px; height: 24px; margin-top: 2px; border-radius: 6px;
2759  background: rgba(184,137,61,.2); color: #B8893D; font-size: 12px;
2760  display: flex; align-items: center; justify-content: center;
2761}
2762.fsc-hrd .hrd-lftext { font-size: 14px; color: rgba(251,248,242,.85); }
2763.fsc-hrd .hrd-lcard {
2764  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.15);
2765  border-radius: 16px; padding: 34px; text-align: center;
2766  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
2767}
2768.fsc-hrd .hrd-lctitle { font-size: 20px; font-weight: 600; margin-bottom: 12px; }
2769.fsc-hrd .hrd-lcprice { font-size: 34px; font-weight: 800; color: #B8893D; margin: 12px 0; }
2770.fsc-hrd .hrd-lcnote { font-size: 13px; color: rgba(251,248,242,.6); margin-bottom: 18px; }
2771.fsc-hrd .hrd-lcextra { font-size: 14px; line-height: 1.9; color: rgba(251,248,242,.72); }
2772
2773/* ── 6 文章推荐(动态)── */
2774.fsc-hrd .hrd-articles { background: #fff; }
2775/* 文章条数由后台决定(实测首页 4 条)。用 auto-fit 让列数自适应:
2776   4 条 → 一行 4 列;3 条 → 一行 3 列;不多不少,不会出现「1 张卡孤零零占一行」。 */
2777.fsc-hrd .hrd-agrid {
2778  display: grid; gap: 24px;
2779  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
2780}
2781.fsc-hrd .hrd-acard {
2782  display: block; background: #FBF8F2; border-radius: 12px; padding: 22px;
2783  border: 1px solid #efe9dd; transition: all .3s;
2784}
2785.fsc-hrd .hrd-acard:hover { transform: translateY(-4px); border-color: #B8893D;
2786  box-shadow: 0 8px 24px rgba(15,57,43,.1); }
2787.fsc-hrd .hrd-acat {
2788  display: inline-block; background: rgba(184,137,61,.15); color: #B8893D;
2789  padding: 3px 10px; border-radius: 8px; font-size: 11px; font-weight: 600; margin-bottom: 10px;
2790}
2791.fsc-hrd .hrd-atitle {
2792  font-size: 15px; font-weight: 600; color: #1a1a1a; line-height: 1.5;
2793  margin: 0 0 8px; min-height: 45px;
2794}
2795.fsc-hrd .hrd-adate { font-size: 12px; color: #999; }
2796.fsc-hrd .hrd-amore { text-align: center; margin-top: 30px; }
2797.fsc-hrd .hrd-amore a {
2798  display: inline-block; padding: 11px 30px; border-radius: 8px;
2799  border: 1.5px solid #0F392B; color: #0F392B; font-size: 14px; font-weight: 600;
2800}
2801.fsc-hrd .hrd-amore a:hover { background: #0F392B; color: #FBF8F2; }
2802
2803/* ── 7 尾屏 CTA ── */
2804.fsc-hrd .hrd-cta {
2805  background: linear-gradient(135deg, #0F392B 0%, #1a5c42 100%);
2806  color: #FBF8F2; padding: 58px 0; text-align: center;
2807}
2808.fsc-hrd .hrd-cta h2 {
2809  font-size: 30px; font-weight: 700; margin: 0 0 12px; color: #FBF8F2; padding: 0; border: 0;
2810}
2811.fsc-hrd .hrd-cta p { font-size: 16px; color: rgba(251,248,242,.7); margin: 0 0 26px; }
2812.fsc-hrd .hrd-contact { font-size: 20px; font-weight: 600; color: #B8893D; }
2813.fsc-hrd .hrd-contact small {
2814  display: block; margin-top: 6px; font-size: 13px; font-weight: 400;
2815  color: rgba(251,248,242,.5);
2816}
2817.fsc-hrd .hrd-cta .hrd-btn-1 { margin-top: 22px; }
2818
2819/* ── 响应式 ── */
2820@media (max-width: 768px) {
2821  .fsc-hrd .hrd-hero { padding: 44px 0; }
2822  .fsc-hrd .hrd-hero-grid,
2823  .fsc-hrd .hrd-live-grid { grid-template-columns: 1fr; gap: 30px; }
2824  .fsc-hrd .hrd-hero .hrd-h1 { font-size: 28px; }
2825  .fsc-hrd .hrd-sec { padding: 40px 0; }
2826  .fsc-hrd .hrd-pgrid,
2827  .fsc-hrd .hrd-cgrid,
2828  .fsc-hrd .hrd-clgrid,
2829  .fsc-hrd .hrd-agrid { grid-template-columns: 1fr; }
2830  .fsc-hrd .hrd-lfeats { grid-template-columns: 1fr; }
2831  .fsc-hrd .hrd-stats { gap: 20px; }
2832  .fsc-hrd .hrd-num { font-size: 22px; }
2833  .fsc-hrd .hrd-sec-title { font-size: 23px; }
2834  .fsc-hrd .hrd-live h2 { font-size: 24px; }
2835  .fsc-hrd .hrd-cta h2 { font-size: 23px; }
2836  .fsc-hrd .hrd-ccover img,
2837  .fsc-hrd .hrd-clcover { height: 150px; }
2838}
2839</style>
2840<script id="fsc-home-redesign">
2841/* ============================================================================
2842   范士闯数学 · 首页 DOM 重组(指令卡 P3-4 · 2026-09-19)
2843   段ID: fsc-home-redesign
2844   ----------------------------------------------------------------------------
2845   目标:把 EduSoho 默认首页(轮播 + 推荐课程两栏)重组为品牌化 7 区块布局。
2846   动态内容全部现读现渲染,不硬编码:
2847     · 精选课程 ← li.es-course-list          (标题/封面/报名数/链接)
2848     · 学通班级 ← ul.home-class-list > li    (标题/封面/学员数/课数/链接)
2849     · 文章推荐 ← .es-box.news li            (分类/标题/日期/链接)
2850   原 #content-container 不删除,只在 body 加 .fsc-hrd-on 后由 CSS 隐藏(含轮播)。
2851   ★执行时机:重试闸门,等三处动态内容齐了再重组;防闪烁做法是「离屏构建 →
2852     一次性插入 → 加类」在同一帧完成,不先隐藏再填内容。
2853   回退:python xt_inject.py p34home revert
2854   ============================================================================ */
2855(function () {
2856  'use strict';
2857  if (window.__fscHomeRd) { return; }
2858  window.__fscHomeRd = 1;
2859
2860  /* ── 只在首页生效 ── */
2861  function isHome() {
2862    var p = location.pathname;
2863    return (p === '/' || p === '/index' || p === '/index.php') &&
2864           document.body && document.body.className.indexOf('homepage') >= 0;
2865  }
2866  if (!isHome()) { return; }
2867
2868  function esc(s) {
2869    return String(s == null ? '' : s)
2870      .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
2871      .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
2872  }
2873  function txt(e) { return e ? (e.innerText || e.textContent || '').replace(/\s+/g, ' ').trim() : ''; }
2874  function q(root, sel) { return root ? root.querySelector(sel) : null; }
2875  function qa(root, sel) { return root ? Array.prototype.slice.call(root.querySelectorAll(sel)) : []; }
2876
2877  /* ── 从原有 DOM 里采集动态数据 ── */
2878
2879  /* ★为什么课程卡片没有价格:
2880     实测 ①首页 li.es-course-list 里只有 a/img/h3/.student-num,**没有价格元素**;
2881          ②公开接口 /api/courses 返回 {"code":500,"message":"API Token不存在!"}
2882            (需后台 Token,前端拿不到)。
2883     所以卡片展示「报名数 + 查看详情」,不显示价格 —— 硬编码价格会与后台脱节,
2884     违反指令卡注意事项 #9(不硬编码业务事实)。 */
2885  function pickCourses() {
2886    var out = [];
2887    qa(document, 'li.es-course-list').forEach(function (li) {
2888      var a  = q(li, 'a[href]');
2889      var im = q(li, 'img');
2890      var h3 = q(li, 'h3');
2891      var title = txt(h3);
2892      if (!title || !a) { return; }
2893      out.push({
2894        title: title,
2895        href: a.getAttribute('href') || '#',
2896        img: im ? (im.getAttribute('src') || im.getAttribute('data-echo') || '') : '',
2897        num: txt(q(li, '.student-num'))
2898      });
2899    });
2900    return out;
2901  }
2902
2903  function pickClasses() {
2904    var out = [];
2905    qa(document, 'ul.home-class-list > li').forEach(function (li) {
2906      var a  = q(li, 'a[href]');
2907      var im = q(li, 'img');
2908      var t  = q(li, '.class-title');
2909      var title = txt(t);
2910      if (!title || !a) { return; }
2911      var m = [];
2912      var stu = txt(q(li, '.class-student'));
2913      var cnt = txt(q(li, '.course-num'));
2914      var tea = txt(q(li, '.class-teacher .text-color')) || txt(q(li, '.class-teacher'));
2915      /* 加中文标签:`.class-student` 的文本只是一个数字(图标+数字),
2916         光秃秃一个「2」读者不知道是什么,所以补「学员」。 */
2917      if (tea) { m.push('师资 ' + tea); }
2918      if (stu) { m.push('学员 ' + stu); }
2919      if (cnt) { m.push(cnt); }
2920      out.push({
2921        title: title,
2922        href: a.getAttribute('href') || '#',
2923        img: im ? (im.getAttribute('src') || im.getAttribute('data-echo') || '') : '',
2924        metas: m
2925      });
2926    });
2927    return out;
2928  }
2929
2930  function pickArticles() {
2931    var out = [];
2932    qa(document, '.es-box.news li').forEach(function (li) {
2933      var a = q(li, 'a[href]');
2934      if (!a) { return; }
2935      /* 分类在原模板里带方括号(如「[教学方法]」)。
2935徽章本身已有底色,
2936         再套一层方括号很啰嗦,先剥掉。 */
2937      var cat = txt(q(a, 'span')).replace(/^[\s\[[【]+|[\s\]]】]+$/g, '');
2938      var title = txt(a).replace(txt(q(a, 'span')), '').trim();
2939      if (!title) { title = txt(a); }
2940      out.push({
2941        title: title,
2942        cat: cat,
2943        href: a.getAttribute('href') || '#',
2944        date: txt(q(li, 'em'))
2945      });
2946    });
2947    return out;
2948  }
2949
2950  /* ── 渲染 ── */
2951
2952  function courseCards(list) {
2953    return list.map(function (c) {
2954      var badge = /免费/.test(c.title) ? '<span class="hrd-badge">免费体验</span>' : '';
2955      var cover = c.img
2956        ? '<img src="' + esc(c.img) + '" alt="' + esc(c.title) + '" loading="lazy">'
2957        : '';
2958      return '<a class="hrd-ccard" href="' + esc(c.href) + '">' +
2959               '<div class="hrd-ccover">' + cover + badge + '</div>' +
2960               '<div class="hrd-cinfo">' +
2961                 '<h3 class="hrd-ctitle">' + esc(c.title) + '</h3>' +
2962                 '<div class="hrd-cmeta">' +
2963                   '<span>' + (c.num ? esc(c.num) : '录播课') + '</span>' +
2964                   '<span class="hrd-cnum">查看详情 &rsaquo;</span>' +
2965                 '</div>' +
2966               '</div></a>';
2967    }).join('');
2968  }
2969
2970  function classCards(list) {
2971    return list.map(function (c) {
2972      var cover = c.img
2973        ? '<img class="hrd-clcover" src="' + esc(c.img) + '" alt="' + esc(c.title) + '" loading="lazy">'
2974        : '';
2975      var metas = (c.metas || []).map(function (m) {
2976        return '<span>' + esc(m) + '</span>';
2977      }).join('');
2978      return '<a class="hrd-clcard" href="' + esc(c.href) + '">' + cover +
2979               '<div class="hrd-clinfo">' +
2980                 '<h3 class="hrd-cltitle">' + esc(c.title) + '</h3>' +
2981                 '<div class="hrd-clmeta">' + metas + '</div>' +
2982               '</div></a>';
2983    }).join('');
2984  }
2985
2986  function articleCards(list) {
2987    return list.map(function (a) {
2988      return '<a class="hrd-acard" href="' + esc(a.href) + '">' +
2989               (a.cat ? '<span class="hrd-acat">' + esc(a.cat) + '</span>' : '') +
2990               '<h3 class="hrd-atitle">' + esc(a.title) + '</h3>' +
2991               '<div class="hrd-adate">' + esc(a.date) + '</div>' +
2992             '</a>';
2993    }).join('');
2994  }
2995
2996  function buildHTML(courses, classes, articles) {
2997    return '' +
2998    /* 1 首屏 Hero */
2999    '<section class="hrd-hero">' +
3000      '<div class="hrd-in"><div class="hrd-hero-grid">' +
3001        '<div>' +
3002          '<div class="hrd-tag">范士闯数学 · 学通在线</div>' +
3003          '<h2 class="hrd-h1">学会,不是学过<br><span class="gold">专注数学这一件事</span></h2>' +
3004          '<p class="hrd-sub">166 门录播课 + 10 个打包班 + 范老师直播课,覆盖小学到初中全学段。' +
3005            '精确审题 · 独立思考 · 精细计算 · 规范书写。</p>' +
3006          '<div class="hrd-ctas">' +
3007            '<a class="hrd-btn-1" href="/vip/">开通畅学年卡</a>' +
3008            '<a class="hrd-btn-2" href="/course/explore">浏览全部课程</a>' +
3009          '</div>' +
3010          '<div class="hrd-stats">' +
3011            '<div><div class="hrd-num">166</div><div class="hrd-lab">门录播课程</div></div>' +
3012            '<div><div class="hrd-num">10</div><div class="hrd-lab">个打包班级</div></div>' +
3013            '<div><div class="hrd-num">12</div><div class="hrd-lab">人小班直播课</div></div>' +
3014          '</div>' +
3015        '</div>' +
3016        '<div>' +
3017          '<div class="hrd-hero-card">' +
3018            '<div class="hrd-hc-title">畅学年卡</div>' +
3019            '<div class="hrd-hc-price">&yen;1,499<small> / å¹´</small></div>' +
3020            '<div class="hrd-hc-desc">全站 166 门课 + 10 个班,一年随便学</div>' +
3021            '<ul class="hrd-hc-list">' +
3022              '<li>166 门数学课全部免费</li>' +
3023              '<li>10 个打包班全部包含</li>' +
3024              '<li>新课上线自动包含</li>' +
3025              '<li>反复看,不限次数</li>' +
3026              '<li>折合每天约 &yen;4.1</li>' +
3027            '</ul>' +
3028            '<a class="hrd-hc-btn" href="/vip/">查看年卡详情</a>' +
3029          '</div>' +
3030        '</div>' +
3031      '</div></div>' +
3032    '</section>' +
3033
3034    /* 2 核心产品三入口 */
3035    '<section class="hrd-sec hrd-products">' +
3036      '<div class="hrd-in">' +
3037        '<div class="hrd-head">' +
3038          '<div class="hrd-sec-tag">CORE PRODUCTS</div>' +
3039          '<h2 class="hrd-sec-title">三种学习方式,总有一种适合您</h2>' +
3040          '<p class="hrd-sec-desc">从自主学习到小班直播,覆盖不同需求和预算</p>' +
3041        '</div>' +
3042        '<div class="hrd-pgrid">' +
3043          '<div class="hrd-pcard">' +
3044            '<div class="hrd-picon">&#127891;</div>' +
3045            '<div class="hrd-pname">畅学年卡</div>' +
3046            '<div class="hrd-pdesc">全站 166 门课 + 10 个班,一年不限次随便学,性价比最高</div>' +
3047            '<div class="hrd-pprice">&yen;1,499<small> / å¹´</small></div>' +
3048          '</div>' +
3049          '<div class="hrd-pcard">' +
3050            '<div class="hrd-picon">&#128250;</div>' +
3051            '<div class="hrd-pname">
3051范老师直播课</div>' +
3052            '<div class="hrd-pdesc">满班 12 人小班,每周固定一次,每节都有回放,互动性最强</div>' +
3053            '<div class="hrd-pprice">咨询范老师</div>' +
3054          '</div>' +
3055          '<div class="hrd-pcard">' +
3056            '<div class="hrd-picon">&#128218;</div>' +
3057            '<div class="hrd-pname">单课 / 单班</div>' +
3058            '<div class="hrd-pdesc">只想补某一块?单买一门课或一个班,精准解决问题</div>' +
3059            '<div class="hrd-pprice">&yen;129<small> èµ·</small></div>' +
3060          '</div>' +
3061        '</div>' +
3062      '</div>' +
3063    '</section>' +
3064
3065    /* 3 精选课程(动态) */
3066    (courses.length ?
3067    '<section class="hrd-sec hrd-courses">' +
3068      '<div class="hrd-in">' +
3069        '<div class="hrd-head">' +
3070          '<div class="hrd-sec-tag">SELECTED COURSES</div>' +
3071          '<h2 class="hrd-sec-title">推荐课程</h2>' +
3072          '<p class="hrd-sec-desc">先免费体验,再决定要不要系统学</p>' +
3073        '</div>' +
3074        '<div class="hrd-cgrid">' + courseCards(courses) + '</div>' +
3075      '</div>' +
3076    '</section>' : '') +
3077
3078    /* 4 学通班级(动态) */
3079    (classes.length ?
3080    '<section class="hrd-sec hrd-classes">' +
3081      '<div class="hrd-in">' +
3082        '<div class="hrd-head">' +
3083          '<div class="hrd-sec-tag">PACKAGED CLASSES</div>' +
3084          '<h2 class="hrd-sec-title">学通班级</h2>' +
3085          '<p class="hrd-sec-desc">按学期成体系打包,跟着班级节奏走</p>' +
3086        '</div>' +
3087        '<div class="hrd-clgrid">' + classCards(classes) + '</div>' +
3088        '<div class="hrd-amore"><a href="/classroom/explore">查看全部班级 &rsaquo;</a></div>' +
3089      '</div>' +
3090    '</section>' : '') +
3091
3092    /* 5 直播课介绍 */
3093    '<section class="hrd-sec hrd-live">' +
3094      '<div class="hrd-in"><div class="hrd-live-grid">' +
3095        '<div>' +
3096          '<div class="hrd-sec-tag" style="color:#B8893D;">LIVE CLASS</div>' +
3097          '<h2>范士闯直播课<br><span class="gold">满班 12 人 · 每周固定一次</span></h2>' +
3098          '<p class="hrd-ldesc">不同于录播课的自主学习,直播课是真正的「面对面」教学。' +
3099            '范老师亲自授课,实时互动答疑,每节都有回放可反复观看。</p>' +
3100          '<div class="hrd-lfeats">' +
3101            '<div class="hrd-lfeat"><div class="hrd-lfico">&#10003;</div>' +
3102              '<div class="hrd-lftext">满班 12 人小班,关注度高</div></div>' +
3103            '<div class="hrd-lfeat"><div class="hrd-lfico">&#10003;</div>' +
3104              '<div class="hrd-lftext">每周固定时间,养成学习习惯</div></div>' +
3105            '<div class="hrd-lfeat"><div class="hrd-lfico">&#10003;</div>' +
3106              '<div class="hrd-lftext">实时互动答疑,问题不过夜</div></div>' +
3107            '<div class="hrd-lfeat"><div class="hrd-lfico">&#10003;</div>' +
3108              '<div class="hrd-lftext">每节都有回放,可反复观看</div></div>' +
3109          '</div>' +
3110          '<a class="hrd-btn-1" href="/page/liveclass">查看直播课</a>' +
3111        '</div>' +
3112        '<div class="hrd-lcard">' +
3113          '<div class="hrd-lctitle">范士闯直播课</div>' +
3114          '<div class="hrd-lcprice">名额有限</div>' +
3115          '<div class="hrd-lcnote">满班 12 人,需提前预约</div>' +
3116          '<div class="hrd-lcextra">小学各年级均有开班<br>具体时间和费用请咨询范老师</div>' +
3117        '</div>' +
3118      '</div></div>' +
3119    '</section>' +
3120
3121    /* 6 文章推荐(动态) */
3122    (articles.length ?
3123    '<section class="hrd-sec hrd-articles">' +
3124      '<div class="hrd-in">' +
3125        '<div class="hrd-head">' +
3126          '<div class="hrd-sec-tag">TEACHING NOTES</div>' +
3127          '<h2 class="hrd-sec-title">教学方法 · 黑板报</h2>' +
3128          '<p class="hrd-sec-desc">教学经验分享,帮您更懂数学教育</p>' +
3129        '</div>' +
3130        '<div class="hrd-agrid">' + articleCards(articles) + '</div>' +
3131        '<div class="hrd-amore"><a href="/article">查看全部文章 &rsaquo;</a></div>' +
3132      '</div>' +
3133    '</section>' : '') +
3134
3135    /* 7 尾屏 CTA */
3136    '<section class="hrd-cta">' +
3137      '<div class="hrd-in">' +
3138        '<h2>开始孩子的数学学习之旅</h2>' +
3139        '<p>
3139166 门课 + 10 个班 + 范老师直播课,总有一种适合您的孩子</p>' +
3140        '<div class="hrd-contact">范老师:183-1075-0509(微信同电话)' +
3141          '<small>微信 / 银行转账均可,收到后立即开通,全程几分钟</small>' +
3142        '</div>' +
3143        '<a class="hrd-btn-1" href="/course/explore">开始选课</a>' +
3144      '</div>' +
3145    '</section>';
3146  }
3147
3148  /* ── 执行:同步首挂 + 重试闸门 + 原子切换 ── */
3149  var MAX_TRY = 30;                     /* 30 × 200ms ≈ 6 秒 */
3150  function mount() {
3151    if (document.getElementById('fscHomeRedesign')) { return true; }
3152    var cc = document.getElementById('content-container');
3153    if (!cc) { return false; }
3154    var wrap = cc.parentNode;                 /* 不写死 .es-wrap,用真实父节点 */
3155    if (!wrap) { return false; }
3156
3157    var courses = pickCourses();
3158    var classes = pickClasses();
3159    var articles = pickArticles();
3160    /* 内容闸门:三处动态内容一处都没采到就不挂载(避免渲染出空区块) */
3161    if (!courses.length && !classes.length && !articles.length) { return false; }
3162
3163    var box = document.createElement('div');
3164    box.className = 'fsc-hrd';
3165    box.id = 'fscHomeRedesign';
3166    box.innerHTML = buildHTML(courses, classes, articles);   /* 离屏构建 */
3167
3168    wrap.insertBefore(box, cc);          /* 一次性插入 */
3169    document.body.classList.add('fsc-hrd-on');  /* 同一帧内隐藏原内容 → 无中间态 */
3170    return true;
3171  }
3172
3173  function safeMount() {
3174    try { return mount(); } catch (e) { return false; }
3175  }
3176
3177  function boot(tries) {
3178    tries = tries || 0;
3179    if (safeMount() || tries >= MAX_TRY) { return; }
3180    setTimeout(function () { boot(tries + 1); }, 200);
3181  }
3182
3183  /* ★防闪烁的关键:
3184     实测本段注入内容位于首页 HTML 的 51% 处(正文与页脚之后),
3185     浏览器解析到这里时 #content-container、课程/班级/资讯卡片都已在 DOM 中,
3186     所以「同步挂载一次」——挂载与首次绘制落在同一帧,旧布局几乎不会露面。
3187     万一模板改动导致尚未就绪,再退回到 200ms 重试闸门(等异步渲染)。 */
3188  if (!safeMount()) {
3189    if (document.readyState === 'loading') {
3190      document.addEventListener('DOMContentLoaded', function () { boot(0); });
3191    } else {
3192      boot(0);
3193    }
3194  }
3195})();
3196</script>
3196
3197<!-- FSC:P3-4:END -->
3198
3199      
3200    </div>
3201  </div>
3202  <div class="text-gray " data-role="default-foot-bar" id="license-footer">
3203    <div class="container clearfix">
3204    
3205    
3206        </div>
3207  </div>
3208</div>
3209
3210<div class="fixed-bar">
3211      <a href="/mobile/" class="mobile-badge-container">
3212      <span class="iconfont icon-mobile"></span>
3213      <small class="badge"> </small>
3214    </a>
3215  </div>    
3216        
3217        </div>
3218
3219        
3220        
3221  
3222        
3223      
3224  <div id="login-modal" class="modal" data-url="/login/ajax"></div>
3225  <div id="modal" class="modal"></div>
3226  <div id="attachment-modal" class="modal"></div>
3227
3228    
3229
3230  
3231
3232
3233  
3233<script>
3234  if (typeof app === 'undefined') {
3235      var app = {};
3236  }
3237  app.version = '26.3.6';
3238  app.httpHost = 'https://xuetong.com';
3239  app.basePath = 'https://xuetong.com';
3240  app.theme = 'graceful';
3241
3242    
3243  var CLOUD_FILE_SERVER = "";
3244
3245  app.config = {"api":{"weibo":{"key":""},"qq":{"key":"101196906"},"douban":{"key":""},"renren":{"key":""}},"loading_img_path":"\/assets\/img\/default\/loading.gif?version=26.3.6"};
3246
3247  app.arguments = {};
3248    
3249  app.scripts = null;
3250
3251  app.fileSingleSizeLimit = 10;
3252  app.uploadUrl = '/file/upload';
3253  app.imgCropUrl = '/file/img/crop';
3254  app.lessonCopyEnabled = '0';
3255  app.cloudSdkBaseUri = '';
3256  app.cloudDisableLogReport = 0;
3257  app.cloudPlayerSdkUrl = '//service-cdn.qiqiuyun.net/js-sdk/sdk-v1.js?17913833';
3258  app.cloudPlayServer = 'play1.qiqiuyun.net';
3259  app.cloudVideoPlayerSdkUrl = '//service-cdn.qiqiuyun.net/js-sdk-v2/sdk-v1.js?17913833';
3260  app.cloudOldUploaderSdkUrl = '//service-cdn.qiqiuyun.net/js-sdk/uploader/sdk-v1.js?17913833';
3261  app.cloudOldDocumentSdkUrl = '//service-cdn.qiqiuyun.net/js-sdk/document-player/v7/viewer.html?17913833';
3262  app.aiApiServer = '';
3263  app.aiSignalServer = '';
3264  app.lang = 'zh_CN';
3265  app.mainColor = 'default';
3266</script>
3266
3267
3268<script src="/translations/translator.min.js?version=26.3.6"></script>
3268
3269
3270  
3270<script src="/translations/zh_CN.js?version=26.3.6"></script>
3270
3271
3272       
3272<script src="/static-dist/libs/base.js?version=26.3.6"></script>
3272
3273        
3273<script src="/static-dist/app/js/common.js?version=26.3.6"></script>
3273
3274        
3274<script src="/static-dist/vue3/js/common.js?version=26.3.6"></script>
3274
3275        
3275<script src="/static-dist/app/js/main.js?version=26.3.6"></script>
3275
3276        
3276<script src="/static-dist/gracefultheme/js/main.js?version=1.7.15"></script>
3276
3277        
3277<script src="/static-dist/libs/bootstrap-datetimepicker.js?version=26.3.6"></script>
3277
3278        
3278<script src="/static-dist/libs/jquery-validation.js?version=26.3.6"></script>
3278
3279        
3279<script src="/static-dist/app/js/auth/register/index.js?version=26.3.6"></script>
3279
3280  
3281<script type="text/javascript">
3282  window.seajsBoot && window.seajsBoot();
3283</script>
3283
3284
3285</body>
3286</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.