/**
 * 控制台首页皮肤
 *
 * 类名与版式 1:1 对齐 /前端demo：
 *   pages/console.html（DOM 结构）+ assets/css/base/console.css（数值）
 *   - bento 7fr/3fr、欢迎条 34/36 + 80px 头像、四宫格 18/20 + 32px 数值
 *   - 安全仪表盘 100×58 半圆、资源表 --status、右栏 5 卡
 *
 * 三条约束：
 *   1) 颜色一律用 theme-vars 令牌，不写第二套配色；
 *   2) 作用域全部挂在 .home-main 下（首页独占文件）；
 *   3) 侧栏/顶栏不在此文件重定义 —— 它们来自 clientarea 的 theme-ui.css。
 */

/* 内容区背景（网格）
 *
 * 选择器必须写成 html .el-main.home-main，不能只写 .home-main。
 * 原因：外壳 theme-ui.css 有一条 html .el-main { padding: …!important;
 * background: var(--bg-color) }，优先级 (0,1,1)，高于 .home-main 的 (0,1,0)，
 * 而且 background 简写会把 background-image 重置成 none。
 * 只写 .home-main 的话网格一直不渲染——之前柔光版的径向光晕也是这样被吃掉的。
 *
 * padding 不在这里写：它由外壳的 !important 接管，页面回写是死代码。
 *
 * 底纹：20px 点阵
 *   2px 直径圆点 / 18% 主色——淡蓝颗粒，与侧栏底色同一色相，
 *   整页看起来是「一张淡蓝的纸」，而不是灰底上撒了点
 *   background-attachment: fixed —— 纹理钉在视口上，页面滚动时不动，
 *   只有卡片在纹理上滑过；否则长列表滚到底时纹理跟着走，会显得「纸在动」
 * 底色带 fallback：--bg-color 若未定义会让底色透明，点阵浮在白底上更难看清。
 */
html .el-main.home-main {
  background-color: var(--bg-color, #f4f5f7);
  background-image: radial-gradient(circle, rgba(37, 99, 235, .18) 1px, transparent 1px);
  background-size: 20px 20px;
  background-attachment: fixed;
}

/* ===== 外层栅格：demo console.css:291-303 ===== */
.console-bento {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(260px, 3fr);
  gap: var(--space-20);
  align-items: start;
}
.console-bento-main,
.console-bento-side {
  display: flex;
  flex-direction: column;
  gap: 22px;
  min-width: 0;
}

/* ===== 一、欢迎条：demo console.css:151-225 =====
   demo 用 banner-1.png 位图 + rgba(10,12,28,.45) 遮罩，此处 1:1 还原 */
/* 圆角按容器尺寸分档，不是随机不同：
   XL 欢迎条 180px 高 → 20px（占 11%）
   L  标准卡片 110px+ → 14px（占 13%）
   M  图标方块 36px   → 10px
   S  内嵌小格 60px   → 8px
   XS 小标签 20px     → 6px
   Pill 状态胶囊      → 999px
   统一成 14px 的话，欢迎条会显得「硬」，小标签会显得「圆」。 */
.welcome-banner {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-24);
  padding: 34px var(--space-36);
  /* 钉死高度：内容列在「骨架 / 真实」两态下差 7px（179 / 186，实测），
     会让下方所有卡片整体上下移动，所以钉在加载后的真实高度 186。
     box-sizing 必须显式写 border-box：本元素拿不到全局的 border-box
     （外壳那条 html .el-main > * 只作用于 .el-main 的直接子元素，也就是
     .console-bento），默认 content-box 下 min-height 不含 34×2 的 padding，
     写 187 实际渲染成 255 —— 欢迎条被凭空撑高 69px。 */
  box-sizing: border-box;
  min-height: 186px;
  border-radius: 12px;
  /* 位图本身很重，投影用中性色不用主色——染蓝会让图片看起来在发蓝光 */
  box-shadow: 0 2px 4px rgba(16, 24, 40, .08), 0 12px 28px rgba(16, 24, 40, .10);
  overflow: hidden;
  background-image: url('../img/banner-1.png');
  background-size: cover;
  background-position: center;
}
.welcome-banner::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(10, 12, 28, .45);
  pointer-events: none;
}
.welcome-avatar {
  position: relative;
  z-index: 1;
  width: 80px;
  height: 80px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: rgba(255, 255, 255, .12);
  color: #ffffff;
  font-size: var(--fs-32);
  font-weight: 900;
  line-height: 1;
  cursor: pointer;
}
.welcome-info {
  position: relative;
  z-index: 1;
  flex: 1;
  min-width: 0;
}
.welcome-greeting {
  margin-bottom: 2px;
  font-family: var(--font-mono);
  font-size: var(--fs-14);
  /* demo 未设 line-height（继承 normal），body 的 1.5 会放大行高 → 显式归位 */
  line-height: normal;
  color: rgba(255, 255, 255, .55);
}
.welcome-name {
  margin-bottom: 6px;
  font-size: var(--fs-26);
  font-weight: 900;
  /* demo 无 line-height，normal = 26×~1.2 ≈ 31px（此前 --lh-heading 1.3 偏高） */
  line-height: normal;
  color: #ffffff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.welcome-level {
  font-size: var(--fs-13);
  font-weight: 700;
  cursor: pointer;
}
.welcome-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-16);
  font-family: var(--font-mono);
  font-size: var(--fs-13);
  line-height: normal; /* 同 demo：无显式行高 */
  color: rgba(255, 255, 255, .5);
}
.welcome-binds {
  display: flex;
  gap: 10px;
  margin-top: 12px;
}
.welcome-bind {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 14px;
  font-size: var(--fs-13);
  font-weight: 700;
  line-height: normal; /* demo 徽章高 27 = 5+17+5 */
  background: rgba(255, 255, 255, .14);
  color: rgba(255, 255, 255, .9);
}
.welcome-bind--off {
  background: rgba(255, 255, 255, .06);
  color: rgba(255, 255, 255, .4);
}
.welcome-actions {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 10px;
  flex-shrink: 0;
}
.welcome-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px var(--space-20);
  font-size: var(--fs-14);
  font-weight: 700;
  font-family: inherit;
  border: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--motion-base), color var(--motion-base);
}
.welcome-btn--white {
  background: #ffffff;
  color: var(--brand-blue);
}
.welcome-btn--white:hover {
  background: rgba(255, 255, 255, .9);
}
.welcome-btn--glass {
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .18);
  color: #ffffff;
}
.welcome-btn--glass:hover {
  background: rgba(255, 255, 255, .22);
}

