/*!
 * 应用层补丁 —— 只补齐 MXone 模板在 SPA 化之后缺失的部分
 */

/* ============================ 设计变量 ============================
 * 模板把强调色硬编码在 style.css 里（#ff2a14 出现 59 次，另有 #ff5f00 /
 * #ff008c / #cc00ff / #00b7ee 各成一套），改一次主色要全库搜替换，黑/白皮肤
 * 还总是漏项。这里把颜色收成单点定义，模板与补丁层里对应的位置统一走 var()。
 * 换主题色只需要改下面这一处。
 */
:root {
  --mx-primary: #ff2a14;          /* 主色：选中态 / 强调 / 链接 hover / 进度条 */
  --mx-accent: #ff5f00;           /* 次级强调：模块标题图标（与主色同暖色族） */
  --mx-primary-weak: rgba(255, 42, 20, .29);
  --mx-bg: #16161a;               /* 页面底色（黑皮肤） */
  --mx-surface: #25252b;          /* 卡片 / 面板底色 */
  --mx-surface-2: #32323c;        /* 边框 / 分隔线 */
  --mx-focus: #00b7ee;            /* 键盘焦点环（与主色刻意不同，避免和选中态混淆） */
}

.mx-accent { color: var(--mx-accent); }

/* ---------------- 键盘焦点可见性 ----------------
 * 模板把 outline 全局清掉了（style.css 的 input/button/a/select/textarea 都写了
 * outline:none），只留搜索按钮一个 :focus。键盘用户 Tab 一圈完全看不到焦点在哪。
 * 用 :focus-visible 而不是 :focus —— 鼠标点击不会冒出焦点环，键盘操作才会。
 */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--mx-focus);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ---------------- 下拉菜单：移动端点击展开 ----------------
 * 光把 .drop-content 设成 display:block 是不够的：它默认 pointer-events:none
 * （style.css），.drop-content-box 默认 opacity:0 + translate3d(0,-100%,0)，
 * 这两个属性只有 :hover 分支才复位。非触摸环境点开后内容仍是透明的、点不动。
 */
.drop.open > .drop-content { display: block; pointer-events: auto; }
.drop.open > .drop-content-box { display: block; opacity: 1; transform: none; }
@media (max-width: 899px) {
  .drop.open > .drop-content { display: block !important; }
}

/* ---------------- 头部背景：非首页也保持同一底色 ---------------- */
/* 主题里 .header-content 是 position:fixed，靠 #header 的 padding-top:70px
 * （≤899px 是 60px，style.css:1027 / :4922）预留出等高的占位。
 * 这里改成 relative 之后它自己就占位了，那段 padding 变成纯粹的空白 ——
 * 实测内页页头因此高出一倍（1440 下 140px vs 首页 70px，390 下 120px vs 60px），
 * 连 .view #header::after（top:100% 的详情页大图渐变）也跟着下移 70px。
 * 占位改由 .header-content 自己承担，把 padding 清零即可还原成与首页同高。 */
body.search #header,
body.view #header { padding-top: 0 !important; }
body.search .header-content,
body.view .header-content { position: relative; }
body.search .header-content.header-bg,
body.view .header-content.header-bg { background: var(--mx-bg); }

/* 内页页头的左右留白。
 * 主题只给首页写了 `.homepage .header-content { padding: 0 15px }`（style.css:1146），
 * 内页没有 —— 实测 1440 下最右的用户菜单贴着窗口右缘（1425/1425），而首页留了 15px。
 * 移动端还多一层：`.nav` 自身带 -15px 负边距做整宽横滑，首页靠这 15px padding 抵消，
 * 内页没有就整体左移 15px（实测 .nav 起点 -15）。补上与首页一致的留白，两处一起归位。 */
body.search .header-content,
body.view .header-content { padding: 0 15px; }

/* ---------------- 播放弹窗 ---------------- */
#play-modal {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;
  overflow: auto;
  background: rgba(0, 0, 0, .86);
  -webkit-overflow-scrolling: touch;
}
#play-modal.open { display: block; }
#play-modal .player-block { padding-top: 0; }
#play-modal .content { padding-top: 30px; padding-bottom: 30px; }
#play-modal .player-box-main { min-height: 60vh; }
#play-modal .player-wrapper { background: #000; }
#play-modal .player-box-side { max-height: 70vh; overflow: auto; }
#play-modal .module-blocklist { max-height: 55vh; overflow: auto; }
#play-modal .module-blocklist a {
  display: inline-block;
  min-width: 52px;
  text-align: center;
  margin: 0 8px 8px 0;
}
#play-modal #p-close { color: inherit; }

