/* pages-v4.jsx — 第四轮
   · 首页按「从未接触 → 认知 → 信任 → 课程 → 行动」重排；朵奶奶头像进入页首
   · 学员证言：手写体摘句 + 头像星群 + 横向流动的长卷，不再弹窗
   · 课程：三级价格、二阶段上的职业套餐、报名方式选择（付款 / 客服 / 公众号）
   · 活动：时间与地点放大成日历块；往期活动 = 同类活动介绍；相册独立成页
*/

function V4Styles() {
  return (
    <style>{`
:root{--f-hand:"Long Cang","ZCOOL XiaoWei","Noto Serif SC",serif;--f-quote:"ZCOOL XiaoWei","Noto Serif SC",serif}

/* ================= Hero · 创始人入页首 ================= */
.h4{position:relative;overflow:hidden;background:var(--cloud)}
.h4-cloud{position:absolute;inset:0;background:url(${img('cloudTexture')}) center top/cover;opacity:.38;
  -webkit-mask-image:linear-gradient(180deg,#000 0%,rgba(0,0,0,.6) 50%,transparent 92%);mask-image:linear-gradient(180deg,#000 0%,rgba(0,0,0,.6) 50%,transparent 92%)}
.h4-in{position:relative;display:grid;grid-template-columns:minmax(0,1.12fr) minmax(0,.88fr);gap:clamp(24px,4vw,70px);align-items:end;padding:clamp(36px,5vw,72px) 0 0}
.h4-copy{padding-bottom:clamp(36px,5vw,76px)}
.h4 h1{margin-top:22px}
.h4 .lede{margin-top:24px;max-width:50ch}
.h4-actions{display:flex;flex-wrap:wrap;gap:14px;margin-top:34px;align-items:center}
.h4-meta{display:flex;flex-wrap:wrap;gap:8px 26px;margin-top:40px;padding-top:20px;border-top:1px solid var(--line);font-family:var(--f-mono);font-size:10.5px;letter-spacing:.1em;color:var(--txt-3);text-transform:uppercase}
.h4-fig{position:relative;align-self:end;margin:0;display:flex;justify-content:center}
.h4-fig{padding-bottom:clamp(36px,5vw,72px)}
.h4-disc{position:relative;width:min(100%,440px);aspect-ratio:1}
.h4-halo{position:absolute;inset:-16%;border-radius:50%;background:radial-gradient(circle,color-mix(in oklab,var(--teal-300) 42%,transparent),transparent 62%);pointer-events:none}
.h4-disc img{position:relative;display:block;width:100%;height:100%;border-radius:50%;object-fit:cover;box-sizing:border-box;border:2px solid var(--gold);box-shadow:0 30px 70px -30px rgba(12,63,68,.45)}
.h4-dot{position:absolute;left:50%;bottom:-6px;width:12px;height:12px;margin-left:-6px;border-radius:50%;background:var(--gold);box-shadow:0 0 0 4px var(--cloud)}
.h4-name{position:absolute;right:-8px;bottom:clamp(40px,5vw,80px);border-radius:10px;background:var(--paper);border:1px solid var(--line);padding:14px 16px;box-shadow:var(--shadow-float);max-width:230px}
.h4-name b{display:block;font-family:var(--f-serif);font-weight:500;font-size:17px;color:var(--ink)}
.h4-name span{display:block;font-family:var(--f-mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--txt-3);margin-top:4px}
.h4-name em{display:block;font-style:normal;font-family:var(--f-quote);font-size:14px;line-height:1.6;color:var(--teal-700);margin-top:10px;padding-top:10px;border-top:1px solid var(--line-soft)}

/* 首页 · 步骤标尺 */
.step-tag{display:inline-flex;align-items:center;gap:10px;font-family:var(--f-mono);font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--gold-deep)}
.step-tag i{font-style:normal;width:24px;height:24px;border-radius:50%;border:1px solid currentColor;display:grid;place-items:center;font-size:10px;letter-spacing:0}
.journey{display:grid;grid-template-columns:repeat(5,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.journey a{padding:18px clamp(10px,1.4vw,22px);border-right:1px solid var(--line-soft);display:flex;flex-direction:column;gap:6px;transition:background .3s}
.journey a:last-child{border-right:0}
.journey a:hover{background:color-mix(in oklab,var(--teal-500) 6%,transparent)}
.journey .n{font-family:var(--f-mono);font-size:10px;color:var(--gold-deep);letter-spacing:.14em}
.journey .t{font-size:14.5px;color:var(--ink)}
.journey .d{font-size:12px;color:var(--txt-3);line-height:1.55}

/* 问答式认知 */
.qa{display:grid;grid-template-columns:repeat(3,1fr);gap:0;border-top:1px solid var(--line)}
.qa > div{padding:28px clamp(16px,2vw,30px) 30px 0;border-right:1px solid var(--line-soft)}
.qa > div + div{padding-left:clamp(16px,2vw,30px)}
.qa > div:last-child{border-right:0}
.qa .q{font-family:var(--f-serif);font-size:clamp(19px,1.6vw,23px);color:var(--ink);line-height:1.35}
.qa .a{margin-top:12px;font-size:14.5px;line-height:1.82;color:var(--txt-2);font-weight:300}

/* ================= 证言 · 新设计 ================= */
.vx{position:relative;background:var(--ink);color:var(--on-dark);overflow:hidden}
.vx-glow{position:absolute;inset:auto -10% -40% -10%;height:80%;background:radial-gradient(60% 60% at 50% 0%,color-mix(in oklab,var(--teal-500) 30%,transparent),transparent 70%);pointer-events:none}
.vx-head{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:30px;align-items:end}
.vx-faces{display:flex;align-items:center}
.vx-faces img{width:44px;height:44px;border-radius:50%;object-fit:cover;border:2px solid var(--ink);margin-left:-12px;filter:saturate(.9)}
.vx-faces img:first-child{margin-left:0}
.vx-faces span{margin-left:12px;font-family:var(--f-mono);font-size:10.5px;letter-spacing:.12em;color:rgba(238,244,243,.6);text-transform:uppercase}
.vx-big{position:relative;margin-top:clamp(34px,4vw,56px);display:grid;grid-template-columns:auto minmax(0,1fr);gap:clamp(18px,2.6vw,40px);align-items:center}
.vx-big img{width:clamp(76px,8vw,112px);aspect-ratio:1;border-radius:50%;object-fit:cover;border:1px solid rgba(238,244,243,.2)}
.vx-big blockquote{margin:0;font-family:var(--f-hand);font-size:clamp(30px,3.9vw,58px);line-height:1.32;color:#fff;letter-spacing:.01em}
.vx-big cite{display:block;margin-top:14px;font-style:normal;font-family:var(--f-mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--gold)}
.vx-dots{display:flex;gap:6px;margin-top:22px}
.vx-dots button{width:22px;height:3px;border:0;padding:0;background:rgba(238,244,243,.2);transition:all .35s}
.vx-dots button.on{width:44px;background:var(--gold)}

.vx-river{position:relative;margin-top:clamp(36px,4vw,60px);display:flex;flex-direction:column;gap:12px;-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
.vx-lane{display:flex;gap:12px;width:max-content;animation:vxflow 80s linear infinite}
.vx-lane.rev{animation-direction:reverse;animation-duration:96s}
.vx-river:hover .vx-lane{animation-play-state:paused}
@keyframes vxflow{from{transform:translateX(0)}to{transform:translateX(-50%)}}
.vx-pill{display:flex;align-items:center;gap:12px;padding:10px 18px 10px 10px;border:1px solid rgba(238,244,243,.14);background:rgba(238,244,243,.04);border-radius:999px;white-space:nowrap;cursor:pointer;transition:background .3s,border-color .3s}
.vx-pill:hover,.vx-pill.on{background:rgba(238,244,243,.1);border-color:rgba(238,244,243,.32)}
.vx-pill img{width:34px;height:34px;border-radius:50%;object-fit:cover}
.vx-pill q{font-family:var(--f-quote);font-size:15px;color:rgba(238,244,243,.9);quotes:"「" "」"}
.vx-pill small{font-family:var(--f-mono);font-size:9.5px;letter-spacing:.1em;color:rgba(238,244,243,.45);text-transform:uppercase}

/* 证言页 · 全文长卷 */
.vp-hero{background:var(--ink);color:var(--on-dark);position:relative;overflow:hidden}
.vp-constel{position:relative;height:clamp(260px,30vw,380px);margin-top:28px}
.vp-constel button{position:absolute;border:0;padding:0;background:none;cursor:pointer;transform:translate(-50%,-50%);transition:transform .4s var(--ease)}
.vp-constel button:hover{transform:translate(-50%,-50%) scale(1.12)}
.vp-constel img{border-radius:50%;object-fit:cover;border:2px solid rgba(238,244,243,.18);display:block;filter:saturate(.9)}
.vp-constel button.on img{border-color:var(--gold);box-shadow:0 0 0 6px color-mix(in oklab,var(--gold) 22%,transparent)}
.vp-constel span{position:absolute;left:50%;top:100%;transform:translateX(-50%);margin-top:6px;font-size:10.5px;color:rgba(238,244,243,.6);white-space:nowrap}
.vp-list{columns:3 300px;column-gap:clamp(18px,2.4vw,36px)}
.vp-item{break-inside:avoid;margin:0 0 clamp(18px,2.2vw,30px);padding:22px 22px 20px;background:var(--paper);border:1px solid var(--line);position:relative;transition:border-color .4s,box-shadow .4s}
.vp-item.on{border-color:var(--gold);box-shadow:0 0 0 4px color-mix(in oklab,var(--gold) 16%,transparent)}
.vp-item .hl{font-family:var(--f-hand);font-size:clamp(23px,2vw,28px);line-height:1.38;color:var(--teal-900)}
.vp-item .full{margin-top:14px;font-family:var(--f-quote);font-size:15px;line-height:1.9;color:var(--txt-2);white-space:pre-wrap}
.vp-item .who{display:flex;align-items:center;gap:11px;margin-top:16px;padding-top:14px;border-top:1px dashed var(--line)}
.vp-item .who img{width:38px;height:38px;border-radius:50%;object-fit:cover}
.vp-item .who b{font-weight:400;font-size:13.5px;color:var(--ink)}
.vp-item .who span{display:block;font-family:var(--f-mono);font-size:9.5px;letter-spacing:.1em;color:var(--txt-3);text-transform:uppercase;margin-top:2px}
.vp-item .mk{position:absolute;right:16px;top:8px;font-family:var(--f-serif);font-size:52px;line-height:1;color:color-mix(in oklab,var(--gold) 45%,transparent)}

/* ================= 课程价格 ================= */
.lv .price{display:flex;align-items:baseline;gap:8px;margin-top:16px}
.lv .price b{font-family:var(--f-serif);font-weight:400;font-size:clamp(30px,2.6vw,38px);letter-spacing:-.02em;color:var(--ink)}
.lv .price span{font-family:var(--f-mono);font-size:10px;letter-spacing:.12em;color:var(--txt-3);text-transform:uppercase}
.lv .price.tbd b{color:var(--txt-3)}
.bundle{margin:16px clamp(20px,2.2vw,26px) 0;position:relative;padding:14px 16px;background:linear-gradient(135deg,color-mix(in oklab,var(--gold) 18%,var(--paper)),var(--paper));border:1px solid color-mix(in oklab,var(--gold) 55%,transparent)}
.bundle .rib{position:absolute;top:-10px;left:14px;background:var(--gold);color:#25190a;font-family:var(--f-mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;padding:3px 9px}
.bundle .row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-top:4px}
.bundle .t{font-size:14px;color:var(--ink)}
.bundle .p{font-family:var(--f-serif);font-size:26px;color:var(--gold-deep)}
.bundle .s{font-size:11.5px;color:var(--txt-3);margin-top:3px}
.bundle .old{font-family:var(--f-mono);font-size:10.5px;color:var(--txt-3);text-decoration:line-through;margin-left:6px}

/* 报名方式选择 */
.enr-opts{display:grid;gap:10px;margin-top:18px}
.enr-opt{display:grid;grid-template-columns:42px minmax(0,1fr) auto;gap:14px;align-items:center;padding:14px 16px;border:1px solid var(--line);background:var(--paper);text-align:left;cursor:pointer;transition:border-color .3s,background .3s}
.enr-opt:hover{border-color:var(--teal-500);background:color-mix(in oklab,var(--teal-500) 4%,var(--paper))}
.enr-opt .ic{width:42px;height:42px;border-radius:50%;background:color-mix(in oklab,var(--teal-500) 10%,transparent);color:var(--teal-700);display:grid;place-items:center;font-size:16px}
.enr-opt b{display:block;font-weight:500;font-size:14.5px;color:var(--ink)}
.enr-opt span{display:block;font-size:12px;color:var(--txt-3);margin-top:2px;line-height:1.5}
.enr-opt .ar{color:var(--teal-700)}
.enr-sum{display:flex;justify-content:space-between;align-items:baseline;gap:10px;padding:14px 0;border-bottom:1px solid var(--line)}

/* ================= 活动 · 时间地点放大 ================= */
.cal{display:grid;grid-template-columns:auto minmax(0,1fr);gap:0;border:1px solid var(--line);background:var(--paper)}
.cal-date{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:14px 18px;background:var(--teal-900);color:#fff;min-width:96px}
.cal-date .m{font-family:var(--f-mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--gold)}
.cal-date .d{font-family:var(--f-serif);font-size:40px;line-height:1;margin-top:4px}
.cal-date .w{font-size:11px;color:rgba(255,255,255,.65);margin-top:4px}
.cal-place{padding:14px 18px;display:flex;flex-direction:column;justify-content:center;gap:3px}
.cal-place .k{font-family:var(--f-mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--txt-3)}
.cal-place .city{font-family:var(--f-serif);font-size:24px;color:var(--ink);line-height:1.2}
.cal-place .v{font-size:12.5px;color:var(--txt-2)}

.ev-top{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);gap:clamp(22px,3vw,44px);background:var(--paper);border:1px solid var(--line);overflow:hidden}
.ev-top .cv{position:relative;min-height:340px}
.ev-top .cv img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.ev-top .cv .cd{position:absolute;left:16px;bottom:16px;background:rgba(11,36,38,.86);color:#fff;padding:10px 14px;backdrop-filter:blur(8px);font-family:var(--f-mono);font-size:10.5px;letter-spacing:.12em}
.ev-top .cv .cd b{font-family:var(--f-serif);font-size:26px;font-weight:400;letter-spacing:0;margin-right:6px;color:var(--gold)}
.ev-top .bd{padding:clamp(22px,2.6vw,36px) clamp(22px,2.6vw,36px) clamp(22px,2.6vw,36px) 0;display:flex;flex-direction:column;gap:16px}
.big-when{display:grid;grid-template-columns:1fr 1fr;gap:0;border:1px solid var(--line)}
.big-when > div{padding:16px 18px}
.big-when > div + div{border-left:1px solid var(--line)}
.big-when .k{font-family:var(--f-mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--gold-deep)}
.big-when .v{font-family:var(--f-serif);font-size:clamp(22px,2.2vw,30px);line-height:1.2;color:var(--ink);margin-top:6px}
.big-when .s{font-size:12.5px;color:var(--txt-2);margin-top:4px}

.ev-list{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(14px,1.8vw,22px)}
.ev-row{display:grid;grid-template-columns:auto minmax(0,1fr);background:var(--paper);border:1px solid var(--line);transition:transform .35s var(--ease),box-shadow .35s}
.ev-row:hover{transform:translateY(-3px);box-shadow:var(--shadow-float)}
.ev-row .bd{padding:18px 20px;display:flex;flex-direction:column;gap:8px}
.ev-row h3{font-size:17px;line-height:1.4}
.ev-row .where{font-family:var(--f-serif);font-size:19px;color:var(--teal-700)}
.ev-row .where small{font-family:var(--f-sans);font-size:12px;color:var(--txt-3);margin-left:8px}

/* 往期活动介绍 */
.past-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.8vw,24px)}
.past-card{background:var(--paper);border:1px solid var(--line);display:flex;flex-direction:column;cursor:pointer;text-align:left;padding:0;transition:transform .35s var(--ease),box-shadow .35s,border-color .35s}
.past-card:hover{transform:translateY(-3px);box-shadow:var(--shadow-float);border-color:var(--line-strong)}
.past-card .cv{position:relative;aspect-ratio:16/10;overflow:hidden;background:var(--cloud-2)}
.past-card .cv img{width:100%;height:100%;object-fit:cover;filter:saturate(.85)}
.past-card .cv .ended{position:absolute;right:10px;top:10px;font-family:var(--f-mono);font-size:9.5px;letter-spacing:.12em;padding:3px 8px;background:rgba(255,255,255,.88);color:var(--txt-2)}
.past-card .bd{padding:16px 18px 18px;display:flex;flex-direction:column;gap:8px;flex:1}
.past-card .yr{font-family:var(--f-mono);font-size:10px;letter-spacing:.14em;color:var(--gold-deep);text-transform:uppercase}
.past-card h3{font-size:16.5px;line-height:1.4}
.past-card p{font-size:13px;line-height:1.7;color:var(--txt-2);font-weight:300;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.past-card .m{display:flex;gap:12px;font-size:12px;color:var(--txt-3);margin-top:auto;padding-top:8px}

/* 往期详情页 */
.pd-hero{position:relative;min-height:clamp(320px,38vw,480px);display:flex;align-items:flex-end;color:#fff;overflow:hidden}
.pd-hero img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.pd-hero::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(7,26,28,.15),rgba(7,26,28,.88))}
.pd-hero .wrap{position:relative;z-index:1;padding-bottom:clamp(28px,3.6vw,52px)}
.pd-facts{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.pd-facts > div{padding:18px 20px;border-right:1px solid var(--line-soft)}
.pd-facts > div:last-child{border-right:0}
.pd-facts .k{font-family:var(--f-mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--txt-3)}
.pd-facts .v{font-family:var(--f-serif);font-size:22px;color:var(--ink);margin-top:4px}

/* 相册页 */
.gal-hero{background:var(--ink);color:var(--on-dark);padding:clamp(36px,4.4vw,64px) 0 clamp(18px,2vw,28px)}
.gal-tabs{display:flex;gap:6px;overflow-x:auto;padding:16px var(--pad-x);scrollbar-width:none;background:var(--ink);border-top:1px solid rgba(238,244,243,.1)}
.gal-tabs::-webkit-scrollbar{display:none}
.gal-tabs button{flex:none;border:1px solid rgba(238,244,243,.18);background:none;color:rgba(238,244,243,.7);padding:7px 14px;border-radius:999px;font-size:12.5px;transition:all .3s}
.gal-tabs button.on{background:#fff;color:var(--ink);border-color:#fff}
.gal-stage{background:#061416;padding:clamp(18px,2.6vw,36px) 0 clamp(22px,3vw,44px)}
.gal-main{position:relative;max-width:1180px;margin:0 auto;padding:0 var(--pad-x)}
.gal-main .frame{position:relative;aspect-ratio:3/2;background:#0a2224;overflow:hidden}
.gal-main .frame img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;transition:opacity .45s var(--ease)}
.gal-main .nv{position:absolute;top:50%;transform:translateY(-50%);width:48px;height:48px;border-radius:50%;border:1px solid rgba(255,255,255,.3);background:rgba(0,0,0,.35);color:#fff;font-size:20px;display:grid;place-items:center;z-index:2;transition:all .3s}
.gal-main .nv:hover{background:#fff;color:var(--ink)}
.gal-main .nv.l{left:calc(var(--pad-x) + 12px)}.gal-main .nv.r{right:calc(var(--pad-x) + 12px)}
.gal-cap{display:flex;justify-content:space-between;gap:16px;margin-top:12px;font-family:var(--f-mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:rgba(238,244,243,.55)}
.gal-thumbs{display:flex;gap:8px;overflow-x:auto;padding:14px var(--pad-x) 4px;max-width:1180px;margin:0 auto;scrollbar-width:thin}
.gal-thumbs button{flex:none;width:96px;aspect-ratio:3/2;padding:0;border:2px solid transparent;background:none;opacity:.5;transition:opacity .3s,border-color .3s}
.gal-thumbs button.on{opacity:1;border-color:var(--gold)}
.gal-thumbs img{width:100%;height:100%;object-fit:cover}

@media(max-width:1080px){
  .h4-in{grid-template-columns:1fr;align-items:start}
  .h4-copy{padding-bottom:0}
  .h4-fig{max-width:420px;margin:0 auto}
  .journey{grid-template-columns:repeat(3,1fr)}
  .journey a:nth-child(3){border-right:0}
  .qa{grid-template-columns:1fr}
  .qa > div,.qa > div + div{padding:22px 0;border-right:0;border-bottom:1px solid var(--line-soft)}
  .ev-top{grid-template-columns:1fr}
  .ev-top .bd{padding:0 22px 24px}
  .past-grid{grid-template-columns:1fr 1fr}
  .vx-head{grid-template-columns:1fr}
}
@media(max-width:820px){
  .journey{grid-template-columns:1fr 1fr}
  .journey a{border-bottom:1px solid var(--line-soft)}
  .ev-list{grid-template-columns:1fr}
  .past-grid{grid-template-columns:1fr}
  .pd-facts{grid-template-columns:1fr 1fr}
  .pd-facts > div:nth-child(2){border-right:0}
  .vx-big{grid-template-columns:1fr}
  .vp-constel{height:300px}
  .h4-name{right:auto;left:0;bottom:16px;max-width:200px}
  .gal-main .nv{width:38px;height:38px}
}
@media(max-width:560px){
  .big-when{grid-template-columns:1fr}
  .big-when > div + div{border-left:0;border-top:1px solid var(--line)}
  .cal-date{min-width:78px;padding:12px}
  .cal-date .d{font-size:32px}
  .vx-big blockquote{font-size:28px}
}
`}</style>
  );
}