/* ===== 二、四宫格统计：demo console.css:228-288 ===== */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-16);
}
.stat-card {
  padding: 18px var(--space-20);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
  /* 数值行在骨架态比真实态矮 2px（0 台 / 4 条 与实际字高不同），钉住。
     border-box：让 min-height 表示含 padding 的总高，别被 18×2 再叠加一次。 */
  box-sizing: border-box;
  min-height: 100px;
  cursor: default;
}
.stat-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-8);
}
.stat-card-label {
  font-size: var(--fs-13);
  font-weight: 600;
  line-height: normal; /* demo 无显式行高（17px），body 1.5 会变 19.5 */
  color: var(--text-4);
}
.stat-card-icon {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
}
.stat-card-icon .ss-icon,
.stat-card-icon svg {
  width: 16px;
  height: 16px;
}
.stat-card-icon--blue { background: var(--brand-blue-tint-10); color: var(--brand-blue); }
.stat-card-icon--green { background: rgba(34, 197, 94, .1); color: var(--success); }
.stat-card-icon--amber { background: rgba(245, 158, 11, .1); color: var(--warning); }
.stat-card-icon--red { background: rgba(225, 29, 72, .1); color: var(--danger-bright); }
.stat-card-value {
  font-family: var(--font-numbers);
  font-size: var(--fs-32);
  font-weight: 500;
  line-height: var(--lh-compact);
  letter-spacing: -.5px;
  color: var(--text-main);
}
.stat-card-value .unit {
  margin-left: 6px;
  font-family: "Microsoft YaHei", "微软雅黑", sans-serif;
  font-size: var(--fs-14);
  font-weight: 700;
  color: var(--text-4);
}
.stat-card-value--success { color: var(--success); }
.stat-card-value--danger { color: var(--danger-vivid); }
.stat-card-footer {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--divider);
}
.stat-card-link {
  font-family: var(--font-mono);
  font-size: var(--fs-13);
  color: var(--text-5);
  cursor: pointer;
}
.stat-card-link:hover { color: var(--brand-blue); }
.stat-card-link--accent { color: var(--brand-blue); }

/* ===== 三、卡片基类：demo .cy-card console.css:314-330 ===== */
/* 卡片 / 卡头 / 分区标记 / 表格的定义已收口到 ss-ui.css 第 13 节
   （.ss-card ∪ .cy-card 共用一份），这里只留首页自己的卡内元素。 */
.cy-card-link {
  font-size: var(--fs-12);
  font-weight: 500;
  color: var(--text-5);
  cursor: pointer;
  transition: color var(--motion-fast);
}
.cy-card-link:hover { color: var(--brand-blue); }

/* ===== 并排行：demo .bento-row console.css:306-311（3fr/7fr） ===== */
.bento-row {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 7fr);
  gap: var(--space-20);
  /* 原来是 start：两卡各算各的高度（账号安全 199 / 最近活动 240），并排看
     底边错开一截。改成 stretch 让同一行的卡等高——矮的那张被拉齐，
     而不是去砍高那张的内容（日志条数是数据给的，砍了就永远对不齐）。 */
  align-items: stretch;
}

/* ===== 情绪问候卡 ===== */
/* 这张卡不做数据，只负责「页面有人味」。
   核心是右上角那团柔光：按时段换色（清晨琥珀、白天蓝、傍晚紫、深夜靛），
   不写一个字也在提示「现在是什么时候」。文字只留三行，其余交给留白。 */
