成绩投屏的系数赛制评分卡改为展示“难度得分”“表现系数”“规定系数”“扣分系数 M”,让标签与评分含义一致。沿用赛制判断,规定赛继续显示“创意编排分”“完成质量分”和实际扣分,不误标为系数;交互绳等赛制的评分项隐藏规则保持不变。 仅修改前端成绩大屏页面,不涉及后端接口或计分计算。验证:npm run build:local 通过,git diff --check 通过。业务契约脚本因硬编码的后端路径在本机不存在而未能执行。
398 lines
40 KiB
Vue
398 lines
40 KiB
Vue
<template>
|
||
<div :class="['score-screen', `view-${viewType}`, `entity-${displayKind}`, { embedded: !isBigScreen, offline }]">
|
||
<div class="design-stage" :style="{ '--screen-scale': screenScale }">
|
||
<div class="ambient ambient-one"></div><div class="ambient ambient-two"></div><div class="aurora-strip"></div><div class="screen-grid"></div><div class="horizon"></div><div class="frame-corners"><i></i><i></i><i></i><i></i></div>
|
||
<Transition name="cast" mode="out-in">
|
||
<main v-if="effectiveCast" :key="castKey" class="screen-content">
|
||
<header class="screen-header"><div class="title-wing left"><i></i><i></i><i></i></div><div class="event-title"><span>LIVE RESULTS</span><h1>{{ title }}</h1></div><div class="title-wing right"><i></i><i></i><i></i></div></header>
|
||
<section class="context-bar"><div><span class="context-icon"><el-icon><User /></el-icon></span><small>项目 / 组别</small><b>{{ projectGroup }}</b></div><i></i><div><span class="context-icon"><el-icon><Location /></el-icon></span><small>场次 / 场地</small><b>{{ sessionVenue }}</b></div></section>
|
||
<section v-if="viewType === 'score'" class="score-layout">
|
||
<div class="hero-card"><div class="panel-shine"></div><div class="entity-chip"><el-icon><component :is="displayKind === 'team' ? UserFilled : User" /></el-icon><span>{{ displayKind === 'team' ? 'TEAM' : 'PLAYER' }}</span>{{ displayKindLabel }}成绩</div><div class="entity-name">{{ singleName }}</div><div v-if="singleAffiliation" class="entity-affiliation">{{ singleAffiliation }}</div><div class="hero-meta"><span v-if="payload.entryNo">出场号 <b>{{ payload.entryNo }}</b></span><span v-if="payload.rank">当前排名 <b>第 {{ payload.rank }} 名</b></span></div><div class="hero-score"><strong class="score-ticker">{{ animatedValue('hero', payload.totalScore ?? payload.score) }}</strong><small>分</small></div><div class="score-beam"><i></i></div><div v-if="payload.isDisqualified" class="dq-stamp">DQ</div></div>
|
||
<div class="score-metrics" :style="{ gridTemplateColumns: `repeat(${Math.max(scoreCards.length, 1)}, 1fr)` }"><article v-for="(item,index) in scoreCards" :key="item.key" :class="['metric-card', item.key]" :style="{ '--delay': `${index * 90}ms` }"><div class="metric-head"><span class="metric-icon"><el-icon><component :is="scoreIconComponents[item.key]" /></el-icon></span><small>{{ item.en }}</small></div><strong class="score-ticker">{{ item.field === 'deductionFactor' ? Number(payload[item.field]).toFixed(3) : animatedValue(`metric:${item.key}`, payload[item.field]) }}</strong><div class="metric-line"></div><b>{{ item.label }}</b></article></div>
|
||
</section>
|
||
<section v-else class="ranking-layout">
|
||
<div class="ranking-heading"><div><span><i></i>{{ displayKind === 'team' ? 'TEAM RANKING' : 'INDIVIDUAL RANKING' }}</span><h2>{{ displayKindLabel }}排名</h2></div><div class="ranking-status"><small>共 {{ rankingTotal }} 个{{ displayKind === 'team' ? '队伍' : '参赛者' }}<template v-if="rankingPageCount > 1"> · 第 {{ rankingPageIndex + 1 }}/{{ rankingPageCount }} 页</template></small><div v-if="rankingPageCount > 1" class="page-dots"><i v-for="page in rankingPageCount" :key="page" :class="{ active: page - 1 === rankingPageIndex }"></i></div></div></div>
|
||
<div v-if="rankingRows.length" class="ranking-list"><article v-for="(row,index) in rankingRows" :key="`${row.entryNo || displayName(row)}-${index}`" :class="['rank-row', { podium: rankNumber(row,index) <= 3 }]" :style="{ '--delay': `${index * 85}ms` }"><div :class="['rank-badge', `rank-${rankNumber(row,index)}`]"><template v-if="rankNumber(row,index) <= 3"><span class="medal-ribbon left"></span><span class="medal-ribbon right"></span><el-icon><Trophy /></el-icon><b>{{ rankNumber(row,index) }}</b></template><b v-else>{{ rankNumber(row,index) }}</b></div><div class="rank-person"><div class="rank-title"><strong>{{ displayName(row) }}</strong><small v-if="displaySubName(row)">{{ displaySubName(row) }}</small></div><div class="rank-track"><i :style="{ width: rankWidth(row) }"></i></div></div><div class="rank-value"><strong class="score-ticker">{{ animatedValue(rankAnimationKey(row,index), row.totalScore ?? row.score) }}</strong><small>分</small></div></article></div>
|
||
<div v-else class="ranking-empty">当前组别暂无可展示排名</div>
|
||
</section>
|
||
<footer class="screen-footer"><span></span><b>跃动赛事 · 实时成绩系统</b><span></span></footer>
|
||
</main>
|
||
<section v-else key="waiting" class="waiting"><div class="waiting-orbit"><i></i><i></i><i></i><span>YD</span></div><small>LIVE RESULTS SYSTEM</small><h1>等待后台投屏</h1><p>请在赛事控制台选择组别,并投出个人、团队成绩或排名</p></section>
|
||
</Transition>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||
import { useRoute } from 'vue-router';
|
||
import { DocumentChecked, Flag, Location, Medal, Setting, Trophy, User, UserFilled } from '@element-plus/icons-vue';
|
||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||
import { workbenchScreenCastCurrentGet } from '/@/api/match/workbench';
|
||
import { isFactorRule, isWireRule } from '../score-format.mjs';
|
||
|
||
const route=useRoute(),storesTagsViewRoutes=useTagsViewRoutes();
|
||
let savedContext={};try{savedContext=JSON.parse(sessionStorage.getItem('scoring-context')||'{}')}catch{savedContext={}}
|
||
const eventId=Number(route.query.eventId)||Number(savedContext.eventId)||0;
|
||
const venueId=route.query.venueId?Number(route.query.venueId):(Number(savedContext.venueId)||undefined);
|
||
const cast=ref(null),offline=ref(false),rankPage=ref(0),viewport=ref({width:window.innerWidth,height:window.innerHeight}),animatedNumbers=ref({});
|
||
let pollTimer,rankTimer,castChannel,numberAnimationFrame;
|
||
function normalizePayload(value){if(Array.isArray(value))return value.map(normalizePayload);if(!value||typeof value!=='object')return value;return Object.fromEntries(Object.entries(value).map(([key,item])=>[key.charAt(0).toLowerCase()+key.slice(1),normalizePayload(item)]))}
|
||
function unwrapApiData(response){let value=response;for(let i=0;i<3&&value&&typeof value==='object'&&Object.prototype.hasOwnProperty.call(value,'data');i++)value=value.data;return value}
|
||
function normalizeCast(value){const normalized=normalizePayload(value),castType=Number(normalized?.castType);return normalized&&(castType===1||castType===2)&&normalized.payloadJson!=null?{...normalized,castType}:null}
|
||
function cacheKey(scope=venueId){return `yd-event-screen-cast:${eventId}:${scope??'all'}`}
|
||
function readCachedCast(){try{const scoped=localStorage.getItem(cacheKey()),fallback=localStorage.getItem(cacheKey(null));const cached=normalizeCast(JSON.parse(scoped||fallback||'null'));return cached&&Date.now()-Number(cached.cachedAt||0)<30000?cached:null}catch{return null}}
|
||
function acceptPublishedCast(value){const next=normalizeCast(value);if(next){cast.value=next;offline.value=false;rankPage.value=0}else cast.value=null}
|
||
const effectiveCast=computed(()=>cast.value);
|
||
const payload=computed(()=>{try{const raw=effectiveCast.value?.payloadJson;if(!raw)return {};return normalizePayload(typeof raw==='string'?JSON.parse(raw):raw)}catch{return {}}});
|
||
const viewType=computed(()=>effectiveCast.value?.castType===2?'ranking':'score');
|
||
const displayKind=computed(()=>{const configured=String(effectiveCast.value?.displayKind||route.query.displayKind||'').toLowerCase();if(configured==='team'||configured==='individual')return configured;const sample=Array.isArray(payload.value)?payload.value[0]:payload.value;return sample?.teamName&&!sample?.participantName?'team':'individual'});
|
||
const displayKindLabel=computed(()=>displayKind.value==='team'?'团队':'个人');
|
||
const castKey=computed(()=>`${effectiveCast.value?.screenCastId||effectiveCast.value?.castTime||'cast'}-${viewType.value}-${displayKind.value}`);
|
||
const title=computed(()=>effectiveCast.value?.eventName||String(route.query.eventName||'赛事成绩大屏'));
|
||
const projectGroup=computed(()=>[effectiveCast.value?.projectName,effectiveCast.value?.groupName||(!Array.isArray(payload.value)&&payload.value.groupName)].filter(Boolean).join(' · ')||'未设置');
|
||
function formatScreenSession(sessionNo){if(!sessionNo)return '';const tail=String(sessionNo).match(/-(\d+)$/);if(tail&&Number(tail[1])>0)return `第${Number(tail[1])}场`;if(/^\d+$/.test(String(sessionNo)))return `第${Number(sessionNo)}场`;return String(sessionNo)}
|
||
const sessionVenue=computed(()=>[formatScreenSession(effectiveCast.value?.sessionNo),effectiveCast.value?.venueName].filter(Boolean).join(' · ')||'全场地');
|
||
const singleName=computed(()=>displayKind.value==='team'?(payload.value.teamName||payload.value.participantName||'未命名队伍'):(payload.value.participantName||payload.value.teamName||'未命名选手'));
|
||
const singleAffiliation=computed(()=>displayKind.value==='team'?(payload.value.unitName||''):(payload.value.teamName&&payload.value.teamName!==singleName.value?payload.value.teamName:(payload.value.unitName||'')));
|
||
const scoreIconComponents={difficulty:Setting,performance:Medal,required:DocumentChecked,deduction:Flag};
|
||
const scoreCards=computed(()=>{
|
||
const scoreRuleCode=effectiveCast.value?.scoreRuleCode;
|
||
const prescribed=String(scoreRuleCode||'').toUpperCase().includes('PRESCRIBED');
|
||
const factor=isFactorRule(scoreRuleCode);
|
||
const wire=isWireRule(scoreRuleCode);
|
||
return [{key:'difficulty',label:'难度得分',en:'DIFFICULTY',field:'difficultyScore'},{key:'performance',label:prescribed?'创意编排分':factor?'表现系数':'表现',en:'PERFORMANCE',field:'performanceScore'},{key:'required',label:prescribed?'完成质量分':factor?'规定系数':'规定',en:'REQUIRED',field:'requiredScore'},{key:'deduction',label:factor?'扣分系数 M':'扣分',en:'DEDUCTION',field:payload.value.deductionFactor!=null?'deductionFactor':'deductionScore'}]
|
||
.filter(item=>(item.key!=='difficulty'||!prescribed)&&(item.key!=='required'||!wire));
|
||
});
|
||
const rankingAll=computed(()=>Array.isArray(payload.value)?payload.value:[]),rankingTotal=computed(()=>rankingAll.value.length),rankingPageCount=computed(()=>Math.max(1,Math.ceil(rankingTotal.value/6))),rankingPageIndex=computed(()=>rankPage.value%rankingPageCount.value),rankingRows=computed(()=>rankingAll.value.slice(rankingPageIndex.value*6,rankingPageIndex.value*6+6)),maxRankScore=computed(()=>Math.max(...rankingAll.value.map(row=>Number(row.totalScore??row.score)||0),1));
|
||
function displayName(row){return displayKind.value==='team'?(row.teamName||row.participantName||'未命名队伍'):(row.participantName||row.teamName||'未命名选手')}
|
||
function displaySubName(row){if(displayKind.value==='team')return row.unitName||'';return row.teamName&&row.teamName!==displayName(row)?row.teamName:(row.unitName||'')}
|
||
function rankNumber(row,index){const rank=Number(row.rank);return Number.isFinite(rank)&&rank>0?rank:rankingPageIndex.value*6+index+1}
|
||
function rankWidth(row){return `${Math.max(12,Math.round((Number(row.totalScore??row.score)||0)/maxRankScore.value*100))}%`}
|
||
function value(input){if(input===undefined||input===null||input==='')return '0';const n=Number(input);return Number.isFinite(n)?n.toFixed(2):input}
|
||
function rankAnimationKey(row,index){return `rank:${row.entryNo||displayName(row)||rankingPageIndex.value*6+index}`}
|
||
function animatedValue(key,fallback){return Object.prototype.hasOwnProperty.call(animatedNumbers.value,key)?value(animatedNumbers.value[key]):value(fallback)}
|
||
function animateScoreNumbers(){
|
||
window.cancelAnimationFrame(numberAnimationFrame);
|
||
const targets={};
|
||
if(viewType.value==='score'){
|
||
targets.hero=payload.value.totalScore??payload.value.score;
|
||
for(const item of scoreCards.value)targets[`metric:${item.key}`]=payload.value[item.field];
|
||
}else{
|
||
rankingRows.value.forEach((row,index)=>{targets[rankAnimationKey(row,index)]=row.totalScore??row.score});
|
||
}
|
||
if(window.matchMedia?.('(prefers-reduced-motion: reduce)').matches){animatedNumbers.value=targets;return}
|
||
const numericTargets=Object.fromEntries(Object.entries(targets).filter(([,target])=>Number.isFinite(Number(target))).map(([key,target])=>[key,Number(target)]));
|
||
const staticTargets=Object.fromEntries(Object.entries(targets).filter(([,target])=>!Number.isFinite(Number(target))));
|
||
const startedAt=performance.now(),duration=viewType.value==='score'?1280:960;
|
||
const tick=(now)=>{
|
||
const progress=Math.min(1,(now-startedAt)/duration),eased=1-Math.pow(1-progress,3);
|
||
animatedNumbers.value={...staticTargets,...Object.fromEntries(Object.entries(numericTargets).map(([key,target])=>[key,target*eased]))};
|
||
if(progress<1)numberAnimationFrame=window.requestAnimationFrame(tick);
|
||
};
|
||
numberAnimationFrame=window.requestAnimationFrame(tick);
|
||
}
|
||
const isBigScreen=computed(()=>storesTagsViewRoutes.isTagsViewCurrenFull);
|
||
const screenScale=computed(()=>Math.min(viewport.value.width/1920,viewport.value.height/1080));
|
||
let castRequesting=false;
|
||
async function loadCast(){if(!eventId||castRequesting)return;castRequesting=true;try{const current=normalizeCast(unwrapApiData(await workbenchScreenCastCurrentGet({eventId,venueId,_t:Date.now()})));if(current)acceptPublishedCast({...current,displayKind:current.displayKind||route.query.displayKind});else if(!cast.value||Date.now()-Number(cast.value.cachedAt||0)>=30000)cast.value=null;offline.value=false}catch{offline.value=true}finally{castRequesting=false}}
|
||
function onViewportResize(){viewport.value={width:window.innerWidth,height:window.innerHeight}}
|
||
watch([castKey,rankingPageIndex],()=>nextTick(animateScoreNumbers),{immediate:true,flush:'post'});
|
||
onMounted(()=>{storesTagsViewRoutes.setCurrenFullscreen(true);acceptPublishedCast(readCachedCast());if('BroadcastChannel' in window){castChannel=new BroadcastChannel(`yd-event-score-screen-${eventId}`);castChannel.onmessage=event=>acceptPublishedCast(event.data)}loadCast();pollTimer=window.setInterval(()=>document.visibilityState==='visible'&&loadCast(),3000);rankTimer=window.setInterval(()=>rankPage.value++,9000);window.addEventListener('resize',onViewportResize);onViewportResize()});
|
||
onBeforeUnmount(()=>{window.clearInterval(pollTimer);window.clearInterval(rankTimer);window.cancelAnimationFrame(numberAnimationFrame);castChannel?.close();window.removeEventListener('resize',onViewportResize)});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.score-screen{--cyan:#54ecff;--navy:#061847;position:relative;width:100vw;height:100vh;min-width:0;min-height:0;overflow:hidden;color:#fff;background:radial-gradient(circle at 50% -18%,#175dcc 0,rgba(11,52,143,.92) 35%,#061847 73%,#030b29 100%);font-family:"Microsoft YaHei","PingFang SC",sans-serif}.score-screen.view-ranking{background:radial-gradient(circle at 50% -20%,#174ba9 0,rgba(8,38,112,.96) 40%,#030b2a 100%)}.ambient{position:absolute;border-radius:50%;filter:blur(80px);opacity:.25}.ambient-one{left:-12vw;top:10vh;width:42vw;height:42vw;background:#008cff}.ambient-two{right:-14vw;bottom:-20vh;width:42vw;height:42vw;background:#0963e8}.screen-grid{position:absolute;inset:0;opacity:.14;background-image:linear-gradient(rgba(75,192,255,.18) 1px,transparent 1px),linear-gradient(90deg,rgba(75,192,255,.18) 1px,transparent 1px);background-size:5vw 5vw;mask-image:linear-gradient(to bottom,transparent 4%,#000 48%,transparent 100%);transform:perspective(600px) rotateX(55deg) scale(1.6);transform-origin:center bottom}.horizon{position:absolute;left:4%;right:4%;bottom:-12%;height:42%;border-top:1px solid rgba(91,216,255,.38);border-radius:50%;box-shadow:0 -12px 90px rgba(30,150,255,.28)}
|
||
.screen-content{position:relative;z-index:2;display:flex;flex-direction:column;width:100%;height:100%;box-sizing:border-box;padding:clamp(18px,2.3vh,42px) clamp(24px,3.1vw,82px) clamp(12px,1.8vh,32px)}.screen-header{display:flex;align-items:center;justify-content:center;gap:clamp(20px,2.3vw,60px);flex:none}.event-title{text-align:center}.event-title span{display:block;margin-bottom:.25vh;color:var(--cyan);font-size:clamp(9px,.65vw,17px);font-weight:700;letter-spacing:.42em}.event-title h1{max-width:70vw;margin:0;font-size:clamp(30px,3.1vw,80px);line-height:1.16;letter-spacing:.02em;text-shadow:0 8px 28px rgba(0,4,34,.5)}.title-wing{display:flex;align-items:center;gap:5px}.title-wing i{display:block;width:clamp(20px,2vw,54px);height:4px;clip-path:polygon(0 35%,100% 0,82% 100%,0 72%);background:linear-gradient(90deg,transparent,var(--cyan))}.title-wing i:nth-child(2){width:clamp(12px,1.1vw,30px);opacity:.72}.title-wing i:nth-child(3){width:clamp(6px,.55vw,15px);opacity:.45}.title-wing.right{transform:scaleX(-1)}
|
||
.context-bar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;width:min(76%,1900px);min-height:clamp(40px,5.2vh,86px);box-sizing:border-box;margin:clamp(12px,1.6vh,28px) auto clamp(13px,1.8vh,32px);padding:0 clamp(16px,1.6vw,44px);border:1px solid rgba(87,195,255,.3);border-radius:999px;background:linear-gradient(90deg,rgba(4,25,77,.18),rgba(15,82,168,.38),rgba(4,25,77,.18));box-shadow:inset 0 1px rgba(255,255,255,.05)}.context-bar>div{display:grid;grid-template-columns:auto 1fr;column-gap:clamp(7px,.7vw,18px);align-items:center}.context-bar>div:last-child{justify-content:end}.context-icon{grid-row:1/3;color:var(--cyan);font-size:clamp(18px,1.25vw,34px)}.context-bar small{color:#81b9e2;font-size:clamp(9px,.65vw,17px);letter-spacing:.08em}.context-bar b{font-size:clamp(13px,1vw,27px);font-weight:600}.context-bar>i{width:1px;height:56%;margin:0 clamp(22px,3vw,80px);background:linear-gradient(transparent,rgba(91,210,255,.5),transparent)}
|
||
.score-layout{display:grid;grid-template-rows:minmax(0,1fr) clamp(120px,19vh,320px);gap:clamp(12px,1.7vh,30px);min-height:0;flex:1}.hero-card{position:relative;min-height:0;overflow:hidden;border:1px solid rgba(86,197,255,.52);border-radius:clamp(17px,1.45vw,38px);background:radial-gradient(circle at 50% 45%,rgba(24,111,233,.62),transparent 48%),linear-gradient(135deg,rgba(14,77,182,.74),rgba(4,24,90,.82));box-shadow:inset 0 1px rgba(255,255,255,.08),inset 0 -70px 120px rgba(0,10,57,.22),0 24px 70px rgba(0,5,40,.28)}.panel-shine{position:absolute;inset:0;background:linear-gradient(115deg,rgba(255,255,255,.07),transparent 24% 76%,rgba(38,194,255,.05))}.entity-chip{position:absolute;left:50%;top:clamp(10px,1.5vh,28px);transform:translateX(-50%);min-width:clamp(150px,16vw,430px);padding:clamp(7px,.75vh,14px) clamp(24px,2vw,52px);border:1px solid rgba(91,221,255,.45);border-radius:999px;color:#b9f4ff;background:rgba(6,46,133,.78);font-size:clamp(14px,1.2vw,31px);font-weight:700;text-align:center;letter-spacing:.12em}.entity-chip span{margin-right:.8em;color:var(--cyan);font-size:.62em;letter-spacing:.22em}.entity-name{position:absolute;left:6%;right:6%;top:22%;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap;font-size:clamp(30px,3vw,78px);font-weight:800;letter-spacing:.08em;text-shadow:0 7px 24px rgba(0,4,45,.46)}.entity-affiliation{position:absolute;left:8%;right:8%;top:35%;color:#aad8f4;text-align:center;font-size:clamp(13px,1vw,26px);letter-spacing:.1em}.hero-score{position:absolute;left:0;right:0;top:39%;display:flex;align-items:flex-end;justify-content:center}.hero-score strong{font-size:clamp(104px,12.2vw,315px);font-weight:900;line-height:1;font-variant-numeric:tabular-nums;letter-spacing:-.055em;text-shadow:0 18px 42px rgba(0,5,46,.55),0 0 28px rgba(84,236,255,.16)}.hero-score small{margin:0 0 1.5em .7em;color:#b8dff5;font-size:clamp(14px,1vw,28px)}.score-beam{position:absolute;left:25%;right:25%;bottom:11%;height:2px;background:#d6fdff;box-shadow:0 0 9px 3px rgba(75,226,255,.9),0 0 42px 15px rgba(24,126,255,.72)}.score-beam i{position:absolute;left:50%;top:50%;width:18px;height:18px;transform:translate(-50%,-50%) rotate(45deg);border:2px solid #d8fdff;background:#35d9ff;box-shadow:0 0 18px #2bdfff}.dq-stamp{position:absolute;right:8%;top:28%;transform:rotate(-10deg);padding:.15em .35em;border:5px solid #ff7c8e;border-radius:12px;color:#ff9aa7;font-size:clamp(50px,6vw,150px);font-weight:900}
|
||
.score-metrics{display:grid;gap:clamp(8px,1.35vw,36px)}.metric-card{position:relative;display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto 1fr auto auto;align-items:center;column-gap:clamp(9px,1vw,26px);overflow:hidden;padding:clamp(11px,1.25vh,23px) clamp(12px,1.55vw,40px) clamp(9px,1vh,19px);border:1px solid rgba(255,255,255,.28);border-radius:clamp(13px,1.2vw,32px);background:linear-gradient(145deg,#36ac7a,#146e6b);box-shadow:inset 0 1px rgba(255,255,255,.18),0 14px 36px rgba(0,8,48,.24);animation:metric-in .55s both;animation-delay:var(--delay)}.metric-card::before{content:"";position:absolute;inset:0;background:radial-gradient(circle at 13% 0,rgba(255,255,255,.23),transparent 42%)}.metric-card.performance{background:linear-gradient(145deg,#1eaaa9,#116087)}.metric-card.required{background:linear-gradient(145deg,#e9a32b,#a9561d)}.metric-card.deduction{background:linear-gradient(145deg,#cc3e81,#592588)}.metric-head{position:relative;z-index:1;display:flex;align-items:center;gap:.6vw}.metric-icon{display:grid;place-items:center;width:clamp(38px,3.9vw,104px);height:clamp(38px,3.9vw,104px);border:3px solid rgba(255,255,255,.24);border-radius:50%;font-size:clamp(20px,1.7vw,44px);box-shadow:inset 0 0 0 1px rgba(255,255,255,.5),0 0 20px rgba(111,255,232,.24)}.metric-head small{display:none}.metric-card>strong{position:relative;z-index:1;font-size:clamp(35px,4.25vw,110px);font-variant-numeric:tabular-nums}.metric-line{position:relative;z-index:1;grid-column:1/-1;height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,.46),transparent)}.metric-card>b{position:relative;z-index:1;grid-column:1/-1;padding-top:.55vh;text-align:center;font-size:clamp(14px,1.4vw,36px);letter-spacing:.28em}
|
||
.ranking-layout{display:flex;flex-direction:column;min-height:0;flex:1;padding:clamp(18px,2.2vh,38px) clamp(18px,2vw,52px);border:1px solid rgba(85,193,255,.38);border-radius:clamp(17px,1.5vw,40px);background:linear-gradient(145deg,rgba(8,54,151,.72),rgba(3,22,82,.82));box-shadow:inset 0 1px rgba(255,255,255,.07),0 22px 65px rgba(0,4,36,.3)}.ranking-heading{display:flex;align-items:end;justify-content:space-between;flex:none;margin-bottom:clamp(12px,1.8vh,30px);padding:0 clamp(5px,.5vw,14px)}.ranking-heading span{color:var(--cyan);font-size:clamp(9px,.65vw,17px);font-weight:700;letter-spacing:.3em}.ranking-heading h2{margin:.2vh 0 0;font-size:clamp(23px,2vw,52px);letter-spacing:.08em}.ranking-heading>small{color:#8fbddb;font-size:clamp(11px,.8vw,20px)}.ranking-list{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:repeat(3,minmax(0,1fr));gap:clamp(8px,1.1vh,20px) clamp(14px,1.5vw,38px);min-height:0;flex:1}.rank-row{--rank-color:#28bdf3;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:clamp(10px,1vw,26px);min-height:0;padding:clamp(8px,.8vh,15px) clamp(11px,1.05vw,27px);border:1px solid rgba(75,164,235,.28);border-radius:clamp(12px,1vw,26px);background:linear-gradient(90deg,rgba(10,58,151,.72),rgba(5,31,101,.46));animation:rank-in .55s both;animation-delay:var(--delay)}.rank-row.podium{border-color:rgba(84,220,255,.5);box-shadow:inset 4px 0 var(--rank-color),0 8px 26px rgba(0,7,48,.2)}.rank-row:has(.rank-1){--rank-color:#ffd65c}.rank-row:has(.rank-2){--rank-color:#bde4ff}.rank-row:has(.rank-3){--rank-color:#f3a769}.rank-badge{display:grid;place-items:center;width:clamp(42px,3.5vw,90px);height:clamp(42px,3.5vw,90px);border:1px solid rgba(80,207,255,.62);border-radius:50%;color:#d5f7ff;background:rgba(5,39,119,.78);font-size:clamp(18px,1.5vw,38px);font-weight:800}.rank-badge.rank-1,.rank-badge.rank-2,.rank-badge.rank-3{color:#071743;border-color:rgba(255,255,255,.4);background:linear-gradient(145deg,var(--rank-color),#9d6b18);box-shadow:0 0 24px rgba(255,215,92,.25)}.rank-person{min-width:0}.rank-title{display:flex;align-items:center;gap:.8vw;margin-bottom:clamp(5px,.6vh,11px)}.rank-title strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:clamp(14px,1.1vw,28px)}.rank-title small{overflow:hidden;color:#82b6dc;font-size:clamp(9px,.7vw,17px);text-overflow:ellipsis;white-space:nowrap}.rank-track{height:clamp(7px,.75vh,14px);overflow:hidden;border-radius:999px;background:rgba(2,15,61,.72);box-shadow:inset 0 2px 6px rgba(0,0,0,.28)}.rank-track i{display:block;height:100%;border-radius:999px;background:linear-gradient(90deg,#0879ff,var(--rank-color));box-shadow:0 0 14px rgba(40,189,243,.4);transition:width .8s cubic-bezier(.2,.8,.2,1)}.rank-value{display:flex;align-items:baseline;justify-content:end;width:clamp(70px,5.4vw,145px)}.rank-value strong{font-size:clamp(25px,2.25vw,58px);font-variant-numeric:tabular-nums;letter-spacing:-.04em}.rank-value small{margin-left:.25em;color:#8ebbd8;font-size:clamp(9px,.65vw,17px)}.ranking-empty{display:grid;place-items:center;flex:1;color:#8ebbd8;font-size:clamp(17px,1.4vw,36px)}
|
||
.screen-footer{display:flex;align-items:center;justify-content:center;gap:clamp(10px,1.2vw,28px);height:clamp(20px,2.8vh,46px);flex:none;color:#609ac6;font-size:clamp(9px,.6vw,16px);letter-spacing:.16em}.screen-footer span{width:clamp(40px,5vw,130px);height:1px;background:linear-gradient(90deg,transparent,#277ebc)}.screen-footer span:last-child{transform:scaleX(-1)}
|
||
.waiting{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;text-align:center}.waiting-orbit{position:relative;display:grid;place-items:center;width:clamp(100px,9vw,220px);height:clamp(100px,9vw,220px);margin-bottom:clamp(26px,3vh,50px);border:1px solid rgba(86,222,255,.26);border-radius:50%;box-shadow:0 0 70px rgba(32,154,255,.2)}.waiting-orbit::before,.waiting-orbit::after{content:"";position:absolute;border:1px solid rgba(83,222,255,.18);border-radius:50%;animation:orbit 6s linear infinite}.waiting-orbit::before{inset:-18%}.waiting-orbit::after{inset:18%;animation-direction:reverse;animation-duration:4s}.waiting-orbit span{color:#d7fbff;font-size:clamp(28px,2.4vw,58px);font-weight:900;letter-spacing:.08em}.waiting-orbit i{position:absolute;width:9px;height:9px;border-radius:50%;background:var(--cyan);box-shadow:0 0 14px var(--cyan)}.waiting-orbit i:first-child{top:-5px}.waiting-orbit i:nth-child(2){right:2%;bottom:19%}.waiting-orbit i:nth-child(3){left:8%;bottom:8%}.waiting>small{color:var(--cyan);font-size:clamp(10px,.75vw,18px);font-weight:700;letter-spacing:.42em}.waiting h1{margin:clamp(11px,1.4vh,24px) 0 clamp(7px,.8vh,14px);font-size:clamp(34px,3.2vw,82px);letter-spacing:.1em}.waiting p{margin:0;color:#78aace;font-size:clamp(13px,1vw,25px)}
|
||
.cast-enter-active,.cast-leave-active{transition:opacity .34s ease,transform .42s cubic-bezier(.2,.8,.2,1);transform-origin:center}.cast-enter-from{opacity:0;transform:scale(.975) translateY(12px)}.cast-leave-to{opacity:0;transform:scale(1.015)}@keyframes metric-in{from{opacity:0;transform:translateY(18px) scale(.97)}to{opacity:1;transform:none}}@keyframes rank-in{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:none}}@keyframes orbit{to{transform:rotate(360deg)}}
|
||
@media(max-width:1100px){.context-bar{width:92%}.ranking-list{grid-template-columns:1fr}.rank-row:nth-child(n+4){display:none}.event-title h1{max-width:78vw}.title-wing{display:none}}@media(max-height:720px){.screen-content{padding-top:10px;padding-bottom:7px}.context-bar{margin-top:7px;margin-bottom:8px}.score-layout{grid-template-rows:minmax(0,1fr) 126px;gap:9px}.entity-chip{top:7px}.entity-name{top:20%}.entity-affiliation{top:33%}.hero-score{top:37%}.metric-card{padding-top:8px;padding-bottom:6px}.screen-footer{height:18px}.ranking-layout{padding-top:12px;padding-bottom:12px}.ranking-heading{margin-bottom:8px}}
|
||
|
||
/* Pixso 大屏画板:以 1920 × 1080 为唯一设计基准,外层只做等比例缩放。 */
|
||
.score-screen {
|
||
display: grid;
|
||
place-items: center;
|
||
background: #020829;
|
||
}
|
||
.design-stage {
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 50%;
|
||
width: 1920px;
|
||
height: 1080px;
|
||
overflow: hidden;
|
||
transform: translate(-50%, -50%) scale(var(--screen-scale));
|
||
transform-origin: center;
|
||
background:
|
||
radial-gradient(circle at 50% 36%, rgba(18, 94, 224, 0.7), transparent 44%),
|
||
linear-gradient(145deg, #0a47c8 0%, #082b89 42%, #061f70 72%, #04164f 100%);
|
||
}
|
||
.score-screen.view-ranking .design-stage {
|
||
background:
|
||
radial-gradient(circle at 50% 24%, rgba(20, 99, 226, 0.58), transparent 43%),
|
||
linear-gradient(145deg, #0a43bd, #072878 56%, #04164e);
|
||
}
|
||
.design-stage .ambient { filter: blur(110px); }
|
||
.design-stage .ambient-one { left: -180px; top: 120px; width: 720px; height: 720px; }
|
||
.design-stage .ambient-two { right: -180px; bottom: -250px; width: 760px; height: 760px; }
|
||
.design-stage .screen-grid { background-size: 96px 96px; }
|
||
.design-stage .horizon { left: 70px; right: 70px; bottom: -150px; height: 430px; }
|
||
.screen-content {
|
||
width: 1920px;
|
||
height: 1080px;
|
||
padding: 28px 50px 20px;
|
||
}
|
||
.screen-header { height: 74px; gap: 42px; }
|
||
.event-title span { margin-bottom: 2px; font-size: 11px; letter-spacing: 0.46em; }
|
||
.event-title h1 { max-width: 1260px; font-size: 42px; line-height: 1.2; }
|
||
.title-wing { display: flex; }
|
||
.title-wing i { width: 54px; height: 4px; }
|
||
.title-wing i:nth-child(2) { width: 30px; }
|
||
.title-wing i:nth-child(3) { width: 15px; }
|
||
.context-bar {
|
||
width: 100%;
|
||
height: 78px;
|
||
min-height: 78px;
|
||
margin: 10px 0 18px;
|
||
padding: 0 42px;
|
||
border-radius: 14px;
|
||
background: linear-gradient(90deg, rgba(2, 33, 112, 0.5), rgba(14, 83, 184, 0.62), rgba(2, 33, 112, 0.5));
|
||
}
|
||
.context-bar > div { column-gap: 13px; }
|
||
.context-icon { font-size: 24px; }
|
||
.context-bar small { font-size: 12px; }
|
||
.context-bar b { font-size: 19px; }
|
||
.context-bar > i { height: 46px; margin: 0 90px; }
|
||
.score-layout { grid-template-rows: minmax(0, 1fr) 218px; gap: 18px; }
|
||
.hero-card {
|
||
border-radius: 18px;
|
||
background:
|
||
radial-gradient(ellipse at 50% 49%, rgba(25, 123, 245, 0.68), transparent 46%),
|
||
linear-gradient(135deg, rgba(13, 74, 181, 0.78), rgba(3, 26, 99, 0.86));
|
||
box-shadow: inset 0 1px rgba(255, 255, 255, 0.1), inset 0 -80px 130px rgba(0, 11, 68, 0.25), 0 18px 52px rgba(0, 6, 43, 0.28);
|
||
}
|
||
.entity-chip {
|
||
top: 17px;
|
||
min-width: 310px;
|
||
padding: 10px 36px;
|
||
font-size: 20px;
|
||
}
|
||
.entity-name { top: 22%; font-size: 50px; }
|
||
.entity-affiliation { top: 35%; font-size: 18px; }
|
||
.hero-score { top: 39%; }
|
||
.hero-score strong { font-size: 168px; }
|
||
.hero-score small { margin: 0 0 25px 14px; font-size: 18px; }
|
||
.score-beam { left: 31%; right: 31%; bottom: 11%; }
|
||
.score-beam i { width: 16px; height: 16px; }
|
||
.dq-stamp { font-size: 94px; }
|
||
.score-metrics { gap: 18px; }
|
||
.metric-card {
|
||
grid-template-columns: auto 1fr;
|
||
grid-template-rows: 1fr auto auto;
|
||
column-gap: 16px;
|
||
padding: 22px 26px 16px;
|
||
border-radius: 17px;
|
||
}
|
||
.metric-icon { width: 66px; height: 66px; font-size: 30px; }
|
||
.metric-card > strong { font-size: 60px; }
|
||
.metric-line { margin-top: 8px; }
|
||
.metric-card > b { padding-top: 12px; font-size: 22px; letter-spacing: 0.25em; }
|
||
.ranking-layout {
|
||
padding: 20px 34px 22px;
|
||
border-radius: 18px;
|
||
background: linear-gradient(145deg, rgba(7, 50, 151, 0.76), rgba(3, 24, 91, 0.88));
|
||
}
|
||
.ranking-heading { margin-bottom: 15px; padding: 0 8px; }
|
||
.ranking-heading span { font-size: 11px; }
|
||
.ranking-heading h2 { margin-top: 4px; font-size: 32px; }
|
||
.ranking-heading > small { font-size: 14px; }
|
||
.ranking-list {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
grid-template-rows: repeat(6, minmax(0, 1fr));
|
||
gap: 10px;
|
||
}
|
||
.rank-row,
|
||
.rank-row:nth-child(n+4) {
|
||
display: grid;
|
||
grid-template-columns: 70px minmax(0, 1fr) 150px;
|
||
gap: 20px;
|
||
padding: 9px 24px 9px 13px;
|
||
border-radius: 11px;
|
||
background: linear-gradient(90deg, rgba(8, 77, 193, 0.78), rgba(4, 42, 129, 0.65));
|
||
}
|
||
.rank-row.podium { box-shadow: inset 4px 0 var(--rank-color), 0 6px 18px rgba(0, 7, 48, 0.18); }
|
||
.rank-badge { width: 54px; height: 54px; font-size: 23px; }
|
||
.rank-title { margin-bottom: 8px; gap: 18px; }
|
||
.rank-title strong { font-size: 22px; }
|
||
.rank-title small { font-size: 14px; }
|
||
.rank-track { height: 10px; }
|
||
.rank-value { width: 150px; }
|
||
.rank-value strong { font-size: 36px; }
|
||
.rank-value small { font-size: 13px; }
|
||
.screen-footer { height: 27px; font-size: 11px; }
|
||
.screen-footer span { width: 110px; }
|
||
.waiting { width: 1920px; height: 1080px; }
|
||
.waiting-orbit { width: 170px; height: 170px; margin-bottom: 38px; }
|
||
.waiting-orbit span { font-size: 44px; }
|
||
.waiting > small { font-size: 13px; }
|
||
.waiting h1 { margin: 20px 0 12px; font-size: 56px; }
|
||
.waiting p { font-size: 18px; }
|
||
|
||
/* 统一 SVG 图标语言与奖牌细节,避免依赖系统字体符号。 */
|
||
.title-wing { filter: drop-shadow(0 0 8px rgba(59, 225, 255, 0.55)); }
|
||
.title-wing i {
|
||
border-radius: 2px;
|
||
background: linear-gradient(90deg, transparent 2%, #1ac7ff 48%, #77f4ff 100%);
|
||
}
|
||
.context-icon {
|
||
display: grid;
|
||
grid-row: 1 / 3;
|
||
place-items: center;
|
||
width: 38px;
|
||
height: 38px;
|
||
border: 1px solid rgba(92, 225, 255, 0.45);
|
||
border-radius: 50%;
|
||
background: rgba(13, 111, 210, 0.25);
|
||
box-shadow: inset 0 0 12px rgba(79, 222, 255, 0.12), 0 0 15px rgba(40, 184, 255, 0.1);
|
||
}
|
||
.context-icon .el-icon { font-size: 21px; stroke-width: 1.4; }
|
||
.entity-chip {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 9px;
|
||
box-sizing: border-box;
|
||
box-shadow: inset 0 1px rgba(255, 255, 255, 0.08), 0 7px 22px rgba(0, 15, 70, 0.25);
|
||
}
|
||
.entity-chip .el-icon { color: #66eaff; font-size: 22px; }
|
||
.entity-chip span { margin-right: 4px; }
|
||
.metric-card {
|
||
border-color: rgba(255, 255, 255, 0.32);
|
||
box-shadow: inset 0 1px rgba(255, 255, 255, 0.2), inset 0 -45px 80px rgba(0, 16, 55, 0.12), 0 14px 32px rgba(0, 7, 45, 0.25);
|
||
}
|
||
.metric-card::after {
|
||
content: '';
|
||
position: absolute;
|
||
right: -28px;
|
||
top: -45px;
|
||
width: 145px;
|
||
height: 145px;
|
||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||
border-radius: 50%;
|
||
}
|
||
.metric-icon {
|
||
border-width: 2px;
|
||
background: rgba(255, 255, 255, 0.07);
|
||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4), 0 0 22px rgba(109, 245, 255, 0.2);
|
||
}
|
||
.metric-icon .el-icon { font-size: 34px; stroke-width: 1.25; }
|
||
.rank-badge { position: relative; overflow: visible; isolation: isolate; }
|
||
.rank-badge > b { position: relative; z-index: 3; line-height: 1; }
|
||
.rank-badge > .el-icon {
|
||
position: absolute;
|
||
z-index: 1;
|
||
font-size: 37px;
|
||
opacity: 0.2;
|
||
}
|
||
.rank-badge.rank-1,
|
||
.rank-badge.rank-2,
|
||
.rank-badge.rank-3 { color: #13254c; text-shadow: 0 1px rgba(255, 255, 255, 0.45); }
|
||
.rank-badge.rank-1 { background: linear-gradient(145deg, #fff2a3 0%, #ffc93f 48%, #d68a12 100%); }
|
||
.rank-badge.rank-2 { background: linear-gradient(145deg, #f7fbff 0%, #b9dcf2 48%, #6f9fbd 100%); }
|
||
.rank-badge.rank-3 { background: linear-gradient(145deg, #ffd0a1 0%, #e9954f 48%, #a45128 100%); }
|
||
.medal-ribbon {
|
||
position: absolute;
|
||
z-index: -1;
|
||
top: 39px;
|
||
width: 16px;
|
||
height: 22px;
|
||
clip-path: polygon(0 0, 100% 0, 82% 100%, 50% 73%, 18% 100%);
|
||
background: #2087e2;
|
||
}
|
||
.medal-ribbon.left { left: 12px; transform: rotate(8deg); }
|
||
.medal-ribbon.right { right: 12px; transform: rotate(-8deg); }
|
||
.rank-1 .medal-ribbon { background: #f0aa1f; }
|
||
.rank-2 .medal-ribbon { background: #7faecc; }
|
||
.rank-3 .medal-ribbon { background: #bb6d3d; }
|
||
.rank-row.podium { background: linear-gradient(90deg, rgba(12, 86, 206, 0.92), rgba(5, 42, 130, 0.67)); }
|
||
.rank-row:has(.rank-1) { border-color: rgba(255, 215, 91, 0.45); }
|
||
.rank-row:has(.rank-2) { border-color: rgba(189, 228, 255, 0.42); }
|
||
.rank-row:has(.rank-3) { border-color: rgba(243, 167, 105, 0.42); }
|
||
|
||
/* 更有层次的动态舞台;所有动效只改变合成层,确保大屏持续轮播时保持流畅。 */
|
||
.aurora-strip {
|
||
position: absolute;
|
||
left: 12%;
|
||
right: 12%;
|
||
top: -145px;
|
||
height: 300px;
|
||
border-radius: 50%;
|
||
background: conic-gradient(from 90deg at 50% 100%, transparent, rgba(78, 235, 255, 0.42), rgba(40, 110, 255, 0.18), transparent 72%);
|
||
filter: blur(48px);
|
||
opacity: 0.58;
|
||
animation: aurora-breathe 8s ease-in-out infinite alternate;
|
||
}
|
||
.frame-corners { position: absolute; z-index: 1; inset: 22px; pointer-events: none; }
|
||
.frame-corners i { position: absolute; width: 54px; height: 54px; opacity: 0.52; }
|
||
.frame-corners i::before,
|
||
.frame-corners i::after { content: ''; position: absolute; background: linear-gradient(90deg, #63ebff, rgba(99, 235, 255, 0.08)); box-shadow: 0 0 10px rgba(69, 219, 255, 0.35); }
|
||
.frame-corners i::before { width: 54px; height: 2px; }
|
||
.frame-corners i::after { width: 2px; height: 54px; }
|
||
.frame-corners i:nth-child(1) { left: 0; top: 0; }
|
||
.frame-corners i:nth-child(2) { right: 0; top: 0; transform: rotate(90deg); }
|
||
.frame-corners i:nth-child(3) { right: 0; bottom: 0; transform: rotate(180deg); }
|
||
.frame-corners i:nth-child(4) { left: 0; bottom: 0; transform: rotate(270deg); }
|
||
.design-stage .ambient-one { animation: ambient-float-one 12s ease-in-out infinite alternate; }
|
||
.design-stage .ambient-two { animation: ambient-float-two 14s ease-in-out infinite alternate; }
|
||
.design-stage .screen-grid { animation: grid-flow 18s linear infinite; }
|
||
.panel-shine::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: -35%;
|
||
bottom: -35%;
|
||
left: -24%;
|
||
width: 14%;
|
||
transform: rotate(15deg);
|
||
background: linear-gradient(90deg, transparent, rgba(132, 239, 255, 0.12), transparent);
|
||
animation: panel-sweep 7s ease-in-out infinite;
|
||
}
|
||
.hero-meta { position: absolute; z-index: 2; left: 28px; bottom: 20px; display: flex; gap: 10px; }
|
||
.hero-meta span { padding: 7px 12px; border: 1px solid rgba(100, 220, 255, 0.22); border-radius: 999px; color: #78b9e7; background: rgba(3, 28, 91, 0.5); font-size: 12px; backdrop-filter: blur(8px); }
|
||
.hero-meta b { margin-left: 5px; color: #d7f9ff; font-size: 13px; }
|
||
.score-ticker { display: inline-block; will-change: transform, contents; }
|
||
.hero-score strong { animation: score-arrive 0.72s cubic-bezier(0.18, 0.82, 0.3, 1) both; }
|
||
.metric-card .score-ticker { animation: number-pop 0.72s cubic-bezier(0.18, 0.9, 0.32, 1.18) both; animation-delay: calc(var(--delay) + 100ms); }
|
||
.rank-row .score-ticker { animation: number-pop 0.62s cubic-bezier(0.18, 0.9, 0.32, 1.18) both; animation-delay: var(--delay); }
|
||
.score-beam { animation: beam-breathe 2.8s ease-in-out infinite; }
|
||
.ranking-heading span { display: flex; align-items: center; gap: 9px; }
|
||
.ranking-heading span > i { width: 7px; height: 7px; border-radius: 50%; background: #49e6ff; box-shadow: 0 0 12px #49e6ff; animation: live-pulse 1.8s ease-in-out infinite; }
|
||
.ranking-status { display: flex; flex-direction: column; align-items: flex-end; gap: 9px; }
|
||
.ranking-status small { color: #8fbddb; font-size: 14px; }
|
||
.page-dots { display: flex; gap: 6px; }
|
||
.page-dots i { width: 18px; height: 3px; border-radius: 99px; background: rgba(111, 190, 238, 0.28); transition: width 0.35s ease, background 0.35s ease, box-shadow 0.35s ease; }
|
||
.page-dots i.active { width: 34px; background: #56e7ff; box-shadow: 0 0 10px rgba(86, 231, 255, 0.6); }
|
||
.rank-row { transition: border-color 0.3s ease, background 0.3s ease, transform 0.3s ease; }
|
||
|
||
@keyframes aurora-breathe { from { opacity: 0.36; transform: scaleX(0.9); } to { opacity: 0.68; transform: scaleX(1.08); } }
|
||
@keyframes ambient-float-one { from { transform: translate3d(0, 0, 0) scale(1); } to { transform: translate3d(90px, -35px, 0) scale(1.12); } }
|
||
@keyframes ambient-float-two { from { transform: translate3d(0, 0, 0) scale(1); } to { transform: translate3d(-75px, -25px, 0) scale(1.1); } }
|
||
@keyframes grid-flow { to { background-position: 96px 96px; } }
|
||
@keyframes panel-sweep { 0%, 18% { transform: translateX(0) rotate(15deg); opacity: 0; } 38% { opacity: 1; } 68%, 100% { transform: translateX(980%) rotate(15deg); opacity: 0; } }
|
||
@keyframes score-arrive { from { opacity: 0; transform: translateY(22px) scale(0.9); filter: blur(7px); } to { opacity: 1; transform: none; filter: blur(0); } }
|
||
@keyframes number-pop { 0% { opacity: 0; transform: translateY(15px) scale(0.86); } 68% { opacity: 1; transform: translateY(-4px) scale(1.045); } 100% { opacity: 1; transform: none; } }
|
||
@keyframes beam-breathe { 0%, 100% { opacity: 0.7; transform: scaleX(0.94); } 50% { opacity: 1; transform: scaleX(1.03); } }
|
||
@keyframes live-pulse { 0%, 100% { opacity: 0.58; transform: scale(0.78); } 50% { opacity: 1; transform: scale(1.18); } }
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.aurora-strip, .ambient, .screen-grid, .panel-shine::after, .score-ticker, .hero-score strong, .score-beam, .ranking-heading span > i, .metric-card, .rank-row, .waiting-orbit::before, .waiting-orbit::after { animation: none !important; }
|
||
.rank-track i, .page-dots i, .cast-enter-active, .cast-leave-active { transition: none !important; }
|
||
}
|
||
</style>
|