/* ============ 小工具 ============ */
const MONTHS = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
const WEEK = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
function dparts(iso) {
  const d = new Date(iso + 'T00:00:00');
  return { m: MONTHS[d.getMonth()], mn: d.getMonth() + 1, d: d.getDate(), w: WEEK[d.getDay()], y: d.getFullYear() };
}
function CalBlock({ a, compact }) {
  const s = dparts(a.start);
  return (
    <div className="cal" style={compact ? { border: 0, borderRight: '1px solid var(--line)' } : null}>
      <div className="cal-date">
        <span className="m">{s.mn} 月</span>
        <span className="d">{s.d}</span>
        <span className="w">{s.w}{a.days > 1 ? ` · ${a.days} 天` : ''}</span>
      </div>
      {!compact && (
        <div className="cal-place">
          <span className="k">地点</span>
          <span className="city">{a.city}</span>
          <span className="v">{a.venue}</span>
        </div>
      )}
    </div>
  );
}

/* ============ 首页 Hero（创始人入页首） ============ */
function Hero4() {
  const go = window.__go;
  return (
    <section className="h4">
      <div className="h4-cloud" />
      <div className="wrap h4-in">
        <div className="h4-copy">
          <Eyebrow>量子催眠中国 · 官方站点</Eyebrow>
          <h1 className="d1">
            <span style={{ display: 'block' }}>有一种状态，</span>
            <span style={{ display: 'block' }}>你知道所有的答案。</span>
          </h1>
          <p className="lede">
            量子催眠（QHHT®）是朵洛莉丝·侃南用近五十年回溯催眠实践留下的一门技术。
            它不是让人失去意识，而是带人抵达一个更清醒的地方——在那里，身体与人生的议题，会以它自己的方式被看见。
          </p>
          <div className="h4-actions">
            <Btn kind="primary" size="lg" arw onClick={() => document.getElementById('know')?.scrollIntoView({ behavior: 'smooth' })}>先弄明白它是什么</Btn>
            <Btn kind="quiet" onClick={() => go('courses')}>已经了解，直接看课程 →</Btn>
          </div>
          <div className="h4-meta">
            <span>2012 年进入中国</span>
            <span>简体中文唯一官方代表</span>
            <span>禁止远程催眠</span>
          </div>
        </div>
        <figure className="h4-fig">
          <div className="h4-disc">
            <div className="h4-halo" />
            <img src={img('doloresDisc')} alt="量子催眠创始人 朵洛莉丝·侃南" />
            <span className="h4-dot" />
          </div>
          <figcaption className="h4-name">
            <b>朵洛莉丝·侃南</b>
            <span>Dolores Cannon · 1931—2014 · 创始人</span>
            <em>「我不是灵媒，我是向导，也是记者。」</em>
          </figcaption>
        </figure>
      </div>
    </section>
  );
}