/* ---------------- 提示条 ---------------- */
#toast {
  position: fixed;
  left: 50%;
  bottom: 60px;
  transform: translateX(-50%) translateY(20px);
  z-index: 10001;
  padding: 10px 20px;
  border-radius: 6px;
  background: rgba(0, 0, 0, .85);
  color: #fff;
  font-size: 14px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s, transform .25s;
  max-width: 80vw;
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------------- 加载态 / 空态 ----------------
 * 模板给一批「行内块排布」的容器写了 font-size:0 来消掉 inline-block 之间的空白符
 * （.module-list 2366、.module-heading 2227、.module-item-style 2508、.drop-content 1169…），
 * 它自己的子元素都各自带字号，所以模板里没问题。
 * 而这两个状态类是本站新增的，一旦落进 .module-list 里就会把字号一起继承成 0 ——
 * 实测「还没有播放记录，随便点开一部看看」渲染成 1260×120 的一块纯空白，一个字看不见；
 * 加载态同理，网速慢时用户看到的是一整页白屏，没有任何「正在加载」的反馈。
 * 两个类不合并成一条规则，是为了各自还能单独调 padding。 */
.mx-loading { padding: 60px 0; text-align: center; opacity: .6; font-size: 14px; line-height: 1.7; }
.mx-empty { padding: 60px 0; text-align: center; opacity: .6; font-size: 14px; line-height: 1.7; }

/* ---------------- 续看进度条（.mx-progress） ----------------
 * 模板没有这个组件：MacCMS 不记录播放进度，所以主题里没有对应样式。
 * 数据来自 Emby 的 UserData.PlayedPercentage，只有「看过但没看完」的条目才有。
 * 放在 .module-item-cover 内、海报图正下方，压在封面下缘上。
 */
.mx-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: rgba(0, 0, 0, .45);
  z-index: 3;
  pointer-events: none;
}
.mx-progress > i {
  display: block;
  height: 100%;
  background: var(--mx-primary);
  /* 跟主色走（见 :root）。模板里导航高亮原本是另一套青色 #00b7ee，
     已统一到主色，进度条同步，否则同一屏会出现两种「进行中」的颜色。 */
}
/* 悬停浮层（.module-item-content）会盖住封面下缘，此时进度条要压到浮层之上，
 * 否则一悬停进度条就被吃掉 —— 浮层的 z-index 在 style.css 里是 2。 */
.module-item:hover .mx-progress { z-index: 5; }

/* ---------------- 卡片悬停浮层：把「类型」行放回来 ----------------
 * 模板 .module-item-style 带 font-size:0（style.css:2506），是给 .video-tag 里的
 * <a> 类型标签做「行内块之间不留空白」的复位 —— 模板自己的标签是 <a>，
 * 由 .module-item-style.video-tag a（style.css:772）单独赋 12px 行内块胶囊，
 * 所以容器归零没问题。
 * 本站的卡片浮层（app.js 的 MX.vodbox）放的是纯文本，会直接继承这个 0 ——
 * 实测浮层顶部因此多出一条 190×16 的空白带，类型文字一个字都看不见，
 * 而浮层滑上来时正好盖住封面下缘的 .module-item-caption（年份/类型/分级），
 * 等于悬停后这些信息全没了。给纯文本形态补回字号即可；
 * 简介 .video-text 本就有自己的 12px，不受影响。 */
.module-item-style.video-tag { font-size: 12px; line-height: 20px; }

/* ---------------- 详情页补丁 ---------------- */
/* 「已看」角标（#d-playlist … a em）的样式已移到 app.item.css，避免两处重复维护。 */
#d-head .video-info-content { position: relative; }
#d-playlist .module-blocklist a { min-width: 52px; }

/* ---------------- 首页轮播 ---------------- */
#bigslide { margin: 0 auto; }
#bigslide .swiper-slide a.banner { display: block; padding-top: 30%; position: relative; }

