/* 抖音式竖滑信息流。刻意不用任何外部字体/图标/CDN —— 断网也能开。
   所有 SVG 图标都在 feed.html 里内联，颜色跟随 currentColor。 */

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0; padding: 0; height: 100%;
  background: #000; color: #fff; overflow: hidden;
  font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-user-select: none; user-select: none;
}

/* ── 滚动容器：一次只滑一屏 ─────────────────────────────
   scroll-snap-stop: always 是关键 —— 少它的话手指一甩会连翻好几条，
   抖不出"卡住"的观感。y mandatory 保证松手后必定对齐到某一屏。 */
#feed {
  height: 100vh; height: 100dvh;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  scrollbar-width: none;
}
#feed::-webkit-scrollbar { display: none; width: 0; }

.slide {
  position: relative;
  height: 100vh; height: 100dvh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overflow: hidden;
  background: #000;
}

/* 画面用 canvas 呈现。
   之所以不是 <video>：小米浏览器这类内核会扫描 DOM 里的 video 标签并强行接管播放器，
   pointer-events:none / playsinline / x5 属性都拦不住（它不是靠点击触发的）。
   canvas 不在它们的接管名单里，所以画面能老老实实待在页面内。

   这里必须是 cover 不是 contain：
   我们的视频是 480×832（比例 0.577），手机视口是 390×844（0.462）。
   contain 会按宽度铺满、上下各留 84px 黑边，一眼就是"嵌进去的视频"；
   抖音是铺满全屏、宁可把两侧裁掉 —— 这才是"全屏沉浸"的观感来源。 */
/* 竖屏视频铺满全屏（宁可两侧裁掉，这是沉浸感的来源）。
   横屏视频**不放大**：按原始比例显示、上下留黑边，再给个"全屏"按钮让用户
   自己转到横屏看 —— 这也是抖音的做法。硬把 16:9 拉成 9:19.5 会变形，
   裁掉两边又看不出画面在讲什么，两种都不对。
   由 JS 量 videoWidth/videoHeight 之后加 .wide。 */
.slide .cv {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center center;
  background: #000;
  display: block;
  pointer-events: none;
}
/* 横屏视频在竖屏下**不放大**：按原始比例显示，上下留黑边。
   画面偏上而不是垂直居中 —— 抖音真机截图里下方留白明显更大，
   那是给文案和「全屏观看」按钮让位的；居中会让文案挤在黑边边缘。 */
.slide.wide .cv { object-fit: contain; object-position: center 34%; }

/* 全屏播放：只把画面本身全屏，互动栏和文案不跟着进去。
   全屏后浏览器给的盒子是横的，这里必须 contain，否则 480x832 会被拉扁。 */
.slide .cv:fullscreen {
  position: fixed; inset: 0;
  width: 100vw; height: 100vh;
  object-fit: contain;
  background: #000;
  pointer-events: auto;
}

/* ── 假全屏（WebView 兜底）──────────────────────────────
   APK 里的 WebView 如果没实现 onShowCustomView，requestFullscreen() 会直接 reject，
   点"全屏观看"就完全没反应 —— 这正是用户遇到的"点击全屏后无法全屏"。
   这条兜底不依赖任何 API：自己把 canvas 撑满视口 + 藏掉界面。
   只作用于被点的那一张（.fsed），否则 #feed 里所有 canvas 会一起铺满。 */
