@@ -143,6 +143,42 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
. cst button { height : 34 px ; border-radius : 10 px ; background : #fff ; border : 1 px solid #F0E6EE ; box-shadow : 0 2 px 6 px rgba ( 150 , 110 , 140 , .06 ) ; font-size : 13 px ; font-weight : 700 ; color : #5A4C58 ; white-space : nowrap }
. cst button . on { background : linear-gradient ( 135 deg , #EFEAFF , #E6F0FF ) ; border-color : #D9D0FA ; color : #4F45B5 ; font-weight : 900 }
. csg { margin-top : 22 px }
/* 11-04 测试列表「热闹」:实时在测 + 战报 + 手气测 + 卡片在测 / TOP / 弹入 / 扫光 */
. csv { display : grid ; grid-template-columns : 1 fr auto ; align-items : center ; gap : 8 px 10 px ; margin : 10 px 12 px 0 ; padding : 10 px 12 px ; border-radius : 16 px ; background : linear-gradient ( 135 deg , #FFF1EA , #FFF7F0 60 % , #F6F0FF ) ; box-shadow : 0 4 px 14 px -8 px rgba ( 240 , 112 , 79 , .35 ) }
. csv-n { font-size : 13 px ; font-weight : 700 ; color : #6E5A55 ; display : flex ; align-items : center ; gap : 6 px }
. csv-n b { font-size : 17 px ; font-weight : 900 ; color : #F0453A ; display : inline-block }
. csv-n b . bp { animation : csvBp .5 s ease }
@ keyframes csvBp { 40 % { transform : translateY ( -2 px ) scale ( 1.08 ) } }
. csv-dot { width : 8 px ; height : 8 px ; border-radius : 50 % ; background : #F0453A ; box-shadow : 0 0 0 0 rgba ( 240 , 69 , 58 , .5 ) ; animation : csvDot 1.4 s ease-out infinite }
@ keyframes csvDot { 70 % { box-shadow : 0 0 0 7 px rgba ( 240 , 69 , 58 , 0 ) } 100 % { box-shadow : 0 0 0 0 rgba ( 240 , 69 , 58 , 0 ) } }
. csv-go { display : inline-flex ; align-items : center ; gap : 4 px ; height : 30 px ; padding : 0 12 px 0 8 px ; border-radius : 99 px ; background : linear-gradient ( 135 deg , #8D6BFF , #B08CFF ) ; color : #fff ; font-size : 12.5 px ; font-weight : 800 ; box-shadow : 0 4 px 10 px -4 px #8D6BFF }
. csv-go svg { width : 18 px ; height : 18 px ; color : #fff ; opacity : .95 }
. csv-go svg rect { fill : rgba ( 255 , 255 , 255 , .28 ) }
. csv-go . roll svg { animation : csvRoll .65 s cubic-bezier ( .3 , 1.4 , .6 , 1 ) }
@ keyframes csvRoll { to { transform : rotate ( 720 deg ) scale ( 1.15 ) } }
. csv-r { grid-column : 1 /- 1 ; position : relative ; height : 24 px ; overflow : hidden }
. csv-i { position : absolute ; inset : 0 ; display : flex ; align-items : center ; gap : 6 px ; width : 100 % ; font-size : 12.5 px ; color : #7A6863 ; text-align : left ; opacity : 0 ; transform : translateY ( 100 % ) ; transition : transform .45 s ease , opacity .45 s ease }
. csv-i . on { opacity : 1 ; transform : none } . csv-i . up { opacity : 0 ; transform : translateY ( -100 % ) }
. csv-i img { flex : none ; width : 20 px ; height : 20 px ; border-radius : 50 % ; object-fit : cover ; border : 1.5 px solid #fff ; background : #FFE3D3 }
. csv-i span { flex : 1 ; min-width : 0 ; white-space : nowrap ; overflow : hidden ; text-overflow : ellipsis }
. csv-i em { font-style : normal ; font-weight : 800 ; color : #3A2A26 ; margin-right : 4 px }
. csv-i b { font-weight : 800 ; color : #8D6BFF }
. csv-i small { flex : none ; font-size : 11 px ; color : #B5A39C }
. ck . cv . ck-live { position : absolute ; left : 7 px ; top : 7 px ; z-index : 1 ; display : inline-flex ; align-items : center ; gap : 3 px ; height : 19 px ; padding : 0 7 px 0 6 px ; border-radius : 99 px ; background : rgba ( 255 , 255 , 255 , .82 ) ; color : #6E5A55 ; font-size : 10 px ; font-style : normal ; font-weight : 700 }
. ck . cv . ck-live > i { width : 6 px ; height : 6 px ; border-radius : 50 % ; background : #2EC47A ; box-shadow : 0 0 0 0 rgba ( 46 , 196 , 122 , .5 ) ; animation : csvDot2 1.6 s ease-out infinite }
@ keyframes csvDot2 { 70 % { box-shadow : 0 0 0 5 px rgba ( 46 , 196 , 122 , 0 ) } 100 % { box-shadow : 0 0 0 0 rgba ( 46 , 196 , 122 , 0 ) } }
# more . ck . cv . ck-live b { margin : 0 ; padding : 0 ; font-size : 11 px ; line-height : 1 ; color : #2A1E1E ; font-weight : 900 ; font-variant-numeric : tabular-nums ; -webkit- line-clamp : unset ; display : inline }
# more . ck . cv . ck-live . bp b { animation : csvBp .5 s ease ; display : inline-block ; color : #F0453A }
. ck . cv . ck-top { position : absolute ; right : 0 ; top : 0 ; z-index : 1 ; height : 20 px ; padding : 0 8 px 0 9 px ; border-radius : 0 0 0 12 px ; color : #fff ; font-size : 10.5 px ; font-style : italic ; font-weight : 900 ; line-height : 20 px ; letter-spacing : .3 px }
. ck-top . t1 { background : linear-gradient ( 135 deg , #F0453A , #FF8A3D ) } . ck-top . t2 { background : linear-gradient ( 135 deg , #FF8A2E , #FFC06E ) } . ck-top . t3 { background : linear-gradient ( 135 deg , #8D6BFF , #B9A3FF ) }
. ck . cv i . dn { top : 30 px }
. ck . cv em { position : relative ; overflow : hidden }
. ck . cv em :: after { content : "" ; position : absolute ; top : 0 ; bottom : 0 ; left : -60 % ; width : 40 % ; background : linear-gradient ( 100 deg , transparent , rgba ( 255 , 255 , 255 , .55 ) , transparent ) ; transform : skewX ( -18 deg ) ; animation : ckShine 3.6 s ease-in-out infinite }
@ keyframes ckShine { 0 % , 62 % { left : -60 % } 88 % , 100 % { left : 130 % } }
. pre { opacity : 0 }
. pre . pop-in { animation : ckPop .5 s cubic-bezier ( .3 , 1.35 , .5 , 1 ) both }
@ keyframes ckPop { from { opacity : 0 ; transform : translateY ( 14 px ) scale ( .96 ) } to { opacity : 1 ; transform : none } }
@ media ( prefers-reduced-motion : reduce ) { . pre { opacity : 1 } . pre . pop-in , . ck . cv em :: after , . csv-dot , . ck . cv . ck-live > i { animation : none } }
. csg-h { display : flex ; flex-direction : column ; gap : 5 px ; padding : 0 2 px }
. csg-h b { display : flex ; align-items : center ; gap : 6 px ; padding-left : 10 px ; border-left : 3 px solid #B9B3D6 ; font-size : 19 px ; font-weight : 900 ; line-height : 1.1 ; color : #2B2433 }
. csg-h b i { font-style : normal ; font-size : 18 px }
@@ -183,6 +219,7 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
. c2 . ck . cv b { font-size : 15.5 px ; padding : 0 6 px }
. ck . cv { height : 146 px }
. c2 . ck . cv { height : 160 px }
# more . ck . cv { padding-top : 22 px ; height : 166 px } # more . c2 . ck . cv { height : 178 px }
. ck . cnn { margin-top : 8 px }
. ck . cv small { font-size : 10.5 px ; color : #8D8091 ; white-space : nowrap }
. ck . cv em { margin-top : 2 px ; height : 22 px ; padding : 0 10 px ; border-radius : 6 px ; background : var ( - - cb ) ; color : #fff ; font-size : 11 px ; font-style : normal ; font-weight : 800 ; line-height : 22 px ; box-shadow : 0 3 px 8 px -3 px var ( - - cb ) }
@@ -711,10 +748,10 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
< div id = "sheet" role = "dialog" aria-modal = "true" > < i class = "sg" > < / i > < div class = "sbd" id = "sbd" > < / div > < / div >
< div class = "toast" id = "toast" > < / div >
< script src = "topics.js?v=26110290 " > < / script >
< script src = "data.js?v=26110290 " > < / script >
< script src = "feed.js?v=26110290 " > < / script >
< script src = "ceshi/meta.js?v=26110290 " > < / script >
< script src = "topics.js?v=26110291 " > < / script >
< script src = "data.js?v=26110291 " > < / script >
< script src = "feed.js?v=26110291 " > < / script >
< script src = "ceshi/meta.js?v=26110291 " > < / script >
< script >
( function ( ) {
'use strict' ;
@@ -780,7 +817,7 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
var CMD = null , CMERR = false ;
/* 头像编码:数字 = av/NNNN.webp( 旧代码头像) ; 'av:c012' = av/c012.webp( 卡通/可爱卡通);'/…' = 站内绝对路径(内置头像库 /_bridge/avatars/);其余 = assets/img/mom/xxx.jpg */
var avP = function ( a ) { return typeof a === 'number' ? 'av/' + ( '000' + a ) . slice ( - 4 ) + '.webp' : a . indexOf ( 'av:' ) === 0 ? 'av/' + a . slice ( 3 ) + '.webp' : a . charAt ( 0 ) === '/' ? a : '../assets/img/mom/' + a + '.jpg' ; } ;
fetch ( 'cm.json?v=26110290 ' ) . then ( function ( r ) { return r . json ( ) ; } ) . then ( function ( j ) {
fetch ( 'cm.json?v=26110291 ' ) . then ( function ( r ) { return r . json ( ) ; } ) . then ( function ( j ) {
CMD = j ; if ( openId && NBY [ openId ] ) { renderComments ( NBY [ openId ] ) ; syncBar ( NBY [ openId ] ) ; }
} ) . catch ( function ( ) { CMERR = true ; if ( openId && NBY [ openId ] ) renderComments ( NBY [ openId ] ) ; } ) ;
function commentsOf ( n ) {
@@ -1026,10 +1063,75 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
} ;
function csCardHTML ( x , done , i ) {
var d = done [ x . id ] , who = ( x . sub || '' ) . split ( '·' ) [ 0 ] . trim ( ) ;
var top = byHot ( TM ) . slice ( 0 , 3 ) . map ( function ( y ) { return y . id ; } ) . indexOf ( x . id ) , nw = csNowOn ( x . id ) ;
return '<button type="button" class="ck ' + CS _GPAL [ x . group ] + '" data-test="' + x . id + '"><span class="cv">' + ( CS _BLOBS [ x . group ] || CS _BLOB ) +
'<i class="ck-live"><i></i><b data-v="' + nw + '">' + nw + '</b> 人在测</i>' + ( top >= 0 ? '<i class="ck-top t' + ( top + 1 ) + '">TOP' + ( top + 1 ) + '</i>' : '' ) +
'<b>' + esc ( x . title . replace ( /^测一测|/ , '' ) ) + '</b><small>' + esc ( who ) + ' · ' + x . n + ' 题</small><em>' + ( d ? '再测一次' : '开始测试' ) + '</em>' + ( d ? '<i class="dn">已测</i>' : '' ) + '</span>' +
'<span class="cnn"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12.6 2.5c.4 3-1.6 4.6-3 6.2C8 10.4 7 12 7 14.3A5 5 0 0012 19.5a5 5 0 005-5.2c0-2-1-3.6-1.9-4.6-.2 1.3-.9 2.2-1.9 2.6.6-3.4-.2-7-.6-9.8z" fill="currentColor"/></svg>' + gcTestedText ( x . id ) + '</span></button>' ;
}
/* ---------- 11-04 用户:「测试列表页太安静,要热闹、有创意」 ----------
① banner 下一条「此刻 N 人正在测」(红点呼吸、数字隔 2 秒小跳)+ 战报滚动「谁 刚测出「结果」· 哪个测试」(点了进那个测试);
② 右边「手气测」骰子:随机挑一个还没测过的测试,骰子转一下就进;
③ 卡片封面左上「● N 人在测」,隔几秒随机两张卡数字跳;全站最热 3 个封面右上 TOP1~ 3 角标;卡片进屏错落弹入、「开始测试」按钮定时扫光。
人数 / 昵称 / 头像都是模拟( 同「N 人测过」口径, AGENTS.md 12b, 12-31 复核);战报只写「测出了哪个结果」,结果名取 meta.js GC_RES( 真实结果名) 。 */
var CL _NM = [ '小满妈妈' , '糯米团子' , '橙子不酸' , '鹿鹿呀' , '安安的妈' , '豆包本包' , '一只小葵' , '阿圆' , '栗子酱' , '桃桃乌龙' , '芝麻汤圆' , '晴天娃娃' ,
'果冻布丁' , '岁岁平安' , '叮当妈' , '饭团子' , '奶糖不甜' , '小鱼干' , '朵朵妈咪' , '暖暖' , '布丁要长大' , '花卷儿' , '柚子茶' , '星星的妈' ,
'甜甜圈' , '小熊软糖' , '一颗青梅' , '冬冬妈' , '可乐加冰' , '麦穗儿' , '云朵朵' , '橘子汽水' , '乐乐的妈' , '荔枝' , '蜜桃乌龙' , '小葡萄' ] ;
var CL _AV = [ 'p02' , 'm05' , 'p05' , 'm12' , 'k04' , 'p09' , 'm16' , 'p11' , 'm07' , 'k10' , 'p03' , 'm19' , 'p13' , 'm02' , 'k06' , 'p06' , 'm10' , 'p12' , 'm21' , 'p07' , 'm04' , 'k12' , 'p14' , 'm15' ,
'p01' , 'm01' , 'k01' , 'm03' , 'p04' , 'm06' , 'k02' , 'm08' , 'p08' , 'm09' , 'k03' , 'm11' ] ;
var CS _DICE = '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="5" fill="currentColor"/><g fill="#fff"><circle cx="8" cy="8" r="1.7"/><circle cx="16" cy="8" r="1.7"/><circle cx="12" cy="12" r="1.7"/><circle cx="8" cy="16" r="1.7"/><circle cx="16" cy="16" r="1.7"/></g></svg>' ;
function csNowBase ( ) { return Math . round ( TM . reduce ( function ( a , x ) { return a + gcTested ( x . id ) ; } , 0 ) / 1150 ) ; }
function csLiveHTML ( ) {
return '<div class="csv"><div class="csv-n"><i class="csv-dot"></i>此刻 <b id="csvN" class="num">' + csNowBase ( ) . toLocaleString ( ) + '</b> 人正在测</div>' +
'<button type="button" class="csv-go" id="csvGo">' + CS _DICE + '手气测</button>' +
'<div class="csv-r" id="csvR"></div></div>' ;
}
var csvT = 0 , csvI = 0 , csvRec = [ ] ;
function csvOne ( ) {
var R = window . GC _RES || { } , ids = TM . filter ( function ( x ) { return R [ x . id ] && R [ x . id ] . length ; } ) ;
if ( ! ids . length ) return '' ;
var t = ids [ Math . floor ( Math . random ( ) * ids . length ) ] , rs = R [ t . id ] , r = rs [ Math . floor ( Math . random ( ) * rs . length ) ] , k , c = [ ] ;
for ( k = 0 ; k < CL _NM . length ; k ++ ) if ( csvRec . indexOf ( k ) < 0 ) c . push ( k ) ;
k = c [ Math . floor ( Math . random ( ) * c . length ) ] ; csvRec . push ( k ) ; if ( csvRec . length > 14 ) csvRec . shift ( ) ;
return '<button type="button" class="csv-i" data-test="' + t . id + '"><img src="../assets/img/mom/' + CL _AV [ k ] + '.jpg" alt="" width="20" height="20">' +
'<span><em>' + esc ( CL _NM [ k ] ) + '</em>刚测出<b>「' + esc ( r ) + '」</b></span><small>' + esc ( CS _SHORT [ t . id ] || '' ) + '</small></button>' ;
}
function csLiveRun ( ) {
clearInterval ( csvT ) ;
var box = $ ( '#csvR' ) ; if ( ! box ) return ;
box . innerHTML = csvOne ( ) ; if ( box . firstChild ) box . firstChild . classList . add ( 'on' ) ;
var base = csNowBase ( ) , n = base , tick = 0 ;
csvT = setInterval ( function ( ) {
if ( document . hidden || ! document . getElementById ( 'csvR' ) ) return ;
tick ++ ;
if ( tick % 2 === 0 ) { /* 战报每 2.6 秒换一条 */
var b = document . getElementById ( 'csvR' ) , old = b . querySelector ( '.csv-i.on' ) ;
b . insertAdjacentHTML ( 'beforeend' , csvOne ( ) ) ;
var nw = b . lastElementChild ; void nw . offsetWidth ; nw . classList . add ( 'on' ) ;
if ( old ) { old . classList . remove ( 'on' ) ; old . classList . add ( 'up' ) ; setTimeout ( function ( ) { if ( old . parentNode ) old . parentNode . removeChild ( old ) ; } , 450 ) ; }
}
n = Math . max ( Math . round ( base * . 93 ) , Math . min ( Math . round ( base * 1.07 ) , n + Math . round ( ( Math . random ( ) - . 45 ) * 14 ) ) ) ;
var e = document . getElementById ( 'csvN' ) ; if ( e ) { e . textContent = n . toLocaleString ( ) ; e . classList . remove ( 'bp' ) ; void e . offsetWidth ; e . classList . add ( 'bp' ) ; }
if ( tick % 3 === 0 ) { /* 随机两张卡的「在测」数小跳 */
var cs = document . querySelectorAll ( '#more .ck-live b' ) ;
for ( var q = 0 ; q < 2 && cs . length ; q ++ ) {
var x = cs [ Math . floor ( Math . random ( ) * cs . length ) ] , v = + x . dataset . v || 10 ;
v = Math . max ( 3 , v + ( Math . random ( ) < . 6 ? 1 : - 1 ) * ( 1 + Math . floor ( Math . random ( ) * 3 ) ) ) ; x . dataset . v = v ; x . textContent = v ;
x . parentNode . classList . remove ( 'bp' ) ; void x . parentNode . offsetWidth ; x . parentNode . classList . add ( 'bp' ) ;
}
}
} , 1300 ) ;
}
function csNowOn ( id ) { var h = 0 ; for ( var i = 0 ; i < id . length ; i ++ ) h = ( h * 31 + id . charCodeAt ( i ) ) >>> 0 ; return 6 + h % 9 + Math . round ( gcTested ( id ) / 2600 ) ; }
function csFx ( ) { /* 卡片进屏错落弹入 */
var els = document . querySelectorAll ( '#more .ck, #more .csr' ) ;
if ( ! ( 'IntersectionObserver' in window ) ) return ;
var io = new IntersectionObserver ( function ( es ) {
var k = 0 ;
es . forEach ( function ( e ) { if ( ! e . isIntersecting ) return ; e . target . style . animationDelay = ( k ++ * 70 ) + 'ms' ; e . target . classList . add ( 'pop-in' ) ; io . unobserve ( e . target ) ; } ) ;
} , { threshold : . 15 } ) ;
[ ] . forEach . call ( els , function ( el ) { el . classList . add ( 'pre' ) ; io . observe ( el ) ; } ) ;
}
function ceshiListHTML ( ) {
var done = csDone ( ) , gs = [ 'quiz' , 'psy' , 'game' , 'shop' ] . filter ( function ( g ) { return ! tGrp || tGrp === g ; } ) , k = 0 ;
return '<div class="csl">' + gs . map ( function ( g , gi ) {
@@ -1066,7 +1168,7 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
}
function renderHead ( ) {
var t = TBY [ cur ] , el = $ ( '#head' ) , fh = $ ( '#fh' ) ;
if ( catF === 'ceshi' ) { el . innerHTML = cbnHTML ( 'ceshi' ) ; ceshiFh ( fh ) ; return ; } /* 原一行介绍 ceshiHead 并进 banner */
if ( catF === 'ceshi' ) { el . innerHTML = cbnHTML ( 'ceshi' ) + csLiveHTML ( ) ; ceshiFh ( fh ) ; csLiveRun ( ) ; return ; } /* 原一行介绍 ceshiHead 并进 banner */
if ( ! t ) {
var hl = hotList ( ) ;
el . innerHTML = ( catF ? cbnHTML ( catF ) : qifuHTML ( ) ) + /* 祈福树只在「全部」 */
@@ -1116,7 +1218,7 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
/* 真瀑布流:每张卡放进当前更矮的那一列(逐张量高,标题一行/两行也算进去) */
var hs = [ 0 , 0 ] , tmp = document . createElement ( 'div' ) , lastTx = [ false , true ] , txN = [ 0 , 1 ] ; /* 11-02 用户:图上带字的卡至少占 40% → 每列「带字 / 不带字」交替(测试卡算不带字),两列错开一格,带字的在压大字 ov / 贴纸字 tg 间轮换;整体约 45% */
if ( catF === 'ceshi' ) {
$ ( '#more' ) . innerHTML = ceshiListHTML ( ) ; return ;
$ ( '#more' ) . innerHTML = ceshiListHTML ( ) ; csFx ( ) ; return ;
}
/* 「全部」信息流:穿插测试卡 */
if ( ! cur && ! catF && TM . length ) {
@@ -1271,7 +1373,14 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
$ ( '#more' ) . addEventListener ( 'click' , function ( e ) { if ( e . target . closest ( '[data-t]' ) ) { haptic ( ) ; selectTopic ( '' ) ; } } ) ;
$ ( '#head' ) . addEventListener ( 'click' , function ( e ) {
if ( e . target . closest ( '#qfBanner' ) ) { goQifu ( ) ; return ; }
var cb = e . target . closest ( '.cbn[data-test]' ) ; if ( cb ) { haptic ( ) ; location . href = ceshiURL ( cb . dataset . test , true ) ; return ; }
var cb = e . target . closest ( '.cbn[data-test], .csv-i[data-test] ' ) ; if ( cb ) { haptic ( ) ; location . href = ceshiURL ( cb . dataset . test , true ) ; return ; }
var dc = e . target . closest ( '#csvGo' ) ;
if ( dc ) { /* 手气测:优先没测过的 */
haptic ( ) ; dc . classList . add ( 'roll' ) ;
var dn = csDone ( ) , pool = TM . filter ( function ( x ) { return ! dn [ x . id ] ; } ) ; if ( ! pool . length ) pool = TM ;
var pk = pool [ Math . floor ( Math . random ( ) * pool . length ) ] ;
setTimeout ( function ( ) { location . href = ceshiURL ( pk . id , true ) ; } , 650 ) ; return ;
}
var j = e . target . closest ( '[data-join]' ) ; if ( j ) { haptic ( ) ; openRule ( j . dataset . join ) ; return ; }
if ( e . target . closest ( '[data-rule]' ) ) { openRule ( '' ) ; return ; }
if ( e . target . closest ( '[data-all]' ) ) { openTopics ( ) ; return ; }