/* 首页：删掉「幻灯下导航」整块（含第二个小轮播 #slide）后，
 * 大轮播与「最新热播」之间就没有东西撑间距了，这里补回一段留白。 */
#view-home #module-hot { margin-top: 30px; }

/* ---------------- 工具类：.hidden-xs ----------------
 * index.html 的 #friendlink 用了 class="wrapper hidden-xs"。该类的唯一定义在
 * mxone.css:1370（@media(max-width:767px){ display:none !important }），而 mxone.css
 * 已确认全站零引用、不加载，于是「移动端隐藏友情链接」的意图失效。这里补回。
 */
@media (max-width: 767px) {
  .hidden-xs { display: none !important; }
}

/* ---------------- 浅色皮肤：次级文字的对比度对不齐深色皮肤 ----------------
 * 主题给同一批「次要文字」在两套皮肤里写了不同强度，深色那套明显更狠：
 *   .module-item-text      深 hsla(0,0%,100%,.6)（mxhtmlblack.css:28） → 6.97
 *                          浅 rgba(0,0,0,.4)（white.css:28）          → 2.85
 *   .video-info-itemtitle  深 hsla(0,0%,100%,.6)（:199）              → 6.97
 *                          浅 rgba(0,0,0,.51)（white.css:202）        → 4.07
 *   .video-serial          深 hsla(0,0%,100%,.6)（:250）              → 5.4
 *                          浅 rgba(0,0,0,.4)（white.css:248）         → 2.79
 *   #footer                深 hsla(0,0%,100%,.6)（:109）              → 6.97
 *                          浅 rgba(0,0,0,.51)（white.css:115）        → 4.04
 * 同一处文字换套皮肤就差一倍多，是浅色那套漏了，不是刻意压暗。
 * 这几处都不是装饰：.module-item-text 是每张卡片第二行（「全2集」「1小时58分钟」），
 * .video-serial 是搜索结果右上角的「更新至26集」，.video-info-itemtitle 是详情页的
 * 「类型：」「评分：」，#footer 是页脚那两行声明 —— 12–14px 的字压在 2.8 上确实费眼。
 * 统一抬到 rgba(0,0,0,.62)（浅底上 6.2），与深色那套的 6.97 基本齐平，
 * 也和本仓库其他补丁里次级文字用的 .62 一致。
 * 只作用于浅色皮肤：深色皮肤本来就是 .6，不动。 */
html.theme-white .module-item-text,
html.theme-white .video-info-itemtitle,
html.theme-white .video-serial {
  color: rgba(0, 0, 0, .62);
}
html.theme-white #footer {
  color: rgba(0, 0, 0, .62);
}

/* 同一批漏项里还有下拉框的小标题：顶栏「我的观影记录」、搜索框「大家都在搜这些影片」。
 * 主题在这两处也是深 .6 / 浅 .4 两套写法（mxhtmlblack.css:119 对 white.css:122），
 * 浅底上 rgba(0,0,0,.4) 压白底只有 2.85，而它是个 12–14px 的列表标题，
 * 下拉一展开第一眼就是它。跟上面几处一起抬到 .62。 */
html.theme-white .list-item-title strong {
  color: rgba(0, 0, 0, .62);
}

/* 例外：播放弹窗里那两个同名的标签（「直链：」「版本：」）。
 * 它们虽然在 .video-info-itemtitle 这个类上，但所处背景与详情页相反 ——
 * 桌面端 .player-info 是 rgba(0,0,0,.88)（style.css:4033），主题给它们单独写了
 * 浅灰 #8f8f8f（style.css:4077 .player-info .video-info-itemtitle，(0,2,0)）。
 * 而上面那条 html.theme-white .video-info-itemtitle 是 (0,2,1)，权重刚好压过它，
 * 于是白皮肤下这两个标签变成近黑字压在近黑底上 —— 实测对比度 1.00，整行消失。
 * 这里用 ID 选择器把主题自己的颜色还回去（#8f8f8f 压 rgba(0,0,0,.88) 实测 6.5）。
 * ≤1239px 时主题把这两个标签 display:none 掉了（style.css:4826），不受影响。 */
html.theme-white #play-modal .video-info-itemtitle {
  color: #8f8f8f;
}