.cy-card--mood {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.cy-card--mood::after {
  content: "";
  position: absolute;
  top: -56px;
  right: -56px;
  width: 180px;
  height: 180px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, var(--mood-glow) 0%, rgba(255, 255, 255, 0) 70%);
  /* 10 秒一轮的极缓呼吸：不动的时候像静态，盯着看才发现它在起伏 */
  animation: mood-breathe 10s ease-in-out infinite;
}
@keyframes mood-breathe {
  0%, 100% { opacity: .82; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.07); }
}
.cy-card--mood.is-late { --mood-glow: rgba(99, 102, 241, .16); }
.cy-card--mood.is-morning { --mood-glow: rgba(245, 158, 11, .16); }
.cy-card--mood.is-noon { --mood-glow: rgba(37, 99, 235, .13); }
.cy-card--mood.is-evening { --mood-glow: rgba(139, 92, 246, .15); }
/* 暗色底上同样的 alpha 会显得发灰，换亮一档的色号并把透明度抬高 */
[data-theme="dark"] .cy-card--mood.is-late { --mood-glow: rgba(129, 140, 248, .28); }
[data-theme="dark"] .cy-card--mood.is-morning { --mood-glow: rgba(251, 191, 36, .24); }
[data-theme="dark"] .cy-card--mood.is-noon { --mood-glow: rgba(96, 165, 250, .24); }
[data-theme="dark"] .cy-card--mood.is-evening { --mood-glow: rgba(167, 139, 250, .26); }
.cy-card--mood .cy-card-body {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}
.cy-mood-hero {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 12px;
}
.cy-mood-greet {
  font-size: 40px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -1px;
  color: var(--text-main);
}
.cy-mood-note {
  font-size: var(--fs-13);
  line-height: 1.6;
  color: var(--text-4);
}
.cy-mood-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-top: 10px;
  border-top: 1px solid var(--divider);
  font-size: var(--fs-11);
  color: var(--text-5);
}
.cy-mood-tag {
  font-family: var(--font-mono);
  font-weight: 700;
  letter-spacing: 1px;
}

/* ===== 最近活动：demo .cy-log console.css:663-680 ===== */
.cy-log-list,
.cy-news-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* 时间轴：左边一条竖线 + 节点，时间移到右端。
   普通列表里时间和内容挤在同一行，扫读时两种信息互相干扰；
   时间右对齐后，左列是「发生了什么」，右列是「什么时候」，各读各的。 */
.cy-log {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 9px 0 9px 16px;
}
.cy-log::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--divider);
}
/* 首尾不画全高，线只在节点之间延伸 */
.cy-log:first-child::before { top: 15px; }
.cy-log:last-child::before { bottom: calc(100% - 16px); }
.cy-log::after {
  content: "";
  position: absolute;
  left: 0;
  top: 12px;
  width: 7px;
  height: 7px;
  box-sizing: border-box;
  border-radius: 50%;
  background: var(--surface);
  border: 1.5px solid #b9c9ea;
}
.cy-log-time {
  order: 2;
  flex-shrink: 0;
  margin-left: auto;
  font-family: var(--font-numbers);
  font-size: var(--fs-11);
  color: var(--text-5);
  white-space: nowrap;
}
.cy-log-text {
  order: 1;
  flex: 1;
  font-size: var(--fs-13);
  line-height: var(--lh-base);
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cy-empty {
  padding: var(--space-24) 0;
  font-size: var(--fs-13);
  color: var(--text-5);
  text-align: center;
}
.cy-card--activity .cy-card-body {
  max-height: 200px;
  overflow: hidden;
}
.cy-news-scroll {
  /* 限高 180 = 5 行，超出仍可滚（鼠标滚轮 / 触控板 / 键盘都能滚），只是不画
     滚动条：这条滚动条太窄、颜色又淡，挂在卡片右侧更像一道划痕。 */
  max-height: 180px;
  overflow-y: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.cy-news-scroll::-webkit-scrollbar {
  width: 0;
  height: 0;
}

/* 到期列：原来只有一个日期，看不出还有几天。
   倒计时给「多少天」，3px 条给「紧迫到什么程度」——扫一列就能找到该续费的。
   条的宽度不是「已用时长」，而是 30 天兜底期的消耗度：越接近 100% 越紧急。 */
.cy-due-text {
  font-family: var(--font-numbers);
  font-size: var(--fs-12);
  color: var(--text-3);
  white-space: nowrap;
}
.cy-due-text.is-warn { color: var(--warning); }
.cy-due-text.is-danger { color: var(--danger); font-weight: 600; }
.cy-due-bar {
  width: 56px;
  height: 3px;
  margin: 5px 0 0 auto;
  border-radius: 2px;
  background: var(--divider);
  overflow: hidden;
}
.cy-due-bar > span {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--brand-blue);
  transition: width .4s ease;
}
.cy-due-bar > span.is-warn { background: var(--warning); }
.cy-due-bar > span.is-danger { background: var(--danger); }

/* ===== 资源表：demo .cy-table console.css:448-527 ===== */
.cy-table-wrap {
  width: 100%;
  overflow-x: auto;
  max-height: 380px;
}
/* 表格基类同样在 ss-ui.css 第 13 节，这里只留本页的列宽/对齐修饰 */
.cy-table--status { min-width: 820px; }
.cy-table th.cy-th-center { text-align: center; }
.cy-table th.cy-th-right { text-align: right; }
.cy-table th.cy-th-check { width: 30px; }
.cy-table td.cy-td-strong { font-weight: 700; }
.cy-table td.cy-td-mono { font-family: var(--font-mono); }
.cy-table td.cy-td-center { text-align: center; }
.cy-table td.cy-td-date {
  text-align: right;
  font-family: var(--font-mono);
}
.cy-table td.cy-td-strong.cy-td-date { color: var(--warning); }
.cy-td-link {
  color: var(--text-main);
  font-weight: 700;
}
.cy-td-link:hover { color: var(--brand-blue); }
.cy-st-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.cy-st-dot--ok {
  background: var(--success);
  box-shadow: 0 0 0 3px rgba(34, 197, 94, .2);
}
.cy-st-dot--warn {
  background: var(--warning);
  box-shadow: 0 0 0 3px rgba(245, 158, 11, .2);
}
.cy-st-tag {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 10px;
  border-radius: 999px;
  font-size: var(--fs-11);
  font-weight: 500;
  white-space: nowrap;
}
.cy-st-tag--ok {
  background: rgba(34, 197, 94, .1);
  color: var(--success);
}
.cy-st-tag--warn {
  background: rgba(245, 158, 11, .1);
  color: var(--warning);
}
.cy-empty-box {
  /* 与骨架表（thead + 4 行 = 220px）等高，切换过去时整卡不跳。
     220 是含上下 48px padding 的总高，所以必须 border-box；
     content-box 下原来的 246 实际渲染成 342，空态卡比骨架态高 122px。 */
  box-sizing: border-box;
  min-height: 220px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--space-48) var(--space-20);
  text-align: center;
}
.cy-empty-box h2 {
  margin-bottom: var(--space-8);
  font-size: var(--fs-15);
  font-weight: 700;
  color: var(--text-main);
}
.cy-empty-box p {
  margin-bottom: var(--space-16);
  font-size: var(--fs-13);
  color: var(--text-5);
}

