/* 短剧介绍页 /drama/:id/ 与选集播放页 /drama/:id/:ep/ 的页面级样式。
 *
 * 配色/字号一律沿用 dx127 现有前台口径(components/theme-app.css):
 *   底色 #0a0a0b  正文 #f0ebe0  次要文字 #a8a39a  主色 #e81c2b  卡片底 #222
 * 没有引入 dx158 那套独立 drama 主题的任何变量或类名, 免得同一个站出现两种视觉语言。
 *
 * 断点与全站一致, 切在 768px。文件按「基础层 → max-width:768px(手机) →
 * min-width:769px(电脑)」三段排:
 *   基础层     两端共用的视觉与介绍页布局
 *   ≤768px     手机版(单列, 海报与信息并排缩小, 选集栏变贴底 bottom sheet)
 *   ≥769px     电脑版播放页专属(播放器吃满首屏 + 选集栏变贴右滑出面板, 对齐 dx150)
 * 电脑端那一段是 2026-09 才加的第二个断点, 原因写在它自己的段首注释里。 */

/* ── 只在**短剧播放页**关掉浏览器的下拉刷新 ───────────────────────────────
 * 运营实测: 手机端在页面顶部下滑本该切到上一集, 结果被 Chrome 的 pull-to-refresh
 * (下拉刷新)抢走 —— 手势起点必然在「滚动区顶部」, 那正是 PTR 的触发条件,
 * 于是本页最想要的那个手势成了唯一一个必然被系统吃掉的手势。
 *
 * ── 为什么是 contain 而不是 none ──
 *   contain: 关掉「链到外层的过度滚动」, 即下拉刷新与滑动前进/后退这类**浏览器手势**,
 *            但**保留元素自身的过度滚动反馈**(安卓的边缘辉光、iOS 的橡皮筋回弹);
 *   none:    在 contain 的基础上连自身那点回弹/辉光也一起抹掉。
 * 我们要治的只是「手势被浏览器抢走」, 回弹是用户判断「到头了」的原生反馈, 抹掉它
 * 只会让第一集下滑显得像页面卡死。所以取能解决问题的最小值 contain。
 *
 * ── 为什么必须写在 html 上, 又为什么只写 -y ──
 * ⚠️ 第一版写在 body 上, 运营实测**没治住**, 下拉刷新照旧。
 * 原因是 overscroll-behavior 的传播规则与 overflow **不一样**: 只有写在根元素(html)
 * 上才传播到视口, 写在 body 上不传播 —— body 上那份只约束 body 自己这个盒子,
 * 而本页真正的滚动容器是 html(document.scrollingElement 实测就是 HTML)。
 * 实测证据: 改前 body 的计算值确实是 contain, 但 html 仍是 auto, 于是 PTR 照常触发。
 * 只覆盖 -y: 横向留 auto, 不干扰系统的左右滑返回手势。
 *
 * ── 作用域: 只有本页 ──
 * html 上没有页面标识类, 所以由模板给播放页的 <html> 打一个 data-drama-play 标记。
 * 用 data 属性而不是 class: 站内有脚本会往 html.className 上追加 os-mac/screen-phone
 * 之类的类, 万一哪天换成整体赋值, class 会被冲掉, data 属性不会。
 * 只有短剧播放页的模板带这个标记, 首页/列表/帖子的下拉刷新一动没动。
 *
 * ── 对页面内可滚动子容器没有影响 ──
 * overscroll-behavior 管的是「从**本元素**滚到头之后要不要把滚动链给祖先」, 不是
 * 「本元素能不能滚」。选集面板(.drama-play-side-sheet{overflow-y:auto})、评论列表
 * (.drama-comments{overflow-y:auto})各自的 overscroll-behavior 仍是默认 auto, 内部照常滚,
 * 滚到头也照常把剩下的位移链给外层 —— 只是链到 body 就停住, 不再变成一次下拉刷新。
 * (面板打开时 body 本来就被 .drama-ep-sheet-open 锁成 overflow:hidden, 更没得滚。) */
html[data-drama-play] {
  overscroll-behavior-y: contain;
}

body.theme-app .page-drama {
  background: #0a0a0b;
  min-height: 0;
  overflow-x: hidden;
  padding-bottom: 24px;
}

/* 全站 .breadcrumb 把高度写死成 61px(手机端 32px), 只够放一行。
 * 本页面包屑末级是完整剧名, 剧名一长必然换行, 第二行就会压到下面的 <h1> 上
 * (430px 视口下实测重叠)。这里只把本页的面包屑改成自适应高度, 不动全局那条
 * —— 列表页/标签页的末级都是短词, 固定高度是它们对齐首屏用的。 */
body.theme-app .page-drama .drama-breadcrumb {
  height: auto;
  min-height: 61px;
  padding-bottom: 8px;
}

/* ── 介绍页: 标题 + 左海报右信息 ───────────────────────────────────────── */
body.theme-app .drama-detail,
body.theme-app .drama-play {
  padding: 16px 20px 0;
}

body.theme-app .drama-title {
  margin: 0 0 16px;
  color: #f0ebe0;
  font-size: 28px;
  line-height: 39px;
  font-weight: 600;
  word-break: break-word;
}

body.theme-app .drama-main {
  display: flex;
  gap: 24px;
  align-items: flex-start;
}

/* 海报固定 9:16 竖版。aspect-ratio 直接锁比例, 图片未解密到位时也不会跳版
 * (封面是 AES 密文, 由 lazyload 解密后才替换 src, 中间有一段占位期)。 */
body.theme-app .drama-poster {
  position: relative;
  flex: 0 0 288px;
  width: 288px;
  aspect-ratio: 9 / 16;
  border-radius: 8px;
  overflow: hidden;
  background: #1a1a1c;
}

body.theme-app .drama-poster-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

body.theme-app .drama-poster-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  padding: 2px 8px;
  border-radius: 4px;
  background: #e81c2b;
  color: #fff;
  font-size: 12px;
  line-height: 18px;
}

body.theme-app .drama-info {
  flex: 1 1 auto;
  min-width: 0;
}

body.theme-app .drama-block {
  margin-bottom: 18px;
}

body.theme-app .drama-sub {
  margin: 0 0 8px;
  color: #f0ebe0;
  font-size: 16px;
  line-height: 22px;
  font-weight: 600;
}

/* ── 作品简介: 默认 4 行 clamp, 由 drama-detail.js 判定溢出后才亮出「展开」 ── */
body.theme-app .drama-desc {
  margin: 0;
  color: #a8a39a;
  font-size: 14px;
  line-height: 24px;
  white-space: pre-wrap;
  word-break: break-word;
}

body.theme-app .drama-desc.is-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

body.theme-app .drama-desc-toggle {
  margin-top: 6px;
  padding: 0;
  border: 0;
  background: transparent;
  color: #e81c2b;
  font-size: 13px;
  line-height: 20px;
  cursor: pointer;
}

/* ── 作品评分: 星条宽度 = score*10%, 无评分时整块不渲染(见模板 {{if .score}}) ── */
body.theme-app .drama-rating {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

body.theme-app .drama-stars {
  position: relative;
  display: inline-block;
  /* 宽度写成 5em(= 5 个 ★ 的字宽)而不是固定 px: 亮星层的 width 是百分比,
   * 容器宽度必须正好等于星串宽度, 百分比才对得上分值(8.4 分 → 84% 正好压到第 4.2 颗)。
   * letter-spacing 同理不能加, 会让字符总宽 > 容器宽而整体偏移。 */
  width: 5em;
  height: 20px;
  /* 底层灰星 + 上层同字符裁比例宽度当亮星, 免额外图片请求。 */
  color: rgba(255, 255, 255, 0.22);
  font-size: 18px;
  line-height: 20px;
  overflow: hidden;
}

body.theme-app .drama-stars::before {
  content: '★★★★★';
}

body.theme-app .drama-stars i {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  overflow: hidden;
  color: #e81c2b;
  font-style: normal;
  white-space: nowrap;
}

body.theme-app .drama-stars i::before {
  content: '★★★★★';
}

body.theme-app .drama-score {
  color: #e81c2b;
  font-size: 22px;
  line-height: 26px;
  font-weight: 700;
}

body.theme-app .drama-score-unit {
  color: #a8a39a;
  font-size: 12px;
}

/* ── 作品标签: 胶囊, 链到全站标签页 ─────────────────────────────────────── */
body.theme-app .drama-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

body.theme-app .drama-tags a,
body.theme-app .drama-tags span {
  display: inline-flex;
  align-items: center;
  height: 26px;
  padding: 0 12px;
  border-radius: 13px;
  background: #222;
  color: rgba(255, 255, 255, 0.72);
  font-size: 12px;
  line-height: 26px;
}

body.theme-app .drama-tags a:hover {
  background: #e81c2b;
  color: #fff;
}

/* ── 作品资料: 两列键值表 ───────────────────────────────────────────────── */
body.theme-app .drama-meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 24px;
  margin: 0;
}

body.theme-app .drama-meta > div {
  display: flex;
  gap: 10px;
  min-width: 0;
  font-size: 13px;
  line-height: 22px;
}

body.theme-app .drama-meta dt {
  flex: 0 0 40px;
  color: #6f6a63;
  font-weight: 400;
}

body.theme-app .drama-meta dd {
  margin: 0;
  min-width: 0;
  color: #d8d2c7;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

body.theme-app .drama-meta dd a {
  color: #e81c2b;
}

/* ── 底部按钮排 ─────────────────────────────────────────────────────────── */
body.theme-app .drama-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 20px;
}

body.theme-app .drama-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 104px;
  height: 38px;
  padding: 0 18px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 19px;
  background: transparent;
  color: #f0ebe0;
  font-size: 14px;
  line-height: 38px;
  cursor: pointer;
}

body.theme-app .drama-btn-play {
  border-color: #e81c2b;
  background: #e81c2b;
  color: #fff;
  font-weight: 600;
}

body.theme-app .drama-btn-ghost:hover {
  border-color: #e81c2b;
  color: #e81c2b;
}

body.theme-app .drama-btn.is-active {
  border-color: #e81c2b;
  color: #e81c2b;
}

body.theme-app .drama-btn.is-disabled {
  opacity: 0.4;
  cursor: default;
  pointer-events: none;
}

body.theme-app .drama-btn-ico {
  font-size: 13px;
}

/* ── 选集: 分段 tabs + 网格 ─────────────────────────────────────────────── */
body.theme-app .drama-eps {
  margin-top: 28px;
}

body.theme-app .drama-sec-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