/* ============================ 骨架屏（Skeleton Screen） ============================
 * 数据没回来之前不再只印一行「加载中…」。那行字只有二十来像素高，而它下面要落的是
 * 30% 视宽的大轮播加四段海报墙（1440 宽下合计数千像素），真实内容一插进来整页就被
 * 撑开，用户看到的「啪」地一下展开就是这么来的。这里按真实组件的尺寸先摆好灰色占位块，
 * 数据到达时只换填充物，高度几乎不变。
 */
:root {
  --mx-skel: rgba(255, 255, 255, .08);      /* 占位块底色（黑皮肤） */
  --mx-skel-hi: rgba(255, 255, 255, .17);   /* 流光高光 */
}
html.theme-white {
  --mx-skel: rgba(0, 0, 0, .07);
  --mx-skel-hi: rgba(0, 0, 0, .15);
}

.mx-skel {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--mx-skel);
  border-radius: 5px;
}
/* 流光：一条比底色略亮的斜带从左扫到右。用 ::after + transform 而不是动画
 * background-position —— 后者每帧都要重绘整块背景，一屏上百个占位块时开销可观；
 * transform 走合成层，只画一次。.mx-skel 自带 overflow:hidden，流光不会漏到相邻卡片。 */
.mx-skel::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--mx-skel-hi), transparent);
  animation: mx-skel-shimmer 1.4s ease-in-out infinite;
}
@keyframes mx-skel-shimmer {
  100% { transform: translateX(100%); }
}

/* ---- 海报卡占位 ----
 * 外壳用的是真实卡片的类名，所以 .module-item-cover 的 padding-top:140% 已经把
 * 5:7 的海报位留好了，这里只要把灰块铺满它。.module-item-pic 自身没有定位，
 * 绝对定位的参照是 .module-item-cover（position:relative）。 */
.mx-skel-poster { position: absolute; inset: 0; }

.mx-skel-line { display: block; height: 13px; border-radius: 4px; }

/* 搜索结果里那个「查看详情」按钮的占位（对应主题的 .btn-important.btn-base） */
.mx-skel-btn { display: inline-block; width: 104px; height: 34px; border-radius: 17px; }

/* 「最新首播」卡头那条日期（真实的是 .pack_reserve，固定 30px 高、居中）。
 * 高度由 .pack_reserve 自己撑着，这里只要画一块居中的灰条。 */
.mx-skel-reserve { display: inline-block; width: 96px; height: 30px; border-radius: 15px; }
/* 海报卡里那两行字（片名 / 备注）在主题里的行盒是 14px 字号 x 1.6 = 22.4px。
 * 占位块取同样的高度，整张卡的高度才和真实卡片一致 —— 差 1px 乘以 12 张卡 x 3 排
 * 就是几十像素的整体位移。 */
.mx-skel-item .module-item-titlebox .mx-skel-line,
.mx-skel-item .module-item-text .mx-skel-line { height: 1.6em; }

/* ---- 大轮播占位 ----
 * 容器高度必须与真实 banner 一致（见本文件上面的 #bigslide .swiper-slide a.banner，
 * 是 padding-top:30%）。不写这条，1440 宽的屏上会先塌成 0 再弹到 432px ——
 * 这一次跳动就是首页布局抖动的最大一笔。 */
#bigslide .mx-skel-slide { padding-top: 30%; }
#bigslide .mx-skel-slide .mx-skel-hero { position: absolute; inset: 0; border-radius: 0; }

/* ---- 分区标题 / 地区胶囊 / 侧栏榜 ----
 * .module-title 的 line-height 随断点变（1.3 / 1.1 / 1.6），所以高度写 1em 并做成行内块：
 * 撑开 h2 的是行高本身，占位块跟着 h2 的字号一起缩放，不必在每个断点各写一遍数字。 */