/* ===== 余额 / 按钮：demo console.css:352-374 + 529-566 ===== */
.cy-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: var(--space-8) 18px;
  font-size: var(--fs-12);
  font-weight: 700;
  font-family: inherit;
  border: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--motion-base), color var(--motion-base);
}
.cy-btn--blue {
  background: var(--brand-blue);
  color: #ffffff;
}
.cy-btn--blue:hover { background: var(--brand-blue-dark); }
.cy-btn--ghost {
  background: var(--accent-tint);
  border: 1px solid var(--card-border);
  color: var(--text-3);
}
.cy-btn--ghost:hover {
  color: var(--brand-blue);
  border-color: var(--brand-blue);
  background: var(--brand-blue-tint-06);
}
.cy-btn--sm {
  padding: 5px 12px;
  font-size: var(--fs-11);
}
.cy-balance-label {
  margin-bottom: 6px;
  font-size: var(--fs-13);
  color: var(--text-4);
}
.cy-balance-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.cy-balance-value {
  font-family: var(--font-numbers);
  font-size: var(--fs-28);
  font-weight: 500;
  line-height: var(--lh-solid);
  color: var(--text-main);
}
.cy-balance-value--flat { letter-spacing: 0; }
.cy-balance-yen {
  margin-right: 2px;
  font-size: var(--fs-14);
  color: var(--accent, var(--brand-blue));
  font-weight: 500;
}
/* ===== 余额 / 按钮：demo console.css:352-374 + 529-566 ===== */
.cy-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: var(--space-8) 18px;
  font-size: var(--fs-12);
  font-weight: 700;
  font-family: inherit;
  border: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--motion-base), color var(--motion-base);
}
.cy-btn--blue {
  background: var(--brand-blue);
  color: #ffffff;
}
.cy-btn--blue:hover { background: var(--brand-blue-dark); }
.cy-btn--ghost {
  background: var(--accent-tint);
  border: 1px solid var(--card-border);
  color: var(--text-3);
}
.cy-btn--ghost:hover {
  color: var(--brand-blue);
  border-color: var(--brand-blue);
  background: var(--brand-blue-tint-06);
}
.cy-btn--sm {
  padding: 5px 12px;
  font-size: var(--fs-11);
}
.cy-balance-label {
  margin-bottom: 6px;
  font-size: var(--fs-13);
  color: var(--text-4);
}
.cy-balance-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.cy-balance-value {
  font-family: var(--font-numbers);
  font-size: var(--fs-28);
  font-weight: 500;
  line-height: var(--lh-solid);
  color: var(--text-main);
}
.cy-balance-value--flat { letter-spacing: 0; }
.cy-balance-yen {
  margin-right: 2px;
  font-size: var(--fs-14);
  color: var(--accent, var(--brand-blue));
  font-weight: 500;
}
.cy-mini-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 12px;
}
.cy-mini-card {
  flex: 1;
  padding: 10px 14px;
  border-radius: 8px;
  background: var(--accent-tint);
}
.cy-mini-label {
  margin-bottom: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--fs-13);
  color: var(--text-5);
}
.cy-mini-val {
  font-family: var(--font-numbers);
  font-size: var(--fs-20);
  font-weight: 500;
  color: var(--text-main);
}