body.theme-app .drama-sec-head h2 {
  margin: 0;
  color: #f0ebe0;
  font-size: 18px;
  line-height: 25px;
  font-weight: 600;
}

body.theme-app .drama-sec-head span {
  color: #6f6a63;
  font-size: 12px;
}

body.theme-app .drama-ep-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

body.theme-app .drama-ep-tabs button {
  height: 28px;
  padding: 0 14px;
  border: 0;
  border-radius: 14px;
  background: #222;
  color: rgba(255, 255, 255, 0.62);
  font-size: 12px;
  cursor: pointer;
}

body.theme-app .drama-ep-tabs button.is-active {
  background: #e81c2b;
  color: #fff;
}

body.theme-app .drama-ep-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  gap: 10px;
}

body.theme-app .drama-ep {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 6px;
  background: #17171a;
}

/* 分段切换靠 JS 写 hidden 属性(drama-play.js / drama-detail.js 的 showChunk)，
 * 但上面那条 .drama-ep{display:flex} 特异性 (0,2,1) 会把 UA 默认的
 * [hidden]{display:none}(0,1,0) 压掉 —— 结果 hidden 属性写上了，元素照样显示，
 * 45 集的剧一次性把三段全铺出来。这条把它按回去，特异性 (0,3,1) 稳压。
 * 用属性选择器而不是让 JS 改类名: hidden 属性同时带无障碍语义(读屏跳过)，
 * 换成类名就丢了这一层。 */
body.theme-app .drama-ep[hidden] {
  display: none;
}

body.theme-app .drama-ep b {
  color: #f0ebe0;
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
}

/* 分集标题一行截断: 标题长短不一时网格仍然齐整。 */
body.theme-app .drama-ep span {
  color: #6f6a63;
  font-size: 12px;
  line-height: 17px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

body.theme-app .drama-ep:hover {
  border-color: #e81c2b;
}

body.theme-app .drama-ep.is-cur {
  border-color: #e81c2b;
  background: rgba(232, 28, 43, 0.12);
}

body.theme-app .drama-ep.is-cur b {
  color: #e81c2b;
}

/* 置灰格(未更新 / 已下架 / 缺号)。2026-09-09 集号网格改成「按总集数铺满 1..N」后新增:
 * 缺的集不再被跳过, 而是灰在原位, 用户才不会看到「最后一格 121, 头上却写 119 集」。
 *
 * 这里只管视觉 —— 它在 HTML 里已经是 <span> 而不是无 href 的 <a>(理由见 drama.go
 * 的 dramaEpisodeVMs 注释), 本来就点不动。比可播格更暗 + 鼠标不变手型 + 收掉 hover,
 * 一眼看得出「这一格没得点」。
 *
 * 刻意不用 dx150 那条 pointer-events:none: 它会连 title 提示一起吃掉(鼠标悬停看不到
 * 「未更新」/「暂不可播」的说明), 而 <span> 本来就没有可点行为, 不需要靠它兜。 */
body.theme-app .drama-ep.is-locked {
  opacity: 0.38;
  cursor: default;
}

/* hover 单独按回去: 上面那条 .drama-ep:hover{border-color:#e81c2b} 与本条特异性同为
 * (0,2,1), 谁后写谁赢 —— 必须写在它后面, 否则置灰格鼠标划过还会亮红边。 */
body.theme-app .drama-ep.is-locked:hover {
  border-color: rgba(255, 255, 255, 0.1);
}

/* ══ 播放页 ══════════════════════════════════════════════════════════════ */

body.theme-app .drama-play-title {
  margin: 0 0 14px;
  color: #f0ebe0;
  font-size: 22px;
  line-height: 30px;
  font-weight: 600;
  word-break: break-word;
}

/* 主区栅格。基础层是**单列**(手机端形态): 播放器 → 按钮排 → 选集依次堆叠。
 * 电脑端由文件末尾的 min-width:769px 段改成两栏(左 1fr + 右 380px 常驻选集卡片,
 * 对齐 dx150 的 .hg-web-play__main)。
 *
 * 用 grid 而不是块级: 两端的间距都靠 gap 一处控制, 换成块级得给 aside 单独补 margin,
 * 还得在电脑端再清掉。align-items:start 让右栏卡片贴顶而不是被拉到与播放器等高。 */
body.theme-app .drama-play-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}

body.theme-app .drama-play-main {
  min-width: 0;
}

/* 横版大播放器。不设 max-width —— 宽度由上面的栅格列决定,
 * 再加一层 max-width 只会在宽屏上让播放器和右栏之间空出一条无意义的缝。 */
body.theme-app .drama-player-frame {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
  overflow: hidden;
  background: #000;
}

body.theme-app .drama-player-mount {
  width: 100%;
  height: 100%;
}

body.theme-app .drama-play-sub {
  margin: 10px 0 0;
  color: #6f6a63;
  font-size: 13px;
  line-height: 20px;
}

/* ── 操作按钮排: 五格等宽平铺 ───────────────────────────────────────────── */
/* 用 grid 的 repeat(5, minmax(0,1fr)) 而不是 flex:1 —— minmax(0,...) 是关键:
 * 默认 min-width:auto 会让内容最宽的那格(带计数的「点赞」)撑得比别人宽, 五格立刻不齐。 */
body.theme-app .drama-play-actions {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
  margin-top: 14px;
}

/* 多集剧多一格「选集」= 六格。
 * 这条实际只对手机端有意义: 电脑端 2026-09-09 改回右侧常驻选集卡片后, 「选集」按钮
 * 在 min-width:769px 段被 display:none 掉了, 那边同时把列数按回 5 —— 否则 6 列只站
 * 5 个按钮, 最右边空出一格。留在基础层是因为手机端沉浸式那段还要继承它的 grid 语义。
 * 手机端 430px 视口的算账(为什么六格一行放得下)保留在下面手机端那节的注释里。 */