/* ============ 首页（按潜在学员心态重排） ============ */
function Home4() {
  const go = window.__go;
  const scrollTo = (id) => document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
  return (
    <>
      <V3Styles />
      <V4Styles />
      <RealStyles />

      <Hero4 />

      {/* 阅读路径 */}
      <div className="wrap">
        <nav className="journey" aria-label="首页阅读路径">
          {[
            ['know', '01', '它是什么', '三个最常被问的问题'],
            ['founder', '02', '谁创立了它', '听朵奶奶自己讲'],
            ['trust', '03', '真的有人学', '15 场课 · 17 段证言'],
            ['course', '04', '怎么学', '三个阶段与价格'],
            ['next', '05', '下一步', '活动 · 报名 · 咨询'],
          ].map(([id, n, t, d]) => (
            <a key={id} href={'#' + id} onClick={(e) => { e.preventDefault(); scrollTo(id); }}>
              <span className="n">{n}</span><span className="t">{t}</span><span className="d">{d}</span>
            </a>
          ))}
        </nav>
      </div>

      {/* 01 认知 */}
      <section className="sec" id="know">
        <div className="wrap">
          <div className="step-tag"><i>01</i>它是什么</div>
          <h2 className="d2" style={{ marginTop: 16, maxWidth: '18ch' }}>第一次听说量子催眠，<br />通常会先问这三件事。</h2>
          <div className="qa" style={{ marginTop: 'clamp(28px,3.4vw,46px)' }}>
            {[
              ['它到底在做什么？', '把人带到最深的 θ 脑波状态（梦游态），在那里回溯更早的经历，并与一个比头脑更清醒的层面——它称之为「潜意识」——对话，找到当下议题的根源。'],
              ['和普通催眠有什么不同？', '传统催眠多在浅层 α 脑波运作，常强调「暗示」。量子催眠更深，而且操作者只是协助者：不暗示、不主导、不替你回答。'],
              ['它安全吗，能帮我什么？', '全程一对一、面对面，禁止任何形式的远程。来访者最常反馈的是：情绪与创伤的松动、对人生课题的理解、对死亡与失去的释怀。它不做医疗诊断，也不替代治疗。'],
            ].map(([q, a]) => (
              <div key={q}><div className="q">{q}</div><p className="a">{a}</p></div>
            ))}
          </div>
          <div style={{ marginTop: 30, display: 'flex', gap: 12, flexWrap: 'wrap' }}>
            <Btn kind="ghost" onClick={() => go('learn')} arw>读完整说明（30 秒 / 5 分钟 / 深读）</Btn>
          </div>
        </div>
      </section>

      {/* 四原则 */}
      <section className="sec dark noise">
        <div className="wrap">
          <div className="split">
            <div>
              <Eyebrow>技术内核</Eyebrow>
              <h2 className="d2" style={{ marginTop: 18 }}>四条它绝不妥协的原则</h2>
              <p className="lede" style={{ marginTop: 20 }}>
                这些原则决定了量子催眠「是什么」，也决定了它「不是什么」。
              </p>
            </div>
            <ul className="nlist">
              {[
                ['深度', 'Depth', '带至最深层 θ 脑波状态（梦游态），而非浅层 α 脑波。'],
                ['定位', 'Position', '操作者是协助者，不是主导者或治疗者，不把自己的信念强加给来访者。'],
                ['简洁', 'Simplicity', '没有一个多余的步骤，也没有一个可以减掉的环节。'],
                ['并非"管道"', 'Not a Channel', '真正的管道是来访者自己。朵奶奶说：她不是灵媒，而是向导与记者。'],
              ].map(([a, b, c]) => (
                <li key={a}><span className="k">{b.slice(0, 2).toUpperCase()}</span><div><h4>{a}<span className="en">{b}</span></h4><p>{c}</p></div></li>
              ))}
            </ul>
          </div>
        </div>
      </section>

      {/* 02 创始人 · 视频 */}
      <div id="founder"><CinemaSection step="02" kicker="谁创立了它" title="听她自己讲。" /></div>

      {/* 03 信任：相册 + 证言 */}
      <div id="trust">
        <section className="sec-tight" style={{ paddingBottom: 18 }}>
          <div className="wrap">
            <div className="step-tag"><i>03</i>真的有人学过</div>
          </div>
        </section>
        <AlbumStrip limit={18} />
        <VoicesRiver />
      </div>

      {/* 04 课程 */}
      <section className="sec" id="course">
        <div className="wrap">
          <div className="step-tag"><i>04</i>怎么学</div>
          <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 24, flexWrap: 'wrap', marginTop: 16 }}>
            <h2 className="d2" style={{ maxWidth: '16ch' }}>三个阶段，<br />每一级都有它的边界。</h2>
            <Btn kind="ghost" onClick={() => go('courses')} arw>课程详情</Btn>
          </div>
          <div style={{ marginTop: 'clamp(26px,3vw,40px)' }}><CourseCards compact /></div>
        </div>
      </section>

      {/* 05 下一步 */}
      <section className="sec" id="next" style={{ background: 'var(--cloud-2)' }}>
        <div className="wrap">
          <div className="step-tag"><i>05</i>下一步</div>
          <h2 className="d2" style={{ marginTop: 16, maxWidth: '18ch' }}>还没想好？<br />先来一场活动。</h2>
          <div style={{ marginTop: 'clamp(24px,3vw,38px)' }}>
            <UpcomingCard5 a={QD.upcoming[0]} big />
          </div>
          <div style={{ marginTop: 22, display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
            <Btn kind="primary" onClick={() => { window.__scrollTo = 'sec-events'; go('courses'); }} arw>全部即将到来的活动</Btn>
            <Btn kind="quiet" onClick={() => go('book')}>或填一张咨询表 →</Btn>
          </div>
        </div>
      </section>

      {/* 文章 + 公众号 */}
      <section className="sec">
        <div className="wrap">
          <SecHead eyebrow="文章 · 同步自公众号" title="继续读" right={<Btn kind="ghost" onClick={() => go('posts')} arw>全部文章</Btn>} />
          <div className="grid g3">
            {QD.posts.slice(0, 3).map((p, i) => <Reveal key={p.id} delay={i * 80}><PostCard p={p} /></Reveal>)}
          </div>
          <div style={{ marginTop: 'clamp(40px,5vw,64px)' }}><FollowStrip /></div>
        </div>
      </section>
    </>
  );
}

