mirror of
https://github.com/Gloridust/WechatOnCloud.git
synced 2026-08-31 02:31:27 -07:00
738 lines
15 KiB
CSS
738 lines
15 KiB
CSS
/* WechatOnCloud 面板 —— 牛奶布艺(soft neumorphism)+ 微信绿 + iOS26 圆角极简
|
||
* 比喻:整个界面是盖在桌面上的一整块白布,组件是被布顶起的物体。
|
||
* - 高光在物体顶面(radial,中心偏上)
|
||
* - 阴影是布料折痕(小半径、紧贴边缘、冷灰蓝),不是悬浮投影
|
||
* - 组件亮度 ≥ 背景;层级靠明度,不靠边框/分割线 */
|
||
:root {
|
||
--base: #ebedf1; /* 整块布底色(立体档,91% 区间) */
|
||
--surface: #ffffff; /* 浮起表面:纯白 */
|
||
--trough: #e0e3ea; /* 凹槽:比 base 更暗(输入框/进度槽) */
|
||
--shadow: 51 66 102; /* 冷灰蓝阴影 RGB(配合 rgba()) */
|
||
|
||
--wx-green: #07c160;
|
||
--wx-green-dark: #06ad56;
|
||
--green-rgb: 7 193 96;
|
||
|
||
--text: #1a1d24;
|
||
--muted: #8a9099;
|
||
--danger: #fa5151;
|
||
--danger-rgb: 250 81 81;
|
||
|
||
--r-card: 28px;
|
||
--r-blob: 22px;
|
||
--r-small: 16px;
|
||
|
||
/* 布料折痕:两层,紧贴边缘 */
|
||
--crease: 0 1px 3px rgba(var(--shadow) / 0.4), 0 2px 8px rgba(var(--shadow) / 0.22);
|
||
--crease-press: 0 1px 2px rgba(var(--shadow) / 0.28), 0 1px 3px rgba(var(--shadow) / 0.16);
|
||
--crease-accent: 0 1px 3px rgba(var(--green-rgb) / 0.45), 0 4px 14px rgba(var(--green-rgb) / 0.32);
|
||
/* 顶面高光(中心偏上的 radial),所有浮起组件共用 */
|
||
--sheen: radial-gradient(
|
||
ellipse at 50% 28%,
|
||
rgba(255, 255, 255, 0.55) 0%,
|
||
rgba(255, 255, 255, 0.16) 38%,
|
||
transparent 74%
|
||
);
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
html,
|
||
body,
|
||
#root {
|
||
height: 100%;
|
||
margin: 0;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', 'Segoe UI', Roboto, sans-serif;
|
||
background: var(--base);
|
||
color: var(--text);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
input,
|
||
button {
|
||
font-family: inherit;
|
||
}
|
||
|
||
.center-screen {
|
||
min-height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 24px;
|
||
padding-top: max(24px, env(safe-area-inset-top));
|
||
padding-bottom: max(24px, env(safe-area-inset-bottom));
|
||
}
|
||
|
||
/* ── 浮起原子:surface + 折痕 + 顶面高光 ──────────────────── */
|
||
.mf-raised,
|
||
.card,
|
||
.enter-card,
|
||
.list,
|
||
.wx-state {
|
||
position: relative;
|
||
background: var(--surface);
|
||
box-shadow: var(--crease);
|
||
}
|
||
.mf-raised::before,
|
||
.card::before,
|
||
.enter-card::before,
|
||
.list::before,
|
||
.wx-state::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
background: var(--sheen);
|
||
pointer-events: none;
|
||
}
|
||
.card > *,
|
||
.enter-card > *,
|
||
.list > *,
|
||
.wx-state > * {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.card {
|
||
border-radius: var(--r-card);
|
||
padding: 24px;
|
||
width: 100%;
|
||
max-width: 360px;
|
||
}
|
||
|
||
/* 登录 */
|
||
.login-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14px;
|
||
}
|
||
.brand {
|
||
text-align: center;
|
||
margin-bottom: 8px;
|
||
}
|
||
.brand-logo {
|
||
position: relative;
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 18px;
|
||
background: var(--wx-green);
|
||
color: #fff;
|
||
font-size: 32px;
|
||
font-weight: 700;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin: 0 auto 14px;
|
||
box-shadow: var(--crease-accent);
|
||
overflow: hidden;
|
||
}
|
||
.brand-logo::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: var(--sheen);
|
||
pointer-events: none;
|
||
}
|
||
.brand h1 {
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
margin: 0 0 4px;
|
||
}
|
||
.muted {
|
||
color: var(--muted);
|
||
}
|
||
.small {
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* 输入框:凹陷(trough fill + 顶部内阴影),聚焦叠绿色半透环 */
|
||
.input {
|
||
width: 100%;
|
||
height: 48px;
|
||
padding: 0 16px;
|
||
border: none;
|
||
border-radius: var(--r-small);
|
||
font-size: 16px;
|
||
outline: none;
|
||
color: var(--text);
|
||
background: var(--trough);
|
||
box-shadow: inset 0 1px 2px rgba(var(--shadow) / 0.18), inset 0 2px 6px rgba(var(--shadow) / 0.1);
|
||
transition: box-shadow 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
.input::placeholder {
|
||
color: var(--muted);
|
||
}
|
||
.input:focus {
|
||
box-shadow: inset 0 1px 2px rgba(var(--shadow) / 0.16), 0 0 0 3px rgba(var(--green-rgb) / 0.22);
|
||
}
|
||
|
||
/* 按钮:浮起 blob,按下缩小 + 折痕收紧 */
|
||
.btn {
|
||
position: relative;
|
||
height: 48px;
|
||
border: none;
|
||
border-radius: var(--r-small);
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
background: var(--surface);
|
||
color: var(--text);
|
||
cursor: pointer;
|
||
box-shadow: var(--crease);
|
||
overflow: hidden;
|
||
transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
.btn::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: var(--sheen);
|
||
pointer-events: none;
|
||
}
|
||
.btn:active:not(:disabled) {
|
||
transform: scale(0.97);
|
||
box-shadow: var(--crease-press);
|
||
}
|
||
.btn-primary {
|
||
background: var(--wx-green);
|
||
color: #fff;
|
||
box-shadow: var(--crease-accent);
|
||
}
|
||
/* 绿底上用更克制的顶面高光,避免白色 sheen 把绿冲淡 */
|
||
.btn-primary::before,
|
||
.wx-btn.btn-primary::before {
|
||
background: radial-gradient(
|
||
ellipse at 50% 22%,
|
||
rgba(255, 255, 255, 0.28) 0%,
|
||
rgba(255, 255, 255, 0.08) 42%,
|
||
transparent 72%
|
||
);
|
||
}
|
||
.btn-primary:active:not(:disabled) {
|
||
background: var(--wx-green-dark);
|
||
}
|
||
.btn:disabled {
|
||
opacity: 0.6;
|
||
cursor: default;
|
||
}
|
||
/* 文本按钮:无浮起,绿字,按下淡绿底 */
|
||
.btn-text {
|
||
background: none;
|
||
border: none;
|
||
color: var(--wx-green);
|
||
font-size: 15px;
|
||
cursor: pointer;
|
||
padding: 6px 10px;
|
||
border-radius: 10px;
|
||
transition: background 0.18s;
|
||
}
|
||
.btn-text:active {
|
||
background: rgba(var(--green-rgb) / 0.12);
|
||
}
|
||
.btn-text.danger {
|
||
color: var(--danger);
|
||
}
|
||
.btn-text.danger:active {
|
||
background: rgba(var(--danger-rgb) / 0.12);
|
||
}
|
||
|
||
.error {
|
||
color: var(--danger);
|
||
font-size: 14px;
|
||
}
|
||
.ok {
|
||
color: var(--wx-green);
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* ── 页面骨架 ──────────────────────────────────────────── */
|
||
.page {
|
||
min-height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
/* 顶栏走浅色布面(不再整条绿),标题深色、操作绿字 —— iOS26 + 牛奶布艺 */
|
||
.topbar {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 8px;
|
||
padding-top: env(safe-area-inset-top);
|
||
height: calc(52px + env(safe-area-inset-top));
|
||
background: var(--base);
|
||
}
|
||
.topbar-title {
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
color: var(--text);
|
||
position: absolute;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
.content {
|
||
flex: 1;
|
||
padding: 16px;
|
||
max-width: 560px;
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.hello {
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
margin: 8px 4px 18px;
|
||
}
|
||
.tag {
|
||
display: inline-block;
|
||
font-size: 11px;
|
||
background: rgba(var(--green-rgb) / 0.14);
|
||
color: var(--wx-green-dark);
|
||
border-radius: 999px;
|
||
padding: 2px 9px;
|
||
margin-left: 8px;
|
||
vertical-align: middle;
|
||
font-weight: 600;
|
||
}
|
||
.tag-off {
|
||
background: rgba(var(--danger-rgb) / 0.14);
|
||
color: var(--danger);
|
||
}
|
||
|
||
/* 进入微信入口卡 */
|
||
.enter-card {
|
||
width: 100%;
|
||
border: none;
|
||
border-radius: var(--r-card);
|
||
padding: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
cursor: pointer;
|
||
text-align: left;
|
||
transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
.enter-card:active {
|
||
transform: scale(0.985);
|
||
box-shadow: var(--crease-press);
|
||
}
|
||
.enter-icon {
|
||
position: relative;
|
||
width: 46px;
|
||
height: 46px;
|
||
flex: none;
|
||
border-radius: 14px;
|
||
background: var(--wx-green);
|
||
color: #fff;
|
||
font-size: 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: var(--crease-accent);
|
||
overflow: hidden;
|
||
}
|
||
.enter-icon::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: var(--sheen);
|
||
pointer-events: none;
|
||
}
|
||
.enter-text {
|
||
flex: 1;
|
||
}
|
||
.enter-title {
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
}
|
||
.enter-sub {
|
||
font-size: 13px;
|
||
color: var(--muted);
|
||
margin-top: 3px;
|
||
}
|
||
.enter-arrow {
|
||
color: #c2c7d0;
|
||
font-size: 22px;
|
||
}
|
||
|
||
/* 列表卡:行间用折痕细缝分隔,不用 border */
|
||
.list {
|
||
margin-top: 16px;
|
||
border-radius: var(--r-card);
|
||
overflow: hidden;
|
||
}
|
||
.list-item {
|
||
position: relative;
|
||
z-index: 1;
|
||
width: 100%;
|
||
background: none;
|
||
border: none;
|
||
box-shadow: inset 0 -1px 0 rgba(var(--shadow) / 0.08);
|
||
padding: 16px 18px;
|
||
font-size: 16px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
transition: background 0.18s;
|
||
}
|
||
.list-item:active {
|
||
background: rgba(var(--shadow) / 0.04);
|
||
}
|
||
.list-item:last-child {
|
||
box-shadow: none;
|
||
}
|
||
|
||
/* 子账号列表 */
|
||
.user-row {
|
||
position: relative;
|
||
z-index: 1;
|
||
padding: 14px 18px;
|
||
box-shadow: inset 0 -1px 0 rgba(var(--shadow) / 0.08);
|
||
}
|
||
.user-row:last-child {
|
||
box-shadow: none;
|
||
}
|
||
.user-main {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.user-name {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
}
|
||
.user-actions {
|
||
display: flex;
|
||
gap: 4px;
|
||
margin-top: 6px;
|
||
}
|
||
|
||
/* ── 微信安装/更新状态卡(启动下载 + 更新到最新版) ──────── */
|
||
.wx-state {
|
||
margin-top: 16px;
|
||
border-radius: var(--r-card);
|
||
padding: 20px;
|
||
}
|
||
.wx-state-row {
|
||
position: relative;
|
||
z-index: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
}
|
||
.wx-state-text {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
.wx-state-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
.wx-state-sub {
|
||
font-size: 13px;
|
||
color: var(--muted);
|
||
margin-top: 3px;
|
||
}
|
||
.wx-btn {
|
||
height: 40px;
|
||
flex: none;
|
||
padding: 0 18px;
|
||
border-radius: 999px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
/* 进度条:凹槽轨 + 绿色带光晕填充 */
|
||
.wx-progress {
|
||
position: relative;
|
||
z-index: 1;
|
||
margin-top: 16px;
|
||
height: 8px;
|
||
border-radius: 999px;
|
||
background: var(--trough);
|
||
box-shadow: inset 0 1px 2px rgba(var(--shadow) / 0.2);
|
||
overflow: hidden;
|
||
}
|
||
.wx-progress-bar {
|
||
height: 100%;
|
||
border-radius: 999px;
|
||
background: linear-gradient(90deg, var(--wx-green-dark), var(--wx-green));
|
||
box-shadow: 0 0 8px rgba(var(--green-rgb) / 0.5);
|
||
transition: width 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
/* 进度不确定(拿不到总大小)时来回滑动 */
|
||
.wx-progress-bar.indeterminate {
|
||
width: 40%;
|
||
transition: none;
|
||
animation: wx-slide 1.1s ease-in-out infinite;
|
||
}
|
||
@keyframes wx-slide {
|
||
0% {
|
||
margin-left: -40%;
|
||
}
|
||
100% {
|
||
margin-left: 100%;
|
||
}
|
||
}
|
||
.wx-progress-text {
|
||
position: relative;
|
||
z-index: 1;
|
||
margin-top: 8px;
|
||
font-size: 12px;
|
||
color: var(--muted);
|
||
text-align: right;
|
||
}
|
||
|
||
/* ── 弹窗 ──────────────────────────────────────────────── */
|
||
.modal-mask {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(26, 29, 36, 0.4);
|
||
-webkit-backdrop-filter: blur(6px);
|
||
backdrop-filter: blur(6px);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 24px;
|
||
z-index: 20;
|
||
}
|
||
.modal {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
border-radius: var(--r-card);
|
||
}
|
||
.modal h2 {
|
||
margin: 0 0 4px;
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
}
|
||
.modal-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
.modal-actions .btn {
|
||
flex: 1;
|
||
}
|
||
|
||
/* ── 桌面 ──────────────────────────────────────────────── */
|
||
.desktop-wrap {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: #000;
|
||
}
|
||
.desktop-frame {
|
||
width: 100%;
|
||
height: 100%;
|
||
border: none;
|
||
display: block;
|
||
}
|
||
/* 返回钮:浮起白色圆 blob */
|
||
.desktop-back {
|
||
position: fixed;
|
||
top: max(12px, env(safe-area-inset-top));
|
||
left: 12px;
|
||
width: 42px;
|
||
height: 42px;
|
||
border-radius: 50%;
|
||
border: none;
|
||
background: var(--surface);
|
||
color: var(--text);
|
||
font-size: 24px;
|
||
line-height: 1;
|
||
cursor: pointer;
|
||
z-index: 10;
|
||
box-shadow: var(--crease);
|
||
transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.18s;
|
||
}
|
||
.desktop-back:active {
|
||
transform: scale(0.94);
|
||
box-shadow: var(--crease-press);
|
||
}
|
||
|
||
/* ── loading ───────────────────────────────────────────── */
|
||
.spinner {
|
||
width: 32px;
|
||
height: 32px;
|
||
border: 3px solid rgba(var(--green-rgb) / 0.2);
|
||
border-top-color: var(--wx-green);
|
||
border-radius: 50%;
|
||
animation: spin 0.8s linear infinite;
|
||
}
|
||
@keyframes spin {
|
||
to {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
/* ---------- 多实例:分区标题 ---------- */
|
||
.section-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin: 6px 6px 12px;
|
||
}
|
||
.section-title {
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
}
|
||
|
||
/* ---------- 实例网格 ---------- */
|
||
.inst-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||
gap: 14px;
|
||
margin-bottom: 22px;
|
||
}
|
||
.inst-card {
|
||
position: relative;
|
||
background: var(--surface);
|
||
border-radius: var(--r-card);
|
||
box-shadow: var(--crease);
|
||
padding: 18px;
|
||
overflow: hidden;
|
||
}
|
||
.inst-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
background: var(--sheen);
|
||
pointer-events: none;
|
||
}
|
||
.inst-card > * {
|
||
position: relative;
|
||
}
|
||
.inst-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
}
|
||
.inst-name {
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.inst-sub {
|
||
margin-top: 6px;
|
||
font-size: 13px;
|
||
color: var(--muted);
|
||
min-height: 18px;
|
||
}
|
||
.inst-actions {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-top: 14px;
|
||
}
|
||
.inst-enter {
|
||
flex: 1;
|
||
}
|
||
.inst-act {
|
||
flex: none;
|
||
}
|
||
|
||
/* 状态徽章配色 */
|
||
.tag-on {
|
||
background: rgba(var(--green-rgb) / 0.16);
|
||
color: var(--wx-green-dark);
|
||
}
|
||
.tag-busy {
|
||
background: rgba(51 102 204 / 0.16);
|
||
color: #2f5fd0;
|
||
}
|
||
.tag-warn {
|
||
background: rgba(245 158 11 / 0.18);
|
||
color: #b9770a;
|
||
}
|
||
|
||
/* ---------- chip 多选 / 展示 ---------- */
|
||
.field-label {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: var(--muted);
|
||
margin: 14px 2px 8px;
|
||
}
|
||
.chip-row {
|
||
display: inline-flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
margin-top: 4px;
|
||
}
|
||
.chip-row-pick {
|
||
display: flex;
|
||
}
|
||
.chip {
|
||
font-size: 12px;
|
||
border-radius: 999px;
|
||
padding: 5px 12px;
|
||
font-weight: 600;
|
||
line-height: 1.4;
|
||
}
|
||
.chip-static {
|
||
background: rgba(var(--green-rgb) / 0.12);
|
||
color: var(--wx-green-dark);
|
||
}
|
||
.chip-toggle {
|
||
border: none;
|
||
cursor: pointer;
|
||
background: var(--trough);
|
||
color: var(--muted);
|
||
box-shadow: inset 0 1px 2px rgba(var(--shadow) / 0.16);
|
||
transition: transform 0.15s cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
.chip-toggle:active {
|
||
transform: scale(0.95);
|
||
}
|
||
.chip-toggle.on {
|
||
background: var(--wx-green);
|
||
color: #fff;
|
||
box-shadow: var(--crease-accent);
|
||
}
|
||
|
||
/* ---------- 空状态 ---------- */
|
||
.empty-state {
|
||
text-align: center;
|
||
padding: 30px 16px 36px;
|
||
}
|
||
.empty-blob {
|
||
width: 96px;
|
||
height: 96px;
|
||
margin: 0 auto 16px;
|
||
border-radius: 50%;
|
||
background: var(--surface);
|
||
box-shadow: var(--crease);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 40px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.empty-blob::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
background: var(--sheen);
|
||
}
|
||
.empty-title {
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
}
|
||
.empty-sub {
|
||
margin-top: 6px;
|
||
font-size: 13px;
|
||
color: var(--muted);
|
||
}
|