body.theme-app .drama-play-actions.has-eplist {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

body.theme-app .drama-act {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  height: 40px;
  padding: 0 6px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 6px;
  background: #17171a;
  color: #d8d2c7;
  font-size: 13px;
  line-height: 20px;
  text-align: center;
  cursor: pointer;
}

body.theme-app .drama-act:hover {
  border-color: #e81c2b;
  color: #e81c2b;
}

body.theme-app .drama-act.is-active {
  border-color: #e81c2b;
  color: #e81c2b;
}

body.theme-app .drama-act.is-disabled {
  opacity: 0.38;
  cursor: default;
  pointer-events: none;
}

body.theme-app .drama-act-svg {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  object-fit: contain;
}

/* 点赞/收藏的双图标: 默认灰线稿, is-active 时换成实心红。
 * 与 /video/:id/ 右侧互动列同一套 icon 与同一种切换方式。 */
body.theme-app .drama-act-svg-on {
  display: none;
}

body.theme-app .drama-act.is-active .drama-act-svg-off {
  display: none;
}

body.theme-app .drama-act.is-active .drama-act-svg-on {
  display: block;
}

body.theme-app .drama-act-ico {
  flex: 0 0 auto;
  font-size: 16px;
  line-height: 1;
}

/* 文字一行截断: 「上一集」这种三字标签在窄格里也不能把按钮撑高成两行。 */
body.theme-app .drama-act-txt {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── 五个「只在手机端存在」的节点, 基础层一律关掉 ─────────────────────────
 * 电脑端是禁改区, 这几条保证它们在 ≥769px 上完全不参与布局。
 * **关键**: 用「基础层 display:none + 手机端打开」这个方向, 而不是「基础层显示 +
 * 电脑端关掉」—— 后者要往 min-width:769px 那段里加规则, 而那段这轮一个字都不能动。
 *   .drama-act-share       右侧互动列的「分享」。.drama-play-actions 是 grid,
 *                          display:none 的子元素不占格子, 电脑端仍是原来的 5/6 格。
 *   .drama-sheet-close     评论抽屉的关闭按钮(电脑端这块是正常流, 没有可关的东西)。
 *   .drama-play-mobile-sub 沉浸式左下角信息区的第二行(电脑端由 .drama-play-sub 承担)。
 *   .drama-side-tabs       选集面板内的「选集/猜你喜欢/最新地址」tab 条。电脑端那张
 *                          380px 常驻卡片必须只有选集内容, 这条就是它的保险丝。
 *   .drama-swipe-tip       「↑ 上滑看下一集」提示, 电脑端没有手势也就没有提示。 */
body.theme-app .drama-act-share,
body.theme-app .drama-sheet-close,
body.theme-app .drama-play-mobile-sub,
body.theme-app .drama-side-tabs,
body.theme-app .drama-swipe-tip {
  display: none;
}

/* 板块标题(猜你喜欢 / 评论 / 最新地址), **只在电脑端存在**, 走的是上面同一个方向:
 * 基础层关掉, 由 min-width:769px 段打开(手机端整段这轮一个字都不能动)。
 * 为什么手机端不要它: 那三块在手机端分别待在选集面板和评论抽屉里, 上头已经有 tab 条
 * 或抽屉标题说明「这是哪一块」, 再来一行大标题就是重复, 还白占抽屉里本就紧张的高度。
 * 电脑端则相反 —— 三块常驻铺开依次排列, 没有标题就分不清一块到哪结束, 锚点滚过去
 * 也看不出落到了哪。 */
body.theme-app .drama-sec-title {
  display: none;
}

/* [hidden] 兜底(与本文件 .drama-ep / .drama-comment-more 同一条教训):
 * 只要某条规则给这些容器写了 display 值, UA 样式表里那条低优先级的
 * [hidden]{display:none} 就压不住, JS 切 tab 写了 hidden 属性也不隐藏。
 * 这两个容器眼下没被写过 display, 但 tab 切换完全依赖 hidden, 先把闸门焊死。
 *   .drama-side-panel  选集面板里的「选集」那一栏(手机端由 .drama-side-tabs 切);
 *   .drama-tab-panel   猜你喜欢/评论/最新地址三块(电脑端由下方 tab 条切,
 *                      手机端前两者会被搬进选集面板, 由 .drama-side-tabs 切)。 */
body.theme-app .drama-side-panel[hidden],
body.theme-app .drama-tab-panel[hidden] {
  display: none;
}

/* 「↑ 上滑看下一集」的淡出。5s 后停在 opacity:0(animation-fill-mode:forwards),
 * 节点仍留在 DOM 与无障碍树里 —— 它只是一句纯文本, 不值得为它写 display:none
 * 或一条 setTimeout。keyframes 放基础层而不是塞进 max-width:768px 段:
 * @keyframes 是全局命名空间, 定义在哪个断点里都一样, 放外面更好找。 */
@keyframes dramaSwipeTipFade {
  0% {
    opacity: 0;
  }

  12% {
    opacity: 1;
  }

  76% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

/* 遮罩只服务手机端的 bottom sheet, 基础层 display:none, 由文件末尾的
 * max-width:768px 媒体查询打开。
 * 电脑端 2026-09-09 起选集是右侧常驻卡片, 根本没有「打开」这个动作, 遮罩在那边
 * 永远不该出现。JS 那边照旧写 mask.hidden(手机端要用), 这条 display:none 兜着,
 * 即使脚本在电脑端误摘了 hidden 也不会有黑幕盖住页面。 */
body.theme-app .drama-play-mask {
  display: none;
}

/* 选集面板的关闭按钮。只有手机端 bottom sheet 用得上, 但样式放在基础层、由
 * min-width:769px 段 display:none 掉 —— 这样手机端那整段不必再为它写一份定义,
 * 与本文件既有的 .drama-act-share / .drama-sheet-close 是同一套隐藏策略(方向相反)。 */
body.theme-app .drama-side-close {
  display: block;
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: #a8a39a;
  font-size: 14px;
  line-height: 28px;
  text-align: center;
  cursor: pointer;
}

/* ── 选集栏 ─────────────────────────────────────────────────────────────── */
/* 基础层 = 流内一张小卡片。2026-09-09 起**没有任何页面停在这个形态**(单集剧也进了
 * 面板/卡片), 它只剩两个作用: 给下面两种形态提供共同底色, 以及 CSS 没加载完时的退化态。
 * 两种真实形态各自改写:
 *   电脑端(≥769px)   右侧 380px 常驻大卡片, 对齐 dx150;
 *   手机端(≤768px)   贴底 bottom sheet(.drama-play-side-sheet, 现在无条件加)。 */
body.theme-app .drama-play-side {
  min-width: 0;
  padding: 14px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  background: #131316;
}

/* align-items 用 center 而不是 baseline: 标题行右端现在恒有一颗圆形 ✕(两端共用),
 * baseline 会把它按文字基线吊到标题下沿。 */
body.theme-app .drama-side-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

body.theme-app .drama-side-title {
  min-width: 0;
  margin: 0;
  overflow: hidden;
  color: #f0ebe0;
  font-size: 16px;
  line-height: 22px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

body.theme-app .drama-side-cur {
  flex: 0 0 auto;
  color: #e81c2b;
  font-size: 12px;
  line-height: 18px;
}

body.theme-app .drama-side-sub {
  margin: 6px 0 12px;
  color: #6f6a63;
  font-size: 12px;
  line-height: 18px;
}

/* 选集栏里的格子比介绍页那张大网格窄一档, 否则窄栏里每行只放得下两格。
 * 这条是基础层兜底; 两种主形态各自改写:
 * 电脑端常驻卡片 5 列定宽(见 min-width:769px 段), 手机端 bottom sheet auto-fill 64px。 */
body.theme-app .drama-side-grid {
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 8px;
  max-height: 420px;
  overflow-y: auto;
}

/* ══ 下方 tab: 猜你喜欢 / 评论 / 最新地址 ═══════════════════════════════ */
body.theme-app .drama-tabs-wrap {
  margin-top: 28px;
}

body.theme-app .drama-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

body.theme-app .drama-tabs button {
  height: 32px;
  padding: 0 16px;
  border: 0;
  border-radius: 16px;
  background: #222;
  color: rgba(255, 255, 255, 0.62);
  font-size: 14px;
  cursor: pointer;
}

body.theme-app .drama-tabs button.is-active {
  background: #e81c2b;
  color: #fff;
}

body.theme-app .drama-tab-empty {
  margin: 0;
  padding: 24px 0;
  color: #6f6a63;
  font-size: 13px;
  text-align: center;
}

/* ══ 猜你喜欢: 竖版海报卡片网格(介绍页底部与播放页 tab 共用) ═════════════ */
/* PC 五列(2026-09 运营要求, 由四列改来), 手机端两列。auto-fill 会在超宽屏上排出
 * 七八列把卡片压扁, 所以列数写死, 只让每列宽度随容器伸缩。
 * 播放页这块网格挂在 .drama-tabs-wrap 上, 是 .drama-play-body 的**兄弟**节点。
 * 选集栏 2026-09 改成滑出面板后已脱离正常流, 两栏也收成了单列, 这块网格拿到的是
 * 整个主区宽度, 五列后卡片有 227px(1440 视口), 与介绍页同宽。 */
body.theme-app .drama-rec-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}

body.theme-app .drama-rec-item {
  min-width: 0;
}

body.theme-app .drama-rec-link {
  display: block;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

/* 海报 9:16。aspect-ratio 直接锁比例, 图片未解密到位时也不会跳版
 * (封面是 AES 密文, 由 lazyload 解密后才替换 src, 中间有一段占位期)。 */
body.theme-app .drama-rec-cover {
  position: relative;
  width: 100%;
  aspect-ratio: 9 / 16;
  border-radius: 6px;
  overflow: hidden;
  background: #1a1a1c;
}

body.theme-app .drama-rec-img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

/* 三个角标共用一套底色, 只靠定位区分: 左上独播 / 右上评分 / 右下集数。 */
body.theme-app .drama-rec-flag,
body.theme-app .drama-rec-score,
body.theme-app .drama-rec-ep {
  position: absolute;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 11px;
  line-height: 18px;
  white-space: nowrap;
}

body.theme-app .drama-rec-flag {
  top: 6px;
  left: 6px;
  background: #e81c2b;
  color: #fff;
}

body.theme-app .drama-rec-score {
  top: 6px;
  right: 6px;
  background: rgba(0, 0, 0, 0.62);
  color: #ffc53d;
  font-weight: 600;
}

body.theme-app .drama-rec-ep {
  right: 6px;
  bottom: 6px;
  background: rgba(0, 0, 0, 0.62);
  color: rgba(255, 255, 255, 0.86);
}

body.theme-app .drama-rec-title {
  margin: 8px 0 0;
  overflow: hidden;
  color: #f0ebe0;
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 简介固定两行: 长短不一的简介不截断会让同一行的卡片高度参差。 */
body.theme-app .drama-rec-desc {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  margin: 4px 0 0;
  height: 36px;
  overflow: hidden;
  color: #6f6a63;
  font-size: 12px;
  line-height: 18px;
}

body.theme-app .drama-rec-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
  max-height: 22px;
  overflow: hidden;
}

body.theme-app .drama-rec-tags a {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 8px;
  border-radius: 11px;
  background: #222;
  color: rgba(255, 255, 255, 0.66);
  font-size: 11px;
  line-height: 22px;
}

body.theme-app .drama-rec-tags a:hover {
  background: #e81c2b;
  color: #fff;
}

/* ══ 评论 tab ═══════════════════════════════════════════════════════════ */
/* 视觉对齐 /video/:id/ 的评论面板(.video-comment*), 但类名另起 drama-* ——
 * video.css 里带 `body.theme-app.layout-menu .app-main{...}` 这类全局覆盖,
 * 在本页引入会把外壳布局整个改掉, 所以只能把需要的那几条按同样的视觉重写。
 * 交互(登录拦截/发评论接口/提示文案)是完全复用的, 见 js/pages/drama-play.js。 */
body.theme-app .drama-comment-head {
  padding-bottom: 12px;
  color: #f0ebe0;
  font-size: 15px;
  line-height: 20px;
}

body.theme-app .drama-comments {
  margin: 0;
  padding: 0;
  list-style: none;
}

body.theme-app .drama-comment {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

body.theme-app .drama-comment-avatar {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #1976d2;
  color: #fff;
  font-size: 15px;
  font-weight: 700;
}

body.theme-app .drama-comment:nth-child(3n) .drama-comment-avatar {
  background: #15945d;
}

body.theme-app .drama-comment:nth-child(4n) .drama-comment-avatar {
  background: #6f2dbd;
}

body.theme-app .drama-comment-body {
  min-width: 0;
}

body.theme-app .drama-comment-author {
  margin: 0;
  color: rgba(255, 255, 255, 0.5);
  font-size: 13px;
  line-height: 18px;
  font-weight: 500;
}

body.theme-app .drama-comment-text {
  margin: 2px 0 0;
  color: #f0ebe0;
  font-size: 14px;
  line-height: 21px;
  word-break: break-word;
}

body.theme-app .drama-comment-time {
  display: block;
  margin-top: 2px;
  color: rgba(255, 255, 255, 0.34);
  font-size: 12px;
  line-height: 18px;
}

body.theme-app .drama-comment-empty {
  padding: 24px 0;
  color: #6f6a63;
  font-size: 13px;
  text-align: center;
}

/* ── 评论「加载更多」 ───────────────────────────────────────────────────── */
/* 首屏 20 条是 SSR 直出的, 这个按钮只管第 2 页起的追加; 模板在「确实还有下一页」
 * 时才渲染它, 所以基础层不需要隐藏态。翻到最后一页后由 JS 把整个 wrap 摘掉。 */
body.theme-app .drama-comment-more {
  display: flex;
  justify-content: center;
  margin-top: 14px;
}

/* [hidden] 兜底: 上面那条 display:flex 特异性 (0,2,1), 压得过 UA 默认的
 * [hidden]{display:none}(它是靠 UA 样式表的低优先级生效的), JS 写 hidden 属性就不灵了。
 * 本文件的 .drama-ep / .drama-play-mask 已经各栽过一次, 这里一起守住。 */
body.theme-app .drama-comment-more[hidden] {
  display: none;
}

body.theme-app .drama-comment-more-btn {
  min-width: 140px;
  height: 34px;
  padding: 0 18px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 17px;
  background: #17171a;
  color: #d8d2c7;
  font-size: 13px;
  line-height: 32px;
  cursor: pointer;
}

body.theme-app .drama-comment-more-btn:hover {
  border-color: #e81c2b;
  color: #e81c2b;
}

/* 加载中: 置灰 + 禁点。JS 同时会写 disabled, 这条只负责让「不能点」看得出来。 */
body.theme-app .drama-comment-more-btn[disabled] {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}

body.theme-app .drama-comment-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 72px;
  gap: 10px;
  align-items: end;
  margin-top: 14px;
}

body.theme-app .drama-comment-form textarea {
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  padding: 8px 12px;
  border: 0;
  border-radius: 4px;
  background: #222;
  color: #fff;
  font-size: 14px;
  line-height: 20px;
  resize: none;
  outline: 0;
}

body.theme-app .drama-comment-form textarea::placeholder {
  color: rgba(255, 255, 255, 0.42);
}

body.theme-app .drama-comment-form button {
  height: 38px;
  border: 0;
  border-radius: 4px;
  background: #e81c2b;
  color: #fff;
  font-size: 14px;
  cursor: pointer;
}

/* ══ 最新地址 tab ═══════════════════════════════════════════════════════ */
body.theme-app .drama-addr-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

body.theme-app .drama-addr-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

body.theme-app .drama-addr-label {
  flex: 0 0 72px;
  color: #6f6a63;
  font-size: 13px;
  line-height: 20px;
}

body.theme-app .drama-addr-link {
  min-width: 0;
  color: #e81c2b;
  font-size: 14px;
  line-height: 20px;
  word-break: break-all;
}

body.theme-app .drama-addr-tip {
  margin: 12px 0 0;
  color: #6f6a63;
  font-size: 12px;
  line-height: 18px;
}

/* 后台录入的整块自定义 HTML(sq_setting 的 web_video_addr_html)的容器。
 * 只给字色/字号/行高这类**继承属性**兜底 —— 页面底色是深色, 运营多半只写纯文本或
 * 一串 <a>, 不兜的话会拿到浏览器默认的黑字, 在 #0a0a0b 上等于看不见。
 * 刻意不写 display / padding / 布局类属性: 「整块自定义」的意义就是版式由运营决定,
 * 我们多加一条都可能把他们的排版顶歪。
 * 里面的链接跟随 .drama-addr-link 的主色口径, 与默认版式看起来是同一块东西。 */
body.theme-app .drama-addr-custom {
  color: rgba(255, 255, 255, 0.72);
  font-size: 14px;
  line-height: 22px;
  word-break: break-all;
}

body.theme-app .drama-addr-custom a {
  color: #e81c2b;
}

/* ── 手机端 ─────────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  body.theme-app .page-drama .drama-breadcrumb {
    min-height: 32px;
    padding-bottom: 6px;
  }

  body.theme-app .drama-detail,
  body.theme-app .drama-play {
    padding: 12px 10px 0;
  }

  body.theme-app .drama-title {
    font-size: 20px;
    line-height: 28px;
    margin-bottom: 12px;
  }

  /* 手机端改单列: 375px 宽再挤两栏, 右侧信息区只剩 220px, 作品资料的两列表格和
   * 底部四个按钮全部会折行叠成一坨。海报单独一行居中(收到 150px, 不占满首屏),
   * 简介/评分/标签/资料/按钮整幅铺开。 */
  body.theme-app .drama-main {
    flex-direction: column;
    align-items: center;
    gap: 14px;
  }

  body.theme-app .drama-poster {
    flex: 0 0 auto;
    width: 150px;
  }

  body.theme-app .drama-info {
    width: 100%;
  }

  body.theme-app .drama-sub {
    font-size: 15px;
  }

  body.theme-app .drama-meta {
    grid-template-columns: minmax(0, 1fr);
    gap: 4px;
  }

  body.theme-app .drama-btn {
    flex: 1 1 auto;
    min-width: 0;
    height: 34px;
    padding: 0 12px;
    font-size: 13px;
    line-height: 34px;
  }

  body.theme-app .drama-ep-grid {
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 8px;
  }

  body.theme-app .drama-player-frame {
    border-radius: 0;
    margin: 0 -10px;
    width: calc(100% + 20px);
    max-width: none;
  }

  body.theme-app .drama-play-title {
    font-size: 18px;
    line-height: 25px;
  }

  /* 手机端堆叠顺序 = DOM 顺序: 播放器 → 操作按钮排 → 选集(单集剧才在流内) →
   * tab(推荐/评论/最新地址)。单列本身已经写在基础层了, 这里只收窄间距。 */
  body.theme-app .drama-play-body {
    gap: 16px;
  }

  /* 按钮排在 430px 下每格只有约 76px(五格), 图标 + 三个字横排必然溢出;
   * 改成图标在上文字在下的纵向排布, 字号收到 11px 正好放得下「上一集」。 */
  body.theme-app .drama-play-actions {
    gap: 6px;
  }

  /* 多集剧加「选集」后是六格(规则本身在基础层, 两端共用)。430px 视口实测算账,
   * 说明六格在最窄的目标机型上也放得下:
   *   可用宽 = 430 - .drama-play 左右各 10px = 410; 减 5 条 6px 的 gap = 380; 每格 63.3px。
   *   每格再去掉 .drama-act 的 padding 0 2px, 文字可用 59.3px;
   *   最宽的标签「上一集」是 3 个全角字 × 11px = 33px, 余量近一倍, 不会截断。
   *   375px 的老机型同理算得每格 54.2px / 文字可用 50.2px, 仍放得下 33px。
   * 所以六格一行成立, 不需要退成两行三格 —— 折两行会把播放器下方顶高一截,
   * 首屏就看不到选集栏和 tab 了。 */
  body.theme-app .drama-act {
    flex-direction: column;
    gap: 2px;
    height: 52px;
    padding: 0 2px;
    font-size: 11px;
    line-height: 16px;
  }

  body.theme-app .drama-act-svg {
    width: 20px;
    height: 20px;
  }

  body.theme-app .drama-act-ico {
    font-size: 15px;
    line-height: 20px;
  }

  /* 手机端选集栏去掉卡片外框与限高: 它已经是页面正常流里的一段, 再套一层框
   * 只是多两条线; 限高则会在页面本身能滚动时造成「框内框外两个滚动条」。 */
  body.theme-app .drama-play-side {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
  }

  body.theme-app .drama-side-grid {
    grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
    max-height: none;
    overflow-y: visible;
  }

  /* ── 手机端选集 bottom sheet ─────────────────────────────────────────────
   * 模板给 aside 加的 .drama-play-side-sheet 在手机端把**同一个**选集栏变成贴底面板,
   * 由按钮排的「选集」唤起。2026-09-09 起这个类**无条件**加(运营: 单集剧也要有选集),
   * 单集剧的面板里就一格集号 —— 与「平铺一小块」相比它至少入口一致、位置可预期。
   *
   * 为什么是「变形」而不是「另渲染一份面板」: 另渲染会让每个集号在同一页出现两个
   * <a href>, 内链重复、DOM 也大一倍; 变形则全页每集恰好一个链接, SSR 直出不变。
   * 平铺那份因此自然消失, 页面更紧凑 —— 这正是隐藏平铺栏想要的效果, 且没有
   * 「同一份内容出现两次」的副作用。
   *
   * 收起态用 transform 位移出视口, **不用 display:none / visibility:hidden**:
   * 那两者是明确的「隐藏内容」信号, 而本页是 noindex,follow, 这批集号内链是权重
   * 回流的主通道, 不值得冒被打折的风险。代价是收起时链接仍在 Tab 焦点序列里
   * (dx158 线上同款取舍); inert 属性能治, 但 Chrome 78 不支持, 本站必须兼容。
   *
   * 必须 position:fixed 而不是 absolute: 移动端浏览器工具栏会让 100vh 比真实可视区
   * 高出约 56px, absolute 贴底会被工具栏盖住(团队踩过)。 */
  body.theme-app .drama-play-side-sheet {
    position: fixed;
    z-index: 310;
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 72vh;
    padding: 16px 12px calc(20px + env(safe-area-inset-bottom, 0px));
    border: 0;
    border-radius: 14px 14px 0 0;
    background: #131316;
    box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.5);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    transform: translateY(100%);
    transition: transform 0.26s ease;
  }

  body.theme-app .drama-play-side-sheet.is-open {
    transform: translateY(0);
  }

  /* 遮罩压在面板之下、站内其它浮层(登录框 430/440)之上。
   * 开合由 JS 摘 hidden 属性控制, 这里只负责有 display 值可用。 */
  /* 四边写成 top/right/bottom/left 长写法而不是 inset:0 —— inset 简写要 Chrome 87+,
   * 本站兼容底线是 Chrome 78 的安卓存量机。在那些机器上 inset 整条被丢弃, 遮罩会缩成
   * 0×0, 表现就是「点遮罩关不掉面板」, 而遮罩正是最顺手的收起方式。 */
  body.theme-app .drama-play-mask {
    display: block;
    position: fixed;
    z-index: 300;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.55);
  }

  body.theme-app .drama-play-mask[hidden] {
    display: none;
  }

  /* 面板打开时锁住背景滚动。theme-app.css 上有 `body.theme-app{overflow-y:auto}`,
   * 单靠 .drama-ep-sheet-open 一个类特异性不够压不住, 必须连着 .theme-app 写。
   * 只在手机端定义: 万一 JS 在 PC 上误加这个类也不会把整页滚动锁死。 */
  body.theme-app.drama-ep-sheet-open {
    overflow: hidden;
  }

  /* 面板内格子比平铺时略窄一档: 贴底面板要在一屏里尽量多露几行集号。 */
  body.theme-app .drama-play-side-sheet .drama-side-grid {
    grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  }

  /* ── 选集面板内的三 tab: 选集 / 猜你喜欢 / 最新地址 ─────────────────────────
   * 2026-09-09 运营:「猜你喜欢和最新地址 都放到选集那个弹框里」。
   * 视觉沿用下方 tab 条那套胶囊(同色同圆角), 只把高度收到 28px —— 面板本身就只有
   * 72vh, tab 条占太高会挤掉能看见的集号行数。
   * 只在这一段打开(基础层 display:none): 电脑端那张 380px 常驻卡片只放选集内容,
   * 而 min-width:769px 那段这轮一个字都不能动, 所以开关必须在手机端这边。 */
  body.theme-app.drama-play-page .drama-side-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 10px 0 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  }

  body.theme-app.drama-play-page .drama-side-tabs button {
    height: 28px;
    padding: 0 12px;
    border: 0;
    border-radius: 14px;
    background: #222;
    color: rgba(255, 255, 255, 0.62);
    font-size: 13px;
    cursor: pointer;
  }

  body.theme-app.drama-play-page .drama-side-tabs button.is-active {
    background: #e81c2b;
    color: #fff;
  }

  /* 推荐网格手机端两列: 四列在 430px 下每张卡只有 96px, 海报缩到看不清封面。 */
  body.theme-app .drama-rec-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }

  body.theme-app .drama-rec-title {
    font-size: 13px;
    line-height: 18px;
  }

  body.theme-app .drama-comment-form {
    grid-template-columns: minmax(0, 1fr) 60px;
  }

  /* ══ 手机端沉浸式播放页 ═══════════════════════════════════════════════════
   * 2026-09 运营: 「手机端短剧播放页 样式和其他分类一样就行, 只不过是在右边加一个
   * 选集弹窗就行」。「其他分类」= 普通短视频播放页 /video/:id/ 的手机端 ——
   * 播放器铺满一屏、右侧竖排互动列、左下角标题信息、评论走贴底抽屉。
   *
   * ── 为什么是在这里照着 video.css 的视觉重写一份, 而不是让本页直接引 video.css ──
   * video.css 的**基础层**(不在任何媒体查询里)有这么一条全局覆盖:
   *     body.theme-app.layout-menu .app-main{margin-left:0;min-height:100vh;background:#151515}
   * 而 theme-app.css 的基础层是 `body.theme-app.layout-menu .app-main{margin-left:200px}`
   * —— 电脑端左侧那条 200px 固定 sidebar 的让位就靠它。两条选择器特异性完全相同
   * (0,3,1), 谁后加载谁赢。本页要引 video.css 只能排在 theme-app.css 之后,
   * 于是 margin-left 被清零, **电脑端**整个主区会滑到 sidebar 底下。
   * 电脑端是这轮的禁改区, 所以引 video.css 这条路直接堵死。
   * (/video/:id/ 自己没这个问题: 它的模板压根没有 sidebar, 清零正是它要的。)
   *
   * 另外两页的外壳也不同构: video.tpl 没有 h5-header / sidebar / footer / 面包屑 /
   * 下方 tab, drama-play.tpl 全都有。把 DOM 改成同构等于把本页重写成 video.tpl,
   * 选集内链、三个 tab 面板、评论列表都得重新安置, 改动面远大于抄一份手机端视觉。
   *
   * 所以沿用本文件既有的做法: **同一份 DOM, 两端两种 CSS 形态**(选集面板已经是这么做的),
   * 类名保持 drama-*, 像素值/配色/图标则逐项对齐 video.css 的手机端, 视觉一致。
   *
   * ── 隐藏策略 ──
   * 全篇没有一处对**站内链接**用 display:none。面包屑、页脚、猜你喜欢都还在 DOM 里:
   *   · 面包屑/页脚: 留在正常流, 被 z-index 更高的固定播放器盖住 + .app-main 的
   *     overflow:hidden 裁掉, 不是隐藏声明。
   *   · 猜你喜欢/最新地址: 跟评论一起进贴底抽屉, 用 transform 位移出视口
   *     (与选集面板同一套取舍)。
   * 本页是 noindex,follow, 这些内链是权重回流的通道, 而 Google 是移动优先渲染,
   * 手机端 display:none 等于对爬虫隐藏。
   *
   * ── z-index 分层(与本文件既有档位对齐) ──
   *   90  back-to-top(components) → 被播放器盖住
   *  100  .drama-player-frame 固定播放层
   *  120  左下信息区 + 右侧互动列(浮在播放器之上)
   *  160  .h5-header(components/top-bar.css 既定值, 顶栏仍可点)
   *  300  两个遮罩   310  选集面板 / 内容抽屉
   *  430+ 登录框(不动) */

  /* 整页收成一屏、不滚动 —— 对齐 /video/:id/ 手机端的
   * `.app-main{width:100vw;height:100vh;overflow:hidden}`。
   * 必须连 .drama-play-page 一起写: drama.css 同时被介绍页 /drama/:id/ 引用,
   * 只写 body.theme-app 会把介绍页也收成一屏, 那页是要能滚的。 */
  body.theme-app.drama-play-page {
    overflow: hidden;
  }

  body.theme-app.drama-play-page.layout-menu .app-main {
    height: 100vh;
    overflow: hidden;
  }

  /* .page-drama-play 同时挂着 .home-main, theme-app.css 在手机端给它
   * padding-top:50px 为固定顶栏让位。沉浸式下播放器要从视口顶端铺起, 这 50px 得收掉
   * (顶栏改成透明浮层, 不再需要让位)。 */
  body.theme-app.drama-play-page .page-drama-play {
    min-height: 0;
    height: 100vh;
    padding-top: 0;
  }

  /* 顶栏透明化: 保留导航/logo/搜索三个入口浮在播放器上方(/video/:id/ 手机端同样是
   * 一条浮在画面上的透明操作条)。不隐藏它 —— 短剧播放页是站内正常页面, 侧边分类
   * 导航是用户唯一的返回路径, 而 video.tpl 那页压根没有 sidebar 可回。 */
  body.theme-app.drama-play-page .h5-header {
    background: transparent;
    border-bottom: 0;
  }

  /* 播放器: 固定铺满整个视口。基础层与上面手机端那条 `margin:0 -10px` 的横版 16:9
   * 全部作废, 所以 aspect-ratio/height/margin/border-radius 逐条改写。 */
  body.theme-app.drama-play-page .drama-player-frame {
    position: fixed;
    z-index: 100;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: auto;
    height: auto;
    margin: 0;
    max-width: none;
    aspect-ratio: auto;
    border-radius: 0;
    background: #0a0a0b;
  }

  body.theme-app.drama-play-page .drama-player-mount {
    width: 100%;
    height: 100%;
  }

  /* object-fit 取 contain 而**不是** video.css 那边的 cover。
   * /video/:id/ 敢用 cover 是因为它的素材全是 9:16 竖版, 裁掉的只是上下几十像素;
   * 短剧分集素材比例不统一(既有竖版也有 16:9 横版), 在 9:16 的视口里对一条 16:9
   * 用 cover 等于放大约 3 倍、只剩画面正中一条竖带, 等于把片子毁了。
   * contain 在竖版素材上与 cover 视觉等价(都铺满), 在横版素材上老实上下留黑边。
   * left/transform 要显式改写: xgplayer 给 <video> 上的是
   * position:absolute;left:50%;transform:translateX(-50%), 不清掉画面会偏出去一半。 */
  body.theme-app.drama-play-page .drama-player-mount video {
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: transparent;
    transform: none;
  }

  /* 播放器上压一层自上而下的暗角, 保证白色标题/图标在任何画面上都读得清
   * (对齐 video.css 的 .video-swipe-slide::after)。pointer-events:none ——
   * 它必须完全不挡点击, 否则点画面暂停就失灵了。 */
  body.theme-app.drama-play-page .drama-player-frame::after {
    content: "";
    position: absolute;
    z-index: 4;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background: linear-gradient(
      180deg,
      rgba(0, 0, 0, 0.16) 0,
      rgba(0, 0, 0, 0.03) 42%,
      rgba(17, 17, 17, 0.86) 100%
    );
    pointer-events: none;
  }

  /* ── 左下信息区(对齐 .video-mobile-info) ────────────────────────────────
   * 两行: h1 剧名+集号 / 分集标题·总集数·状态。
   * right:76px 是给右侧互动列让出的宽度(列宽 48 + 右边距 12 + 间隙 16)。
   * 两个节点各自 fixed, 用**不同的 bottom 锚点**叠起来: 下面那行锁死单行高 20px,
   * 上面那行的 bottom 就能算准(70+20+4=94), 而且标题变长时是向**上**长, 不会压到下行。 */
  body.theme-app.drama-play-page .drama-play-title {
    position: fixed;
    z-index: 120;
    left: 15px;
    right: 76px;
    bottom: 94px;
    margin: 0;
    color: #eee;
    font-size: 15px;
    line-height: 21px;
    font-weight: 600;
    /* 最多两行, 超出省略 —— 剧名可以很长, 放任换行会一路顶到画面中间。 */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  body.theme-app.drama-play-page .drama-play-mobile-sub {
    display: block;
    position: fixed;
    z-index: 120;
    left: 15px;
    right: 76px;
    bottom: 70px;
    height: 20px;
    margin: 0;
    color: rgba(255, 255, 255, 0.92);
    font-size: 13px;
    line-height: 20px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* 电脑端那条副标题在手机端由上面的 .drama-play-mobile-sub 顶替。
   * 这里 display:none 不涉及任何链接, 只是同一句纯文本的两个呈现节点二选一。 */
  body.theme-app.drama-play-page .drama-play-sub {
    display: none;
  }

  /* ── 右侧竖排互动列(对齐 .video-mobile-actions) ─────────────────────────
   * 复用**同一个** .drama-play-actions ——ID 全部不变, 于是 drama-play.js 的点赞/
   * 收藏/评论/选集四个 handler 一行不用改, 两端共用一套。基础层那套
   * grid + repeat(5|6,1fr) 在这里整个换成纵向 flex。 */
  body.theme-app.drama-play-page .drama-play-actions {
    position: fixed;
    z-index: 120;
    right: 12px;
    bottom: 100px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 15px;
    width: 48px;
    margin: 0;
  }

  /* 上一集/下一集在手机端撤掉: 竖排互动列按运营口径只放
   * 点赞/评论/收藏/分享/选集五项, 切集统一走「选集」面板。
   * 这两个不是站内导航意义上的内链损失 —— 相邻集的地址在选集面板里逐集都有。 */
  body.theme-app.drama-play-page .drama-play-actions .drama-act[rel="prev"],
  body.theme-app.drama-play-page .drama-play-actions .drama-act[rel="next"],
  body.theme-app.drama-play-page .drama-play-actions .drama-act.is-disabled {
    display: none;
  }

  /* DOM 顺序是 点赞→收藏→评论→上一集→下一集→选集→分享(尾部追加的),
   * 运营要的展示顺序是 点赞→评论→收藏→分享→选集, 用 order 重排。
   * 改 order 而不是改 DOM 顺序: DOM 顺序是电脑端那排按钮的渲染顺序, 动不得。 */
  body.theme-app.drama-play-page #dramaLike {
    order: 1;
  }

  body.theme-app.drama-play-page #dramaCommentJump {
    order: 2;
  }

  body.theme-app.drama-play-page #dramaCollect {
    order: 3;
  }

  body.theme-app.drama-play-page #dramaShare {
    order: 4;
  }

  body.theme-app.drama-play-page #dramaEpSheetBtn {
    order: 5;
  }

  /* 互动列里的按钮换成「图标在上、文字在下」的无框样式(对齐 video.css 的
   * .video-mobile-actions button): 去掉边框和底色, 靠上面那层暗角保证可读。 */
  body.theme-app.drama-play-page .drama-play-actions .drama-act {
    width: 48px;
    height: auto;
    min-height: 42px;
    flex-direction: column;
    gap: 3px;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: #fff;
    font-size: 11px;
    line-height: 12px;
    font-weight: 500;
    text-shadow: 0 0 3px rgba(0, 0, 0, 0.25);
  }

  body.theme-app.drama-play-page .drama-act-share {
    display: flex;
  }

  /* 选中态只染文字, 图标本身已经由 .drama-act-svg-on 换成实心红图。 */
  body.theme-app.drama-play-page .drama-play-actions .drama-act.is-active {
    border: 0;
    color: #e81c2b;
  }

  body.theme-app.drama-play-page .drama-play-actions .drama-act:hover {
    border: 0;
    color: #fff;
  }

  body.theme-app.drama-play-page .drama-play-actions .drama-act.is-active:hover {
    color: #e81c2b;
  }

  body.theme-app.drama-play-page .drama-play-actions .drama-act-svg {
    width: 32px;
    height: 32px;
  }

  body.theme-app.drama-play-page .drama-play-actions .drama-act-ico {
    font-size: 26px;
    line-height: 32px;
  }

  /* ── 评论抽屉(2026-09-09 运营:「手机端评论还用原来的评论」) ─────────────────
   * 「原来的评论」= 普通播放页 /video/:id/ 手机端那个贴底评论抽屉。像素值逐项照抄
   * pages/video.css 的 .video-comment-drawer:
   *     position:fixed;z-index:20;left:0;right:0;bottom:0;height:56vh;min-height:320px;
   *     display:flex;flex-direction:column;border-radius:16px 16px 0 0;background:#0a0a0b;
   *     transform:translateY(104%);transition:transform .2s ease
   * 只有 z-index 换成本文件既定的 310 档(video.tpl 那页没有 sidebar/顶栏, 分层不同),
   * 类名仍是 drama-*。
   *
   * ⚠️ **不能靠引 video.css 来复用**。它的基础层有
   *     body.theme-app.layout-menu .app-main{margin-left:0}
   * 与 theme-app.css 的 margin-left:200px 特异性完全相同(0,3,1), 谁后加载谁赢;
   * 本页要引它只能排在 theme-app.css 之后 —— 于是**电脑端**主区整个滑到左侧 200px
   * sidebar 底下。电脑端是禁改区, 这条路已经堵死, 只能在这里按同样的视觉重写。
   *
   * 同样必须 position:fixed 而不是 absolute: 移动端浏览器工具栏会让 100vh 比真实可视区
   * 高约 56px, absolute 贴底会把评论输入框压到工具栏后面(团队踩过)。
   * 同样用 transform 收起而不是 display:none —— 见下面 .is-comment-only 的说明。
   *
   * 高度从原来的 max-height:78vh(内容多高就多高)改成 height:56vh 定高, 是抄 video.css
   * 的口径: 抽屉里只剩评论一块, 定高才能让「列表滚动 + 输入框吸底」成立,
   * 内容驱动高度时评论少的剧会缩成一条窄缝, 输入框贴在半空。 */
  body.theme-app.drama-play-page .drama-tabs-wrap {
    position: fixed;
    z-index: 310;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    height: 56vh;
    min-height: 320px;
    max-height: none;
    margin: 0;
    padding: 0 12px;
    border-radius: 16px 16px 0 0;
    background: #0a0a0b;
    box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.5);
    transform: translateY(104%);
    transition: transform 0.2s ease;
  }

  body.theme-app.drama-play-page .drama-tabs-wrap.is-open {
    transform: translateY(0);
  }

  /* 抽屉里只剩评论, tab 条藏掉。
   * 「猜你喜欢/最新地址」由 drama-play.js 搬进了选集面板当另外两个 tab ——
   * 搬的是同一份节点, 所以它们在手机端**仍然是可见的真实站内链接**, 没有被
   * display:none 掉(本页 noindex,follow, 那批内链是权重回流的通道, Google 又是
   * 移动优先渲染, 在手机端隐藏它们等于白丢)。
   *
   * 2026-09-09: .is-comment-only 现在**无条件**加在 wrap 上, 因为单集剧也有了选集面板,
   * 那两块在任何剧上都搬得走。原先「单集剧保留 tab 条继续切换」的例外随之作废, 连同
   * 它配套的那条 .drama-tabs 布局规则(flex/margin/padding, 给抽屉内的真 tab 条用的)
   * 一起删掉 —— 手机端这条 tab 条从此永远是 display:none, 留着只会让人以为它还会露面。
   * 类名与选择器保留不改: 它准确描述了「这个抽屉里只有评论」, 且 JS 侧没有任何代码读它。 */
  body.theme-app.drama-play-page .drama-tabs-wrap.is-comment-only .drama-tabs {
    display: none;
  }

  /* 抽屉里**当前显示**的那块面板撑满剩余高度。抽屉本身是定高 flex 列, 面板是它
   * 唯一在流内的子项, 所以 flex:1 1 auto + min-height:0 —— 少了 min-height:0,
   * flex 子项的默认 min-height:auto 会让它被内容撑高、把输入框顶出抽屉外。
   * 面板自己也是 flex 列: 评论那块要把「列表滚动 / 头与输入框不动」分开(见下),
   * 单集剧才会留在抽屉里的猜你喜欢/最新地址则整块滚(overflow-y:auto 兜住)。 */
  body.theme-app.drama-play-page .drama-tabs-wrap .drama-tab-panel {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* ⚠️ 上面那条 display:flex 特异性 (0,4,1), 压得过基础层那条 [hidden] 兜底 (0,2,1) ——
   * 不在同一段里再钉一次, JS 切 tab 写了 hidden 属性也藏不掉, 三块面板会一起摊出来。
   * 本文件的 .drama-ep / .drama-play-mask / .drama-comment-more 都栽过同一个坑。 */
  body.theme-app.drama-play-page .drama-tabs-wrap .drama-tab-panel[hidden] {
    display: none;
  }

  /* 「N 条评论」这行不参与滚动(对齐 video.css 的 .video-comments-head,
   * padding:16px 0 12px); 右侧留 34px 给右上角的关闭按钮。 */
  body.theme-app.drama-play-page .drama-comment-head {
    flex: 0 0 auto;
    padding: 16px 34px 12px 0;
  }

  /* 只有评论列表滚动 —— 逐字对齐 video.css 的 .video-comments{flex:1 1 auto;overflow-y:auto}。
   * 把滚动放在列表上而不是整块面板上, 「加载更多」和输入框才能一直留在抽屉底部,
   * 否则评论一多, 想发条评论得先把整列滚到底。 */
  body.theme-app.drama-play-page .drama-comments {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  body.theme-app.drama-play-page .drama-comment-more {
    flex: 0 0 auto;
  }

  /* 输入框钉在抽屉最底。底部内边距含 safe-area, 全面屏的手势条不会盖住「发送」。 */
  body.theme-app.drama-play-page .drama-comment-form {
    flex: 0 0 auto;
    margin-top: 12px;
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
  }

  /* 关闭按钮钉在抽屉右上角。改回 absolute(上一版是 sticky+float):
   * 现在滚动的是里面那块面板、不是抽屉本身, 按钮挂在抽屉上就不会跟着内容滚走;
   * 抽屉是 position:fixed, 天然就是它的定位参照。 */
  body.theme-app.drama-play-page .drama-sheet-close {
    display: block;
    position: absolute;
    z-index: 3;
    top: 14px;
    right: 12px;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
    color: #a8a39a;
    font-size: 14px;
    line-height: 28px;
    text-align: center;
    cursor: pointer;
  }

  /* ── 「↑ 上滑看下一集」提示 ───────────────────────────────────────────────
   * 与左下信息区同一条左边界(15px)、同一条右让位(76px, 给右侧竖排互动列),
   * 落在标题上方一档。pointer-events:none —— 它绝不能吃掉播放器的点击暂停,
   * 也不能挡住手势起点判定。 */
  body.theme-app.drama-play-page .drama-swipe-tip {
    display: block;
    position: fixed;
    z-index: 120;
    left: 15px;
    right: 76px;
    bottom: 150px;
    margin: 0;
    color: rgba(255, 255, 255, 0.92);
    font-size: 13px;
    line-height: 20px;
    text-align: center;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
    pointer-events: none;
    animation: dramaSwipeTipFade 5s ease forwards;
  }
}


/* ── 电脑端: 左播放器 + 右侧 380px 常驻选集卡片 ───────────────────────────
 * 2026-09-09 按运营给的 dx150 线上截图**纠正**上一版:
 * 上一版把电脑端选集做成了「点『选集』按钮从右侧滑出的固定定位面板」, 做错了。
 * dx150 电脑端(线上跑的是 layouts/cyber-video.tpl, 类名前缀 hg-web-play__,
 * 不是另一套沉浸式的 hg-play.tpl)是右边一张**一直显示的常驻卡片**, 没有开合动作。
 *
 * 因此本段整体重写, 上一版那套「固定定位 + 横向滑出」已全部拆除, 一条不留:
 * 固定定位与四边锚点、min(320px,92vw) 的面板宽、开合用的横向位移与过渡、
 * 为了让那条过渡跑起来加的合成层提示、侧向投影、以及面板头单独的分隔线写法。
 * 「选集」按钮(.drama-act-eplist)与面板关闭按钮(.drama-side-close)在本段 display:none:
 * 卡片一直在, 再留一个打不开任何新东西的入口只会让人误点。两个节点仍然**渲染**在
 * HTML 里 —— 手机端的 bottom sheet 全靠它们, 而两端共用同一份 DOM。
 *
 * ⚠️ 手机端(max-width:768px 那整段)这轮一条都没动: 竖屏沉浸式播放层、右侧竖排互动列
 * 五项、贴底选集面板与内容抽屉、.drama-ep[hidden] 兜底, 全部原样保留。
 * drama-play.js 的 createSheet / initEpisodeSheet 同理保留 —— 手机端还要用。
 *
 * 逐条对齐的 dx150 参数(取自它的 web/static/web/css/common.css):
 *   .hg-web-play__main{grid-template-columns:minmax(0,1fr) 380px;gap:24px;align-items:start}
 *   .hg-web-play__left{display:flex;flex-direction:column;gap:16px;min-width:0}
 *   .hg-web-play__side{border-radius:12px;border:1px solid rgba(255,255,255,.1);
 *                      background:#161616;padding:24px;min-height:560px}
 *   .hg-web-play__ep-grid{grid-template-columns:repeat(5,minmax(0,1fr));gap:10px}
 *   .hg-web-play__ep{height:40px;border-radius:8px;border:1px solid #22222a;background:#1d1d1e;
 *                    color:#8a8a93;font-size:14px;font-weight:500}
 *   .hg-ep-range{height:32px;padding:0 14px;border-radius:8px;border:1px solid rgba(255,255,255,.12);
 *                background:rgba(255,255,255,.04);color:rgba(255,255,255,.6);font-size:13px;font-weight:600}
 * 底色/边框照抄, **配色一律换成 dx127 自己的主色 #e81c2b**, 不搬 dx150 的品牌黄。
 * dx150 页内 style 还把卡片做成 position:absolute 撑满主区高度, 这里没搬:
 * 那要给栅格容器补 position:relative, 且卡片内容(头部+段签+一段 20 格)本来就到不了
 * 播放器那么高, absolute 只会拉出一张下半截全空的卡片。min-height:560px + align-items:start
 * 已经拿到同样的观感。
 *
 * 本文件仍是两个断点。手机端与电脑端的选集是两种**互斥**形态(贴底浮层 / 右栏卡片),
 * 让某一端去继承基础层就得逐条改写另一端的定位属性, 漏一条就串形态。 */
@media (min-width: 769px) {
  /* --drama-pc-topgap = 播放器上方那截固定占位, 即 dx150 里 var(--dx-header-height)
   * 的等价物。**dx127 电脑端没有顶部导航条**, 不能照抄那个变量:
   *   · components/top-bar.css:1 `body.theme-app .h5-header{display:none}` 在基础层,
   *     顶栏只在 max-width:768px 里才固定定位显示出来;
   *     电脑端的导航是左侧 200px 的固定 sidebar(components/sidebar-nav.css:1)。
   *   · --dx-header-height 定义在 components/app-header.css, 而本页模板
   *     (layouts/drama-play.tpl 的 <head>)根本没引这个文件 —— 直接 var() 会拿到
   *     无效值, 整条 calc 作废。
   * 所以按实测占位逐项相加, 每项都能在源码里对上:
   *     61px  面包屑 .breadcrumb 的写死高度(components/theme-app.css; 本文件把它
   *           改成 min-height:61px + padding-bottom:8px, box-sizing:border-box 下
   *           单行内容 19+20+8=47px < 61px, 实占仍是 61px)。
   *           同一个 61px 已经是站内既定口径: pages/video.css 的
   *           .video-shell{height:calc(100vh - 61px)} 用的就是它。
   *     16px  .drama-play 的 padding-top
   *     44px  .drama-play-title 的 line-height 30px + margin-bottom 14px
   *   合计 121px。改上面任何一项, 回来同步这个数。
   *
   * --drama-pc-actiongap = 播放器下方「副标题 + 操作按钮排」要留的高度(20+16+40+16),
   * 保证点赞/收藏/评论/上下集这排入口落在首屏内, 不用滚。
   * 两个变量现在只用来给播放器算**高度上限**(见下一条规则)。
   *
   * --drama-tabs-h = 板块导航条的高度, 也就是它吸顶后盖住的那一条的厚度。
   * 抽成变量是因为这个值有**两个**消费者, 必须永远一致:
   *   1. .drama-tabs 自己的 height(下面那条规则);
   *   2. 三块内容的 scroll-margin-top —— 锚点滚过去要把这段让出来, 否则板块标题
   *      正好被吸顶条压住(drama-play.js 的 initAnchorNav 直接读这个 computed 值,
   *      所以 JS 里也没有第二处硬编码)。
   * 硬编码两处的后果不是报错而是「差一点」: 改了条子高度, 点 tab 跳过去标题被切一半,
   * 而且要滚到特定位置才看得出来, 最容易漏测。 */
  body.theme-app .page-drama-play {
    --drama-pc-topgap: 121px;
    --drama-pc-actiongap: 92px;
    --drama-tabs-h: 48px;
  }

  /* 播放器: 宽度驱动的 16:9, 再用视口高度封顶。
   *
   * 上一版这里是 `aspect-ratio:auto; height:calc(100vh - topgap - actiongap)` ——
   * 那时主区是**单列**, 播放器吃满整个主区宽(1440 视口下约 1208px), 配 665px 的高
   * 正好接近 16:9, 看着没问题。现在右边让出 380+24px 给常驻卡片, 同一条 height 会把
   * 播放器压成 804×665 的近方形, 16:9 的片源上下左右全是黑边, 与 dx150 截图完全不像。
   * 故改回由宽度驱动比例(dx150 的 .hg-web-play__viewport 同样是 aspect-ratio 驱动),
   * max-height 只在超宽屏(列宽 > 1.78×可用高)时兜一道, 免得播放器高过一屏。 */
  body.theme-app .drama-player-frame {
    aspect-ratio: 16 / 9;
    height: auto;
    max-height: calc(100vh - var(--drama-pc-topgap) - var(--drama-pc-actiongap));
  }

  /* 主区两栏: 左播放器 + 右 380px 常驻选集卡片(对齐 dx150 的 .hg-web-play__main)。
   * align-items:start 让卡片贴顶, 而不是被拉到与左栏等高 —— 卡片有自己的 min-height。 */
  body.theme-app .drama-play-body {
    grid-template-columns: minmax(0, 1fr) 380px;
    gap: 24px;
    align-items: start;
  }

  /* 左栏改成纵向 flex + gap 16(对齐 dx150 的 .hg-web-play__left)。
   * 下面两条把子元素自带的 margin 清零, 否则 margin 与 gap 会叠加成 26/30px 的杂乱间距。 */
  body.theme-app .drama-play-main {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
  }

  body.theme-app .drama-play-main .drama-play-sub {
    margin: 0;
  }

  body.theme-app .drama-play-main .drama-play-actions {
    margin-top: 0;
  }

  /* 「选集」按钮与面板关闭按钮: 电脑端没有开合动作, 一律不显示(理由见段首)。
   * .drama-act 基础层是 display:flex, 特异性 (0,2,1) 与这条相同, 靠**书写顺序**取胜,
   * 所以这条必须留在文件末尾这一段里, 别往前挪。 */
  body.theme-app .drama-act-eplist,
  body.theme-app .drama-side-close {
    display: none;
  }

  /* 藏掉「选集」那一格后按钮排回到 5 格。
   * 基础层的 .has-eplist 是 6 列, display:none 的子元素不占格子, 不改列数就会在最右边
   * 空出一整格, 五个按钮全部左偏。 */
  body.theme-app .drama-play-actions.has-eplist {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  /* ── 常驻选集卡片 ─────────────────────────────────────────────────────── */
  /* min-height 从原先的 .drama-play-side-sheet 挪到这里(2026-09-09)。
   * 那个类名在手机端是「贴底面板」的意思, 在电脑端曾兼职「这是多集剧」的标记 ——
   * 模板只在 {{if gt .total 1}} 时加它。现在运营要求单集剧也有选集面板, 该类无条件加,
   * 兼职语义作废, 挂在它上面的 min-height 也就不再有「只给多集剧」的效果, 索性挪到
   * .drama-play-side 上, 两种剧同一条规则、同一种形态 —— 这正是本轮要的结果:
   * 单集剧不再是「流内一张小卡片」, 而是与多集剧一样的右侧 380px 常驻卡片。
   * 值不变(560px), 多集剧的渲染结果与改动前逐像素一致(同一元素、同一值、同特异性 (0,2,1))。
   * 单集剧只有一格集号, 560px 下半截是空的 —— 这是刻意的: 左栏播放器在 1440 视口下
   * 就有 ~568px 高, 卡片不撑起来会缩成一条与播放器完全不齐的短卡, 比留白更难看。 */
  body.theme-app .drama-play-side {
    padding: 24px;
    min-height: 560px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    background: #161616;
  }

  /* 头部: 左边「剧名选集」+ 下一行「更新至 N 集」, 右上角「当前第 N 集」。
   * align-items 从基础层的 center 改成 flex-start —— 关闭按钮在这一端已经藏了,
   * 右侧只剩一行小字, 居中会把它吊到 20px 大标题的正中间, 与 dx150 的顶对齐不符。 */
  body.theme-app .drama-play-side .drama-side-head {
    align-items: flex-start;
  }

  body.theme-app .drama-play-side .drama-side-title {
    color: #fff;
    font-size: 20px;
    line-height: 28px;
  }

  body.theme-app .drama-play-side .drama-side-cur {
    color: #e81c2b;
    font-size: 12px;
    line-height: 20px;
    font-weight: 600;
    white-space: nowrap;
  }

  /* 「更新至 N 集 · 状态」这行同时充当 dx150 那条 <hr class="hg-web-play__side-rule">
   * (它的口径是 margin:24px 0 + 1px 上边框)。
   * 用底边框而不是真加一个 <hr> 节点: 加节点会连带出现在手机端的贴底面板里,
   * 而手机端这轮是禁改区 —— 同一份 DOM 两端共用, 加什么两边都得跟着变。 */
  body.theme-app .drama-play-side .drama-side-sub {
    margin: 6px 0 24px;
    padding-bottom: 24px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    color: #8a8a93;
  }

  /* ── 分段段签(对齐 dx150 的 .hg-ep-range) ─────────────────────────────
   * 允许折行: 卡片内容宽 380-48=332px, 150 集会切出 8 个段签, 一行放不下。
   * 上一版为了 288px 的窄面板改成了横向滚动条, 卡片宽到 332px 后折行更好读。 */
  body.theme-app .drama-play-side .drama-ep-tabs {
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 12px;
  }

  body.theme-app .drama-play-side .drama-ep-tabs button {
    height: 32px;
    padding: 0 14px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.04);
    color: rgba(255, 255, 255, 0.6);
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
  }

  body.theme-app .drama-play-side .drama-ep-tabs button.is-active {
    border-color: #e81c2b;
    background: rgba(232, 28, 43, 0.08);
    color: #e81c2b;
  }

  /* ── 集号网格: 5 列 ───────────────────────────────────────────────────
   * 卡片内容宽 380-24×2=332; 减 4 条 10px 的 gap = 292; 每格 73px, 三位数集号也放得下。
   * 不设 max-height/overflow: 段签把网格切成每段最多 20 格 = 4 行 × 40px + 3 条 gap
   * = 190px, 卡片自己就装得下; 再套一层内滚就是「框里框外两个滚动条」。
   * 集数 ≤20 的剧不出段签(buildDramaEpTabs 返回 nil), 一次也只有 20 格, 同样成立。 */
  body.theme-app .drama-play-side .drama-side-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 10px;
    align-content: start;
    max-height: none;
    overflow-y: visible;
  }

  /* 格子: 40px 高的居中数字方块(dx150 的 .hg-web-play__ep 也只放一个集号)。
   * position:relative 是给下面那条 sr-only 的 <span> 当定位参照, 否则它会跑去以卡片定位。 */
  body.theme-app .drama-play-side .drama-ep {
    position: relative;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 0;
    height: 40px;
    padding: 0;
    border: 1px solid #22222a;
    border-radius: 8px;
    background: #1d1d1e;
    color: #8a8a93;
    font-size: 14px;
    font-weight: 500;
  }

  body.theme-app .drama-play-side .drama-ep b {
    color: inherit;
    font-size: 14px;
    line-height: 20px;
    font-weight: inherit;
  }

  /* hover 只给可播格。置灰格是 <span>, 但基础层那条 .drama-ep:hover 照样命中它。 */
  body.theme-app .drama-play-side .drama-ep:not(.is-locked):hover {
    border-color: #e81c2b;
    color: #e81c2b;
  }

  body.theme-app .drama-play-side .drama-ep.is-locked:hover {
    border-color: #22222a;
  }

  /* 当前集: 主色实底。文字用 #fff 而不是 dx150 的 #000 —— 那边主色是品牌黄, 黑字才够对比;
   * 本站主色是 #e81c2b 深红, 黑字几乎糊在底色里, 白字才是站内一贯口径
   * (基础层 .drama-ep-tabs button.is-active 也是红底白字)。 */
  body.theme-app .drama-play-side .drama-ep.is-cur {
    border-color: #e81c2b;
    background: #e81c2b;
    color: #fff;
    font-weight: 700;
  }

  body.theme-app .drama-play-side .drama-ep.is-cur b {
    color: #fff;
  }

  /* 分集标题在 73px 的方块里塞不下, 但**不能 display:none**: 那会把 <a> 的锚文本
   * 从「12 第12话 剧情推进」削成光秃秃一个「12」。这里用全站 .sr-only 那套
   * (absolute + 1px + clip)把它从视觉上摘掉、文本仍留在无障碍树和 HTML 里,
   * 视觉等同 dx150 的纯数字方块, 锚文本零损失。 */
  body.theme-app .drama-play-side .drama-ep span {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }

  /* ── 下方内容 tab: 吸顶 + 下划线指示条, 对齐 dx150 ──────────────────────
   *
   * 基础层那套是圆角胶囊(border-radius:16px + 红底激活), **手机端仍用它** ——
   * 抽屉/面板里横向排几颗胶囊是合适的, 截图上运营也认可。所以这里只在电脑端断点
   * 内覆盖, 不动基础层, 手机端零影响。
   *
   * 逐条对齐 dx150 线上实测值(dx150-web.zzriewok.cc 的 .vd-anchor-nav / .vd-anav-tab):
   *   容器  position:sticky; top:78px; z-index:50; height:48px; display:flex;
   *         background:#080808; border-bottom:1px solid rgba(255,255,255,.08)
   *   tab   padding:14px 28px 12px; font-size:17px; border-bottom:2px solid transparent
   *   激活  border-bottom-color:主色; color:#fff; font-weight:700
   *
   * 两处按本站口径改:
   *   1. top 取 0 而不是 dx150 的 78px —— dx150 顶部有一条 78px 高的导航条要让位,
   *      dx127 电脑端导航在左侧 sidebar, 页面顶部没有任何固定元素挡着。
   *   2. 指示条与文字用本站主色 #e81c2b, 不搬 dx150 的品牌黄 #ffd21c。
   *
   * 底色取 #0a0a0b(与 .page-drama 页面底色同值)而不是 dx150 的 #080808:
   * 吸顶元素必须是不透明的, 否则滚动时下面的推荐卡会从 tab 条底下透出来;
   * 用页面同色才看不出这是一条浮在上面的横条。 */
  /* ⚠️ 这条 sticky 目前不会真的吸住, 吸顶行为由 drama-play.js 接管(见该文件 initStickyTabs)。
   * 保留 sticky 声明是为了「JS 没跑起来时也不至于比原来更差」——退化成普通静态 tab 条。
   *
   * 为什么 CSS 单独做不到: body.theme-app 自己写了 overflow-x:hidden + overflow-y:auto
   * (components/theme-app.css), body 因此成为一个滚动容器; 而它的高度等于内容高,
   * 内容永远不会超出它自己 → 这是个「不滚动的滚动容器」。sticky 只相对最近的滚动祖先吸顶,
   * 于是 tab 条相对 body 吸顶 = 永远不动, 实测滚到底后 top = -186px 直接离开视口。
   * 试过把本页 body 改回 overflow:visible, 吸顶确实立刻生效, 但滚动条会从 body 移到 html,
   * .app-main 的 margin-left:200px(给左侧 sidebar 让位)算不进这 10px 差值, 整页横向溢出 10px。
   * 要根治得改全站 .app-main 的宽度算法, 为一个 tab 条动全站布局不划算, 故改用 JS 方案:
   * 只在本页生效, 不碰任何全局规则。 */
  body.theme-app .drama-tabs {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: stretch;
    gap: 0;
    /* 值仍是 48px, 只是改从 --drama-tabs-h 取 —— 板块的 scroll-margin-top 要用同一个数,
     * 见上面那个变量的注释。计算结果与改动前完全一致。 */
    height: var(--drama-tabs-h);
    margin-bottom: 16px;
    padding-bottom: 0;
    background: #0a0a0b;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  }

  /* ── 三块内容常驻铺开(锚点导航, 不是切换) ─────────────────────────────
   *
   * 2026-09-09 运营验收纠正: 电脑端「猜你喜欢 / 评论 / 最新地址」不再互斥显示,
   * 而是按这个顺序全部排在页面上, 上面那条 tab 变成锚点导航。DOM 顺序即视觉顺序,
   * 模板已按「猜你喜欢 → 评论 → 最新地址」渲染, 这里只负责板块之间的间距与落点偏移。
   *
   * scroll-margin-top: tab 条吸顶后是 position:fixed;top:0, 会盖住它下面
   * var(--drama-tabs-h) 那一条。锚点滚过去若不把这段让出来, 落点正好把板块标题压在
   * 条子底下 —— 点了 tab 跳过去看不到自己跳到了哪。再加 8px 呼吸位, 标题不贴着条子边。
   * 这条同时服务两条路径: 浏览器原生的 #hash 跳转/scrollIntoView 直接吃它;
   * drama-play.js 的 initAnchorNav 用 window.scrollTo 手算落点, 也是读**这个** computed
   * 值来减(所以 JS 里没有第二处硬编码, 改高度只需改上面那个变量)。
   *
   * 只写在电脑端段: 手机端三块分别在选集面板和评论抽屉里, 没有页内锚点这回事。 */
  body.theme-app .drama-tabs-wrap .drama-tab-panel {
    scroll-margin-top: calc(var(--drama-tabs-h) + 8px);
  }

  /* 板块之间的分隔。用相邻兄弟选择器只给「第 2 块起」加上边距, 第一块紧跟 tab 条,
   * 不会在导航条和「猜你喜欢」之间多出一截空白。
   * 分隔线做得很淡(0.06): 每块自己已经有标题, 线只是帮眼睛断句, 太重会像三张卡片。 */
  body.theme-app .drama-tabs-wrap .drama-tab-panel + .drama-tab-panel {
    margin-top: 32px;
    padding-top: 28px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
  }

  /* 板块标题。基础层是 display:none(只在电脑端存在, 理由见基础层那条注释),
   * 这里打开。字号 20px 介于 h1(30px) 与推荐卡标题(14px)之间, 层级读得出来;
   * 左侧那道 3px 主色竖条是站内既有的小节标题语言(与 dx150 的 .hg-section-accent 同义),
   * 用 border-left + padding-left 实现, 不额外加节点。 */
  body.theme-app .drama-sec-title {
    display: block;
    margin: 0 0 16px;
    padding-left: 10px;
    border-left: 3px solid #e81c2b;
    color: #fff;
    font-size: 20px;
    font-weight: 700;
    line-height: 24px;
  }

  /* ── 真正生效的吸顶态: 由 drama-play.js 的 initStickyTabs 加/摘这个类 ──────
   *
   * 为什么 fixed 能成而上面那条 sticky 不成: sticky 只认「最近的滚动祖先」, 本页那个
   * 祖先是永远不滚的 body(理由见上一段); fixed 认的是**视口**, 直接绕开这条链。
   * 前提是祖先链上没有 transform / filter / perspective / contain —— 已逐个核过:
   * .drama-tabs-wrap 上那条 transform:translateY 只写在 max-width:768px 段里,
   * 电脑端 .drama-tabs-wrap / .page-drama-play / .app-main / body 全都没有,
   * 所以 fixed 的包含块就是视口本身。
   *
   * left / width **故意不写在这里**, 由 JS 量出 tab 条原位的 getBoundingClientRect
   * 后写成内联值:
   *   · 脱流后宽度会从「主区满宽」塌成内容宽(三颗 tab 加起来才 300 出头);
   *   · 左边缘的位置取决于左侧固定 sidebar 的宽度
   *     (components/theme-app.css 的 body.theme-app.layout-menu .app-main{margin-left:200px}),
   *     在这里写死 200px 的话, sidebar 哪天改宽就得有人记得回来同步这一处。
   * 从实测值取则 sidebar 宽度、主区内边距怎么变都自动跟随, 这里零维护。
   * (.drama-tabs 横向没有 padding/border, 所以 rect.width 不受 box-sizing 口径影响。)
   *
   * margin-bottom 归零: 吸顶期间这 16px 间距由 JS 插入的占位节点顶着, 两边都留会多出一截。 */
  body.theme-app .drama-tabs.is-stuck {
    position: fixed;
    top: 0;
    margin-bottom: 0;
  }

  /* 吸顶占位。tab 条脱流的那一瞬间, 下方内容会整体上跳一个 tab 条的高度(48px + 16px 间距),
   * 由 JS 在原位插入这个等高等下边距的空节点顶住, 还原时再摘掉。
   * 高度与 margin-bottom 由 JS 按实测值写内联, 不在这里写死 48/16 —— 上面那条改了高度,
   * 这里不必跟着改, 也就不存在两处对不上的可能。
   * 这里只声明「它不参与任何布局语义」: 不可见、不吃指针事件、不被 flex/grid 拉伸。 */
  body.theme-app .drama-tabs-holder {
    flex: none;
    pointer-events: none;
    visibility: hidden;
  }

  body.theme-app .drama-tabs button {
    height: auto;
    padding: 14px 28px 12px;
    border: 0;
    /* 指示条常驻但透明: 激活时只换颜色, 不改盒模型, 切 tab 时文字不会跳一下。 */
    border-bottom: 2px solid transparent;
    border-radius: 0;
    background: transparent;
    color: rgba(255, 255, 255, 0.62);
    font-size: 17px;
    line-height: 20px;
    white-space: nowrap;
  }

  body.theme-app .drama-tabs button:hover {
    color: #fff;
  }

  body.theme-app .drama-tabs button.is-active {
    background: transparent;
    border-bottom-color: #e81c2b;
    color: #fff;
    font-weight: 700;
  }
}
