Browse Source

✨ feat: 美化首页样式

Pchen0 1 month ago
parent
commit
7a8de21716

BIN
src/assets/img/homePage/figma/hero-illustration.png


+ 85 - 49
src/components/Header/index.vue

@@ -1,33 +1,40 @@
 <template>
-    <div class="root">
-        <a-menu mode="horizontal" class="menu" :selected-keys="['99']">
-            <a-menu-item key="0"
-                :style="{ cursor: 'pointer', padding: 0, marginRight: '650px', background: 'transparent', color: props.color }"
-                disabled>
-                <div class="logo" @click="$router.push('/')">
-                    <img alt="RunForge" src="/logo.svg" height="40">
-                    <span class="title">RunForge</span>
-                </div>
-            </a-menu-item>
-
-            <a-menu-item key="4" :style="{ background: 'transparent', color: props.color }" v-if="!user"
-                @click="$router.push('/login')">
-                用户登录
-            </a-menu-item>
-            <a-sub-menu key="5" :style="{ background: 'transparent', color: props.color }" v-else>
-                <template #expand-icon-down></template>
-                <template #title>
-                    <div class="userinfo">
-                        <a-avatar :size="30"><img alt="avatar" :src="user.avatar" /></a-avatar>
-                        <span>{{ user.username }}</span>
-                    </div>
-                </template>
-                <a-menu-item key="5_0" @click="$router.push('/user')"><icon-user /> 个人中心</a-menu-item>
-                <a-menu-item key="5_1" @click="logout"><icon-export /> 退出登录</a-menu-item>
-            </a-sub-menu>
-        </a-menu>
-    </div>
-
+    <header class="site-header">
+        <div class="header-inner">
+            <div class="logo" @click="$router.push('/')">
+                <img alt="RunForge" src="/logo.svg" height="40">
+                <span class="title">RunForge</span>
+            </div>
+            <div class="nav-actions">
+                <a-button
+                    v-if="!user"
+                    type="text"
+                    class="nav-btn"
+                    :style="{ color: props.color }"
+                    @click="$router.push('/login')"
+                >
+                    用户登录
+                </a-button>
+                <a-dropdown v-else trigger="click" position="br">
+                    <button type="button" class="user-trigger" :style="{ color: props.color }">
+                        <a-avatar :size="30">
+                            <img alt="avatar" :src="user.avatar" />
+                        </a-avatar>
+                        <span class="username">{{ user.username }}</span>
+                        <icon-down />
+                    </button>
+                    <template #content>
+                        <a-doption @click="$router.push('/user')">
+                            <icon-user /> 个人中心
+                        </a-doption>
+                        <a-doption @click="logout">
+                            <icon-export /> 退出登录
+                        </a-doption>
+                    </template>
+                </a-dropdown>
+            </div>
+        </div>
+    </header>
 </template>
 
 <script setup>
@@ -45,7 +52,7 @@ const props = defineProps({
 const user = ref('')
 const getuser = async () => {
     const userStore = useUserStore()
-    let userInfo = await userStore.getInfo()
+    const userInfo = await userStore.getInfo()
     if (userInfo?.avatar && userInfo?.username && userInfo?.uuid && userInfo?.session)
         user.value = userInfo
 }
@@ -59,49 +66,78 @@ const logout = () => {
             userStore.logout()
             Message.success('退出成功!')
             setTimeout(() => { window.location.reload() }, 1000)
-        },
-        onCancel: () => {
-
         }
-    });
+    })
 }
 
 getuser()
-
 </script>
 
 <style scoped>
