/* ============================================
   稳定性层
   解决三类抖动：字体回流(FOUT)、异步数据重排、
   数字宽度变化。全部用「预留尺寸」而非「等数据到」。
   ============================================ */

/* ── 1. 字体：避免 FOUT 导致重排 ── */
@font-face{
  font-family:'System Fallback';
  /* 本地系统字体立即可用，不发起网络请求，不产生 FOUT */
  src:local(-apple-system),local('PingFang SC'),local('Microsoft YaHei'),
      local('Helvetica Neue'),local('Segoe UI');
  font-display:swap;              /* 兜底：若确有外部字体也不阻塞渲染 */
  size-adjust:100%;
}
/* 首屏关键数字使用等宽数字，且预留最小宽度 */
.tabular{font-variant-numeric:tabular-nums;font-feature-settings:'tnum' 1}

/* ── 2. 骨架屏：数据到达前占位 ── */
.sk{
  position:relative;overflow:hidden;
  background:var(--c-line-soft);
  border-radius:var(--r-sm);
}
.sk::after{
  content:'';position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.65),transparent);
  animation:shimmer 1.4s infinite;
}
@keyframes shimmer{from{transform:translateX(-100%)}to{transform:translateX(100%)}}

/* 各区块的固定骨架高度 = 数据到位后的近似高度 */
.sk-line{height:13px;margin-bottom:9px}
.sk-line:last-child{margin-bottom:0}
.sk-line.w40{width:40%}
.sk-line.w60{width:60%}
.sk-line.w80{width:80%}
.sk-card{height:74px;margin-bottom:11px}
.sk-bars{height:110px}
.sk-chart{height:132px}

/* 容器进入加载态时隐藏真实内容，避免高度跳变 */
.loading .sk{display:block}
.loading > *:not(.sk){display:none}

/* ── 3. 尺寸预留：给动态区域固定最小高度 ── */
/* 收益三卡：数字最多 5 位 + 单位 */
.gain .n{
  min-height:30px;              /* 字号 26px 行高约 30 */
  display:flex;align-items:center;justify-content:center;
}
/* 计时主数字：预留 52px 行高，换数字不推挤下方 */
#heroNum{min-height:54px;display:flex;align-items:center;justify-content:center}
#heroSub{min-height:20px}     /* 一行文字高度 */
#chipDays{min-width:2ch;display:inline-block}

/* 卡片里可能为空/有内容的区域 */
#encourage{min-height:22px}
#riskBox{min-height:0}
#tgNote{min-height:0}
#trendExt{min-width:6ch;display:inline-block;text-align:right}

/* 日历固定 7 列 5 行高度 */
.cal{min-height:190px}
.cal .cd{min-height:34px}

/* 柱状图容器固定高度，最后一个 bar 有底部标签 */
#chartSmoke{min-height:132px}

/* 统计大数字 */
.stat .n{min-height:32px;display:flex;align-items:center;justify-content:center}

/* ── 4. 防止长内容撑破布局 ── */
.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.clamp2{
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;
}
.clamp3{
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden;
}

/* 数字容器不再因位数变化而抖动 */
.numfix{
  font-variant-numeric:tabular-nums;
  display:inline-block;min-width:var(--num-w,auto);
  text-align:right;
}

/* ── 5. 图片/图标占位，防加载后尺寸变化 ── */
.media{
  display:block;width:100%;aspect-ratio:1;object-fit:contain;
  background:var(--c-line-soft);
}

/* ── 6. 减少不必要的重排 ── */
.card,.panel,.row,.stat,.gain{
  /* 避免 transition 全部属性导致意外重排 */
  transition-property:background-color,border-color,box-shadow,transform,opacity;
}
/* 内容更新时不触发 layout shift */
#plist,#urgeList,#smokeList,#healthList,#badgeBox,#calBox,#riskList,#triggerBox{
  contain:layout style;
}

/* ── 7. 加载态与空态统一样式 ── */
.state-box{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  min-height:120px;gap:var(--sp-2);color:var(--c-ink-4);font-size:var(--t-sm);
  text-align:center;padding:var(--sp-4);
}
.state-box .icon{font-size:26px;opacity:.5}

/* ── 8. 减少动效：连布局动画一并关掉 ── */
@media (prefers-reduced-motion:reduce){
  .sk::after{animation:none}
  *{transition-duration:.01ms !important}
}
/* ── 安装引导横幅：曾用内联样式，移入此处便于统一维护 ── */
.install-bar{
  position:fixed;left:0;right:0;bottom:0;z-index:70;
  background:var(--c-primary);color:#fff;
  padding:var(--sp-3) var(--sp-4);
  display:flex;align-items:center;gap:var(--sp-3);
  box-shadow:0 -2px 14px rgba(15,123,108,.3);
  animation:slide-up var(--dur) var(--ease-out);
}
.install-bar[hidden]{display:none}
@keyframes slide-up{from{transform:translateY(100%)}to{transform:translateY(0)}}
.ib-text{flex:1;min-width:0}
.ib-text strong{display:block;font-size:var(--t-sm);font-weight:600}
.ib-text small{font-size:var(--t-xs);opacity:.88}
.ib-btn{padding:9px 16px;flex:0 0 auto;min-height:0}
.ib-x{
  background:none;border:none;color:#fff;font-size:20px;
  padding:0 4px;flex:0 0 auto;line-height:1;
}
/* 已安装为 App 时不再显示底部提示条 */
body.installed .install-bar{display:none!important}