/* KV 行 / 提示行 */
.cy-kv {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-12);
  padding: 10px 0;
  border-bottom: 1px solid var(--divider);
}
.cy-kv:last-child { border-bottom: none; }
.cy-kv-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-13);
  color: var(--text-4);
}
.cy-kv-val {
  font-family: var(--font-numbers);
  font-size: var(--fs-13);
  font-weight: 500;
  color: var(--text-main);
  white-space: nowrap;
}

/* ===== 财务总览：demo .cy-finance console.css:552-558 ===== */
/* 原来是两行「标签 空格 数值」，读起来像表格行，不像卡片。
   改成左右两段指标：标签在上、数值在下，中间一条竖分隔。 */
.cy-finance-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  /* 加载后数值行含「环比」胶囊，比纯骨架高 4px —— 钉住，避免把下面两张卡推走 */
  box-sizing: border-box;
  min-height: 40px;
  margin-top: 6px;
}
.cy-finance-row {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}
.cy-finance-row + .cy-finance-row {
  padding-left: 14px;
  border-left: 1px solid var(--divider);
}
.cy-finance-label {
  font-size: var(--fs-12);
  color: var(--text-5);
  white-space: nowrap;
}
.cy-finance-amount {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
  /* 骨架态这一行只有 16px 的金额（line-height:1），真实态多一枚「环比」胶囊
     （fs-12 + padding 1px → 20px），整行从 16 长到 20，把整张卡和下面的卡
     一起推下去 4px。钉住行高，两态都是 20。—— 注意是钉行盒不是钉 grid：
     grid 的 min-height 只能兜住「内容比它矮」，兜不住「内容比它高」。 */
  min-height: 20px;
}
.cy-finance-value {
  font-family: var(--font-numbers);
  font-size: var(--fs-16);
  font-weight: 600;
  letter-spacing: -.3px;
  line-height: var(--lh-solid);
  color: var(--text-main);
}
.cy-trend {
  font-family: var(--font-numbers);
  font-size: var(--fs-12);
  font-weight: 700;
  padding: 1px 6px;
}
.cy-trend--up {
  color: var(--success);
  background: rgba(34, 197, 94, .08);
}
.cy-trend--down {
  color: var(--danger-bright);
  background: rgba(225, 29, 72, .08);
}

/* ===== API 信息：demo .cy-api console.css:683-692 ===== */
.cy-api {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 0;
  border-bottom: 1px solid var(--divider);
}
.cy-api:last-child { border-bottom: none; }
/* 未激活时整行转「引导态」：虚线框 + 下方一行说明。
   原状只是一行灰字，用户扫过去不会意识到这里缺东西。 */
.cy-api.is-off {
  margin-top: 6px;
  padding: 10px 12px;
  border: 1px dashed var(--card-border);
  border-radius: 10px;
  background: var(--surface-muted);
}
.cy-api-hint {
  margin: 8px 0 0;
  font-size: var(--fs-12);
  line-height: 1.6;
  color: var(--text-5);
}
.cy-api-name {
  font-size: var(--fs-13);
  font-weight: 700;
  color: var(--text-main);
}
.cy-api-st {
  font-family: var(--font-mono);
  font-size: var(--fs-13);
  font-weight: 700;
}
.cy-api-st--on { color: var(--success); }
.cy-api-st--off { color: var(--danger-bright); }

/* ===== 新闻 / 公告：demo .cy-news console.css:694-707 ===== */
/* 日期移到左侧当「日期戳」：左列对齐成一条时间轴，标题在右列自由伸展。
   原来是「标签 + 标题 + 日期」三件挤一行，窄栏里必然折行。 */
.cy-news {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  align-items: baseline;
  gap: 0 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--divider);
  cursor: pointer;
}
.cy-news:last-child { border-bottom: none; }
.cy-news:hover .cy-news-text { color: var(--brand-blue); }
.cy-news-text {
  font-size: var(--fs-13);
  line-height: var(--lh-base);
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cy-news-date {
  font-family: var(--font-numbers);
  font-size: var(--fs-11);
  color: var(--text-5);
  white-space: nowrap;
}
.cy-news-pin {
  width: fit-content;
  padding: 2px 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-12);
  font-weight: 800;
  color: #ffffff;
}
.cy-news-pin--top { background: var(--brand-blue); }
.cy-news-pin--new { background: var(--brand-cyan); }
.cy-news-pin--normal { background: var(--text-5); }

/* ===== 动态卡：新闻 / 公告两组 ===== */
.cy-feed-group + .cy-feed-group {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--divider);
}
.cy-feed-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
  margin-bottom: 2px;
}
.cy-feed-title {
  font-size: var(--fs-12);
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: .02em;
}

