Files
91fans_landpage/src/components/landing-b/LandingBPc.vue
T
2026-09-15 18:00:56 +07:00

3053 lines
72 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import QrcodeVue from 'qrcode.vue'
import { useLandingB } from './useLandingB'
const {
FEATURED,
GENRES,
FAQS,
assetUrl,
currentView,
currentHeroIndex,
isHeroTransitioning,
heroProgKey,
bgFront,
bgAUrl,
bgBUrl,
topImgUrl,
currentHero,
setHero,
onHeroMouseEnter,
onHeroMouseLeave,
handleHeroTouchStart,
handleHeroTouchEnd,
wallDramas,
selectedKind,
selectedGenres,
showPcDownloadModal,
showInstallGuideModal,
installGuideTab,
// showAgeGate,
// confirmAge,
// leaveSite,
handleInstallGuideDownload,
targetDramaForDownload,
isScrolled,
showFloatingQr,
isFloatingQrDismissed,
activeAnchor,
toastMessage,
isToastVisible,
pageQrUrl,
isIos,
hasIosShopPackage,
handleFilterClick,
setKind,
toggleGenre,
filteredTop5,
filteredLatest6,
filteredAllWorks,
faqOpenIndex,
toggleFaq,
handleDownload,
handleCopyIosLiteLink,
handleIosStoreAction,
handlePcAndroidDownload,
handleOpenAppDeepLink,
switchView,
} = useLandingB('pc')
</script>
<template>
<div class="landing-b-root" :class="{ 'view-works-active': currentView === 'works' }">
<!-- SVG 图标系统 -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none">
<symbol id="i-download" viewBox="0 0 24 24">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<polyline points="7 10 12 15 17 10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<line x1="12" y1="15" x2="12" y2="3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-arrow-right" viewBox="0 0 24 24">
<line x1="5" y1="12" x2="19" y2="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<polyline points="12 5 19 12 12 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-chevron-right" viewBox="0 0 24 24">
<polyline points="9 18 15 12 9 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-chevron-down" viewBox="0 0 24 24">
<polyline points="6 9 12 15 18 9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-copy" viewBox="0 0 24 24">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-external-link" viewBox="0 0 24 24">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<polyline points="15 3 21 3 21 9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<line x1="10" y1="14" x2="21" y2="3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-x" viewBox="0 0 24 24">
<line x1="18" y1="6" x2="6" y2="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<line x1="6" y1="6" x2="18" y2="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-alert-circle" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<line x1="12" y1="8" x2="12" y2="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<line x1="12" y1="16" x2="12.01" y2="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-help-circle" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<line x1="12" y1="17" x2="12.01" y2="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="i-si-apple" viewBox="0 0 24 24">
<path fill="currentColor" d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701" />
</symbol>
<symbol id="i-si-android" viewBox="0 0 24 24">
<path fill="currentColor" d="M18.4395 5.5586c-.675 1.1664-1.352 2.3318-2.0274 3.498-.0366-.0155-.0742-.0286-.1113-.043-1.8249-.6957-3.484-.8-4.42-.787-1.8551.0185-3.3544.4643-4.2597.8203-.084-.1494-1.7526-3.021-2.0215-3.4864a1.1451 1.1451 0 0 0-.1406-.1914c-.3312-.364-.9054-.4859-1.379-.203-.475.282-.7136.9361-.3886 1.5019 1.9466 3.3696-.0966-.2158 1.9473 3.3593.0172.031-.4946.2642-1.3926 1.0177C2.8987 12.176.452 14.772 0 18.9902h24c-.119-1.1108-.3686-2.099-.7461-3.0683-.7438-1.9118-1.8435-3.2928-2.7402-4.1836a12.1048 12.1048 0 0 0-2.1309-1.6875c.6594-1.122 1.312-2.2559 1.9649-3.3848.2077-.3615.1886-.7956-.0079-1.1191a1.1001 1.1001 0 0 0-.8515-.5332c-.5225-.0536-.9392.3128-1.0488.5449zm-.0391 8.461c.3944.5926.324 1.3306-.1563 1.6503-.4799.3197-1.188.0985-1.582-.4941-.3944-.5927-.324-1.3307.1563-1.6504.4727-.315 1.1812-.1086 1.582.4941zM7.207 13.5273c.4803.3197.5506 1.0577.1563 1.6504-.394.5926-1.1038.8138-1.584.4941-.48-.3197-.5503-1.0577-.1563-1.6504.4008-.6021 1.1087-.8106 1.584-.4941z" />
</symbol>
</svg>
<!-- ============ NAV 导航栏 ============ -->
<header class="nav" :class="{ scrolled: isScrolled }">
<div class="wrap">
<a class="logo" href="#" @click.prevent="switchView('landing')">
<img class="ico" :src="assetUrl('logo-icon-activity.png')" alt="黄果短剧" />
<img class="wm" :src="assetUrl('wordmark-white-1line.png')" alt="黄果短剧" />
</a>
<nav class="links">
<a
href="#works"
:class="{ on: activeAnchor === '#works' && currentView === 'landing' }"
@click.prevent="switchView('landing', '#works')"
>
作品精选
</a>
<a
href="#about"
:class="{ on: activeAnchor === '#about' && currentView === 'landing' }"
@click.prevent="switchView('landing', '#about')"
>
关于黄果
</a>
<a
href="#faq"
:class="{ on: activeAnchor === '#faq' && currentView === 'landing' }"
@click.prevent="switchView('landing', '#faq')"
>
常见问题
</a>
</nav>
<div class="right">
<button class="btn glass sm" @click="handleDownload()">
<svg class="ic"><use href="#i-download" /></svg>
下载 APP
</button>
</div>
</div>
</header>
<!-- ============ LANDING 主视图 ============ -->
<main v-show="currentView === 'landing'" id="view-landing">
<!-- ① Hero 区域 (支持多图交叉淡入淡出、移动端触摸滑动、进度条与文字换台动效) -->
<section
class="hero"
@mouseenter="onHeroMouseEnter"
@mouseleave="onHeroMouseLeave"
@touchstart="handleHeroTouchStart"
@touchend="handleHeroTouchEnd"
>
<div class="bg">
<div
class="img"
:class="{ on: bgFront === 'a' }"
:style="{ backgroundImage: bgAUrl ? `url(${bgAUrl})` : undefined }"
/>
<div
class="img"
:class="{ on: bgFront === 'b' }"
:style="{ backgroundImage: bgBUrl ? `url(${bgBUrl})` : undefined }"
/>
<div
class="topimg on"
:style="{ backgroundImage: topImgUrl ? `url(${topImgUrl})` : undefined }"
/>
</div>
<div class="scrim l"></div>
<div class="scrim b"></div>
<div class="scrim t"></div>
<div class="wrap inner">
<div class="hero-main">
<div class="copy" :class="{ swap: isHeroTransitioning }">
<div class="kk">
<span class="kicker">本周主打&nbsp;&nbsp;独家首发</span>
<span class="pill glass">18+</span>
</div>
<h1 class="title" :class="{ long: (currentHero?.t?.length || 0) > 6 }">
{{ currentHero?.t }}
</h1>
<div class="credits">
{{ (currentHero?.tags || []).join(' ') }}&nbsp;&nbsp;{{ currentHero?.eps ? `全 ${currentHero.eps} 集 更新至第 ${currentHero.eps} 集` : '连载中' }}&nbsp;&nbsp;2026
</div>
<p class="syn">
{{ currentHero?.syn || '精彩短剧,黄果独家呈现。高清画质与震撼剧情,畅享视听盛宴。' }}
</p>
<div class="dlhero">
<div class="qrbox">
<span class="qr">
<QrcodeVue
v-if="pageQrUrl"
class="qrcode"
:value="pageQrUrl"
:size="116"
level="H"
foreground="#000"
/>
</span>
<span class="qr-lab">扫码下载 App</span>
</div>
<div class="dlbtns">
<button
class="btn primary lg dl-main"
type="button"
@click="handleDownload(undefined, currentHero)"
>
<svg class="ic"><use href="#i-download" /></svg>
下载 App
</button>
<div class="plats">
<button
v-if="hasIosShopPackage"
type="button"
@click="handleDownload('ios-store', currentHero)"
>
iOS 商店版
</button>
<button type="button" @click="handleDownload('ios-lite', currentHero)">
iOS 轻量版
</button>
<button type="button" @click="handleDownload('android', currentHero)">
Android 版
</button>
</div>
<p class="note">
免费下载&nbsp;&nbsp;{{
currentHero?.eps ? `全 ${currentHero.eps} 集 App 内观看` : 'App 内观看全集'
}}
</p>
</div>
</div>
</div>
<!-- 右侧横版主视觉卡片 (平滑交叉淡入淡出,点击可下载) -->
<div class="keyart" role="button" aria-label="下载 App 观看" @click="handleDownload(undefined, currentHero)">
<div
v-for="(f, i) in FEATURED"
:key="'art-' + f.slug"
class="keyart-slide"
:class="{ on: i === currentHeroIndex }"
>
<img :src="assetUrl(`hero/${f.slug}-land.jpg`)" :alt="f.t || ''" />
</div>
<span class="badge" :class="{ dark: currentHero?.kind === '影集' }">
{{ currentHero?.kind === '影集' ? '影集' : '原创' }}
</span>
</div>
</div>
<!-- Hero 底部轮播缩略图 -->
<div class="carousel">
<div class="thumbs">
<button
v-for="(item, k) in FEATURED"
:key="item.slug"
:class="{ on: k === currentHeroIndex }"
:aria-label="item.t"
@click="setHero(k)"
>
<img :src="assetUrl(item.cover)" :alt="item.t" />
</button>
</div>
<div class="counter">
<span class="lab">本周主打&nbsp;&nbsp;5 部</span>
<span class="prog" :class="{ paused: isHeroHovered }">
<i :key="heroProgKey" class="run"></i>
</span>
<span class="num">{{ String(currentHeroIndex + 1).padStart(2, '0') }} / {{ String(FEATURED.length).padStart(2, '0') }}</span>
</div>
</div>
</div>
</section>
<!-- ② 作品精选 -->
<section class="sec" id="works" style="padding-bottom: 0">
<div class="wrap">
<div class="secHead" data-reveal>
<div class="left">
<span class="kicker">作品精选</span>
<h2 class="h2">本周热播榜</h2>
</div>
<a class="link" href="#" @click.prevent="handleDownload()">
查看全部作品
<svg class="ic"><use href="#i-arrow-right" /></svg>
</a>
</div>
<!-- 题材筛选器:点击不切换筛选,统一触发下载 -->
<div class="filters" style="margin-top: 32px" data-reveal>
<div class="seg lg">
<button class="on" @click="handleFilterClick">全部</button>
<button @click="handleFilterClick">短剧</button>
<button @click="handleFilterClick">影集</button>
</div>
<span class="sep"></span>
<div class="gchips">
<button
v-for="g in GENRES"
:key="g"
class="chip"
@click="handleFilterClick"
>
{{ g }}
</button>
</div>
</div>
<!-- TOP5 排行榜 -->
<div class="top5">
<div
v-for="(d, i) in filteredTop5"
:key="d.t"
class="cell"
data-reveal
:style="{ '--i': i }"
>
<div class="rc">
<span class="rank">{{ i + 1 }}</span>
<div class="poster" @click="handleDownload(undefined, d)">
<img :src="assetUrl(d.cover)" :alt="d.t" loading="lazy" />
<span class="badge" :class="{ dark: d.kind === '影集' }">
{{ d.kind === '影集' ? '影集' : '原创' }}
</span>
<div class="hov">
<span class="circ"><svg class="ic"><use href="#i-download" /></svg></span>
<span>下载 App 观看</span>
</div>
</div>
</div>
<div class="card">
<div class="t">{{ d.t }}</div>
<div class="m">
{{ d.kind }}&nbsp;&nbsp;{{ d.eps ? `全 ${d.eps} 集` : '连载中' }}&nbsp;&nbsp;{{ (d.tags || []).join(' ') }}
</div>
</div>
</div>
</div>
<!-- 最新上架 -->
<div class="subhead" data-reveal>
<h3>最新上架</h3>
<a class="link" href="#" @click.prevent="handleDownload()">
查看更多
<svg class="ic"><use href="#i-chevron-right" /></svg>
</a>
</div>
<div class="grid6">
<div
v-for="(d, i) in filteredLatest6"
:key="d.t"
class="card"
data-reveal
:style="{ '--i': i % 6 }"
>
<div class="poster" @click="handleDownload(undefined, d)">
<img :src="assetUrl(d.cover)" :alt="d.t" loading="lazy" />
<span class="badge" :class="{ dark: d.kind === '影集' }">
{{ d.kind === '影集' ? '影集' : '原创' }}
</span>
<div class="hov">
<span class="circ"><svg class="ic"><use href="#i-download" /></svg></span>
<span>下载 App 观看</span>
</div>
</div>
<div class="t">{{ d.t }}</div>
<div class="m">
{{ d.kind }}&nbsp;&nbsp;{{ d.eps ? `全 ${d.eps} 集` : '连载中' }}&nbsp;&nbsp;{{ (d.tags || []).join(' ') }}
</div>
</div>
</div>
</div>
</section>
<!-- ③ 关于我们 -->
<section class="sec" id="about">
<div class="wrap about" data-reveal>
<div class="col">
<span class="kicker">关于我们</span>
<h2 class="h2">不是所有短剧,<br />都能被称作作品。</h2>
<p class="sub">黄果短剧,因为专业,所以领先。</p>
<p>
别人拼命追赶风口,我们定义创造标准。每一支作品都经过精心制作,分镜反复推敲,为一句台词的语气重新生成十次,字幕与剪辑的表情调整到满意为止。这就是我们的匠人精神,也是黄果品质唯一的定义。
</p>
<p>
我们用 AI 帮助提升作品的品质,把不可能的画面化为可能。题材多元,都会、悬疑、古装、奇幻同步推进;每日更新,精彩不断。短剧与影集双轨并行,仿真与动画齐发。我们只做一件事:把每一支作品,做到值得被记得。
</p>
<p class="slogan">黄果一开,全射出来,每一帧都能解你的色。</p>
</div>
<div>
<div class="vis">
<img :src="assetUrl('about-visual.png')" alt="黄果短剧 作品视觉" />
</div>
<div class="tags">
<span class="chip">短剧与影集双轨并行</span>
<span class="chip">仿真与动画齐发</span>
<span class="chip">AI 协力制作</span>
<span class="chip">每日更新</span>
</div>
</div>
</div>
</section>
<!-- ④ 黄果特色 -->
<section class="sec" style="padding-top: 0">
<div class="wrap">
<div class="secHead" data-reveal>
<div class="left">
<span class="kicker">黄果特色</span>
<h2 class="h2">把最好看的留给你</h2>
</div>
</div>
<div class="feat">
<div class="row" data-reveal style="--i: 0">
<div class="n">01</div>
<div class="t">多元齐全</div>
<div class="d">多元的题材、海量的短剧与影集,我们把最好看的留给你。</div>
</div>
<div class="row" data-reveal style="--i: 1">
<div class="n">02</div>
<div class="t">天天上新</div>
<div class="d">持续更新的内容节奏,每天打开都有新惊喜,追剧永不断档。</div>
</div>
<div class="row" data-reveal style="--i: 2">
<div class="n">03</div>
<div class="t">沉浸体验</div>
<div class="d">高清画质、震撼音效,每个动作、每个画面,全心投入剧情。</div>
</div>
</div>
</div>
</section>
<!-- ⑤ 下载横幅带 (海报墙 60s 线性无限平滑滚动) -->
<section class="band" id="download-band">
<div class="wall" aria-hidden="true">
<div v-for="(d, idx) in wallDramas" :key="'w-' + idx" class="wall-cell">
<img :src="assetUrl(d.cover)" :alt="d.t" loading="lazy" />
</div>
</div>
<div class="wscrim"></div>
<div class="wrap in">
<div data-reveal>
<h2>现在下载,海量短剧尽在黄果</h2>
<p class="sub">
支援 iOS / Android&nbsp;&nbsp;双版本 APP,即刻下载,追剧不断档
</p>
</div>
<div class="dlcard" data-reveal style="--i: 1">
<div class="qrbox">
<div class="qr">
<QrcodeVue
v-if="pageQrUrl"
class="qrcode"
:value="pageQrUrl"
:size="160"
level="H"
foreground="#000"
/>
</div>
<span class="qr-lab">扫码下载 App</span>
</div>
<div class="col">
<h4>扫码安装 黄果短剧 App</h4>
<div class="btns">
<template v-if="hasIosShopPackage">
<button
class="btn primary lg has-rec"
type="button"
@click="handleDownload('ios-store')"
>
<svg class="ic brandico"><use href="#i-si-apple" /></svg>
iOS 商店版
<span class="rec">推荐</span>
</button>
<button
class="btn outline lg"
type="button"
@click="handleDownload('ios-lite')"
>
<svg class="ic brandico"><use href="#i-si-apple" /></svg>
iOS 轻量版
</button>
</template>
<button
v-else
class="btn primary lg"
type="button"
@click="handleDownload('ios-lite')"
>
<svg class="ic brandico"><use href="#i-si-apple" /></svg>
iOS 轻量版
</button>
<button
class="btn outline lg"
type="button"
@click="handleDownload('android')"
>
<svg class="ic brandico"><use href="#i-si-android" /></svg>
Android 版
</button>
</div>
<p class="cap">
<template v-if="hasIosShopPackage">
手机打开本页会自动识别设备:iOS 推荐商店版(App Store),也可选轻量版(Safari 安装描述文件);Android 下载 APK 安装
</template>
<template v-else>
手机打开本页会自动识别设备:iOS 使用 Safari 安装轻量版描述文件;Android 下载 APK 安装
</template>
</p>
</div>
</div>
</div>
</section>
<!-- ⑥ FAQ 常见问题 -->
<section class="sec" id="faq">
<div class="wrap faq">
<div class="left" data-reveal>
<span class="kicker">常见问题</span>
<h2 class="h2">关于黄果,<br />你想知道的</h2>
</div>
<div class="acc" data-reveal>
<div
v-for="(item, idx) in FAQS"
:key="idx"
class="item"
:class="{ open: faqOpenIndex === idx }"
>
<button class="q" @click="toggleFaq(idx)">
{{ item.q }}
<svg class="ic"><use href="#i-chevron-down" /></svg>
</button>
<div class="a">
<div><p>{{ item.a }}</p></div>
</div>
</div>
</div>
</div>
</section>
</main>
<!-- ============ WORKS 独立作品页视图 ============ -->
<main v-show="currentView === 'works'" id="view-works">
<div class="wrap head">
<span class="kicker">原创作品</span>
<div class="row">
<h1>全部作品</h1>
<span class="credits">共 {{ filteredAllWorks.length }} 部&nbsp;&nbsp;每日更新</span>
</div>
<div class="fb">
<div class="filters">
<div class="seg lg">
<button :class="{ on: selectedKind === '全部' }" @click="setKind('全部')">全部</button>
<button :class="{ on: selectedKind === '短剧' }" @click="setKind('短剧')">短剧</button>
<button :class="{ on: selectedKind === '影集' }" @click="setKind('影集')">影集</button>
</div>
<span class="sep"></span>
<div class="gchips">
<button
v-for="g in GENRES"
:key="'w-' + g"
class="chip"
:class="{ on: selectedGenres.includes(g) }"
@click="toggleGenre(g)"
>
{{ g }}
</button>
</div>
</div>
<button class="chip" @click="showToast('已按最新上架排序')">
最新上架
<svg class="ic"><use href="#i-chevron-down" /></svg>
</button>
</div>
</div>
<div class="wrap list">
<div class="grid6">
<div
v-for="d in filteredAllWorks"
:key="'all-' + d.t"
class="card"
>
<div class="poster" @click="handleDownload(undefined, d)">
<img :src="assetUrl(d.cover)" :alt="d.t" loading="lazy" />
<span class="badge" :class="{ dark: d.kind === '影集' }">
{{ d.kind === '影集' ? '影集' : '原创' }}
</span>
<div class="hov">
<span class="circ"><svg class="ic"><use href="#i-download" /></svg></span>
<span>下载 App 观看</span>
</div>
</div>
<div class="t">{{ d.t }}</div>
<div class="m">
{{ d.kind }}&nbsp;&nbsp;{{ d.eps ? `全 ${d.eps} 集` : '连载中' }}&nbsp;&nbsp;{{ (d.tags || []).join(' ') }}
</div>
</div>
</div>
<div class="more">
<button class="btn outline" @click="switchView('landing')">
返回首页精选
</button>
<span>已显示全部 {{ filteredAllWorks.length }} 部作品</span>
</div>
</div>
</main>
<!-- ============ FOOTER 页脚 ============ -->
<footer>
<div class="wrap in">
<div class="lockup">
<img class="ico" :src="assetUrl('logo-icon-activity.png')" alt="黄果短剧" />
<img class="wm" :src="assetUrl('wordmark-white-2line.png')" alt="黄果短剧 huangguo.com" />
</div>
<div class="fl">
<a href="#works" @click.prevent="switchView('landing', '#works')">作品精选</a>
<a href="#about" @click.prevent="switchView('landing', '#about')">关于黄果</a>
<a href="#faq" @click.prevent="switchView('landing', '#faq')">常见问题</a>
<a href="#" @click.prevent="handleDownload()">下载 APP</a>
</div>
<div class="legal">
<b>18 U.S.C. 2257 记录保存要求合规声明</b>
<p>本网站所呈现之所有人员,于拍摄当时均已年满 18 岁,符合 18 U.S.C. 第 2257 章规定。</p>
</div>
<div class="bot">
<span>© 2026 黄果短剧 HUANGGUO&nbsp;&nbsp;All rights reserved.</span>
<span>仅限 18 岁以上成年人</span>
</div>
</div>
</footer>
<!-- ============ PC 悬浮二维码 (右下角) ============ -->
<div class="fqr" :class="{ show: showFloatingQr }">
<span class="qr">
<QrcodeVue
v-if="pageQrUrl"
class="qrcode"
:value="pageQrUrl"
:size="88"
level="H"
foreground="#000"
/>
</span>
<div class="c">
<b>扫码下载黄果短剧 App</b>
<span>支援 iOS / Android</span>
<button class="btn primary" @click="handleDownload()">
<svg class="ic"><use href="#i-download" /></svg>
下载 APP
</button>
</div>
<button class="x" aria-label="关闭" @click="isFloatingQrDismissed = true; showFloatingQr = false">
<svg class="ic"><use href="#i-x" /></svg>
</button>
</div>
<!-- ============ H5 底部常驻下载条 ============ -->
<!-- ============ 年龄确认(暂时关闭) ============ -->
<!--
<div class="modal agegate" :class="{ open: showAgeGate, in: showAgeGate }" role="dialog" aria-modal="true" aria-labelledby="agegate-title-pc">
<div class="bd"></div>
<div class="dlg">
<img class="age-ico" :src="assetUrl('logo-icon-activity.png')" alt="黄果短剧" width="72" height="72" />
<h3 id="agegate-title-pc">本站含成人内容</h3>
<p>
黄果短剧仅限 18 岁以上成年人访问。进入即表示您已年满 18 岁、所在地区法律允许浏览成人内容,并同意<a class="privacy" href="#" @click.prevent>《隐私政策》</a>。
</p>
<button class="btn primary lg block enter" type="button" @click="confirmAge">
我已年满 18 岁,进入
</button>
<button class="leave" type="button" @click="leaveSite">未满 18 岁,离开本站</button>
</div>
</div>
-->
<!-- ============ PC 下载弹窗 ============ -->
<div class="modal download" :class="{ open: showPcDownloadModal, in: showPcDownloadModal }">
<div class="bd" @click="showPcDownloadModal = false"></div>
<div class="dlg">
<button class="circ close" aria-label="关闭" @click="showPcDownloadModal = false">
<svg class="ic"><use href="#i-x" /></svg>
</button>
<div class="hd">
<h3>下载黄果短剧 App</h3>
<p>
<template v-if="targetDramaForDownload">
下载后即可观看<b>《{{ targetDramaForDownload.t }}》</b>全 {{ targetDramaForDownload.eps || '' }} 集及更多原创作品&nbsp;&nbsp;支援 iOS / Android
</template>
<template v-else>
{{ hasIosShopPackage ? '支援 iOS 轻量版 / 商店版 与 Android,安装后即可观看全集' : '支援 iOS 轻量版与 Android,安装后即可观看全集' }}
</template>
</p>
</div>
<div class="body">
<div class="scan">
<span class="qr">
<QrcodeVue
v-if="pageQrUrl"
class="qrcode"
:value="pageQrUrl"
:size="180"
level="H"
foreground="#000"
/>
</span>
<b>手机扫码下载</b>
<span>相机或浏览器扫码<br />自动识别 iOS / Android</span>
</div>
<div class="plats">
<div class="plat">
<span class="circ"><svg class="ic brandico"><use href="#i-si-apple" /></svg></span>
<div class="c">
<b>iOS 轻量版</b>
<span>用 Safari 打开本页,允许下载描述文件后依引导安装</span>
</div>
<button class="btn outline sm" @click="handleCopyIosLiteLink">
<svg class="ic"><use href="#i-copy" /></svg>
复制链接
</button>
</div>
<div v-if="hasIosShopPackage" class="plat">
<span class="circ"><svg class="ic brandico"><use href="#i-si-apple" /></svg></span>
<div class="c">
<b>iOS 商店版</b>
<span>前往 App Store 下载安装,适合无法安装描述文件的设备</span>
</div>
<button class="btn outline sm" @click="handleIosStoreAction">
<svg class="ic"><use href="#i-external-link" /></svg>
前往商店
</button>
</div>
<div class="plat">
<span class="circ"><svg class="ic brandico"><use href="#i-si-android" /></svg></span>
<div class="c">
<b>Android 版</b>
<span>下载 APK 安装包,允许安装未知来源应用后打开</span>
</div>
<button class="btn outline sm" @click="handlePcAndroidDownload">
<svg class="ic"><use href="#i-download" /></svg>
下载 APK
</button>
</div>
</div>
</div>
<div class="bot">
<span>
已安装?
<a class="link brand" href="#" @click.prevent="handleOpenAppDeepLink">打开黄果短剧 App</a>
</span>
<a
class="link guide"
href="#"
@click.prevent="showPcDownloadModal = false; showInstallGuideModal = true"
>
<svg class="ic"><use href="#i-help-circle" /></svg>
遇到问题?查看安装引导
</a>
</div>
</div>
</div>
<!-- ============ 移动端 / 通用 安装引导弹窗 ============ -->
<div class="modal install" :class="{ open: showInstallGuideModal, in: showInstallGuideModal }">
<div class="bd" @click="showInstallGuideModal = false"></div>
<div class="dlg">
<button class="circ close" aria-label="关闭" @click="showInstallGuideModal = false">
<svg class="ic"><use href="#i-x" /></svg>
</button>
<div class="hd">
<img :src="assetUrl('logo-icon-activity.png')" alt="黄果短剧" />
<h3>安装黄果短剧 App</h3>
<p>三步完成,约 1 分钟。安装后可在桌面直接打开。</p>
</div>
<div class="seg">
<button :class="{ on: installGuideTab === 'ios' }" @click="installGuideTab = 'ios'">iOS 版</button>
<button :class="{ on: installGuideTab === 'android' }" @click="installGuideTab = 'android'">Android 版</button>
</div>
<div class="steps" v-if="installGuideTab === 'ios'">
<div class="step">
<span class="n">STEP.1</span>
<div class="c">
<b>允许下载描述文件</b>
<span>用 Safari 打开本页,点击「下载 iOS 版」,弹窗选择「允许」,系统提示「已下载描述文件」即可进入下一步。</span>
</div>
</div>
<div class="step">
<span class="n">STEP.2</span>
<div class="c">
<b>安装描述文件</b>
<span>设置 › 已下载描述文件 › 安装 › 输入锁屏密码。安装包报毒提示为杀毒软件误报,可忽略继续。</span>
</div>
</div>
<div class="step">
<span class="n">STEP.3</span>
<div class="c">
<b>返回桌面打开</b>
<span>桌面出现「黄果短剧」图标,点击即可观看。建议同时保存账号凭证。</span>
</div>
</div>
</div>
<div class="steps" v-else>
<div class="step">
<span class="n">STEP.1</span>
<div class="c">
<b>下载 APK 安装包</b>
<span>点击「下载 Android 版」,浏览器开始下载 huangguo.apk,下载完成后在通知栏或下载列表点击打开。</span>
</div>
</div>
<div class="step">
<span class="n">STEP.2</span>
<div class="c">
<b>允许安装未知来源</b>
<span>系统提示「禁止安装来源不明的应用」时,点击「设置」开启允许,再返回继续安装。</span>
</div>
</div>
<div class="step">
<span class="n">STEP.3</span>
<div class="c">
<b>打开黄果短剧</b>
<span>安装完成后点击「打开」,或在桌面找到「黄果短剧」图标即可观看。</span>
</div>
</div>
</div>
<div class="tip">
<svg class="ic"><use href="#i-alert-circle" /></svg>
<span>{{ installGuideTab === 'ios' ? '仅支持 Safari 浏览器。若在微信 / Telegram 内打开,请先点右上角「在浏览器中打开」。' : '首次安装需允许「未知来源」;安装包报毒提示为误报,可忽略继续。' }}</span>
</div>
<div class="bar2">
<button
class="btn primary block"
@click="handleInstallGuideDownload"
>
<svg class="ic brandico"><use :href="installGuideTab === 'ios' ? '#i-si-apple' : '#i-si-android'" /></svg>
{{ installGuideTab === 'ios' ? '下载 iOS 版' : '下载 Android 版' }}
</button>
<a class="link brand open-app" href="#" @click.prevent="handleOpenAppDeepLink">
已安装?打开黄果短剧 App
<svg class="ic"><use href="#i-arrow-right" /></svg>
</a>
</div>
</div>
</div>
<!-- 全局 Toast 提示 -->
<div class="toast" :class="{ show: isToastVisible }">
{{ toastMessage }}
</div>
</div>
</template>
<style scoped>
/* ============ Design Tokens ============ */
.landing-b-root {
--bg: #0b0b0d;
--surface: #141417;
--card: #1b1b1f;
--elev: #232328;
--p900: #2a0d22;
--p950: #150a17;
--t1: #f2f2f4;
--t2: #a1a1aa;
--t3: #7c7c86;
--brand: #ec237f;
--brand4: #ff4a7b;
--gold: #d9a94a;
--gold4: #e9c977;
--b1: rgba(255, 255, 255, 0.07);
--b2: rgba(255, 255, 255, 0.12);
--b3: rgba(255, 255, 255, 0.24);
--ov: rgba(0, 0, 0, 0.6);
--glass: rgba(11, 11, 13, 0.72);
--grad-brand: linear-gradient(135deg, #ff4a7b 0%, #ec237f 52%, #93226f 100%);
--grad-gold: linear-gradient(135deg, #e9c977 0%, #d9a94a 100%);
--grad-plum: linear-gradient(180deg, #2a0d22 0%, #150a17 55%, #0b0b0d 100%);
--zh: "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", "Microsoft YaHei", system-ui, sans-serif;
--en: Inter, "SF Pro Display", -apple-system, system-ui, sans-serif;
--ease: cubic-bezier(0.2, 0.7, 0.2, 1);
font-family: var(--zh);
background: var(--bg);
color: var(--t1);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
position: relative;
min-height: 100vh;
box-sizing: border-box;
}
.landing-b-root *,
.landing-b-root *::before,
.landing-b-root *::after {
box-sizing: border-box;
}
/* ============ 通用排版与容器 ============ */
.wrap {
width: min(100% - 64px, 1200px);
margin-inline: auto;
}
a {
color: inherit;
text-decoration: none;
}
img {
display: block;
max-width: 100%;
}
.ic {
width: 20px;
height: 20px;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
flex: none;
}
.brandico {
fill: currentColor;
stroke: none;
}
.kicker {
display: inline-flex;
align-items: center;
gap: 10px;
font-size: 13px;
font-weight: 500;
letter-spacing: 0.12em;
color: var(--brand4);
}
.kicker::before {
content: "";
display: inline-block;
width: 18px;
height: 2px;
background: currentColor;
border-radius: 1px;
}
.h2 {
font-size: 40px;
line-height: 1.25;
font-weight: 600;
letter-spacing: -0.01em;
}
.credits {
font-size: 14px;
letter-spacing: 0.06em;
color: var(--t2);
min-height: 20px;
}
.link {
display: inline-flex;
align-items: center;
gap: 6px;
color: var(--t2);
font-size: 15px;
font-weight: 500;
transition: color 0.25s;
cursor: pointer;
}
.link:hover {
color: var(--t1);
}
.link.brand {
color: var(--brand4);
}
.link.brand:hover {
color: #ff6e95;
}
/* ============ 按钮与胶囊 ============ */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
font-family: inherit;
font-weight: 500;
border: 1px solid transparent;
border-radius: 999px;
cursor: pointer;
transition: all 0.25s var(--ease);
white-space: nowrap;
background: transparent;
color: var(--t1);
padding: 0 20px;
}
.btn.primary {
position: relative;
overflow: hidden;
background: var(--grad-brand);
color: #fff;
box-shadow: 0 8px 24px -6px rgba(236, 35, 127, 0.45);
}
.btn.primary:hover {
transform: translateY(-2px);
box-shadow: 0 12px 30px -10px rgba(236, 35, 127, 0.55);
}
.btn.primary::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
background: linear-gradient(120deg, transparent 30%, rgba(255, 255, 255, 0.28) 50%, transparent 70%);
opacity: 0;
transform: translateX(-100%);
transition: transform 0.6s ease, opacity 0.3s ease;
pointer-events: none;
}
.btn.primary:hover::after {
opacity: 1;
transform: translateX(100%);
}
/* ============ 滚动揭示动效 ============ */
[data-reveal] {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.7s ease, transform 0.7s var(--ease);
transition-delay: calc(var(--i, 0) * 80ms);
will-change: opacity, transform;
}
[data-reveal].rv {
opacity: 1;
transform: none;
}
.btn.glass {
background: rgba(255, 255, 255, 0.08);
border-color: var(--b2);
color: var(--t1);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.btn.glass:hover {
background: rgba(255, 255, 255, 0.14);
border-color: var(--b3);
}
.btn.outline {
border-color: var(--b2);
color: var(--t1);
}
.btn.outline:hover {
border-color: var(--b3);
background: var(--b1);
}
.btn.sm {
height: 40px;
padding: 0 18px;
font-size: 14px;
}
.btn.lg {
height: 56px;
padding: 0 26px;
font-size: 16px;
}
.btn.block {
width: 100%;
}
.circ {
width: 40px;
height: 40px;
border-radius: 999px;
display: inline-flex;
align-items: center;
justify-content: center;
background: var(--surface);
border: 1px solid var(--b1);
color: var(--t1);
transition: all 0.25s;
cursor: pointer;
}
.circ:hover {
border-color: var(--b3);
background: var(--elev);
}
.pill {
display: inline-flex;
align-items: center;
padding: 2px 10px;
border-radius: 999px;
font-size: 12px;
font-weight: 500;
font-family: var(--en);
line-height: 1.4;
}
.pill.glass {
background: rgba(255, 255, 255, 0.1);
border: 1px solid var(--b2);
color: var(--t1);
}
.badge {
position: absolute;
top: 9px;
right: 9px;
z-index: 2;
font-size: 11px;
font-weight: 500;
line-height: 14px;
padding: 4px 8px;
border-radius: 6px;
background: var(--brand);
color: #fff;
letter-spacing: 0.04em;
}
.badge.dark {
background: rgba(0, 0, 0, 0.6);
border: none;
}
.chip {
height: 36px;
padding: 0 16px;
border-radius: 999px;
background: var(--surface);
border: 1px solid var(--b1);
color: var(--t2);
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.25s;
cursor: pointer;
white-space: nowrap;
}
.chip:hover {
color: var(--t1);
border-color: var(--b2);
}
.chip.on {
background: rgba(236, 35, 127, 0.15);
border-color: var(--brand);
color: var(--brand4);
}
.seg {
display: inline-flex;
background: var(--surface);
padding: 4px;
border-radius: 999px;
border: 1px solid var(--b1);
}
.seg button {
background: none;
border: none;
padding: 0 16px;
height: 32px;
border-radius: 999px;
font-size: 14px;
font-weight: 500;
color: var(--t2);
cursor: pointer;
transition: all 0.25s;
font-family: inherit;
}
.seg button.on {
background: var(--elev);
color: var(--t1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}
.seg.lg button {
height: 36px;
padding: 0 20px;
font-size: 15px;
}
/* ============ NAV 导航条 ============ */
.nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 40;
height: 72px;
display: flex;
align-items: center;
transition: background 0.3s, backdrop-filter 0.3s, border-color 0.3s;
border-bottom: 1px solid transparent;
}
.nav.scrolled {
background: var(--glass);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-color: var(--b1);
}
.nav .wrap {
display: flex;
align-items: center;
justify-content: space-between;
}
.logo {
display: inline-flex;
align-items: center;
gap: 10px;
}
.logo img.ico {
width: 40px;
height: 40px;
border-radius: 10px;
}
.logo img.wm {
height: 22px;
width: auto;
}
.nav .links {
display: flex;
gap: 36px;
font-size: 15px;
font-weight: 500;
color: var(--t2);
}
.nav .links a {
position: relative;
padding: 4px 0;
transition: color 0.25s;
}
.nav .links a:hover,
.nav .links a.on {
color: var(--t1);
}
.nav .links a.on::after {
content: "";
position: absolute;
left: 50%;
bottom: -4px;
transform: translateX(-50%);
width: 16px;
height: 2px;
background: var(--brand);
border-radius: 1px;
}
/* ============ HERO 区域 ============ */
.hero {
position: relative;
min-height: 820px;
height: 92vh;
max-height: 960px;
display: flex;
align-items: center;
overflow: hidden;
}
.hero .bg {
position: absolute;
inset: 0;
z-index: 0;
}
.hero .bg .img {
position: absolute;
inset: 0;
background-size: cover;
background-position: center;
opacity: 0;
transition: opacity 1s ease;
pointer-events: none;
}
.hero .bg .img.on {
opacity: 0.85;
}
.hero .topimg {
display: none;
}
.hero .scrim {
position: absolute;
z-index: 1;
pointer-events: none;
}
.hero .scrim.l {
inset: 0 auto 0 0;
width: 65%;
background: linear-gradient(
90deg,
var(--bg) 0%,
rgba(11, 11, 13, 0.6) 30%,
rgba(11, 11, 13, 0) 62%
);
}
.hero .scrim.b {
inset: auto 0 0 0;
height: 100%;
background: linear-gradient(
180deg,
rgba(11, 11, 13, 0) 0%,
rgba(11, 11, 13, 0) 50%,
var(--bg) 100%
);
}
.hero .scrim.t {
inset: 0 0 auto 0;
height: 200px;
background: linear-gradient(
180deg,
var(--bg) 0%,
rgba(11, 11, 13, 0.6) 35%,
rgba(11, 11, 13, 0) 100%
);
}
.hero .inner {
position: relative;
z-index: 2;
width: min(100% - 64px, 1200px);
padding-top: 96px;
padding-bottom: 40px;
display: flex;
flex-direction: column;
justify-content: flex-end;
gap: 28px;
height: 100%;
}
.hero-main {
display: grid;
grid-template-columns: 560px 600px;
justify-content: space-between;
align-items: center;
gap: 40px;
width: 100%;
}
.copy {
display: flex;
flex-direction: column;
gap: 18px;
width: 560px;
max-width: 100%;
flex: none;
}
/* 首屏入场:仅首次;切换时用 .swap,且保持 .swap 避免 rise 重播导致跳动 */
.copy:not(.swap) > * {
animation: heroRise 0.8s var(--ease) both;
}
.copy:not(.swap) > *:nth-child(1) { animation-delay: 0.05s; }
.copy:not(.swap) > *:nth-child(2) { animation-delay: 0.13s; }
.copy:not(.swap) > *:nth-child(3) { animation-delay: 0.21s; }
.copy:not(.swap) > *:nth-child(4) { animation-delay: 0.29s; }
.copy:not(.swap) > *:nth-child(5) { animation-delay: 0.37s; }
.copy:not(.swap) > *:nth-child(6) { animation-delay: 0.45s; }
.copy.swap > * {
animation: heroSwap 0.5s var(--ease) both;
}
@keyframes heroRise {
from {
opacity: 0;
transform: translateY(24px);
}
to {
opacity: 1;
transform: none;
}
}
@keyframes heroSwap {
from {
opacity: 0;
transform: translateY(12px);
}
to {
opacity: 1;
transform: none;
}
}
@keyframes heroPop {
from {
opacity: 0;
transform: scale(0.92);
}
to {
opacity: 1;
transform: none;
}
}
.copy .kk {
display: flex;
align-items: center;
gap: 12px;
}
.copy .title {
font-size: 72px;
line-height: 84px;
font-weight: 600;
letter-spacing: -0.02em;
min-height: 84px;
}
.copy .title.long {
font-size: 56px;
line-height: 1.15;
min-height: 84px;
}
.copy .syn {
font-size: 16px;
line-height: 26px;
color: var(--t2);
max-width: 520px;
min-height: 78px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.dlhero {
display: flex;
align-items: center;
gap: 20px;
padding: 16px 20px 16px 16px;
border-radius: 20px;
background: var(--glass);
border: 1px solid var(--b1);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
width: fit-content;
}
.qrbox {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
flex: none;
}
.qrbox .qr {
background: #fff;
padding: 6px;
border-radius: 12px;
line-height: 0;
}
.qrbox .qr :deep(canvas) {
display: block;
width: 116px;
height: 116px;
}
.qrbox .qr-lab {
font-size: 12px;
font-weight: 500;
line-height: 16px;
color: var(--t2);
white-space: nowrap;
}
.dlbtns {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 8px;
width: 244px;
flex: none;
}
.dlbtns .dl-main {
width: 100%;
height: 56px;
padding: 0 28px;
font-size: 16px;
font-weight: 500;
gap: 8px;
}
.dlbtns .dl-main .ic {
width: 22px;
height: 22px;
}
.dlbtns .plats {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 0 12px;
width: 100%;
}
.dlbtns .plats button {
appearance: none;
border: 0;
background: none;
padding: 0;
font-family: inherit;
font-size: 12px;
font-weight: 500;
line-height: 16px;
color: var(--t1);
cursor: pointer;
white-space: nowrap;
}
.dlbtns .plats button:hover {
color: var(--brand4);
}
.dlbtns .note {
margin: 0;
width: 100%;
font-size: 13px;
line-height: 20px;
color: var(--t2);
text-align: center;
}
.keyart {
position: relative;
width: 600px;
height: 338px;
flex: none;
border-radius: 16px;
overflow: hidden;
border: 1px solid var(--b2);
background: var(--card);
box-shadow: 0 24px 60px -12px rgba(0, 0, 0, 0.8);
cursor: pointer;
animation: heroPop 0.9s var(--ease) both 0.4s;
transition: border-color 0.35s var(--ease), box-shadow 0.35s var(--ease), transform 0.35s var(--ease);
will-change: auto;
transform: translateZ(0);
}
.keyart:hover {
transform: translateY(-4px);
border-color: var(--b3);
box-shadow: 0 32px 70px -10px rgba(236, 35, 127, 0.25), 0 0 0 1px var(--b3);
}
.keyart-slide {
position: absolute;
inset: 0;
opacity: 0;
transition: opacity 1s ease;
transform: none;
}
.keyart-slide.on {
opacity: 1;
}
.keyart-slide img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* 轮播缩略图 */
.carousel {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding-top: 20px;
border-top: 1px solid var(--b1);
animation: heroRise 0.8s var(--ease) both 0.6s;
}
.thumbs {
display: flex;
gap: 10px;
}
.thumbs button {
width: 52px;
height: 70px;
border-radius: 6px;
overflow: hidden;
border: 1px solid var(--b1);
padding: 0;
cursor: pointer;
background: var(--surface);
opacity: 0.55;
transition: all 0.3s;
}
.thumbs button:hover {
opacity: 0.85;
}
.thumbs button.on {
opacity: 1;
border: 2px solid var(--brand);
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(236, 35, 127, 0.35);
}
.thumbs button img {
width: 100%;
height: 100%;
object-fit: cover;
}
.counter {
display: flex;
align-items: center;
gap: 14px;
font-size: 12px;
color: var(--t3);
}
.counter .lab {
font-weight: 500;
white-space: pre;
}
.counter .prog {
width: 120px;
height: 3px;
background: var(--b2);
border-radius: 999px;
position: relative;
overflow: hidden;
}
.counter .prog i {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 0;
background: var(--grad-brand);
}
.counter .prog i.run {
animation: heroProg 6s linear forwards;
}
.counter .prog.paused i.run {
animation-play-state: paused;
}
@keyframes heroProg {
from {
width: 0%;
}
to {
width: 100%;
}
}
.counter .num {
font-family: var(--en);
font-size: 14px;
font-weight: 500;
letter-spacing: 0.04em;
color: var(--t2);
}
/* ============ SECTION 通用 ============ */
section.sec {
padding: 96px 0;
}
.secHead {
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.secHead .left {
display: flex;
flex-direction: column;
gap: 12px;
}
.filters {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.filters .sep {
width: 1px;
height: 20px;
background: var(--b2);
margin: 0 4px;
}
.gchips {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
/* ============ 作品卡片与网格 ============ */
.top5 {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 20px;
margin-top: 32px;
overflow: visible;
}
.top5 .cell {
display: flex;
flex-direction: column;
gap: 10px;
min-width: 0;
overflow: visible;
}
.top5 .rc {
display: flex;
align-items: flex-end;
overflow: visible;
}
.top5 .rank {
font-family: var(--en);
font-weight: 700;
font-size: 96px;
line-height: 1;
letter-spacing: -0.04em;
color: var(--t3);
margin-right: -6px;
flex: none;
position: relative;
z-index: 0;
transition: color 0.3s;
user-select: none;
pointer-events: none;
}
.top5 .cell:hover .rank {
color: var(--brand4);
}
.top5 .poster {
width: 158px;
height: 211px;
aspect-ratio: auto;
flex: none;
position: relative;
z-index: 1;
}
.poster {
position: relative;
width: 100%;
aspect-ratio: 3 / 4;
border-radius: 12px;
overflow: hidden;
background: var(--card);
cursor: pointer;
border: 1px solid var(--b1);
transition: transform 0.35s var(--ease), border-color 0.35s, box-shadow 0.35s var(--ease);
}
.poster img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s var(--ease);
}
.poster .hov {
position: absolute;
inset: 0;
background: rgba(11, 11, 13, 0.6);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
opacity: 0;
transition: opacity 0.3s ease;
color: #fff;
font-size: 13px;
font-weight: 500;
}
.poster .hov .circ {
width: 44px;
height: 44px;
background: var(--brand);
border-color: transparent;
transition: transform 0.25s var(--ease);
}
.poster:hover {
transform: translateY(-4px);
border-color: rgba(236, 35, 127, 0.45);
box-shadow: 0 16px 36px -8px rgba(0, 0, 0, 0.7);
}
.poster:hover img {
transform: scale(1.05);
}
.poster:hover .hov {
opacity: 1;
}
.poster:hover .hov .circ {
transform: scale(1.08);
}
.card {
display: flex;
flex-direction: column;
gap: 6px;
}
.card .t {
font-size: 16px;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.card .m {
font-size: 13px;
color: var(--t3);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.subhead {
display: flex;
justify-content: space-between;
align-items: center;
margin: 56px 0 20px;
}
.subhead h3 {
font-size: 22px;
font-weight: 600;
}
.grid6 {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 24px;
row-gap: 36px;
}
/* ============ 关于我们 ============ */
.about {
display: grid;
grid-template-columns: 560px 1fr;
gap: 80px;
align-items: center;
}
.about .col {
display: flex;
flex-direction: column;
gap: 24px;
}
.about .col p {
font-size: 16px;
line-height: 1.7;
color: var(--t2);
}
.about .sub {
font-size: 20px;
color: var(--t2);
font-weight: 600;
}
.about .slogan {
font-size: 18px;
font-weight: 600;
color: var(--brand4);
margin-top: 8px;
}
.about .vis {
border-radius: 20px;
overflow: hidden;
box-shadow: 0 24px 60px -12px rgba(0, 0, 0, 0.8), 0 0 0 1px var(--b2);
}
.about .tags {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 20px;
}
/* ============ 黄果特色 ============ */
.feat {
margin-top: 40px;
display: flex;
flex-direction: column;
}
.feat .row {
display: grid;
grid-template-columns: 96px 360px 1fr;
align-items: baseline;
gap: 40px;
padding: 32px 0;
border-bottom: 1px solid var(--b1);
transition: padding-left 0.4s var(--ease);
}
.feat .row:hover {
padding-left: 12px;
}
.feat .row:first-child {
border-top: 1px solid var(--b1);
}
.feat .n {
font-family: var(--en);
font-size: 28px;
font-weight: 700;
color: var(--brand4);
}
.feat .t {
font-size: 28px;
font-weight: 600;
}
.feat .d {
font-size: 18px;
color: var(--t2);
line-height: 1.6;
}
/* ============ 下载带 ============ */
.band {
position: relative;
padding: 112px 0;
overflow: hidden;
background: var(--grad-plum);
text-align: center;
}
.band .wall {
position: absolute;
left: 0;
top: -70px;
display: flex;
gap: 14px;
opacity: 0.2;
width: max-content;
animation: wallMarquee 60s linear infinite;
pointer-events: none;
}
.band .wall .wall-cell {
width: 164px;
height: 219px;
border-radius: 8px;
overflow: hidden;
flex: none;
background: var(--card);
}
.band .wall .wall-cell:nth-child(odd) {
transform: translateY(44px);
}
.band .wall .wall-cell img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
@keyframes wallMarquee {
from {
transform: translateX(0);
}
to {
transform: translateX(-50%);
}
}
.band .wscrim {
position: absolute;
inset: 0;
background: linear-gradient(
180deg,
rgba(21, 10, 23, 0) 0%,
rgba(21, 10, 23, 0.8) 50%,
#0b0b0d 100%
);
pointer-events: none;
}
.band .in {
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 36px;
}
.band h2 {
font-size: 56px;
line-height: 1.18;
font-weight: 600;
letter-spacing: -0.02em;
}
.band .sub {
margin-top: 16px;
font-size: 18px;
line-height: 1.5;
color: var(--t2);
}
.dlcard {
display: flex;
align-items: center;
gap: 28px;
padding: 20px 28px 20px 20px;
border-radius: 20px;
background: var(--glass);
border: 1px solid var(--b1);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
text-align: left;
}
.dlcard .qrbox {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
flex: none;
}
.dlcard .qr {
background: #fff;
padding: 8px;
border-radius: 16px;
line-height: 0;
}
.dlcard .qr :deep(canvas) {
display: block;
width: 160px;
height: 160px;
}
.dlcard .qr-lab {
font-size: 12px;
font-weight: 500;
line-height: 16px;
color: var(--t2);
}
.dlcard .col {
display: flex;
flex-direction: column;
gap: 14px;
min-width: 0;
}
.dlcard .col h4 {
font-size: 20px;
font-weight: 600;
line-height: 1.4;
}
.dlcard .btns {
display: flex;
gap: 12px;
flex-wrap: wrap;
align-items: flex-start;
}
.dlcard .btns .btn {
position: relative;
height: 56px;
padding: 0 28px;
font-size: 16px;
font-weight: 500;
gap: 8px;
overflow: visible;
}
.dlcard .btns .btn .ic {
width: 22px;
height: 22px;
}
.dlcard .btns .btn.has-rec {
overflow: visible;
}
.dlcard .btns .btn .rec {
position: absolute;
top: -8px;
right: -6px;
z-index: 1;
height: 20px;
padding: 0 7px;
border-radius: 999px;
background: #fff;
color: var(--brand4);
font-size: 11px;
font-weight: 500;
line-height: 14px;
display: inline-flex;
align-items: center;
white-space: nowrap;
}
.dlcard .cap {
margin: 0;
font-size: 12px;
line-height: 18px;
color: var(--t3);
max-width: 560px;
}
/* ============ FAQ 常见问题 ============ */
.faq {
display: grid;
grid-template-columns: 360px 1fr;
gap: 80px;
align-items: flex-start;
}
.faq .left {
display: flex;
flex-direction: column;
gap: 16px;
}
.faq .left p {
color: var(--t2);
font-size: 15px;
}
.acc {
display: flex;
flex-direction: column;
border-top: 1px solid var(--b1);
}
.acc .item {
border-bottom: 1px solid var(--b1);
}
.acc .q {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 24px 0;
font-size: 18px;
font-weight: 600;
color: var(--t1);
background: none;
border: none;
cursor: pointer;
text-align: left;
font-family: inherit;
transition: color 0.25s;
}
.acc .q:hover {
color: var(--brand4);
}
.acc .q .ic {
width: 20px;
height: 20px;
color: var(--t3);
transition: transform 0.35s var(--ease), color 0.25s;
}
.acc .item.open .q .ic {
transform: rotate(180deg);
color: var(--brand4);
}
.acc .a {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.4s var(--ease);
}
.acc .a > div {
overflow: hidden;
}
.acc .a p {
padding-bottom: 24px;
color: var(--t2);
font-size: 15px;
line-height: 1.7;
}
.acc .item.open .a {
grid-template-rows: 1fr;
}
/* ============ 作品全部列表视图 ============ */
#view-works {
padding-top: 72px;
}
#view-works .head {
padding: 56px 0 28px;
display: flex;
flex-direction: column;
gap: 16px;
}
#view-works .head .row {
display: flex;
justify-content: space-between;
align-items: flex-end;
}
#view-works .head h1 {
font-size: 56px;
line-height: 1.15;
font-weight: 600;
letter-spacing: -0.02em;
}
#view-works .fb {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 8px;
gap: 16px;
flex-wrap: wrap;
}
#view-works .list {
padding: 24px 0 72px;
display: flex;
flex-direction: column;
align-items: center;
gap: 40px;
}
#view-works .grid6 {
width: 100%;
row-gap: 36px;
}
#view-works .more {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
font-size: 12px;
color: var(--t3);
}
/* ============ FOOTER 页脚 ============ */
footer {
border-top: 1px solid var(--b1);
padding: 64px 0 32px;
background: #08080a;
}
footer .in {
display: flex;
flex-direction: column;
align-items: center;
gap: 36px;
}
footer .lockup {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
footer .lockup img.ico {
width: 56px;
height: 56px;
border-radius: 14px;
}
footer .lockup img.wm {
height: 44px;
width: auto;
}
footer .fl {
display: flex;
gap: 32px;
font-size: 15px;
font-weight: 500;
color: var(--t2);
}
footer .fl a:hover {
color: var(--t1);
}
footer .legal {
text-align: center;
display: flex;
flex-direction: column;
gap: 8px;
}
footer .legal b {
font-size: 15px;
font-weight: 600;
color: var(--t2);
}
footer .legal p {
font-size: 12px;
color: var(--t3);
max-width: 720px;
}
footer .bot {
width: 100%;
display: flex;
justify-content: space-between;
padding-top: 24px;
border-top: 1px solid var(--b1);
font-size: 12px;
color: var(--t3);
}
/* ============ 浮动元素 ============ */
.fqr {
position: fixed;
right: 24px;
bottom: 24px;
z-index: 35;
display: flex;
align-items: center;
gap: 12px;
padding: 12px 40px 12px 12px;
border-radius: 16px;
background: var(--card);
border: 1px solid var(--b2);
box-shadow: 0 24px 48px -24px rgba(0, 0, 0, 0.9);
opacity: 0;
transform: translateY(24px);
pointer-events: none;
transition: opacity 0.4s, transform 0.4s var(--ease);
}
.fqr.show {
opacity: 1;
transform: none;
pointer-events: auto;
}
.fqr .qr {
background: #fff;
padding: 6px;
border-radius: 10px;
line-height: 0;
}
.fqr .qr :deep(canvas) {
display: block;
width: 88px;
height: 88px;
}
.fqr .c {
display: flex;
flex-direction: column;
gap: 4px;
}
.fqr .c b {
font-size: 14px;
font-weight: 600;
}
.fqr .c span {
font-size: 12px;
color: var(--t3);
}
.fqr .c .btn {
margin-top: 6px;
height: 34px;
padding: 0 12px;
font-size: 13px;
}
.fqr .x {
position: absolute;
top: 8px;
right: 8px;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: var(--t3);
border-radius: 999px;
border: none;
background: transparent;
cursor: pointer;
}
.fqr .x:hover {
color: var(--t1);
background: var(--b1);
}
.fqr .x .ic {
width: 14px;
height: 14px;
}
/* 移动端常驻底部下载条 */
.mdl {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 35;
display: none;
gap: 12px;
align-items: center;
padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
background: var(--glass);
border-top: 1px solid var(--b1);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
transform: translateY(100%);
transition: transform 0.4s var(--ease);
}
.mdl.show {
transform: none;
}
.mdl img {
width: 40px;
height: 40px;
border-radius: 9px;
}
.mdl .c {
flex: 1;
display: flex;
flex-direction: column;
line-height: 1.3;
}
.mdl .c b {
font-size: 14px;
font-weight: 600;
}
.mdl .c span {
font-size: 11px;
color: var(--t3);
}
.mdl .btn {
height: 40px;
padding: 0 16px;
font-size: 14px;
}
/* ============ 模态弹窗 ============ */
.modal {
position: fixed;
inset: 0;
z-index: 50;
display: none;
align-items: center;
justify-content: center;
padding: 24px;
}
.modal.open {
display: flex;
}
.modal .bd {
position: absolute;
inset: 0;
background: var(--ov);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
opacity: 0;
transition: opacity 0.35s;
}
.modal.in .bd {
opacity: 1;
}
.modal .dlg {
position: relative;
background: var(--card);
border: 1px solid var(--b1);
border-radius: 20px;
overflow: hidden;
opacity: 0;
transform: translateY(16px) scale(0.97);
transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
}
.modal.in .dlg {
opacity: 1;
transform: none;
}
.modal .close {
position: absolute;
top: 24px;
right: 24px;
width: 36px;
height: 36px;
z-index: 3;
}
.modal .close .ic {
width: 18px;
height: 18px;
}
/* PC 下载弹窗 */
.download .dlg {
width: 760px;
padding: 32px 36px 28px;
display: flex;
flex-direction: column;
gap: 24px;
}
.download .hd h3 {
font-size: 28px;
font-weight: 600;
line-height: 1.35;
}
.download .hd p {
font-size: 14px;
color: var(--t2);
margin-top: 8px;
line-height: 1.55;
max-width: 560px;
}
.download .hd p b {
color: var(--brand4);
font-weight: 500;
}
.download .body {
display: grid;
grid-template-columns: auto 1fr;
gap: 28px;
align-items: stretch;
}
.download .scan {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
padding: 20px;
border-radius: 16px;
background: var(--surface);
border: 1px solid var(--b1);
text-align: center;
}
.download .scan .qr {
background: #fff;
padding: 10px;
border-radius: 16px;
line-height: 0;
}
.download .scan .qr :deep(canvas) {
width: 180px;
height: 180px;
display: block;
}
.download .scan b {
font-size: 15px;
font-weight: 600;
}
.download .scan span {
font-size: 12px;
color: var(--t3);
line-height: 1.5;
}
.download .plats {
display: flex;
flex-direction: column;
gap: 12px;
}
.plat {
display: flex;
align-items: center;
gap: 14px;
padding: 16px;
border-radius: 16px;
background: var(--surface);
border: 1px solid var(--b1);
transition: border-color 0.25s;
}
.plat:hover {
border-color: var(--b3);
}
.plat .circ {
width: 44px;
height: 44px;
background: var(--elev);
border-color: var(--b1);
}
.plat .circ .ic {
width: 20px;
height: 20px;
}
.plat .c {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
min-width: 0;
}
.plat .c b {
font-size: 16px;
font-weight: 600;
}
.plat .c span {
font-size: 12px;
color: var(--t3);
line-height: 1.5;
}
.plat .btn.sm {
flex: none;
height: 40px;
padding: 0 14px;
font-size: 13px;
}
.download .bot {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
padding-top: 24px;
border-top: 1px solid var(--b1);
font-size: 12px;
color: var(--t3);
}
.download .bot .link.brand {
font-size: 14px;
}
.download .bot .link.guide {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--t2);
}
.download .bot .link.guide:hover {
color: var(--t1);
}
.download .bot .link.guide .ic {
width: 14px;
height: 14px;
}
/* 安装引导弹窗 */
.install .dlg {
width: 520px;
max-height: 92vh;
overflow: auto;
display: flex;
flex-direction: column;
}
.install .hd {
padding: 24px 24px 8px;
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
text-align: center;
}
.install .hd img {
width: 72px;
height: 72px;
border-radius: 16px;
}
.install .hd h3 {
font-size: 28px;
font-weight: 600;
}
.install .hd p {
font-size: 14px;
color: var(--t2);
}
.install .seg {
margin: 12px 24px 4px;
display: flex;
}
.install .seg button {
flex: 1;
height: 34px;
}
.install .steps {
padding: 12px 24px 20px;
display: flex;
flex-direction: column;
gap: 12px;
}
.step {
display: flex;
gap: 14px;
padding: 16px;
border-radius: 12px;
background: var(--surface);
border: 1px solid var(--b1);
}
.step .n {
font-family: var(--en);
font-weight: 500;
font-size: 12px;
letter-spacing: 0.06em;
color: var(--brand4);
padding-top: 3px;
flex: none;
}
.step .c {
display: flex;
flex-direction: column;
gap: 6px;
}
.step .c b {
font-size: 16px;
font-weight: 600;
}
.step .c span {
font-size: 13px;
color: var(--t2);
line-height: 1.55;
}
.install .tip {
display: flex;
gap: 8px;
padding: 12px 24px;
font-size: 12px;
color: var(--t3);
}
.install .tip .ic {
width: 16px;
height: 16px;
flex: none;
}
.install .bar2 {
padding: 12px 24px 24px;
background: var(--surface);
border-top: 1px solid var(--b1);
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.install .bar2 .open-app {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 13px;
margin-top: 4px;
}
.install .bar2 .open-app .ic {
width: 14px;
height: 14px;
}
/* 年龄确认(PC 居中) */
.agegate {
z-index: 60;
}
.agegate .bd {
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.agegate .dlg {
width: 480px;
padding: 40px 40px 32px;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
text-align: center;
border-radius: 20px;
border: 1px solid var(--b1);
background: var(--card);
overflow: visible;
}
.agegate .age-ico,
.agegate img {
width: 72px;
height: 72px;
border-radius: 16px;
display: block;
object-fit: cover;
flex: none;
}
.agegate h3 {
font-size: 28px;
font-weight: 600;
line-height: 1.35;
margin: 0;
}
.agegate p {
font-size: 15px;
color: var(--t2);
line-height: 1.6;
max-width: 400px;
margin: 0;
}
.agegate .privacy {
color: var(--t1);
text-decoration: underline;
text-underline-offset: 2px;
}
.agegate .enter {
width: 100%;
height: 56px;
font-size: 16px;
font-weight: 500;
}
.agegate .leave {
appearance: none;
background: none;
border: 0;
font-family: inherit;
font-size: 14px;
line-height: 20px;
color: var(--t3);
cursor: pointer;
padding: 4px 8px;
transition: color 0.25s;
}
.agegate .leave:hover {
color: var(--t2);
}
/* 全局 Toast */
.toast {
position: fixed;
left: 50%;
bottom: 32px;
transform: translate(-50%, 20px);
background: var(--elev);
border: 1px solid var(--b2);
color: var(--t1);
padding: 10px 20px;
border-radius: 999px;
font-size: 14px;
opacity: 0;
transition: all 0.3s var(--ease);
z-index: 70;
pointer-events: none;
}
.toast.show {
opacity: 1;
transform: translate(-50%, 0);
}
/* ============ 响应式适配 (H5 & 平板) ============ */
@media (max-width: 1100px) {
.hero-main {
grid-template-columns: 1fr min(100%, 360px);
gap: 28px;
align-items: center;
}
.copy {
width: 100%;
max-width: 520px;
}
.keyart {
width: min(100%, 360px);
height: auto;
aspect-ratio: 600 / 338;
}
.top5 {
grid-template-columns: repeat(5, 1fr);
gap: 12px;
}
.top5 .poster {
flex: 1;
width: auto;
min-width: 0;
height: auto;
aspect-ratio: 3 / 4;
}
.top5 .rank {
font-size: 64px;
}
.grid6 {
grid-template-columns: repeat(4, 1fr);
}
.about {
grid-template-columns: 1fr;
gap: 32px;
}
.faq {
grid-template-columns: 1fr;
gap: 32px;
}
.feat .row {
grid-template-columns: 72px 240px 1fr;
gap: 24px;
}
}
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
transition: none !important;
}
}
</style>