/* 创始人视频（头像已在页首，这里只放视频） */
function FounderVideos() {
  const go = window.__go;
  const mine = QD.videos.filter((v) => v.kind === '朵洛莉丝');
  const [cur, setCur] = React.useState(mine[0]);
  return (
    <section className="founder">
      <div className="wrap" style={{ padding: 'clamp(48px,6vw,90px) var(--pad-x)' }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1fr) minmax(0,1.6fr)', gap: 'clamp(26px,4vw,64px)', alignItems: 'start' }} className="fv-grid">
          <div>
            <div className="step-tag" style={{ color: 'var(--gold)' }}><i>02</i>谁创立了它</div>
            <h2 className="d2" style={{ marginTop: 16, color: '#fff' }}>听她自己讲。</h2>
            <p className="lede" style={{ marginTop: 18, color: 'rgba(238,244,243,.7)' }}>
              朵奶奶生前的公开访谈片段，中英双语字幕。从「什么是量子催眠」开始，到「为什么要成为一名操作者」。
            </p>
            <ol style={{ marginTop: 24, display: 'grid', gap: 0, borderTop: '1px solid rgba(238,244,243,.14)' }}>
              {mine.map((v, i) => (
                <li key={v.id}>
                  <button onClick={() => setCur(v)}
                    style={{
                      width: '100%', display: 'grid', gridTemplateColumns: '28px 1fr auto', gap: 12, alignItems: 'center',
                      padding: '13px 0', border: 0, borderBottom: '1px solid rgba(238,244,243,.1)', background: 'none',
                      color: cur.id === v.id ? '#fff' : 'rgba(238,244,243,.62)', textAlign: 'left', fontSize: 14
                    }}>
                    <span style={{ fontFamily: 'var(--f-mono)', fontSize: 10, color: cur.id === v.id ? 'var(--gold)' : 'rgba(238,244,243,.4)' }}>{cur.id === v.id ? '▶' : String(i + 1).padStart(2, '0')}</span>
                    <span>{v.t.replace('朵洛莉丝·侃南', '')}</span>
                    <span style={{ fontFamily: 'var(--f-mono)', fontSize: 10, color: 'rgba(238,244,243,.4)' }}>{v.dur}</span>
                  </button>
                </li>
              ))}
            </ol>
            <div style={{ marginTop: 18 }}><Btn kind="quiet" onClick={() => go('dolores')} style={{ color: 'var(--teal-300)' }}>她的生平与二十本著作 →</Btn></div>
          </div>
          <div><VPlayer v={cur} dark /></div>
        </div>
      </div>
      <style>{`@media(max-width:1080px){.fv-grid{grid-template-columns:1fr !important}}`}</style>
    </section>
  );
}