.cv.fsed {
  position: fixed; inset: 0; z-index: 98;
  width: 100vw; height: 100vh;
  object-fit: contain; background: #000;
}
body.fakefs { background: #000; overflow: hidden; }
body.fakefs .rail,
body.fakefs .meta,
body.fakefs .tabbar,
body.fakefs .topbar,
body.fakefs .progress,
body.fakefs .swipehint,
body.fakefs .fsbtn { display: none; }
/* 转屏也失败时（screen.orientation.lock 在 WebView 里多半没有），
   用 CSS 把画面转 90 度铺满竖屏 —— 用户把手机横过来就是正常的横屏观看。 */
.cv.fsed.rot90 {
  inset: auto; top: 50%; left: 50%;
  width: 100vh; height: 100vw;
  transform: translate(-50%, -50%) rotate(90deg);
}
.fsexit {
  display: none;
  position: fixed; z-index: 99;
  top: calc(14px + env(safe-area-inset-top)); right: 14px;
  padding: 8px 14px; border-radius: 999px;
  background: rgba(255,255,255,.16); color: #fff;
  font-size: 13px; white-space: nowrap;
  backdrop-filter: blur(6px); cursor: pointer;
}
body.fakefs .fsexit { display: block; }

/* ── 全屏按钮 ────────────────────────────────────────── */
/* 默认不占位。只有 .slide.wide（横屏视频）才显示，
   这样竖屏视频的界面上不会多出一个用不着的按钮。 */
.fsbtn {
  display: none;
  position: absolute; z-index: 4;
  /* 水平居中、紧贴画面下边。具体 top 由 JS 按画面的实际底边算 ——
     不同宽高比的视频，画面底边差很多，写死必然对不上。
     原来写死 right:12px/bottom:96px，直接压在点赞数字上点都点不到。 */
  left: 50%; transform: translateX(-50%);
  align-items: center; gap: 6px;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(0,0,0,.34);
  color: #fff; font-size: 13px; font-weight: 500;
  white-space: nowrap;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.fsbtn svg { width: 19px; height: 19px; }
.fsbtn:active { background: rgba(0,0,0,.62); }
.slide.wide .fsbtn { display: flex; }

/* 承接点击的透明层：单击暂停/继续，双击点赞。
   z-index 3 —— 压在渐变遮罩(2)之上、互动栏(4)之下，
   所以右侧按钮和底部文案依然能正常点到。 */
.tapzone { position: absolute; inset: 0; z-index: 3; }

/* 顶部/底部的渐变遮罩，让白字在任何画面上都读得清 —— 抖音同样这么做 */
.slide::before,
.slide::after {
  content: ''; position: absolute; left: 0; right: 0; pointer-events: none; z-index: 2;
}
.slide::before { top: 0; height: 130px; background: linear-gradient(to bottom, rgba(0,0,0,.45), transparent); }
.slide::after { bottom: 0; height: 230px; background: linear-gradient(to top, rgba(0,0,0,.62), transparent); }

/* ── 右侧互动栏 ──────────────────────────────────────── */
.rail {
  position: absolute; right: 10px; bottom: 108px; z-index: 4;
  display: flex; flex-direction: column; align-items: center; gap: 19px;
}
.rail .item {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  cursor: pointer;
}
.rail .item svg {
  width: 36px; height: 36px; display: block;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.6));
  transition: transform .12s ease;
  color: #fff;
}
.rail .item:active svg { transform: scale(.86); }
.rail .num {
  font-size: 13px; font-weight: 600; color: #fff; line-height: 1;
  text-shadow: 0 1px 3px rgba(0,0,0,.6);
  font-variant-numeric: tabular-nums;
}
/* 点过赞/收藏后变抖音那个红色 */
.rail .item.on svg { color: #fe2c55; }
.rail .item.on .num { color: #fe2c55; }
/* 收藏在抖音是黄色 */
.rail .item.fav.on svg,
.rail .item.fav.on .num { color: #face15; }
/* 删除：「删除」两个字比上面的数字宽得多，单独收字号免得把整列撑歪 */
.rail .item.del .num {
  font-size: 11.5px; letter-spacing: -.2px; color: rgba(255,255,255,.92);
}
.rail .item.del:active svg { color: #ff5c7a; }
.rail .item.del svg { stroke-width: 1.9; }

/* 音乐转盘：抖音右侧栏最下面那个转的唱片。
   播放时转、暂停时停 —— 用 CSS 动画驱动，JS 只切一个 class，
   不放进 rAF 循环里每帧改样式（那样白白占手机的电和帧）。 */
.disc {
  position: relative; width: 48px; height: 48px; margin-top: 5px;
  border-radius: 50%; cursor: pointer;
  background: radial-gradient(circle at 50% 50%, #303036 0 26%, #141416 27% 100%);
  border: 1px solid rgba(255,255,255,.22);
  box-shadow: 0 1px 5px rgba(0,0,0,.5);
  display: flex; align-items: center; justify-content: center;
  animation: discSpin 7s linear infinite;
  animation-play-state: paused;      /* 默认不转；播起来才加 .playing */
}
.disc.playing { animation-play-state: running; }
/* 唱片纹路。纯装饰，用伪元素免得为它多一个 DOM 节点 */
.disc::after {
  content: ''; position: absolute; inset: 7px;
  border-radius: 50%; border: 1px solid rgba(255,255,255,.12);
}
.disc-note {
  position: relative; width: 19px; height: 19px; color: #fff;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.7));
}
.disc:active { transform: scale(.92); }
@keyframes discSpin { to { transform: rotate(360deg); } }
/* 系统开了"减少动态效果"就别转，转盘本身还在、还点得动 */
@media (prefers-reduced-motion: reduce) {
  .disc { animation: none; }
}

/* 头像 + 关注加号 */
.avatar-wrap { position: relative; width: 48px; height: 48px; margin-bottom: 6px; }
.avatar {
  width: 48px; height: 48px; border-radius: 50%;
  border: 2px solid #fff;
  background: linear-gradient(135deg, #fe2c55, #ff7a45);
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; font-weight: 600; color: #fff; overflow: hidden;
  box-shadow: 0 1px 4px rgba(0,0,0,.35);
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.follow {
  position: absolute; left: 50%; bottom: -9px; transform: translateX(-50%);
  width: 21px; height: 21px; border-radius: 50%;
  background: #fe2c55; color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; line-height: 1; font-weight: 400;
  box-shadow: 0 1px 4px rgba(0,0,0,.45);
}

/* ── 左下角文案区 ────────────────────────────────────── */
.meta {
  position: absolute; left: 12px; right: 82px; bottom: 98px; z-index: 4;
  pointer-events: none;
}
.meta > * { pointer-events: auto; }
/* 抖音这里全是粗体 + 双层描边：一层贴边勾轮廓，一层往下投影。
   单层阴影在亮画面上会糊掉，白字直接看不见。 */
.meta .nick {
  font-size: 17px; font-weight: 700; color: #fff;
  text-shadow: 0 0 2px rgba(0,0,0,.6), 0 1px 3px rgba(0,0,0,.5);
}
.meta .capwrap { position: relative; margin-top: 8px; }
.meta .cap {
  font-size: 15px; line-height: 1.4; color: #fff;
  text-shadow: 0 0 2px rgba(0,0,0,.55), 0 1px 3px rgba(0,0,0,.45);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.meta .cap.open { -webkit-line-clamp: unset; }
.meta .cap b { color: #8ecaff; font-weight: 600; }
/* 「展开」浮在第二行末尾，配一段从左到右的渐变把字压住 —— 抖音同款做法 */
.meta .capwrap .more { display: none; }
.meta .capwrap.cut .more {
  display: inline-block; position: absolute; right: 0; bottom: 0;
  padding-left: 26px; font-size: 15px; line-height: 1.4; cursor: pointer;
  color: rgba(255,255,255,.86);
  background: linear-gradient(to right, transparent, rgba(0,0,0,.55) 30%);
}
.meta .music {
  margin-top: 10px; display: flex; align-items: center; gap: 6px;
  font-size: 13.5px; color: #fff;
  text-shadow: 0 0 2px rgba(0,0,0,.55), 0 1px 3px rgba(0,0,0,.45);
  overflow: hidden; white-space: nowrap;
}
.meta .music svg {
  width: 15px; height: 15px; flex: none;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.5));
}
.meta .music span:last-child {
  display: inline-block; white-space: nowrap;
}
/* 只在真的放不下时才滚 —— 否则短标题也会被推走，截图里「原声」就剩个「声」 */
.meta .music span:last-child.scroll { animation: marquee 12s linear infinite; }
@keyframes marquee { 0% { transform: translateX(0); } 100% { transform: translateX(-42%); } }

/* ── 中央播放按钮 ────────────────────────────────────── */
.playbtn {
  position: absolute; left: 50%; top: 50%; margin: -33px 0 0 -33px;
  width: 66px; height: 66px; z-index: 4; opacity: 0;
  transition: opacity .18s ease; pointer-events: none;
}
.playbtn.show { opacity: 1; }
.playbtn svg { width: 66px; height: 66px; filter: drop-shadow(0 2px 8px rgba(0,0,0,.5)); }

/* 双击点赞：从中心弹出一颗大红心，放大后淡出 */
.heart-pop {
  position: absolute; left: 50%; top: 50%;
  width: 130px; height: 130px; margin: -65px 0 0 -65px;
  z-index: 6; pointer-events: none;
  animation: heartPop .95s cubic-bezier(.2,.6,.3,1) forwards;
}
.heart-pop svg { width: 130px; height: 130px; color: #fe2c55; filter: drop-shadow(0 3px 10px rgba(0,0,0,.4)); }
@keyframes heartPop {
  0%   { transform: scale(0)   rotate(-18deg); opacity: 0; }
  18%  { transform: scale(1.28) rotate(0deg);  opacity: 1; }
  34%  { transform: scale(.94); }
  50%  { transform: scale(1.07); }
  70%  { transform: scale(1);   opacity: 1; }
  100% { transform: scale(1.4); opacity: 0; }
}

/* 进度条。
   三处都是被真机教出来的：
   ① fixed 而不是 absolute —— absolute 相对 .slide 定位，而 .slide 是 100vh。
      会缩放地址栏的浏览器里 100vh 比可视区高，进度条被推到屏幕外，等于没有。
   ② 2.5px → 3px，拖动时再高一点，手指才有落点。
   ③ 上下各 12px 的隐形热区（padding + background-clip 让它不显示），
      3px 高的一条线根本点不中。
   没用 <input type=range>：那会往 DOM 里塞表单控件，
   对会扫描 DOM 的浏览器能少一个是一个。 */
.progress {
  position: fixed; left: 0; right: 0;
  bottom: 52px;
  bottom: calc(52px + env(safe-area-inset-bottom));
  height: 3px; z-index: 19;   /* 19 < tabbar 的 20，压在导航栏下面那层 */
  /* 抖音是白色轨道，不是主题红。红色在这条 3px 的线上显得像报错提示 */
  background: rgba(255,255,255,.34);
  cursor: pointer;
  /* ⚠ 必须是 pan-y（2026-10-03 用户：「进度条滑动很难滑的到」「上下刷视频时失灵划不动」）：
     原来是 none，等于把底部整条带子的上下滑手势全吃了 —— 手指落在热区里就再也滚不动页面。
     pan-y 让浏览器照常处理垂直滚动，横向拖动仍由 JS 接管（改进度）。 */
  touch-action: pan-y;
}
/* 上下各扩 12px 的隐形热区 —— 3px 高的一条线手指点不中。
   必须用 ::before 撑，不能用 padding：全局是 border-box，
   padding 会把 3px 的内容区吃光（3 - 24 → 0），红线塌成看不见。 */
.progress::before {
  content: ''; position: absolute; left: 0; right: 0;
  /* ±10px：3px 的线要够点得到，又不能太厚把上下滑吃掉（原 ±18 就是"划不动"的主因） */
  top: -10px; bottom: -10px;
}
.progress i {
  display: block; height: 100%; width: 0;
  background: #fff;
  position: relative;
  /* 不用 transition：宽度由 rAF 每帧直接写，再加过渡会拖影 */
}
/* 圆点滑块。抖音那个小白点是判断"能不能拖"的唯一视觉线索，
   没有它这条线看起来就是装饰而不是控件。 */
.progress i::after {
  content: '';
  position: absolute; right: -5px; top: 50%;
  width: 10px; height: 10px; margin-top: -5px;
  border-radius: 50%; background: #fff;
  box-shadow: 0 0 4px rgba(0,0,0,.4);
}
/* 播放时间。竖屏在进度条正上方居中（对照抖音图2）。
   tabular-nums 让数字等宽，否则秒数跳动时整行会左右抖。 */
.ptime {
  position: absolute; left: 50%; bottom: 9px;
  transform: translateX(-50%);
  font-size: 12.5px; line-height: 1; color: #fff;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum';
  text-shadow: 0 1px 3px rgba(0,0,0,.65);
  white-space: nowrap; pointer-events: none;
}
/* 拖的时候加高一点，看得见自己拖到哪了 */
.progress.grab { height: 5px; }
.progress.grab i { box-shadow: 0 0 10px rgba(255,255,255,.85); }

/* ── 顶部标签栏 ──────────────────────────────────────── */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 20;
  height: 46px; padding-top: env(safe-area-inset-top);
  display: flex; align-items: center; justify-content: center; gap: 24px;
  pointer-events: none;
}
.topbar .t {
  font-size: 17px; color: rgba(255,255,255,.65); pointer-events: auto; cursor: pointer;
  text-shadow: 0 0 2px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.45);
  transition: color .15s;
}
.topbar .t.on { color: #fff; font-weight: 700; font-size: 18px; }
.topbar .t.on::after {
  content: ''; display: block; width: 18px; height: 2.5px; margin: 5px auto 0;
  background: #fff; border-radius: 2px;
}
.backbtn {
  position: fixed; left: 10px; top: calc(12px + env(safe-area-inset-top)); z-index: 21;
  width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
  color: #fff; text-decoration: none; cursor: pointer;
}
.backbtn svg { width: 26px; height: 26px; filter: drop-shadow(0 1px 3px rgba(0,0,0,.5)); }

/* ── 底部导航栏 ──────────────────────────────────────── */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  height: 52px; padding-bottom: env(safe-area-inset-bottom);
  display: flex; align-items: center;
  background: linear-gradient(to top, rgba(0,0,0,.92), rgba(0,0,0,.55));
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.tabbar .tb {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; color: rgba(255,255,255,.55); font-size: 10px; cursor: pointer;
  transition: color .15s ease;
}
.tabbar .tb svg { width: 26px; height: 26px; }
.tabbar .tb.on { color: #fff; }
.tabbar .tb:active svg { transform: scale(.9); }
.tabbar .tb.plus {
  flex: none; width: 46px; height: 30px; border-radius: 8px;
  background: #fe2c55; color: #fff; margin: 0 6px;
  display: flex; align-items: center; justify-content: center;
}
.tabbar .tb.plus svg { width: 20px; height: 20px; }

/* ── 评论抽屉 ────────────────────────────────────────── */
.mask {
  position: fixed; inset: 0; z-index: 40; background: rgba(0,0,0,.5);
  opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
.mask.show { opacity: 1; pointer-events: auto; }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 41;
  height: 62vh; max-height: 62vh;
  background: #1c1c1e; border-radius: 14px 14px 0 0;
  transform: translateY(102%); transition: transform .26s cubic-bezier(.22,.7,.3,1);
  display: flex; flex-direction: column;
}
.sheet.show { transform: translateY(0); }
.sheet .hd {
  position: relative; text-align: center; padding: 15px 0 11px;
  font-size: 14px; color: rgba(255,255,255,.92); font-weight: 500;
  border-bottom: 1px solid rgba(255,255,255,.08); flex: none;
}
/* 顶部那道灰色小横条 —— 抖音抽屉的标配，暗示"可以往下拖关掉" */
.sheet .hd::before {
  content: ''; position: absolute; left: 50%; top: 6px; transform: translateX(-50%);
  width: 36px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.22);
}
.sheet .hd .x {
  position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
  color: rgba(255,255,255,.55); cursor: pointer; font-size: 19px; line-height: 1;
}
.sheet .list { flex: 1; overflow-y: auto; padding: 6px 0 10px; -webkit-overflow-scrolling: touch; }
.sheet .empty { text-align: center; color: rgba(255,255,255,.35); font-size: 13px; padding: 46px 0; }
.cmt { display: flex; gap: 10px; padding: 11px 14px; }
.cmt .av {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  background: linear-gradient(135deg, #4b6cb7, #182848);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 600; color: #fff;
}
.cmt .bd { flex: 1; min-width: 0; }
.cmt .nm { font-size: 12.5px; color: rgba(255,255,255,.5); }
.cmt .tx { font-size: 14.5px; color: #fff; margin-top: 3px; line-height: 1.4; word-break: break-word; }
.cmt .tm { font-size: 11.5px; color: rgba(255,255,255,.32); margin-top: 5px; }
.sheet .ft {
  flex: none; display: flex; align-items: center; gap: 8px;
  padding: 9px 12px calc(9px + env(safe-area-inset-bottom));
  border-top: 1px solid rgba(255,255,255,.08); background: #1c1c1e;
}
.sheet .ft input {
  flex: 1; height: 38px; border-radius: 19px; border: none; outline: none;
  background: #2c2c2e; color: #fff; font-size: 14.5px; padding: 0 15px;
  font-family: inherit;
}
.sheet .ft input::placeholder { color: rgba(255,255,255,.32); }
.sheet .ft .send {
  flex: none; padding: 0 15px; height: 38px; border-radius: 19px; border: none;
  background: #fe2c55; color: #fff; font-size: 14px; font-weight: 600; cursor: pointer;
  font-family: inherit;
}
.sheet .ft .send:disabled { opacity: .4; }

/* Toast */
#toast {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%,-50%);
  z-index: 60; background: rgba(0,0,0,.82); color: #fff;
  padding: 11px 20px; border-radius: 9px; font-size: 14px;
  opacity: 0; pointer-events: none; transition: opacity .2s ease;
  max-width: 76vw; text-align: center;
}
#toast.show { opacity: 1; }

/* 加载 / 空态 */
.hint {
  position: fixed; inset: 0; display: flex; align-items: center; justify-content: center;
  flex-direction: column; gap: 14px; color: rgba(255,255,255,.5); font-size: 14.5px;
  text-align: center; padding: 30px; z-index: 30; background: #000;
}
.hint a { color: #fe2c55; text-decoration: none; font-weight: 600; }
.spinner {
  width: 26px; height: 26px; border-radius: 50%;
  border: 2.5px solid rgba(255,255,255,.2); border-top-color: #fff;
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── 视图层 ───────────────────────────────────────────
   五个 tab 都是真页面，用显示/隐藏切换，不做路由跳转 ——
   切回首页时视频还能接着播，不会重新加载一遍。 */
.view {
  position: absolute; inset: 0;
  display: none;
  padding-bottom: 52px;              /* 给底部导航让位 */
  padding-bottom: calc(52px + env(safe-area-inset-bottom));
  overflow: hidden;
}
.view.on { display: block; }
/* 推荐流自己就是整屏滚动容器，不能再加内边距，否则一屏对不齐 */
#viewFeed { padding-bottom: 0; }

.scrollpage {
  height: 100%;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* 保险：最后一行不要贴着底部导航，否则会被半透明的 tabbar 压住半截 */
  padding-bottom: 18px;
}

/* 子页面统一页头 */
.pagehd {
  position: sticky; top: 0; z-index: 3;
  padding: calc(14px + env(safe-area-inset-top)) 16px 12px;
  font-size: 17px; font-weight: 600;
  background: rgba(0,0,0,.86);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(255,255,255,.07);
}
.pagehd .sub {
  margin-left: 9px; font-size: 12.5px; font-weight: 400;
  color: rgba(255,255,255,.42);
}

/* 消息 tab 上的小红点 */
.tabbar .tb { position: relative; }
.tabbar .badge {
  position: absolute; top: 3px; left: 50%; margin-left: 6px;
  min-width: 15px; height: 15px; padding: 0 4px;
  border-radius: 8px; background: #fe2c55;
  font-size: 9.5px; line-height: 15px; text-align: center;
  color: #fff; font-style: normal; font-weight: 600;
}

/* ── 右上角搜索（抖音推荐页有这个放大镜）──────────────── */
.searchbtn {
  position: fixed; z-index: 22;
  top: calc(12px + env(safe-area-inset-top)); right: 12px;
  width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  color: #fff; text-decoration: none;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.5));
}
.searchbtn svg { width: 24px; height: 24px; }
.searchbtn:active { transform: scale(.9); }

/* ── 横滑提示 ────────────────────────────────────────── */
/* 抖音左滑时这条从右侧滑出来；松手进评论区。右滑则显示作者名。
   默认完全藏起来（opacity 0 + 位移），免得静止时碍眼。 */
.swipehint {
  position: fixed; z-index: 18;
  top: 50%; left: 0; right: 0;
  transform: translateY(-50%) translateX(10px);
  opacity: 0; pointer-events: none;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-size: 14px; font-weight: 500; color: #fff;
  text-shadow: 0 1px 4px rgba(0,0,0,.7);
  transition: opacity .16s ease-out, transform .16s ease-out;
}
.swipehint svg { width: 21px; height: 21px; filter: drop-shadow(0 1px 3px rgba(0,0,0,.6)); }
.swipehint.show { opacity: 1; }
/* 拖动中不用过渡，否则跟手会飘 */
.swipehint.dragging { transition: none; }

/* ── 个人主页 ────────────────────────────────────────── */
.me-hd { padding: calc(26px + env(safe-area-inset-top)) 18px 16px; }
.me-av {
  /* 抖音个人页头像是 88px（占屏宽 22.6%）。之前是 76px，肉眼看不出来，
     但用 getBoundingClientRect 一量就露了 —— 所以别靠眼睛估尺寸。 */
  width: 88px; height: 88px; border-radius: 50%;
  background: linear-gradient(135deg,#fe2c55,#ff7a45);
  display: flex; align-items: center; justify-content: center;
  font-size: 34px; font-weight: 600; color: #fff;
  box-shadow: 0 4px 16px rgba(254,44,85,.28);
}
.me-name { margin-top: 13px; font-size: 20px; font-weight: 700; }
.me-handle { margin-top: 5px; font-size: 13px; color: rgba(255,255,255,.45); }
.me-sig { margin-top: 11px; font-size: 13.5px; color: rgba(255,255,255,.72); line-height: 1.5; }
.me-stats { display: flex; gap: 26px; margin-top: 17px; }
.me-stats div { text-align: center; }
.me-stats b { display: block; font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
.me-stats span { font-size: 11.5px; color: rgba(255,255,255,.45); }

/* 作品 / 收藏 / 喜欢 三个分页 */
.me-tabs {
  display: flex; gap: 4px; padding: 0 12px;
  border-bottom: 1px solid rgba(255,255,255,.07);
  position: sticky; top: 0; z-index: 3;
  background: rgba(0,0,0,.86);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.me-tabs .mt {
  flex: 1; text-align: center; padding: 13px 0 11px;
  font-size: 14.5px; color: rgba(255,255,255,.5); cursor: pointer;
  position: relative;
}
.me-tabs .mt.on { color: #fff; font-weight: 600; }
.me-tabs .mt.on::after {
  content: ''; position: absolute; left: 50%; bottom: 0;
  width: 26px; height: 2.5px; margin-left: -13px;
  background: #fff; border-radius: 2px;
}
.me-tabs .mt i {
  font-style: normal; font-size: 11.5px;
  color: rgba(255,255,255,.36); margin-left: 3px;
}

/* 作品九宫格：抖音个人页就是三列网格 */
.grid3 {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px;
  padding: 2px;
}
.grid3 .cell {
  position: relative; aspect-ratio: 3 / 4;
  background: #141416; overflow: hidden; cursor: pointer;
}
.grid3 .cell canvas {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.grid3 .cell .play {
  position: absolute; right: 5px; bottom: 4px;
  font-size: 11px; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,.7);
  font-variant-numeric: tabular-nums;
}
.grid3 .cell .seg {
  position: absolute; left: 5px; top: 4px;
  font-size: 10px; padding: 1px 5px; border-radius: 4px;
  background: rgba(254,44,85,.85); color: #fff;
}

/* ── 消息列表 ────────────────────────────────────────── */
.notify { display: flex; align-items: center; gap: 12px; padding: 13px 16px; }
.notify + .notify { border-top: 1px solid rgba(255,255,255,.05); }
.notify .av {
  width: 44px; height: 44px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 600; color: #fff;
}
.notify .bd { flex: 1; min-width: 0; }
.notify .nm { font-size: 14.5px; font-weight: 500; }
.notify .tx {
  font-size: 13px; color: rgba(255,255,255,.55); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.notify .tm { font-size: 11.5px; color: rgba(255,255,255,.3); margin-top: 4px; }
.notify .thumb {
  width: 46px; height: 60px; border-radius: 6px; flex: none;
  background: #1c1c1e; overflow: hidden;
}
.notify .thumb canvas { width: 100%; height: 100%; object-fit: cover; display: block; }
.notify .dot {
  width: 8px; height: 8px; border-radius: 50%; background: #fe2c55; flex: none;
}
.notify.unread { background: rgba(254,44,85,.05); }
/* 关注类通知的头像换成图标 */
.notify .av.icon { background: none; font-size: 30px; }

/* ── 朋友/创作者列表 ─────────────────────────────────── */
.creator { display: flex; align-items: center; gap: 13px; padding: 15px 16px; }
.creator + .creator { border-top: 1px solid rgba(255,255,255,.05); }
.creator .av {
  width: 52px; height: 52px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; font-weight: 600; color: #fff;
}
.creator .bd { flex: 1; min-width: 0; }
.creator .nm { font-size: 15.5px; font-weight: 600; }
.creator .sig { font-size: 12.5px; color: rgba(255,255,255,.5); margin-top: 3px; }
.creator .tags { display: flex; gap: 6px; margin-top: 7px; flex-wrap: wrap; }
.creator .tags span {
  font-size: 11px; padding: 2px 8px; border-radius: 10px;
  background: rgba(255,255,255,.08); color: rgba(255,255,255,.6);
}
.creator .act {
  flex: none; padding: 7px 17px; border-radius: 17px;
  border: 1px solid #fe2c55; color: #fe2c55;
  font-size: 13px; font-weight: 600; cursor: pointer;
  background: none; font-family: inherit;
}
.creator .act.on { border-color: rgba(255,255,255,.25); color: rgba(255,255,255,.5); }
.creator .latest {
  width: 46px; height: 60px; border-radius: 6px; flex: none;
  background: #1c1c1e; overflow: hidden;
}
.creator .latest canvas { width: 100%; height: 100%; object-fit: cover; display: block; }

/* 空态 */
.emptypage {
  padding: 70px 30px; text-align: center;
  color: rgba(255,255,255,.35); font-size: 14px; line-height: 1.7;
}

/* ── 音乐图标转动 ────────────────────────────────────── */
/* 抖音左下角那个 ♪ 是一直匀速转的；暂停时我们也停 */
.meta .music svg {
  animation: spin 3.6s linear infinite;
  transform-origin: 50% 50%;
}
.slide:not(.playing) .meta .music svg { animation-play-state: paused; }

/* ── 长按操作菜单 ────────────────────────────────────── */
/* 菜单项比较多（不感兴趣/举报/倍速/保存/复制/清屏/视频直显/循环/取消），
   62vh 装不下会顶到屏幕外 —— 实测「循环播放」和「取消」都被切掉。
   抬到 80vh 一屏放得下；.acts 那边仍然留着滚动，以后再加项也不会出界。 */
.sheet.act-sheet { height: auto; max-height: 80vh; }
.sheet.act-sheet .acts {
  padding: 6px 12px calc(12px + env(safe-area-inset-bottom));
  /* 必须能滚：.sheet 的 max-height 只有 62vh，菜单项一多（比如加了「视频直显」之后）
     底部的「循环播放」和「取消」就会被切到屏幕外，用户根本点不到。
     min-height:0 是关键 —— flex 子项默认 min-height:auto，不加这行它宁可不收缩也不滚。 */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;   /* 滚到头别把整页一起带着滚 */
}
/* 抖音是"一张卡片一组"，不是一条通栏长列表。
   组与组之间留 10px，卡片自身圆角 —— 一眼能分出哪几项是一类。 */
.sheet.act-sheet .act-card {
  background: rgba(255,255,255,.08);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 10px;
}
.sheet.act-sheet .act-row {
  display: flex; align-items: center; gap: 13px;
  padding: 15px 16px; font-size: 15px; cursor: pointer;
  color: rgba(255,255,255,.9);
}
.sheet.act-sheet .act-row .lbl { flex: 1; }
.sheet.act-sheet .act-row:active { background: rgba(255,255,255,.07); }
.sheet.act-sheet .act-row + .act-row { border-top: 1px solid rgba(255,255,255,.06); }
.sheet.act-sheet .act-row i { font-style: normal; font-size: 19px; width: 22px; text-align: center; }
.sheet.act-sheet .act-row.on { color: #fe2c55; }
/* 倍速：横向选项行，当前档标红（对照抖音真机截图）。
   不给 data-k，点了不关面板，可以连着换档试。 */
.sheet.act-sheet .act-row.speed { cursor: default; padding-right: 12px; }
.sheet.act-sheet .act-row.speed .sp {
  flex: 0 0 auto;
  padding: 5px 9px; border-radius: 8px;
  font-size: 14px; font-weight: 500;
  color: rgba(255,255,255,.72);
  background: rgba(255,255,255,.06);
  cursor: pointer;
}
.sheet.act-sheet .act-row.speed .sp.on { color: #fff; background: #fe2c55; }
.sheet.act-sheet .act-row.speed .sp:active { opacity: .72; }
/* 开关：循环播放 / 自动下一条 这类二值项。
   2026-10-04 用户「这种开关的动画效果没做啊」：
   原来 .18s ease 太平淡、位移只有 18px，看着像"啪"一下跳过去。
   改成 .24s 带过冲的曲线（cubic-bezier 的 1.4 尾巴会轻微回弹），手感接近抖音那种拨动感。
   轨道底色也一起过渡，并给按下态一点缩放反馈。 */
.sheet.act-sheet .sw {
  flex: 0 0 auto;
  width: 44px; height: 25px; border-radius: 999px;
  background: rgba(255,255,255,.2);
  position: relative;
  transition: background .24s cubic-bezier(.22,.9,.3,1.2), box-shadow .24s ease;
}
.sheet.act-sheet .sw::after {
  content: ''; position: absolute; top: 2.5px; left: 2.5px;
  width: 20px; height: 20px; border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.35);
  transition: transform .24s cubic-bezier(.34,1.4,.5,1), width .18s ease;
}
.sheet.act-sheet .sw.on { background: #fe2c55; box-shadow: 0 0 0 1px rgba(254,44,85,.28); }
.sheet.act-sheet .sw.on::after { transform: translateX(19px); }
/* 按下的瞬间：滑块稍微拉长一点，松手弹回 —— 就是"拨动"的手感 */
.sheet.act-sheet .act-row:active .sw::after { width: 25px; }
.sheet.act-sheet .hd { justify-content: center; color: rgba(255,255,255,.5); font-size: 13px; }

/* 清屏播放：藏掉所有界面只留画面（点画面恢复，或点左下「退出清屏」，见 feed.js 的 clear 分支）。
   ⚠ 2026-10-04 修：原来只写 `opacity: 0; pointer-events: none` —— 元素**仍然占位**，
   而且被 JS 的内联样式（switchView 里 tb.style.display = ''）压过去，
   实测截图里顶部「‹ 返回」「🔍 搜索」照样显示，那就不叫清屏了。
   改成 display:none + !important：清屏就该是纯画面，JS 也别想把它放出来。 */
body.clearscreen .rail,
body.clearscreen .meta,
body.clearscreen .acts,
body.clearscreen .tabbar,
body.clearscreen .topbar,
body.clearscreen .backbtn,
body.clearscreen .searchbtn,
body.clearscreen .progress,
body.clearscreen .buf-spin,
body.clearscreen .net-speed,
body.clearscreen .swipehint { display: none !important; }
/* 清屏时画面铺满（顶栏不再占高度） */
body.clearscreen #feed { top: 0 !important; }

/* ── 作者主页 ──────────────────────────────────────────
   抖音是三列九宫格。缩略图复用朋友页那套离屏抽帧（queueThumb），
   绝不往这里塞 <video> —— 小米浏览器扫到就抢播放器。 */
.auback { cursor: pointer; margin-right:auto; }
.pagehd .auback { position:absolute; left:14px; font-size:15px; font-weight:400; color:rgba(255,255,255,.8); }
.au-hd { padding:22px 18px 18px; text-align:center; }
.au-av {
  width: 88px; height: 88px; border-radius: 50%; margin: 0 auto 12px;
  display: flex; align-items: center; justify-content: center;
  font-size: 34px; font-weight: 700; color: #fff;
}
/* 作者主页头像用真人脸时：img 撑满圆形并裁切（原来只有首字母色块，没有图片分支） */
.au-av-img { overflow: hidden; padding: 0; }
.au-av-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.au-nm { font-size: 19px; font-weight: 700; color: #fff; }
.au-sub { margin-top: 5px; font-size: 12.5px; color: rgba(255,255,255,.5); }
.au-stat { margin-top: 14px; display: flex; justify-content: center; gap: 24px; }
.au-stat b { font-size: 17px; color: #fff; }
.au-stat span { margin-left: 5px; font-size: 12.5px; color: rgba(255,255,255,.55); }
.au-follow {
  margin-top: 16px; padding: 9px 34px; border-radius: 9px; border: 0;
  background: #fe2c55; color: #fff; font-size: 14.5px; font-weight: 600; cursor: pointer;
}
.au-follow.on { background: rgba(255,255,255,.14); color: rgba(255,255,255,.8); }
.au-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; padding: 0 2px 20px; }
.au-cell { position: relative; aspect-ratio: 3 / 4; background: #14171b; overflow: hidden; cursor: pointer; }
.au-cell canvas { width: 100%; height: 100%; object-fit: cover; display: block; }
.au-like {
  position: absolute; left: 5px; bottom: 4px;
  font-size: 11.5px; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,.75);
}

/* ── 评论条目（带点赞）──────────────────────────────── */
.cmt-item { display: flex; gap: 11px; padding: 13px 4px; }
.cmt-item + .cmt-item { border-top: 1px solid rgba(255,255,255,.05); }
.cmt-item .cav {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 13.5px; font-weight: 600; color: #fff;
}
.cmt-item .cbody { flex: 1; min-width: 0; }
.cmt-item .cnick { font-size: 13px; color: rgba(255,255,255,.5); }
.cmt-item .ctext { font-size: 14.5px; margin-top: 4px; line-height: 1.45; word-break: break-word; }
.cmt-item .ctime { font-size: 11.5px; color: rgba(255,255,255,.3); margin-top: 5px; }
.cmt-item .clike {
  flex: none; display: flex; flex-direction: column; align-items: center;
  gap: 3px; cursor: pointer; padding: 2px; min-width: 26px;
  color: rgba(255,255,255,.42); font-size: 11px;
  transition: color .15s ease;
}
.cmt-item .clike svg { width: 17px; height: 17px; transition: transform .15s ease; }
.cmt-item .clike.on { color: #fe2c55; }
.cmt-item .clike.on svg { transform: scale(1.14); }

/* ── 「我关注的人」名单 ────────────────────────────────
   从「我」页点「关注」数字进来的列表。排版直接复用上面的 .creator
   （同一套头像/昵称/签名），只补两样：手型光标 + 右侧进主页的箭头。 */
.fu-wrap { margin-top: 4px; }
.creator[data-fu] { cursor: pointer; }
.creator[data-fu]:active { background: rgba(255,255,255,.05); }
.creator .go { color: rgba(255,255,255,.28); font-size: 22px; line-height: 1; padding-left: 2px; }
/* 国产浏览器（实测小米）强制接管 <video>、画布拿不到画面时的提示条。
   以前这里会自动降级成全屏播放器 —— 整个 feed 被盖住，上下滑和点赞全没了。
   现在只提示：页面留着，想看视频自己点这一条。 */
.vfb-hint {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 5; padding: 14px 16px; border-radius: 16px; max-width: 78vw; text-align: center;
  background: rgba(0, 0, 0, .74); color: #fff;
  border: 1px solid rgba(255, 255, 255, .22); backdrop-filter: blur(6px);
}
.vfb-hint .t { font-size: 13px; line-height: 1.5; margin-bottom: 10px; }
.vfb-hint .row { display: flex; gap: 8px; }
.vfb-hint button {
  flex: 1; padding: 8px 12px; border-radius: 16px; font-size: 12.5px; white-space: nowrap;
  border: 1px solid rgba(255, 255, 255, .3); background: rgba(255, 255, 255, .14); color: #fff;
}
.vfb-hint button:active { background: rgba(255, 255, 255, .26); }
/* 用真人脸当头像：服务端 /face/<裁剪图>.jpg 是 YuNet 定位 + 扩边裁出来的头肩小图。
   原来这里只有"渐变底色 + 首字母"。老作品没有脸，继续走旧样式（见 avatarHTML）。 */
.av-img { overflow: hidden; }
.av-img img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: inherit; }
/* ── 「N 人共创」+ 生成信息（2026-10-02）─────────────────
   用户要求：①出镜过的都算共创，像抖音那样标出来并且点头像能点进各自主页；
   ②点「展开」要能看到生成图、提示词和各种生成条件。 */
.nickrow { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.cocreate {
  font-size: 11.5px; line-height: 1; padding: 3px 7px; border-radius: 5px;
  color: #fff; background: rgba(254,44,85,.85); font-weight: 600; cursor: pointer;
}
.castrow { display: flex; align-items: center; gap: 6px; margin: 6px 0 8px; flex-wrap: wrap; }
.castav {
  width: 30px; height: 30px; border-radius: 50%; overflow: hidden; display: block;
  border: 1.5px solid rgba(255,255,255,.55); background: rgba(255,255,255,.18); cursor: pointer;
}
.castav img { width: 100%; height: 100%; object-fit: cover; display: block; }
.castmore {
  font-size: 11.5px; color: rgba(255,255,255,.8); padding: 0 4px;
}
/* 「生成信息」面板（点「展开」出来的那块）。
   ⚠️ 2026-10-04 用户：「点击视频的提示词给出的这个页面全透明的不行」——
   原来背景是 rgba(255,255,255,.08)，几乎全透明，视频画面直接透上来，
   提示词和生成条件（预设/分辨率/种子/耗时…）全糊在一起读不了。
   改成**深色毛玻璃**：够暗保证可读，又保留"浮在画面上"的观感。
   backdrop-filter 在部分国产内核不生效，所以底色本身就足够暗（.62），不依赖模糊。 */
.genbox {
  margin: 8px 0 4px; padding: 10px 12px; border-radius: 10px;
  background: rgba(0, 0, 0, .62);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border: 1px solid rgba(255,255,255,.14);
  box-shadow: 0 4px 20px rgba(0,0,0,.35);
}
/* 面板里的文字对比度也一起提上来（原来标签只有 .5 白、正文 .9，
   在毛玻璃深底上偏灰；这里统一提亮，读起来才不费眼）。 */
/* 「生成信息」标题行：左标题、右「收起 ✕」。
   ⚠️ 这里只保留**一条**规则（2026-10-04）—— 加收起按钮时我一度又叠了一条同选择器的规则，
   属性重复（font-size/color 两处定义），正是今晚反复栽的"叠加补丁"模式。已合并。 */
.genhd {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12px; color: rgba(255,255,255,.7); margin-bottom: 8px;
}
.genclose {
  flex: 0 0 auto; height: 26px; padding: 0 10px;
  border: 1px solid rgba(255,255,255,.22); border-radius: 13px;
  background: rgba(255,255,255,.1); color: rgba(255,255,255,.9); font-size: 12px;
}
.genclose:active { background: rgba(255,255,255,.2); }
.genimg {
  width: 100%; max-height: 220px; object-fit: contain; border-radius: 8px;
  margin-bottom: 8px; background: rgba(0,0,0,.35);
}
.genlabel { font-size: 11.5px; color: rgba(255,255,255,.62); margin: 8px 0 4px; }
.genprompt { font-size: 13px; line-height: 1.5; color: #fff; white-space: pre-wrap; word-break: break-word; }
.genrow { display: flex; gap: 10px; font-size: 12.5px; line-height: 1.9; }
.genrow b { color: rgba(255,255,255,.65); font-weight: 400; min-width: 62px; }
.genrow span { color: rgba(255,255,255,.96); word-break: break-all; }

/* 共创弹层（复用 #sheet） */
.cs-hd { font-size: 15px; font-weight: 600; color: #fff; margin-bottom: 12px; }
.cs-item { display: flex; align-items: center; gap: 12px; padding: 10px 0; cursor: pointer; }
.cs-item:active { background: rgba(255,255,255,.06); }
.cs-av { width: 46px; height: 46px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; background: rgba(255,255,255,.15); }
.cs-av-ph { display: block; }
.cs-info { flex: 1; min-width: 0; }
.cs-nm { font-size: 15px; color: #fff; }
.cs-sub { font-size: 12px; color: rgba(255,255,255,.55); margin-top: 2px; }
.cs-go { font-size: 12.5px; color: rgba(255,255,255,.5); flex: 0 0 auto; }

/* ── 设置页（v2，2026-10-03 参照抖音观感重做）───────────── */
.set-hd { display: flex; align-items: center; justify-content: space-between;
  height: 52px; padding: 0 14px; border-bottom: 1px solid #1c2027; }
.set-back { width: 40px; font-size: 26px; line-height: 1; color: #e8ecf2; }
.set-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #fff; }
.set-hd-r { width: 40px; }

.set-grp { padding: 18px 14px 0; }
.set-gt { font-size: 12.5px; color: #767d89; padding: 0 4px 8px; letter-spacing: .3px; }
.set-card { background: #171a20; border-radius: 12px; overflow: hidden; }

.set-row { display: flex; align-items: center; min-height: 56px; padding: 0 14px;
  border-bottom: 1px solid #20242b; }
.set-row:last-child { border-bottom: none; }
.set-row:active { background: #1e222a; }
.set-row.col { display: block; padding: 12px 14px 14px; }
.set-row-top { display: flex; align-items: center; min-height: 32px; }

.set-ico { width: 26px; font-size: 16px; line-height: 1; text-align: left; flex: 0 0 auto; }
.set-lbl { font-size: 16px; color: #e9edf3; }
.set-val { margin-left: auto; font-size: 14px; color: #868e9b; max-width: 62%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.set-arw { margin-left: 8px; font-size: 18px; line-height: 1; color: #59606b; }

.set-bar { height: 4px; border-radius: 2px; background: #262b34; overflow: hidden; margin-top: 8px; }
.set-bar > i { display: block; height: 100%; border-radius: 2px;
  background: linear-gradient(90deg, #3d7bff, #7aa8ff); transition: width .3s; }

.set-ver { text-align: center; color: #5d646f; font-size: 12.5px; padding: 26px 0 84px; }
/* 设置页底部要给导航栏留位置，否则版本号被挡住（.set-ver 的 padding-bottom 就是干这个的） */
body.setting .scrollpage { padding-bottom: 80px; }

/* ── 设置页弹窗 / 选项 / 输入（2026-10-03）─────────────── */
.set-mask { position: fixed; inset: 0; background: rgba(0,0,0,.62); z-index: 999;
  display: flex; align-items: center; justify-content: center; padding: 24px; }
.set-dlg { width: 100%; max-width: 340px; background: #1b1f26; border-radius: 16px;
  padding: 20px 18px 14px; box-shadow: 0 18px 48px rgba(0,0,0,.55); }
.set-dlg-t { font-size: 16px; font-weight: 600; color: #fff; text-align: center; margin-bottom: 12px; }
.set-dlg-b { color: #cfd5de; font-size: 14px; }
.set-dlg-p { margin: 0 0 10px; text-align: center; word-break: break-all; }
.set-dlg-h { margin: 0 0 6px; color: #868e9b; font-size: 12.5px; line-height: 1.6; }
.set-dlg-a { display: flex; gap: 10px; margin-top: 14px; }
.set-btn { flex: 1; height: 40px; border: none; border-radius: 10px; background: #262b34;
  color: #cfd5de; font-size: 15px; }
.set-btn.primary { background: #3d7bff; color: #fff; }
.set-btn:active { opacity: .8; }
.set-inp { width: 100%; height: 42px; border-radius: 10px; border: 1px solid #2c323b;
  background: #14171c; color: #e9edf3; padding: 0 12px; font-size: 14px; margin: 4px 0 8px; }
.set-opt { display: flex; align-items: center; justify-content: space-between;
  padding: 13px 14px; border-radius: 10px; background: #14171c; margin-bottom: 8px;
  font-size: 15px; color: #e9edf3; }
.set-opt span { color: #868e9b; font-size: 12.5px; }
.set-opt.on { background: #1d2634; box-shadow: inset 0 0 0 1px #3d7bff; }
/* 设置页不显示信息流顶栏（那个 🔍 属于推荐流） */
.set-hd ~ * .topbar, body.setting .topbar, body.setting .backbtn, body.setting .searchbtn, body.setting .swipehint { display: none !important; }

/* ── 离线提示条（2026-10-03）────────────────────────── */
.off-bar { position: fixed; left: 0; right: 0; top: 44px; z-index: 900;
  display: flex; align-items: center; justify-content: center; gap: 14px;
  background: rgba(196, 122, 40, .94); color: #fff; font-size: 13px;
  padding: 9px 14px; }
.off-bar b { font-weight: 600; text-decoration: underline; }

/* ── 更新日志弹窗（2026-10-03）────────────────────────── */
.cl-list { max-height: 52vh; overflow-y: auto; -webkit-overflow-scrolling: touch; margin-top: 4px; }
.cl-ver { font-size: 14px; font-weight: 600; color: #fff; margin: 12px 0 6px; }
.cl-ver span { font-weight: 400; font-size: 12px; color: #7b828e; margin-left: 6px; }
.cl-ver:first-child { margin-top: 4px; }
.cl-ul { margin: 0; padding-left: 18px; }
.cl-ul li { font-size: 13px; line-height: 1.7; color: #b9c0cb; }

/* ── 「排队中」区块（2026-10-03 用户要求：九张图的排队要分别列出来，可置顶）── */
.q-block { margin: 0 0 14px; background: #171a20; border-radius: 12px; padding: 12px 12px 6px; }
.q-title { font-size: 13.5px; color: #e9edf3; font-weight: 600; margin-bottom: 10px; }
.q-tip { float: right; font-weight: 400; font-size: 12px; color: #7b828e; }
.q-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-top: 1px solid #20242b; }
.q-row:first-of-type { border-top: none; }
.q-th { width: 42px; height: 56px; object-fit: cover; border-radius: 6px; background: #22262e; flex: 0 0 auto; }
.q-mid { flex: 1; min-width: 0; }
.q-idx { font-size: 12.5px; color: #7aa8ff; }
.q-cap { font-size: 13px; color: #b9c0cb; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.q-top { flex: 0 0 auto; height: 30px; padding: 0 14px; border: none; border-radius: 8px;
  background: #262b34; color: #cfd5de; font-size: 13px; }
.q-top:active { opacity: .8; }

/* ── 缓冲转圈 / 网速 / 加载条（2026-10-03 用户要求）─────── */
/* 进度条上的「加载条」：画在播放进度下面一层（b 在 i 之前，靠 z-index 压住） */
.progress b { position: absolute; left: 0; top: 0; height: 100%; width: 0;
  background: rgba(255,255,255,.38); display: block; }
.progress i { position: relative; z-index: 2; }

/* 缓冲转圈：屏幕中央，不挡操作 */
.buf-spin { position: fixed; left: 50%; top: 50%; margin: -18px 0 0 -18px; z-index: 30;
  width: 36px; height: 36px; opacity: 0; transition: opacity .18s; pointer-events: none; }
.buf-spin.show { opacity: 1; }
.buf-spin i { display: block; width: 100%; height: 100%; border-radius: 50%;
  border: 3px solid rgba(255,255,255,.28); border-top-color: #fff;
  animation: bufspin .8s linear infinite; }
@keyframes bufspin { to { transform: rotate(360deg); } }

/* 网速：转圈下面一行小字 */
.net-speed { position: fixed; left: 50%; top: 50%; transform: translate(-50%, 26px); z-index: 30;
  font-size: 12.5px; color: rgba(255,255,255,.85); text-shadow: 0 1px 3px rgba(0,0,0,.7);
  opacity: 0; transition: opacity .18s; pointer-events: none; white-space: nowrap; }
.net-speed.show { opacity: 1; }

/* ── 播放浮层分层（2026-10-03 用户要求）──────────────────
   进度条 / 缓冲圈 / 网速都属于「首页」这一层：
   它们挂在 body 上是 fixed，不限定视图就会跟着用户跑到朋友 / 消息 / 我 页面上。
   switchView() 会给 body 打 data-view，这里只在 feed 时放出来。 */
body[data-view="friends"] .progress, body[data-view="friends"] .buf-spin, body[data-view="friends"] .net-speed,
body[data-view="msg"] .progress,     body[data-view="msg"] .buf-spin,     body[data-view="msg"] .net-speed,
body[data-view="me"] .progress,      body[data-view="me"] .buf-spin,      body[data-view="me"] .net-speed {
  display: none !important;
}

/* 列表页标题（从「我/朋友」点进来的收藏/喜欢/作品/朋友列表用，2026-10-03） */
.list-title { position: fixed; left: 0; right: 0; top: 0; z-index: 21;
  padding: calc(10px + env(safe-area-inset-top)) 0 10px; text-align: center;
  font-size: 16px; font-weight: 600; color: #fff;
  text-shadow: 0 1px 4px rgba(0,0,0,.6); pointer-events: none; }

/* ── 放大后的「↻ 还原」按钮（2026-10-04 用户给抖音截图要求）──────
   双指捏合放大后画面是**停住**的，必须有这个明确的还原入口。
   默认 display:none，syncZoomReset() 在放大时给它加 .show。 */
.zoom-reset {
  position: fixed; z-index: 25; display: none;
  left: 16px; bottom: calc(96px + env(safe-area-inset-bottom));
  align-items: center; gap: 5px;
  height: 36px; padding: 0 14px 0 10px; border: 0; border-radius: 18px;
  background: rgba(0, 0, 0, .38); color: #fff; font-size: 13.5px;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.zoom-reset.show { display: inline-flex; }
.zoom-reset svg { width: 18px; height: 18px; }
.zoom-reset:active { background: rgba(0, 0, 0, .58); }

/* ── 清屏 / 放大 两层控制条（2026-10-04 照抖音两张截图重做）────
   清屏层：左下 ✕、右下 ⏸ + 1x
   放大层：左下 ↻ 还原、右下只有 ⏸
   显隐由 feed.js 的 syncClearBar() 按状态切换，这里只管长相。 */
.cs-bar {
  position: fixed; left: 0; right: 0; z-index: 60;
  bottom: calc(18px + env(safe-area-inset-bottom));
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 14px; pointer-events: none;   /* 只有按钮可点，别挡画面手势 */
}
.cs-bar > * { pointer-events: auto; }
.cs-bar button { border: 0; color: #fff; background: rgba(0,0,0,.4); }
.cs-bar button:active { background: rgba(0,0,0,.62); }

/* 左下 ✕（清屏层）：圆形纯图标 */
.cs-exit {
  width: 40px; height: 40px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}
.cs-exit svg { width: 20px; height: 20px; }

/* 左下 ↻ 还原（放大层）：胶囊带文字 */
.cs-reset {
  display: none; align-items: center; gap: 5px;
  height: 36px; padding: 0 14px 0 11px; border-radius: 18px; font-size: 13.5px;
}
.cs-reset svg { width: 17px; height: 17px; }

/* 右下：倍速 + 暂停/播放，并排 */
.cs-right { display: flex; align-items: center; gap: 8px; }
.cs-rate {
  height: 34px; padding: 0 12px; border-radius: 17px;
  font-size: 13.5px; font-variant-numeric: tabular-nums;
}
.cs-play {
  width: 40px; height: 40px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}
.cs-play svg { width: 20px; height: 20px; }

/* clearscreen-progress-guard */
/* 2026-10-04 用户：「清屏的时候进度条没有」——清屏就该是纯画面，
   进度条/时间/缓冲圈一个都不许冒出来（原来只藏在 body.clearscreen .progress 一条规则里，
   别的路径把 progress 设成 display:'' 时还会露头，这里用 !important 兜死）。 */
body.clearscreen #progress,
body.clearscreen .progress,
body.clearscreen #pTime,
body.clearscreen .pbar,
body.clearscreen .buf-spin,
body.clearscreen .net-speed { display: none !important; }

/* sheet-scroll-guard */
/* 2026-10-04 用户：「长按的页面滑动退出后不会退出而是操作底层页面」。
   弹层必须自己吃掉滚动手势，否则会"链"到底下的信息流（页面跟着滚，菜单不关）。 */
.sheet.act-sheet {
  overscroll-behavior: contain;   /* 滚到头也不把滚动传给父级 */
  touch-action: pan-y;            /* 只允许纵向拖（弹层内部滚动），不让它去滚底层 */
}
/* 弹层打开时锁住底层页面滚动 —— 双保险，防止某些内核忽略 overscroll-behavior */
body.sheet-open { overflow: hidden; }

/* 「重新生成」按钮（2026-10-04 用户要求）：在生成信息面板底部，
   点了带着这条视频的参数跳到小说配图。做成整行宽按钮，手指好点。 */
.gen-regen {
  display: block; width: 100%; margin-top: 12px;
  height: 40px; border: 0; border-radius: 9px;
  background: #fe2c55; color: #fff; font-size: 14px; font-weight: 600;
}
.gen-regen:active { opacity: .82; }