-.root {
+.site-header {
     position: absolute;
     top: 0;
-    left: 50%;
-    transform: translateX(-50%);
-    width: 80%;
-    min-width: 1280px;
+    left: 0;
+    right: 0;
     z-index: 100;
+    padding: 16px 24px;
+    box-sizing: border-box;
     user-select: none;
 }
 
-.menu {
+.header-inner {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    gap: 24px;
+    max-width: 1200px;
     width: 100%;
-    background: transparent;
+    margin: 0 auto;
+    box-sizing: border-box;
 }
 
 .logo {
     display: flex;
+    align-items: center;
+    cursor: pointer;
+    flex-shrink: 0;
 }
 
-.logo span {
+.logo .title {
     font-size: 1.5em;
     margin: 5px 8px;
 }
 
-.userinfo {
-    margin-top: -15px;
-    transform: translateY(23px);
+.nav-actions {
+    flex-shrink: 0;
+    margin-left: auto;
+}
+
+.nav-btn {
+    font-size: 15px;
+}
+
+.user-trigger {
+    display: inline-flex;
+    align-items: center;
+    gap: 8px;
+    padding: 4px 8px;
+    border: none;
+    background: transparent;
+    cursor: pointer;
+    font-size: 15px;
+    border-radius: 8px;
+    transition: background-color 0.2s;
+}
+
+.user-trigger:hover {
+    background: rgba(27, 48, 34, 0.06);
 }
 
-.userinfo span {
-    margin-left: 7px;
+.username {
+    max-width: 160px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
 }
-</style>
+</style>

+ 213 - 68
src/pages/Main/Main.vue

@@ -1,25 +1,42 @@
 <template>
-    <div id="section1" class="section root">
-        <div class="videocontainer">
-            <video class="fullscreenvideo" playsinline="" autoplay="" muted="" loop=""
-                src="https://lepao-cloud.xxoo365.top/view.php/4f73ff78996ee4520b24e8044eeeeec5.webm" type="video/mp4" />
-            <div class="overlay" />
+    <div id="section1" class="section hero-section">
+        <div class="hero-bg" aria-hidden="true">
+            <div class="hero-bg-gradient" />
+            <div class="hero-bg-orb hero-bg-orb--1" />
+            <div class="hero-bg-orb hero-bg-orb--2" />
+            <div class="hero-bg-orb hero-bg-orb--3" />
+        </div>
+        <Header color="#1b3022" />
+        <div class="hero-inner">
+            <Center />
+            <div class="hero-visual" aria-hidden="true">
+                <img
+                    class="hero-illustration"
+                    src="@/assets/img/homePage/figma/hero-illustration.png"
+                    alt=""
+                />
+            </div>
         </div>
-        <Header color="white" />
-        <Center />
 
-        <a-button shape="circle" class="floating-button" size="large" @click="scrollToSection('section2')">
+        <a-button
+            shape="circle"
+            class="floating-button"
+            size="large"
+            @click="scrollToSection('section2')"
+        >
             <IconDown />
         </a-button>
     </div>
 
-    <div id="section2" class="section">
+    <div id="section2" class="section features-wrap">
+        <div class="features-bg" aria-hidden="true">
+            <div class="features-bg-gradient" />
+        </div>
         <Section2 />
     </div>
-    <div class="footer">
+    <footer class="site-footer">
         <span>© {{ new Date().getFullYear() }} RunForge - 智能校园乐跑平台</span>
-    </div>
-
+    </footer>
 </template>
 
 <script setup>
@@ -28,101 +45,229 @@ import Center from './components/center.vue'
 import Section2 from './components/section2.vue'
 
 const scrollToSection = (sectionId) => {
-    const section = document.getElementById(sectionId);
+    const section = document.getElementById(sectionId)
     if (section) {
-        section.scrollIntoView({ behavior: 'smooth' });
+        section.scrollIntoView({ behavior: 'smooth' })
     }
-};
-
+}
 </script>
 
 <style lang="less" scoped>
+@import './theme.less';
+
 .section {
     padding: 0;
     margin: 0;
-    min-width: 1280px;
     width: 100%;
     min-height: 100vh;
     scroll-snap-align: start;
     position: relative;
+    box-sizing: border-box;
 }
 
-.root {
-    text-align: center;
+.hero-section {
+    display: flex;
+    flex-direction: column;
+    background: @home-bg-hero;
+    overflow: hidden;
 }
 
-.fullscreenvideo {
+.hero-bg {
     position: absolute;
-    min-width: 100%;
-    min-height: 100%;
-    width: auto;
-    height: auto;
-    z-index: -100;
-    left: 50%;
-    transform: translateX(-50%);
+    inset: 0;
+    z-index: 0;
+    overflow: hidden;
+    pointer-events: none;
 }
 
-.videocontainer {
+.hero-bg-gradient {
     position: absolute;
-    width: 100%;
-    height: 100%;
-    overflow: hidden;
-    z-index: -100;
+    inset: -50%;
+    width: 200%;
+    height: 200%;
+    background: linear-gradient(
+        -45deg,
+        @home-gradient-pale,
+        @home-gradient-mint,
+        @home-gradient-green,
+        @home-gradient-teal,
+        @home-gradient-sage,
+        @home-gradient-mint
+    );
+    background-size: 400% 400%;
+    animation: homeGradientFlow 14s ease infinite;
 }
 
-.overlay {
+.hero-bg-orb {
     position: absolute;
-    width: 100%;
-    height: 100%;
-    background-color: rgba(0, 0, 0, 0.4);
-    z-index: -99;
+    border-radius: 50%;
+    filter: blur(60px);
+    opacity: 0.55;
+    animation: homeOrbFloat 18s ease-in-out infinite;
 }
 
-.center {
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    width: 800px;
-    height: 300px;
-    z-index: 2;
-    transform: translate(-50%, -50%);
-    pointer-events: auto;
-    /* center 可以接收鼠标事件 */
+.hero-bg-orb--1 {
+    width: 420px;
+    height: 420px;
+    top: -8%;
+    right: 5%;
+    background: radial-gradient(circle, fade(@home-gradient-green, 70%) 0%, transparent 70%);
+    animation-duration: 16s;
 }
 
-.button {
-    position: absolute;
-    z-index: 101;
+.hero-bg-orb--2 {
+    width: 360px;
+    height: 360px;
+    bottom: 10%;
+    left: -5%;
+    background: radial-gradient(circle, fade(@home-gradient-teal, 65%) 0%, transparent 70%);
+    animation-duration: 20s;
+    animation-delay: -4s;
+}
+
+.hero-bg-orb--3 {
+    width: 280px;
+    height: 280px;
+    top: 40%;
+    left: 35%;
+    background: radial-gradient(circle, fade(@home-gradient-pale, 80%) 0%, transparent 70%);
+    animation-duration: 22s;
+    animation-delay: -8s;
+}
+
+.hero-inner {
+    position: relative;
+    z-index: 1;
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 48px;
+    max-width: 1200px;
+    width: 90%;
+    margin: 0 auto;
+    padding: 120px 24px 100px;
+    box-sizing: border-box;
+}
+
+.hero-visual {
+    flex: 0 0 auto;
+    max-width: 420px;
+}
+
+.hero-illustration {
+    width: 100%;
+    max-width: 400px;
+    height: auto;
+    object-fit: contain;
+    filter: drop-shadow(0 16px 40px rgba(27, 48, 34, 0.12));
 }
 
 .floating-button {
-    background-color: rgba(255, 255, 255, 0.5);
+    z-index: 2;
+    background-color: fade(@home-primary, 12%);
+    color: @home-primary;
     position: absolute;
     bottom: 50px;
     left: 50%;
     transform: translateX(-50%);
-    border-radius: 50%;
-    border: none;
-    padding: 10px;
-    transition: background-color 0.3s;
+    border: 1px solid fade(@home-primary, 20%);
+    transition: background-color 0.3s, color 0.3s;
+
+    &:hover {
+        background-color: @home-primary;
+        color: #fff;
+    }
+}
+
+.features-wrap {
+    min-height: auto;
+    background: @home-bg-page;
+    overflow: hidden;
+}
+
+.features-bg {
+    position: absolute;
+    inset: 0;
+    z-index: 0;
+    pointer-events: none;
+    overflow: hidden;
 }
 
-.footer {
-    cursor: pointer;
+.features-bg-gradient {
+    position: absolute;
+    inset: -40%;
+    width: 180%;
+    height: 180%;
+    background: linear-gradient(
+        120deg,
+        @home-bg-page,
+        fade(@home-gradient-mint, 55%),
+        @home-bg-page,
+        fade(@home-gradient-teal, 40%),
+        @home-bg-page
+    );
+    background-size: 300% 300%;
+    animation: homeGradientFlow 18s ease infinite reverse;
+}
+
+.features-wrap > :not(.features-bg) {
     position: relative;
-    bottom: 15px;
-    left: 50%;
-    transform: translateX(-50%);
-    color: #777;
-    font-size: 12px;
-    display: flex;
-    min-width: 300px;
-    justify-content: center;
-    gap: 10px;
+    z-index: 1;
+}
+
+@keyframes homeGradientFlow {
+    0% {
+        background-position: 0% 50%;
+    }
+
+    50% {
+        background-position: 100% 50%;
+    }
+
+    100% {
+        background-position: 0% 50%;
+    }
+}
+
+@keyframes homeOrbFloat {
+    0%,
+    100% {
+        transform: translate(0, 0) scale(1);
+    }
+
+    33% {
+        transform: translate(28px, -24px) scale(1.06);
+    }
 
+    66% {
+        transform: translate(-22px, 18px) scale(0.94);
+    }
+}
+
+@media (prefers-reduced-motion: reduce) {
+    .hero-bg-gradient,
+    .hero-bg-orb,
+    .features-bg-gradient {
+        animation: none;
+    }
 
-    a {
-        color: #777;
+    .hero-bg-gradient {
+        inset: 0;
+        width: 100%;
+        height: 100%;
+        background: linear-gradient(135deg, @home-bg-hero 0%, @home-bg-hero-end 55%, @home-gradient-sage 100%);
+        background-size: 100% 100%;
     }
 }
+
+.site-footer {
+    background: @home-primary;
+    color: fade(#fff, 75%);
+    font-size: 13px;
+    text-align: center;
+    padding: 20px 16px;
+    width: 100%;
+    box-sizing: border-box;
+}
 </style>

+ 45 - 85
src/pages/Main/components/center.vue

@@ -1,106 +1,66 @@
 <template>
     <div class="center">
+        <p class="eyebrow">智能校园乐跑平台</p>
         <h1>RunForge</h1>
-        <h2>—— 智能自助校园乐跑平台</h2>
-        <div class="animated-button" @click="$router.push('/lepao')">
-            <span>立即体验</span>
-        </div>
+        <h2>轻松完成乐跑任务,成绩更省心</h2>
+        <button type="button" class="cta-button" @click="$router.push('/lepao')">
+            立即体验
+        </button>
     </div>
 </template>
 
-<style scoped>
+<style lang="less" scoped>
+@import '../theme.less';
+
 .center {
-    margin-top: -200px;
+    flex: 1;
+    max-width: 560px;
+    text-align: left;
 }
 
-.center h1,
-.center h2 {
-    background: linear-gradient(270deg,
-        #a8cfff,
-        #d0e7ff,
-        #ffffff,
-        #a8cfff);
-    background-size: 500% 500%;
-    animation: gradientMove 6s ease infinite;
-    -webkit-background-clip: text;
-    background-clip: text;
-    -webkit-text-fill-color: transparent;
+.eyebrow {
+    margin: 0 0 12px;
+    font-size: 20px;
+    font-weight: 600;
+    letter-spacing: 0.08em;
+    text-transform: uppercase;
+    color: @home-text-muted;
 }
 
-/* h1 特别设置字号和字体 */
 .center h1 {
-    font-size: 10em;
-    line-height: 1.3em;
-    font-family: AlibabaSans, -apple-system, BlinkMacSystemFont;
+    margin: 0;
+    font-size: clamp(4rem, 9vw, 6rem);
+    line-height: 1.1;
+    font-weight: 700;
+    color: @home-primary;
+    font-family: AlibabaSans, -apple-system, BlinkMacSystemFont, sans-serif;
 }
 
-/* h2 特别设置字号和字体 */
 .center h2 {
-    font-size: 2.5em;
-    margin-top: -50px;
-    font-family: Alimama ShuHeiTi, -apple-system, BlinkMacSystemFont;
+    margin: 16px 0 0;
+    font-size: clamp(1.5rem, 3vw, 2rem);
+    line-height: 1.6;
+    font-weight: 400;
+    color: @home-text-muted;
+    font-family: Alimama ShuHeiTi, -apple-system, BlinkMacSystemFont, sans-serif;
 }
 
-/* 动态渐变动画 */
-@keyframes gradientMove {
-    0% {
-        background-position: 0% 50%;
-    }
-
-    50% {
-        background-position: 100% 50%;
-    }
-
-    100% {
-        background-position: 0% 50%;
-    }
-}
-
-
-.animated-button {
-    user-select: none;
+.cta-button {
+    margin-top: 32px;
     cursor: pointer;
-    position: absolute;
-    left: 50%;
-    margin-top: -50px;
-    transform: translateX(-50%);
-    background-color: rgba(22, 93, 255, 0.8);
-    color: #fff;
     border: none;
-    border-radius: 5px;
-    padding: 10px 30px;
-    overflow: hidden;
-    font-size: 20px;
-    position: relative;
-    transition: color 0.4s;
-    margin-top: 160px;
-    width: 100px;
-    font-family: Alimama ShuHeiTi, -apple-system, BlinkMacSystemFont;
-}
-
-.animated-button::before {
-    content: "";
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    background: rgba(255, 255, 255, 0.8);
-    color: rgba(22, 93, 255, 0.8);
-    transform: translateX(-100%);
-    transition: transform 0.4s;
-}
-
-.animated-button:hover::before {
-    transform: translateX(0);
-}
-
-.animated-button:hover {
-    color: rgb(22, 93, 255);
-}
+    border-radius: @home-radius-btn;
+    padding: 14px 32px;
+    font-size: 16px;
+    font-weight: 600;
+    color: #fff;
+    background: @home-primary;
+    font-family: Alimama ShuHeiTi, -apple-system, BlinkMacSystemFont, sans-serif;
+    transition: background-color 0.2s, transform 0.2s;
 
-.animated-button span {
-    position: relative;
-    transition: color 0.1s;
+    &:hover {
+        background: @home-primary-hover;
+        transform: translateY(-1px);
+    }
 }
-</style>
+</style>

+ 80 - 64
src/pages/Main/components/section2.vue

@@ -1,17 +1,23 @@
 <template>
-    <div id="section2" class="features-section">
-        <CanvasBackend />
-        <div v-for="(card, index) in cards" :key="index" :ref="el => cardRefs[index] = el" class="card"
-            :class="[{ 'in-view': inView[index] }, { 'reverse': card.reverse }]">
+    <div class="features-section">
+        <h2 class="section-title">核心能力</h2>
+        <p class="section-subtitle">为校园乐跑场景打造的全流程自助服务</p>
+        <div
+            v-for="(card, index) in cards"
+            :key="index"
+            :ref="el => cardRefs[index] = el"
+            class="card"
+            :class="[{ 'in-view': inView[index] }, { reverse: card.reverse }]"
+        >
             <div class="content">
                 <div class="title">
-                    <img :src="card.icon" />
+                    <img :src="card.icon" alt="" />
                     {{ card.title }}
                 </div>
                 <div class="dec">{{ card.dec }}</div>
             </div>
             <div class="img">
-                <img :src="card.img" />
+                <img :src="card.img" alt="" />
             </div>
         </div>
     </div>
@@ -19,35 +25,33 @@
 
 <script setup>
 import { ref, onMounted, onUnmounted } from 'vue'
-import CanvasBackend from '@/components/CanvasBackend/index.vue'
 
 const cards = [
     {
         title: '全自动乐跑体验',
         icon: new URL('@/assets/img/homePage/icons/visualization.svg', import.meta.url).href,
         dec: '自动上传跑步数据,无需手动操作,轻松完成乐跑任务',
-        img: new URL('https:\/\/lepao-cloud.xxoo365.top\/view.php\/f9192f9d310b16a7e8e4ef2f71ac8629.png').href,
+        img: new URL('https://lepao-cloud.xxoo365.top/view.php/f9192f9d310b16a7e8e4ef2f71ac8629.png').href,
         reverse: false
     },
     {
         title: '智能成绩上传系统',
         icon: new URL('@/assets/img/homePage/icons/ai.svg', import.meta.url).href,
         dec: '支持夜间上传与异常修复,忘跑也能及时补救,成绩无忧',
-        img: new URL('https:\/\/lepao-cloud.xxoo365.top\/view.php\/6cf4d3d8f5d9e6b41c525541c8949329.png').href,
+        img: new URL('https://lepao-cloud.xxoo365.top/view.php/6cf4d3d8f5d9e6b41c525541c8949329.png').href,
         reverse: true
     },
     {
         title: '自由跑区与贴心服务',
         icon: new URL('@/assets/img/homePage/icons/quality.svg', import.meta.url).href,
         dec: '支持自定义跑步区域与乐跑时段,体验便捷又人性化',
-        img: new URL('https:\/\/lepao-cloud.xxoo365.top\/view.php\/3132165c9476e659c710114f963e6814.png').href,
+        img: new URL('https://lepao-cloud.xxoo365.top/view.php/3132165c9476e659c710114f963e6814.png').href,
         reverse: false
     }
 ]
 
-
 const cardRefs = ref([])
-const inView = ref(cards.map(() => false)) // 初始化每个卡片的状态
+const inView = ref(cards.map(() => false))
 
 let observers = []
 
@@ -70,76 +74,88 @@ onMounted(() => {
 onUnmounted(() => {
     observers.forEach(observer => observer.disconnect())
 })
-
 </script>
 
 <style lang="less" scoped>
+@import '../theme.less';
+
 .features-section {
     position: relative;
-    background-image: linear-gradient(to bottom, #ebf2ff, hsla(0, 0%, 100%, 0));
-    padding: 80px 20px;
+    padding: 80px 24px 100px;
     display: flex;
-    gap: 50px;
+    gap: 32px;
     flex-direction: column;
     align-items: center;
-    justify-content: center;
+}
 
-    .reverse {
-        flex-direction: row-reverse;
-        background: linear-gradient(346deg, #ebf2ff, #d6e0ff) !important;
-    }
+.section-title {
+    margin: 0;
+    font-size: 2.25rem;
+    color: @home-primary;
+    font-family: Alimama ShuHeiTi, -apple-system, BlinkMacSystemFont, sans-serif;
+}
 
-    .card {
-        width: 1200px;
-        display: flex;
-        gap: 50px;
-        align-items: center;
-        justify-content: center;
-        background: linear-gradient(135deg, #ebf2ff, #d6e0ff);
-        border-radius: 10px;
-        height: 400px;
-        opacity: 0;
-        transform: translateY(100px);
-        transition: all 0.8s ease-out;
-
-        &.in-view {
-            opacity: 1;
-            transform: translateY(0);
-        }
+.section-subtitle {
+    margin: -16px 0 24px;
+    font-size: 1.1rem;
+    color: @home-text-muted;
+}
 
-        .content {
-            width: 500px;
+.card {
+    width: min(1200px, 100%);
+    display: flex;
+    gap: 48px;
+    align-items: center;
+    justify-content: center;
+    background: @home-card-bg;
+    border: 1px solid @home-card-border;
+    border-radius: @home-radius-card;
+    box-shadow: @home-shadow-card;
+    padding: 40px 48px;
+    box-sizing: border-box;
+    opacity: 0;
+    transform: translateY(48px);
+    transition: opacity 0.8s ease-out, transform 0.8s ease-out;
+
+    &.in-view {
+        opacity: 1;
+        transform: translateY(0);
+    }
 
-            .title {
-                font-weight: bold;
-                font-size: 2.5em;
-                font-family: Alimama ShuHeiTi, -apple-system, BlinkMacSystemFont;
-                display: flex;
-                align-items: center;
-                gap: 10px;
-            }
+    &.reverse {
+        flex-direction: row-reverse;
+    }
 
-            .dec {
-                margin-top: 15px;
-                font-size: 1.4em;
-                line-height: 35px;
-                color: rgb(102, 102, 102);
+    .content {
+        flex: 1;
+        max-width: 500px;
+
+        .title {
+            font-weight: 700;
+            font-size: 1.75rem;
+            color: @home-primary;
+            font-family: Alimama ShuHeiTi, -apple-system, BlinkMacSystemFont, sans-serif;
+            display: flex;
+            align-items: center;
+            gap: 12px;
+
+            img {
+                width: 36px;
+                height: 36px;
             }
         }
 
-        img {
-            max-width: 500px;
-            user-select: none;
+        .dec {
+            margin-top: 16px;
+            font-size: 1.05rem;
+            line-height: 1.75;
+            color: @home-text-muted;
         }
     }
 
-    // 动画定义
-    @keyframes slideFadeIn {
-        to {
-            opacity: 1;
-            transform: translateY(0);
-        }
+    .img img {
+        max-width: min(420px, 40vw);
+        user-select: none;
     }
-
 }
-</style>
+</style>

+ 19 - 0
src/pages/Main/theme.less

@@ -0,0 +1,19 @@
+// Friendly Accounting Services — design tokens (from local .site export)
+@home-bg-hero: #d4f0dc;
+@home-bg-hero-end: #a6e7b8;
+@home-bg-page: #f4faf6;
+@home-primary: #1b3022;
+@home-primary-hover: #142618;
+@home-text-muted: #4a5c52;
+@home-card-bg: #ffffff;
+@home-card-border: #e2efe6;
+@home-radius-btn: 999px;
+@home-radius-card: 16px;
+@home-shadow-card: 0 8px 32px rgba(27, 48, 34, 0.08);
+
+// 动态渐变辅助色
+@home-gradient-mint: #d4f0dc;
+@home-gradient-green: #a6e7b8;
+@home-gradient-sage: #9fd9b0;
+@home-gradient-pale: #e8f8ec;
+@home-gradient-teal: #b8e6d0;