/* ============ 证言：首页长卷 ============ */
function VoicesRiver() {
  const go = window.__go;
  const vs = QD.voices;
  const feat = vs.filter((v) => ['紫园', '七月–梓寒', '毕彤娜', 'Jessy', '茜茜'].includes(v.n));
  const [i, setI] = React.useState(0);
  React.useEffect(() => {
    const t = setInterval(() => setI((x) => (x + 1) % feat.length), 6500);
    return () => clearInterval(t);
  }, [feat.length]);
  const f = feat[i];
  const lane1 = vs.slice(0, 9), lane2 = vs.slice(8);
  return (
    <section className="vx sec">
      <div className="vx-glow" />
      <div className="wrap">
        <div className="vx-head">
          <div>
            <div className="eyebrow on-dark" style={{ display: 'inline-flex' }}>学员证言</div>
            <h2 className="d2" style={{ marginTop: 14, color: '#fff' }}>他们留下的话。</h2>
          </div>
          <div className="vx-faces">
            {vs.slice(0, 9).map((v) => <img key={v.n} src={v.img} alt={v.n} />)}
            <span>+{vs.length - 9} 位学员</span>
          </div>
        </div>
        <div className="vx-big" key={f.n}>
          <img src={f.img} alt={f.n} />
          <div>
            <blockquote>「{f.hl}」</blockquote>
            <cite>— {f.n}</cite>
            <div className="vx-dots">
              {feat.map((x, k) => <button key={x.n} className={k === i ? 'on' : ''} onClick={() => setI(k)} aria-label={x.n} />)}
            </div>
          </div>
        </div>
      </div>
      <div className="vx-river">
        {[lane1, lane2].map((lane, li) => (
          <div key={li} className={'vx-lane' + (li ? ' rev' : '')}>
            {[...lane, ...lane].map((v, k) => (
              <div key={v.n + k} className="vx-pill" onClick={() => go('voices')}>
                <img src={v.img} alt="" />
                <q>{v.hl}</q>
                <small>{v.n}</small>
              </div>
            ))}
          </div>
        ))}
      </div>
      <div className="wrap" style={{ marginTop: 28 }}>
        <Btn kind="ghost" onClick={() => go('voices')} style={{ borderColor: 'rgba(238,244,243,.28)', color: '#fff' }} arw>读完 17 段原文</Btn>
      </div>
    </section>
  );
}