.mx-skel-h { display: inline-block; width: 130px; height: 1em; vertical-align: middle; }
.mx-skel-chip { display: inline-block; width: 62px; height: 30px; border-radius: 16px; margin: 0 8px 8px 0; }
@media (max-width: 899px) { .mx-skel-chip { height: 36px; } }
.mx-skel-rank { display: flex; align-items: center; padding: 12px 10px 11px; }
.mx-skel-rank-num { flex: 0 0 auto; width: 18px; height: 18px; margin-right: 8px; border-radius: 4px; }
.mx-skel-rank-text { flex: 1 1 auto; min-width: 0; }
/* 榜单一行的两行字：片名 14px/1.6，备注 13px/1.6，合起来正好是主题 .text-list-item 的实测高度 */
.mx-skel-rank-text .mx-skel-line { height: 1.6em; }
.mx-skel-rank-text .mx-skel-line:nth-child(2) { font-size: 13px; }
/* ≤899px 时主题把侧栏改成横向滑动的一排（.scroll-content 变 inline-flex），
 * 行本身也跟着换成 padding:10px / width:20vw。骨架照抄，
 * 否则侧栏会比真实内容高出一截，下方的模块整体下移。 */
@media (max-width: 899px) {
  .mx-skel-rank { flex: 0 0 auto; padding: 10px; width: 20vw; margin-right: 10px; }
}

/* ---- 最新影片：横版列表行 ----
 * 三行占位按真实的三行字（15px/1.6、13px/1.6、12px/1.6）逐个对齐，
 * 加上各自的 4px 上间距，正好等于 .mx-newrow-info 实测的 76px。 */
.mx-skel-newrow .mx-skel-line:nth-child(1) { height: 24px; }
.mx-skel-newrow .mx-skel-line:nth-child(2) { height: 20.8px; margin-top: 4px; }
.mx-skel-newrow .mx-skel-line:nth-child(3) { height: 19.2px; margin-top: 4px; }

/* ---- 淡入 ----
 * 数据到达、图片就位、切换地区都走这条，替代生硬的整块替换。 */
@keyframes mx-fade-in { from { opacity: 0; } to { opacity: 1; } }
.mx-fade-in { animation: mx-fade-in .4s ease-out both; }
img.mx-img-in { animation: mx-fade-in .45s ease-out both; }


/* 搜索结果卡是个例外：主题把 .video-cover 设成 float:left，而 overflow:hidden 的块
 * 会主动避开浮动（BFC 规则），于是每一条占位都被挤到封面下方 —— 一行骨架比真实卡片
 * 高出近 200px，比不画骨架还糟。这一支取消裁切，流光改走 background-position：
 * 背景天然只画在盒子内，既躲开了浮动，也不会漏到卡片外面。
 * 代价是每帧重绘而不是走合成层，但只影响搜索页这十几块，可以接受。 */
.module-search-item .mx-skel {
  overflow: visible;
  background-image: linear-gradient(90deg, var(--mx-skel) 25%, var(--mx-skel-hi) 37%, var(--mx-skel) 63%);
  background-size: 400% 100%;
  animation: mx-skel-sweep 1.4s ease infinite;
}
.module-search-item .mx-skel::after { display: none; }
@keyframes mx-skel-sweep {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

/* 列表页筛选条占位（MX.skelFilter）：选项做成「透明文字 + 灰底」的胶囊。
 * 不写死宽度是有原因的 —— 主题在 ≤899px 会把 .library-item 的左右 padding 从 20px
 * 改成 10px，写死宽度的骨架在手机上会偏宽、可能少折一行，整条筛选条的高度就对不上了。
 * 透明文字永远和同字数的真实选项一样宽，高度也直接吃主题的 line-height:35px。 */
.mx-skel-pill { color: transparent; }
/* 统计条里的数字。overflow:visible 是为了让 inline-block 的基线回到文字基线：
 * .mx-skel 默认 overflow:hidden，会让 inline-block 的基线变成盒子底边，
 * 整行被顶高约 5px —— 而这一行正是要靠它撑住高度的地方。 */
.mx-skel-num { display: inline-block; overflow: visible; color: transparent; }

/* 系统开了「减少动态效果」就全部关掉。animation:none 会把 fill-mode 一并取消，
 * 元素回到正常 opacity，不会因为动画被禁用而卡在 from 帧的 opacity:0 上。 */
@media (prefers-reduced-motion: reduce) {
  .mx-skel::after { animation: none; }
  .module-search-item .mx-skel { animation: none; }
  /* 主题自带的图片加载中旋转图标 */
  .mx-fade-in, img.mx-img-in,
  .module-item-pic img.lazyloading + .loading { animation: none; }
}