/* ===== 微信公众号浮标 ===== */
.wx-code {
  position: fixed;
  top: 50%;
  right: 3px;
  z-index: 100;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--card-border);
  box-shadow: var(--shadow-card);
  transform: translateY(50%);
  cursor: pointer;
}
.wx-code .wx-img {
  width: 40px;
  height: 40px;
  background: url('../img/wx.svg') no-repeat;
  background-size: 100% 100%;
}
.wx-code:hover .wx-img {
  background: url('../img/wx_hover.svg') no-repeat;
  background-size: 100% 100%;
}
.wx-box {
  text-align: center;
}
.wx-box .tit {
  margin-bottom: var(--space-8);
  font-size: var(--fs-13);
  color: var(--text-main);
}
.wx-box .img {
  width: 200px;
  height: 200px;
}

/* ===== 响应式：demo console.css:739-755 ===== */
/* ============================================================
   首屏骨架
   目标不是「好看」，是让卡片在数据到达前就占住最终尺寸。
   三条规则保证不抖：
   1) 内联骨架高度用 em，跟着所在元素的字号走 —— 行盒高度不变
   2) 列表/表格骨架的行高与真实行一致（同样的 padding + 同样的条高）
   3) 骨架与真实内容包在同一个定高容器里，切换只换子节点
   ============================================================ */
.sk {
  display: inline-block;
  border-radius: 4px;
  background: linear-gradient(90deg, #e9eef7 25%, #f4f8fe 37%, #e9eef7 63%);
  background-size: 400% 100%;
  animation: sk-shimmer 1.5s ease infinite;
}
@keyframes sk-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
/* 文字骨架的字面高度
 *
 * 之前统一 .68em + vertical-align: middle —— 两个问题：
 *   1) .68em 对数字偏矮（DINPro / 雅黑的数字 cap height 约 .72em）
 *   2) middle 是把「条的垂直中点」对齐到「基线 + 半个 x-height」，
 *      条底并不落在基线上，和数字下缘错开
 *
 * 现在按字面高度分两档，并统一 vertical-align: baseline ——
 * 无内容的 inline-block 以「下外边距边」作为基线，正好贴在文字基线上，
 * 数字的下缘就在基线，两者对齐。
 *
 *   数字 / 拉丁文字：.76em（cap height 上限，略高于 .72 是留一点呼吸）
 *   中文：.88em（微软雅黑汉字字面约占 .88em）
 */
.sk-text {
  height: .76em;
  vertical-align: baseline;
}
/* 中文：字面高 .90em，且下缘低于基线约 .08em —— 无内容的 inline-block
   以底部作基线，只靠 baseline 对齐会让条底停在基线上，比汉字下缘高 3px。
   实测（26px 用户名）：文字墨迹 138..161，条需要 137..161，
   故 height .90em + top .08em。 */
.sk-text--cjk {
  height: .90em;
  position: relative;
  top: .08em;
}
/* 金额：￥ 是等高符号，比纯数字高一档（实测 16px 下 13px vs 12px） */
.sk-text--money {
  height: .82em;
}
.sk-block { display: block; }
.sk-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
}
/* 深色底上的骨架：欢迎条压在深色位图上，浅灰条会像贴纸，
   换成白色低透明度，读起来是「这块还没加载」而不是「这块坏了」 */
.sk--on-dark {
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, .10) 25%,
    rgba(255, 255, 255, .24) 37%,
    rgba(255, 255, 255, .10) 63%
  );
  background-size: 400% 100%;
}
/* 徽章占位：尺寸与 .welcome-bind 一致（高 27 = 5 + 17 + 5，方角无圆角） */
.sk-pill {
  width: 86px;
  height: 27px;
  border-radius: 3px;
}
/* 头像位：直接给圆形底做微光，比在里面塞一根横条自然 */
.welcome-avatar.is-sk {
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, .12) 25%,
    rgba(255, 255, 255, .26) 37%,
    rgba(255, 255, 255, .12) 63%
  );
  background-size: 400% 100%;
  animation: sk-shimmer 1.5s ease infinite;
}
/* 大块（图表、表格行）用整体呼吸，不做扫光——扫光在大面积上会晃眼 */
.cy-table tbody .sk {
  animation: sk-pulse 1.6s ease-in-out infinite;
}
@keyframes sk-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: .55; }
}
/* 真实内容替换进来时淡入，避免硬切 */
@keyframes boot-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.cy-log-list,
.cy-news-list,
.cy-table tbody {
  animation: boot-in .28s ease both;
}
@media (prefers-reduced-motion: reduce) {
  .cy-card--mood::after { animation: none; }
  .sk,
  .cy-table tbody .sk { animation: none; }
  .cy-log-list,
  .cy-news-list,
  .cy-table tbody { animation: none; }
}