/* ============ 证言页 ============ */
function VoicesPage() {
  const [on, setOn] = React.useState(null);
  const refs = React.useRef({});
  const vs = QD.voices;
  /* 星群坐标：确定性分布 */
  const pos = React.useMemo(() => vs.map((v, k) => {
    const a = k * 2.399963;
    const r = 0.18 + 0.32 * Math.sqrt((k + 0.5) / vs.length);
    return { x: 50 + Math.cos(a) * r * 92, y: 50 + Math.sin(a) * r * 88, s: v.short ? 46 : 62 };
  }), []);

  const focus = (n) => {
    setOn(n);
    const el = refs.current[n];
    if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 110, behavior: 'smooth' });
  };

  return (
    <>
      <V4Styles />
      <section className="vp-hero sec">
        <div className="vx-glow" />
        <div className="wrap" style={{ position: 'relative' }}>
          <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 24, flexWrap: 'wrap' }}>
            <div>
              <div className="eyebrow on-dark" style={{ display: 'inline-flex' }}>学员证言 · {vs.length} 位</div>
              <h1 className="d1" style={{ marginTop: 18, color: '#fff', maxWidth: '14ch' }}>他们说过的话。</h1>
            </div>
            <p style={{ maxWidth: '36ch', color: 'rgba(238,244,243,.65)', fontSize: 14.5, lineHeight: 1.8 }}>
              每一张脸都是一位学过的人。点任意一位，直接跳到他的那一段——全部原文，没有删改。
            </p>
          </div>
          <div className="vp-constel">
            {vs.map((v, k) => (
              <button key={v.n} className={on === v.n ? 'on' : ''} style={{ left: pos[k].x + '%', top: pos[k].y + '%' }} onClick={() => focus(v.n)} aria-label={v.n}>
                <img src={v.img} alt={v.n} style={{ width: pos[k].s, height: pos[k].s }} />
                <span>{v.n}</span>
              </button>
            ))}
          </div>
        </div>
      </section>

      <section className="sec" style={{ background: 'var(--cloud)' }}>
        <div className="wrap">
          <div className="vp-list">
            {vs.map((v) => (
              <article key={v.n} ref={(el) => (refs.current[v.n] = el)} className={'vp-item' + (on === v.n ? ' on' : '')}>
                <span className="mk">”</span>
                <div className="hl">{v.hl}</div>
                <div className="full">{v.q}</div>
                <div className="who">
                  <img src={v.img} alt={v.n} />
                  <div><b>{v.n}</b><span>{v.short ? '课后留言' : '学习手记'}</span></div>
                </div>
              </article>
            ))}
          </div>
        </div>
      </section>

      <section className="sec dark noise">
        <div className="wrap" style={{ maxWidth: 780, textAlign: 'center' }}>
          <h2 className="d2">下一段，也许是你写的。</h2>
          <div style={{ marginTop: 28, display: 'flex', gap: 12, justifyContent: 'center', flexWrap: 'wrap' }}>
            <Btn kind="gold" onClick={() => window.__go('courses')} arw>看课程与价格</Btn>
          </div>
        </div>
      </section>
    </>
  );
}

/* ============ 课程卡（含价格与套餐） ============ */
function CourseCards({ compact }) {
  const [enroll, setEnroll] = React.useState(null);
  return (
    <>
      <div className="lv-grid">
        {QD.courses3.map((c) => (
          <article key={c.id} className={'lv' + (c.status === 'open' ? ' open' : '') + (c.status === 'soon' ? ' soon' : '')}>
            <div className="hd">
              <div>
                <div className="lv-tag">{c.lvl} · {c.en}</div>
                <h3>{c.t}</h3>
              </div>
              <div className="nn">{c.n}</div>
            </div>
            <div style={{ padding: '0 clamp(20px,2.2vw,26px)' }}>
              <div className={'price' + (c.price ? '' : ' tbd')}>
                <b>{c.priceText}</b>
                <span>{c.price ? '人民币 · 含教材与证书' : '价格待公布'}</span>
              </div>
              <p className="lead">{c.lead}</p>
              {!compact && <div className="pts">{c.points.map((p) => <li key={p}><span className="bx" />{p}</li>)}</div>}
            </div>
            {c.bundle && (
              <div className="bundle">
                <span className="rib">职业催眠师套餐</span>
                <div className="row">
                  <span className="t">{c.bundle.sub}</span>
                </div>
                <div className="row">
                  <span><span className="p">{c.bundle.priceText}</span><span className="old">¥25,600</span></span>
                </div>
                <div className="s">{c.bundle.save}</div>
              </div>
            )}
            <div className="ft">
              <div className={'st ' + (c.status === 'open' ? 'on' : 'off')}><span className="dot" />{c.statusText}</div>
              {c.status === 'soon' ? (
                <Btn kind="ghost" block size="sm" disabled>尚未开放</Btn>
              ) : (
                <div style={{ display: 'grid', gap: 8 }}>
                  <Btn kind={c.status === 'open' ? 'primary' : 'ghost'} block size="sm" onClick={() => setEnroll({ c, bundle: false })}>
                    报名{c.t.replace('量子催眠', '')}
                  </Btn>
                  {c.bundle && (
                    <Btn kind="gold" block size="sm" onClick={() => setEnroll({ c, bundle: true })}>报名职业套餐 · {c.bundle.priceText}</Btn>
                  )}
                </div>
              )}
            </div>
          </article>
        ))}
      </div>
      {enroll && React.createElement(window.EnrollSheet5 || EnrollSheet, { c: enroll.c, bundle: enroll.bundle, onClose: () => setEnroll(null) })}
    </>
  );
}

/* 报名方式选择：付款 / 客服 / 公众号 */
function EnrollSheet({ c, bundle, onClose }) {
  const [mode, setMode] = React.useState(null);
  const name = bundle ? '职业催眠师套餐（一阶段 + 二阶段）' : c.t;
  const price = bundle ? c.bundle.priceText : c.priceText;
  const locked = c.status === 'locked' && !bundle;
  return (
    <Modal onClose={onClose} max={480}>
      {!mode && (
        <>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12 }}>
            <div>
              <div className="eyebrow">课程报名</div>
              <h3 style={{ marginTop: 10, fontSize: 21 }}>你想怎么报名？</h3>
            </div>
            <button className="btn btn-ghost btn-sm" onClick={onClose} aria-label="关闭">{Ico.close()}</button>
          </div>
          <div className="enr-sum" style={{ marginTop: 14 }}>
            <span style={{ fontSize: 14 }}>{name}</span>
            <b style={{ fontFamily: 'var(--f-serif)', fontWeight: 400, fontSize: 22 }}>{price}</b>
          </div>
          {locked && (
            <p style={{ marginTop: 12, fontSize: 12.5, color: 'var(--gold-deep)', lineHeight: 1.7 }}>
              二阶段需先完成一阶段并取得证书。如果还没学过一阶段，建议选择职业套餐，或先咨询课程顾问。
            </p>
          )}
          <div className="enr-opts">
            <button className="enr-opt" onClick={() => setMode('pay')}>
              <span className="ic">¥</span>
              <span><b>直接付款报名</b><span>跳转到微信课程平台付款页，付款后自动开通</span></span>
              <span className="ar">→</span>
            </button>
            <button className="enr-opt" onClick={() => setMode('service')}>
              <span className="ic">{Ico.wechat()}</span>
              <span><b>先咨询课程顾问</b><span>加客服微信，问清楚适不适合、档期与分期</span></span>
              <span className="ar">→</span>
            </button>
            <button className="enr-opt" onClick={() => setMode('mp')}>
              <span className="ic">◎</span>
              <span><b>关注公众号报名</b><span>扫码关注后，在菜单「课程报名」中完成</span></span>
              <span className="ar">→</span>
            </button>
          </div>
        </>
      )}
      {mode && (
        <div style={{ textAlign: 'center' }}>
          <button className="btn btn-quiet" style={{ fontSize: 12.5 }} onClick={() => setMode(null)}>← 换一种方式</button>
          <h3 style={{ marginTop: 12, fontSize: 20 }}>
            {mode === 'pay' ? '微信扫码付款' : mode === 'service' ? '扫码添加课程顾问' : '扫码关注「量子催眠中国」'}
          </h3>
          <p style={{ marginTop: 8, fontSize: 13, color: 'var(--txt-2)' }}>{name} · {price}</p>
          <div className="qr-frame" style={{ marginTop: 18 }}><QrCanvas ticket={mode + c.id + (bundle ? 'b' : '')} /></div>
          <p className="form-note" style={{ marginTop: 14 }}>
            {mode === 'pay' && '手机上请直接点下方按钮跳转。付款完成后，课程会在公众号自动开通。'}
            {mode === 'service' && <>客服微信：<b style={{ color: 'var(--ink)' }}>{QD.enroll.serviceWx}</b>（{QD.enroll.serviceName}）· 工作日 10:00–21:00</>}
            {mode === 'mp' && '关注后点公众号菜单「课程报名」，选择对应课程即可。'}
          </p>
          {mode === 'pay' && <a className="btn btn-primary btn-block" style={{ marginTop: 16 }} href={QD.enroll.payUrl}>打开付款页面</a>}
          {mode === 'service' && <button className="btn btn-ghost btn-block" style={{ marginTop: 16 }} onClick={() => navigator.clipboard && navigator.clipboard.writeText(QD.enroll.serviceWx)}>复制客服微信号</button>}
        </div>
      )}
    </Modal>
  );
}

/* ============ 课程页 ============ */
function CoursesPage() {
  const go = window.__go;
  return (
    <>
      <V3Styles /><V4Styles />
      <section className="sec-tight" style={{ paddingTop: 'clamp(42px,5vw,74px)' }}>
        <div className="wrap">
          <Eyebrow>课程 · 三个阶段</Eyebrow>
          <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 30, flexWrap: 'wrap' }}>
            <h1 className="d1" style={{ marginTop: 18, maxWidth: '15ch' }}>成为操作者，是一段长路。</h1>
            <p className="lede" style={{ maxWidth: '40ch', paddingBottom: 6 }}>
              一阶段打底，二阶段深入。一、二阶段同时报名，即为职业催眠师套餐。
            </p>
          </div>
        </div>
      </section>
      <section style={{ paddingBottom: 'clamp(40px,4.6vw,68px)' }}>
        <div className="wrap">
          <CourseCards />
          <p style={{ marginTop: 18, fontSize: 12.5, color: 'var(--txt-3)', fontWeight: 300 }}>
            价格单位为人民币。三阶段的课程结构与价格定稿后，会在此页与公众号同时公布。
          </p>
        </div>
      </section>
      <section className="sec" style={{ background: 'var(--cloud-2)' }}>
        <div className="wrap">
          <div className="split" style={{ alignItems: 'start' }}>
            <div>
              <Eyebrow>课程之外</Eyebrow>
              <h2 className="d2" style={{ marginTop: 16 }}>还没决定？<br />先来一场活动。</h2>
              <p className="lede" style={{ marginTop: 18 }}>公开课、开放日、学员聚会与督导——更短，也更容易来。</p>
              <div style={{ marginTop: 24 }}><Btn kind="primary" onClick={() => go('events')} arw>即将到来的活动</Btn></div>
            </div>
            <ul className="nlist">
              {[['付款即开通', '线上部分付款后在公众号自动开通，可反复观看。'], ['分期与发票', '咨询课程顾问可办理分期；发票随开课材料一并寄送。'], ['套餐说明', '职业套餐一次性报名一、二阶段，二阶段在一阶段结业后开放。']].map(([a, b], i) => (
                <li key={a}><span className="k">0{i + 1}</span><div><h4>{a}</h4><p>{b}</p></div></li>
              ))}
            </ul>
          </div>
        </div>
      </section>
    </>
  );
}

/* ============ 活动 ============ */
function UpcomingTop({ a }) {
  const go = window.__go;
  const s = dparts(a.start), e = dparts(a.end);
  return (
    <article className="ev-top">
      <div className="cv">
        <img src={a.cover} alt="" />
        <div className="cd"><b>{Math.max(0, Math.ceil((new Date(a.start) - new Date('2026-11-03')) / 864e5)) || '—'}</b>天后开始</div>
      </div>
      <div className="bd">
        <span className="tag gold" style={{ alignSelf: 'flex-start' }}>{a.form} · {a.level}</span>
        <h3 style={{ fontSize: 'clamp(20px,2vw,27px)', lineHeight: 1.35 }}>{a.title}</h3>
        <div className="big-when">
          <div>
            <div className="k">时间</div>
            <div className="v">{s.mn} 月 {s.d} 日{a.days > 1 ? ` — ${e.mn !== s.mn ? e.mn + ' 月 ' : ''}${e.d} 日` : ''}</div>
            <div className="s">{s.y} · {s.w}{a.days > 1 ? ` 起 · 共 ${a.days} 天` : ''}</div>
          </div>
          <div>
            <div className="k">地点</div>
            <div className="v">{a.city}</div>
            <div className="s">{a.venue}</div>
          </div>
        </div>
        <div className="act-seats"><span>余位 {a.left} / {a.seats}</span><span className="seats-bar"><i style={{ width: Math.round((a.seats - a.left) / a.seats * 100) + '%' }} /></span><span>截止 {a.deadline.slice(5).replace('-', '.')}</span></div>
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 'auto' }}>
          <Btn kind="primary" size="sm" onClick={() => go('book')}>报名这一场</Btn>
          <a className="btn btn-ghost btn-sm" href={a.url}>读公众号原文 →</a>
        </div>
      </div>
    </article>
  );
}