@media (max-width: 1400px) {
  .stats-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 1200px) {
  .console-bento {
    grid-template-columns: minmax(0, 1fr);
  }
  .console-bento-side {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
  }
}
@media (max-width: 900px) {

  .welcome-banner {
    flex-direction: column;
    text-align: center;
    padding: 28px 24px;
  }
  .welcome-avatar { margin: 0 auto; }
  .welcome-binds,
  .welcome-actions,
  .welcome-meta { justify-content: center; }
  .bento-row { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 700px) {
  .console-bento-side { grid-template-columns: minmax(0, 1fr); }
  .stats-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ===== 调试面板：召唤提示条（仅首页，?nodebug 隐藏） ===== */
/* 开发期用来比对五种配色与出入场动画，不属于产品界面。
   做成右下角一颗虚线小胶囊，默认收起、颜色压到最淡，
   不点它几乎看不见；点击后在它上方展开五个按钮。 */
.cy-debug {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 2900;                  /* 低于提示条（3000），点了才看得到提示盖在它上面 */
  display: flex;
  flex-direction: column-reverse; /* 面板向上展开，不会越过窗口底边 */
  align-items: flex-end;
  gap: 8px;
}
.cy-debug-toggle {
  height: 28px;
  padding: 0 12px;
  border: 1px dashed var(--card-border);
  border-radius: 999px;
  background: var(--surface, #fff);
  color: var(--text-5);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .14em;
  cursor: pointer;
  transition: color .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.cy-debug-toggle:hover,
.cy-debug.is-open .cy-debug-toggle {
  color: var(--text-main);
  border-color: var(--text-4);
  box-shadow: 0 6px 16px rgba(15, 23, 42, .08);
}
.cy-debug-panel {
  display: none;
  flex-direction: column;
  gap: 2px;
  min-width: 136px;
  padding: 6px;
  border: 1px solid var(--card-border);
  border-radius: 12px;
  background: var(--surface, #fff);
  box-shadow: 0 12px 28px rgba(15, 23, 42, .12);
}
.cy-debug.is-open .cy-debug-panel { display: flex; }
.cy-debug-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-3);
  font-size: var(--fs-12);
  text-align: left;
  cursor: pointer;
  transition: background-color .16s ease;
}
.cy-debug-item:hover { background: var(--surface-muted, #f7fafe); }
/* 小圆点跟提示条同色，一眼对上是哪一种 */
.cy-debug-item i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}
.cy-debug-item[data-toast="success"] i { background: var(--success-deep); }
.cy-debug-item[data-toast="info"] i { background: #1e3a8a; }
.cy-debug-item[data-toast="warning"] i { background: #78350f; }
.cy-debug-item[data-toast="error"] i { background: #7f1d1d; }
.cy-debug-item[data-toast="default"] i { background: var(--text-4); }
.cy-debug-meta {
  margin-top: 4px;
  padding: 6px 10px 2px;
  border-top: 1px solid var(--divider);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .06em;
  color: var(--text-5);
}
.cy-debug-meta:empty { display: none; }

/* ============================================================
   情绪问候卡 · 氛围加强
   原来只有右上角一团 180px 柔光，存在感偏弱。这里：
     1) 主光放大到 260px、呼吸幅度加大
     2) 左下补一团互补色光，两张光不同周期，形成缓慢的呼吸错位
     3) 问候语改渐变文字，从正文色过渡到主色
     4) 卡片正文铺一层按时段变化的斜向柔光
   ============================================================ */
.cy-card--mood::after {
  top: -70px;
  right: -70px;
  width: 260px;
  height: 260px;
  filter: blur(1px);
  animation: mood-breathe 8s ease-in-out infinite;
}
@keyframes mood-breathe {
  0%, 100% { opacity: .7; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.12); }
}

/* 左下互补光 */
.cy-card--mood::before {
  content: "";
  position: absolute;
  left: -90px;
  bottom: -100px;
  width: 240px;
  height: 240px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, var(--mood-glow-2) 0%, rgba(255, 255, 255, 0) 70%);
  animation: mood-breathe-2 13s ease-in-out infinite;
}
@keyframes mood-breathe-2 {
  0%, 100% { opacity: .45; transform: scale(1); }
  50% { opacity: .85; transform: scale(1.15); }
}
.cy-card--mood.is-late { --mood-glow-2: rgba(139, 92, 246, .11); }
.cy-card--mood.is-morning { --mood-glow-2: rgba(251, 113, 133, .11); }
.cy-card--mood.is-noon { --mood-glow-2: rgba(14, 165, 233, .1); }
.cy-card--mood.is-evening { --mood-glow-2: rgba(99, 102, 241, .12); }
[data-theme="dark"] .cy-card--mood.is-late { --mood-glow-2: rgba(167, 139, 250, .2); }
[data-theme="dark"] .cy-card--mood.is-morning { --mood-glow-2: rgba(251, 113, 133, .18); }
[data-theme="dark"] .cy-card--mood.is-noon { --mood-glow-2: rgba(56, 189, 248, .18); }
[data-theme="dark"] .cy-card--mood.is-evening { --mood-glow-2: rgba(129, 140, 248, .2); }

/* 正文一层按时段走的斜向柔光 */
.cy-card--mood .cy-card-body {
  background: radial-gradient(120% 110% at 100% 0%, var(--mood-glow) 0%, rgba(255, 255, 255, 0) 62%);
}

/* 问候语渐变文字 */
.cy-mood-greet {
  background: linear-gradient(118deg, var(--text-main) 28%, var(--brand-blue) 96%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
[data-theme="dark"] .cy-mood-greet {
  background: linear-gradient(118deg, var(--text-main) 24%, var(--brand-blue-light) 96%);
  -webkit-background-clip: text;
  background-clip: text;
}

/* 左下互补光加强：提高色浓度与基础不透明度，尺寸再放大一档 */
.cy-card--mood::before {
  left: -100px;
  bottom: -110px;
  width: 280px;
  height: 280px;
  animation: mood-breathe-2 13s ease-in-out infinite;
}
@keyframes mood-breathe-2 {
  0%, 100% { opacity: .6; transform: scale(1); }
  50% { opacity: .95; transform: scale(1.15); }
}
.cy-card--mood.is-late { --mood-glow-2: rgba(139, 92, 246, .22); }
.cy-card--mood.is-morning { --mood-glow-2: rgba(251, 113, 133, .22); }
.cy-card--mood.is-noon { --mood-glow-2: rgba(14, 165, 233, .2); }
.cy-card--mood.is-evening { --mood-glow-2: rgba(99, 102, 241, .24); }
[data-theme="dark"] .cy-card--mood.is-late { --mood-glow-2: rgba(167, 139, 250, .36); }
[data-theme="dark"] .cy-card--mood.is-morning { --mood-glow-2: rgba(251, 113, 133, .34); }
[data-theme="dark"] .cy-card--mood.is-noon { --mood-glow-2: rgba(56, 189, 248, .34); }
[data-theme="dark"] .cy-card--mood.is-evening { --mood-glow-2: rgba(129, 140, 248, .36); }

/* ============================================================
   首页卡片质感：三层阴影 + 顶部内高光 + 极淡渐变底
   阴影用主色染色（不是纯黑），卡片才有「透」的感觉；
   内高光模拟顶光，卡片上边缘有一道反光。
   ============================================================ */
.cy-card {
  background: linear-gradient(180deg, var(--surface) 0%, var(--surface-muted) 100%);
  box-shadow:
    0 1px 2px rgba(15, 23, 42, 0.04),
    0 4px 12px rgba(15, 23, 42, 0.05),
    0 12px 32px rgba(37, 99, 235, 0.06),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
}
/* 暗色：底色渐变保持同色系，阴影转纯黑加深，内高光降到极弱 */
[data-theme="dark"] .cy-card {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 4px 14px rgba(0, 0, 0, 0.28),
    0 14px 36px rgba(0, 0, 0, 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

/* ============================================================
   卡片质感降档（上一版叠太狠，看久了累）
   问题：三层阴影 + 内高光 + 渐变底同时存在，每张卡都在抢视线。
   处理：
     - 阴影减到两层，大扩散那层去掉
     - 内高光弱化到几乎察觉不到
     - 渐变底回退成纯色，背景要安静
   立体感靠「一层接触阴影 + 一层极淡染色」就够，多了就是噪音。
   ============================================================ */
.cy-card {
  background: var(--surface);
  box-shadow:
    0 1px 2px rgba(15, 23, 42, 0.03),
    0 3px 10px rgba(37, 99, 235, 0.04);
}
[data-theme="dark"] .cy-card {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.24),
    0 4px 12px rgba(0, 0, 0, 0.2);
}

/* 情绪卡左下光回调：峰值不再顶到接近实色 */
.cy-card--mood::before {
  animation: mood-breathe-2 13s ease-in-out infinite;
}
@keyframes mood-breathe-2 {
  0%, 100% { opacity: 0.45; transform: scale(1); }
  50% { opacity: 0.75; transform: scale(1.1); }
}
.cy-card--mood.is-late { --mood-glow-2: rgba(139, 92, 246, 0.17); }
.cy-card--mood.is-morning { --mood-glow-2: rgba(251, 113, 133, 0.17); }
.cy-card--mood.is-noon { --mood-glow-2: rgba(14, 165, 233, 0.16); }
.cy-card--mood.is-evening { --mood-glow-2: rgba(99, 102, 241, 0.18); }
[data-theme="dark"] .cy-card--mood.is-late { --mood-glow-2: rgba(167, 139, 250, 0.28); }
[data-theme="dark"] .cy-card--mood.is-morning { --mood-glow-2: rgba(251, 113, 133, 0.26); }
[data-theme="dark"] .cy-card--mood.is-noon { --mood-glow-2: rgba(56, 189, 248, 0.26); }
[data-theme="dark"] .cy-card--mood.is-evening { --mood-glow-2: rgba(129, 140, 248, 0.28); }

/* 情绪卡主光也收一档，避免和左下光打架 */
.cy-card--mood::after {
  animation: mood-breathe 9s ease-in-out infinite;
}
@keyframes mood-breathe {
  0%, 100% { opacity: 0.62; transform: scale(1); }
  50% { opacity: 0.9; transform: scale(1.08); }
}

/* 欢迎条头像：QQ 头像铺满圆形（原样式是首字母文字，容器已 overflow:hidden） */
.welcome-avatar img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