function EventsPage4() {
  const go = window.__go;
  const [tab, setTab] = React.useState('upcoming');
  const [detail, setDetail] = React.useState(null);
  if (detail) return <PastEventDetail ev={detail} onBack={() => { setDetail(null); window.scrollTo(0, 0); }} />;
  return (
    <>
      <V3Styles /><V4Styles />
      <section className="sec-tight" style={{ paddingTop: 'clamp(40px,4.8vw,72px)' }}>
        <div className="wrap">
          <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 24, flexWrap: 'wrap' }}>
            <div>
              <Eyebrow>活动</Eyebrow>
              <h1 className="d1" style={{ marginTop: 18, maxWidth: '14ch' }}>下一场，什么时候。</h1>
            </div>
            <div style={{ display: 'flex', gap: 6, paddingBottom: 6, flexWrap: 'wrap' }}>
              {[['upcoming', '即将到来', QD.upcoming.length], ['past', '往期活动', QD.events.length]].map(([k, t, n]) => (
                <button key={k} className={'chip' + (tab === k ? ' on' : '')} onClick={() => setTab(k)} style={{ padding: '9px 18px', fontSize: 13 }}>
                  {t}<span style={{ fontFamily: 'var(--f-mono)', fontSize: 9.5, marginLeft: 6, opacity: .6 }}>{n}</span>
                </button>
              ))}
              <button className="chip" onClick={() => go('gallery')} style={{ padding: '9px 18px', fontSize: 13 }}>活动相册 →</button>
            </div>
          </div>
        </div>
      </section>

      {tab === 'upcoming' && (
        <section style={{ paddingBottom: 'clamp(48px,6vw,84px)' }}>
          <div className="wrap">
            <UpcomingTop a={QD.upcoming[0]} />
            <div className="ev-list" style={{ marginTop: 18 }}>
              {QD.upcoming.slice(1).map((a) => (
                <article key={a.id} className="ev-row">
                  <CalBlock a={a} compact />
                  <div className="bd">
                    <span className="tag" style={{ alignSelf: 'flex-start' }}>{a.form} · {a.level}</span>
                    <h3>{a.title}</h3>
                    <div className="where">{a.city}<small>{a.dateText}</small></div>
                    <ul className="act-pts">{a.points.slice(0, 2).map((p) => <li key={p}>{p}</li>)}</ul>
                    <div className="act-seats"><span>余 {a.left} / {a.seats}</span><span className="seats-bar"><i style={{ width: Math.round((a.seats - a.left) / a.seats * 100) + '%' }} /></span></div>
                    <div style={{ display: 'flex', gap: 10, alignItems: 'center', marginTop: 4 }}>
                      <Btn kind="primary" size="sm" onClick={() => go('book')}>报名</Btn>
                      <a className="btn btn-quiet" style={{ fontSize: 12.5 }} href={a.url}>原文 →</a>
                      <span className="act-src" style={{ marginLeft: 'auto' }}>{Ico.wechat()} {a.source.at}</span>
                    </div>
                  </div>
                </article>
              ))}
            </div>
            <p className="form-note" style={{ marginTop: 18 }}>活动信息由公众号推文自动抓取并经人工确认；以原文为准。</p>
          </div>
        </section>
      )}

      {tab === 'past' && (
        <section style={{ paddingBottom: 'clamp(48px,6vw,84px)' }}>
          <div className="wrap">
            <div className="past-grid">
              {QD.events.map((ev) => (
                <button key={ev.id} className="past-card" onClick={() => { setDetail(ev); window.scrollTo(0, 0); }}>
                  <div className="cv"><img src={ev.cover} alt="" loading="lazy" /><span className="ended">已结束</span></div>
                  <div className="bd">
                    <span className="yr">{ev.date}</span>
                    <h3>{ev.title}</h3>
                    <p>{ev.intro}</p>
                    <div className="m"><span>{ev.place || ev.city}</span><span>{ev.people} 人参加</span></div>
                  </div>
                </button>
              ))}
            </div>
          </div>
        </section>
      )}
    </>
  );
}

function PastEventDetail({ ev, onBack }) {
  const go = window.__go;
  return (
    <>
      <V4Styles />
      <section className="pd-hero">
        <img src={ev.cover} alt="" />
        <div className="wrap">
          <button className="btn btn-ghost btn-sm" style={{ borderColor: 'rgba(255,255,255,.4)', color: '#fff' }} onClick={onBack}>← 返回往期活动</button>
          <div style={{ marginTop: 22 }}><V6Styles /><span className="ev-flag past">往期活动 · 已结束</span></div>
          <h1 className="d1" style={{ color: '#fff', fontSize: 'clamp(30px,3.8vw,52px)', marginTop: 12, maxWidth: '20ch' }}>{ev.title}</h1>
        </div>
      </section>
      <div className="wrap">
        <div className="pd-facts">
          {[['时间', ev.date], ['地点', ev.place || ev.city], ['参加人数', ev.people + ' 人'], ['类型', ev.kind]].map(([k, v]) => (
            <div key={k}><div className="k">{k}</div><div className="v">{v}</div></div>
          ))}
        </div>
      </div>
      <section className="sec-tight">
        <div className="wrap">
          <div className="split" style={{ alignItems: 'start' }}>
            <div>
              <Eyebrow>活动介绍</Eyebrow>
              <p className="lede" style={{ marginTop: 18 }}>{ev.intro}</p>
              {ev.note && <p style={{ marginTop: 14, fontSize: 14.5, color: 'var(--txt-2)', lineHeight: 1.8, fontWeight: 300 }}>{ev.note}</p>}
            </div>
            <ul className="nlist">
              {ev.agenda.map((a, i) => <li key={a}><span className="k">0{i + 1}</span><div><h4>{a}</h4></div></li>)}
            </ul>
          </div>
          <div style={{ marginTop: 36, display: 'flex', gap: 12, flexWrap: 'wrap' }}>
            <Btn kind="primary" onClick={() => go('gallery', ev.id)} arw>看这一场的相册（{ev.photos} 张）</Btn>
            <Btn kind="ghost" onClick={() => go('events')}>即将到来的同类活动</Btn>
          </div>
        </div>
      </section>
    </>
  );
}

/* ============ 相册独立页 ============ */
function GalleryPage({ id }) {
  const [evId, setEvId] = React.useState(id || QD.events[0].id);
  const ev = QD.events.find((e) => e.id === evId) || QD.events[0];
  const [i, setI] = React.useState(0);
  const thumbs = React.useRef(null);
  const list = Array.from({ length: ev.photos }, (_, k) => `assets/gallery/${ev.id}/${String(k + 1).padStart(2, '0')}.jpg`);
  React.useEffect(() => { setI(0); }, [evId]);
  const step = React.useCallback((d) => setI((x) => (x + d + list.length) % list.length), [list.length]);
  React.useEffect(() => {
    const h = (e) => { if (e.key === 'ArrowRight') step(1); if (e.key === 'ArrowLeft') step(-1); };
    window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h);
  }, [step]);
  React.useEffect(() => {
    const el = thumbs.current; const k = el && el.children[i];
    if (k) el.scrollTo({ left: k.offsetLeft - el.clientWidth / 2 + k.offsetWidth / 2, behavior: 'smooth' });
  }, [i]);
  return (
    <>
      <V4Styles />
      <section className="gal-hero">
        <div className="wrap">
          <div className="eyebrow on-dark" style={{ display: 'inline-flex' }}>活动相册 · 2012—2019</div>
          <h1 className="d1" style={{ marginTop: 16, color: '#fff', fontSize: 'clamp(30px,3.8vw,52px)' }}>十五场课的现场。</h1>
        </div>
      </section>
      <div className="gal-tabs">
        {QD.events.map((e) => (
          <button key={e.id} className={e.id === evId ? 'on' : ''} onClick={() => setEvId(e.id)}>{e.year} · {e.city}{e.kind !== '一阶段' ? ' · ' + e.kind : ''}</button>
        ))}
      </div>
      <section className="gal-stage">
        <div className="gal-main">
          <div className="frame">
            {list.map((s, k) => <img key={s} src={s} alt={`${ev.title} ${k + 1}`} style={{ opacity: k === i ? 1 : 0 }} loading={Math.abs(k - i) < 2 ? 'eager' : 'lazy'} />)}
          </div>
          <button className="nv l" onClick={() => step(-1)} aria-label="上一张">‹</button>
          <button className="nv r" onClick={() => step(1)} aria-label="下一张">›</button>
          <div className="gal-cap"><span>{ev.title} · {ev.date} · {ev.people} 人</span><span>{i + 1} / {list.length}</span></div>
        </div>
        <div className="gal-thumbs" ref={thumbs}>
          {list.map((s, k) => <button key={s} className={k === i ? 'on' : ''} onClick={() => setI(k)}><img src={s} alt="" loading="lazy" /></button>)}
        </div>
      </section>
    </>
  );
}

Object.assign(window, {
  V4Styles, Hero4, Home4, FounderVideos, VoicesRiver, VoicesPage, CourseCards, EnrollSheet,
  CoursesPage, UpcomingTop, EventsPage4, PastEventDetail, GalleryPage, CalBlock,
});
