/* ============================================================
   车机模式 · 独立界面
   2026-10-16 重做版：尺寸全部放大，操作重心全部压到左边

   目标设备（诊断编号 9d063dff，2026-10-16 实测）：
     HU_Smart space 4.0 / Linux aarch64 / Adreno 753 / LiBrowser 3.5.18
     物理面板 3138 × 1740，浏览器窗口 3138 × 1230，页面放大 1.5 倍
     → 实际 CSS 视口 2092 × 820，宽高比 2.55 : 1
     触控 5 点、粗指针、无悬停

   ── 为什么这么大 ──
     1 CSS px = 1.5 物理像素，屏幕离眼睛 60~80cm。按网页那套字号给，
     在车上就是要眯着眼睛看。所以这一版把每一档都往上抬：
       正文 34px、卡片名 30px、行标题 44px、页面标题 52px、
       首屏片名 72px、导航文字 36px、时间 48px。
       可点元素底线 80px，次要按钮 88px，主操作 104~112px，
       图标 40~56px。没有「小字」这一档，最小的角标也 26px。

   ── 操作习惯：操作员在左，屏幕在右 ──
     屏幕在操作员右手边，离手最近的是屏幕左边缘。所以「要动手的」一律靠左：
       · 顶栏（时间 / 网络 / 账号 / 登录 / 诊断）全部挤在左边，右半边留空。
       · 左侧一条独立控制带（有底色 + 右边线），六个入口 104px 高，
         上下键在带内走，右键进内容区 —— 这是离手最近的一条。
       · 搜索键放在输入框左边：主操作落在最左侧够得到，
         输入框吃掉剩下的宽度，整行填满不留空档。
       · 热词、加载更多、筛选这些一律靠左，不做居中。
       · 登录页整块贴左，输入框和按钮都落在左手区。
       · 纯信息的横条反过来居中（结果数、提示条）：它们不用手去够，
         居中最醒目，也不跟左边的操作区抢位置。

   ── 版面预算（820 高怎么分的）──
     顶栏 104 + 页面留白 18×2 = 680 给内容。
     首页：没有首屏横幅，一屏就是一行大海报：行标题 46 + 间距 12 + 卡片 622。
     搜索：输入行 104 + 热词/加载更多 88 + 结果数 30 + 间距 42 + 结果网格 416。
     分类：标题+筛选同一行 88 + 网格 476 + 加载更多 88。
     首页那行海报 380 × 570（2:3），一屏一行；分类和搜索结果仍是 242 × 363。

   ── 其他约束 ──
     · 不出现滚动条：车机上滚动条既难看又没用，靠焦点自动滚到可见。
     · 不依赖 hover（粗指针设备上根本没有 hover），焦点环始终可见。
     · 动画只用 opacity 和 transform。
   ============================================================ */

:root {
  --bg: #070a0d;
  --panel: #11161b;
  --line: rgba(255, 255, 255, .1);
  --line-strong: rgba(255, 255, 255, .22);
  --text: #f4f7fa;
  --text-2: #c8d0d8;
  --muted: #9fabb7;
  --amber: #f5b84b;
  --amber-ink: #17110a;
  --amber-soft: rgba(245, 184, 75, .16);
  --teal: #4ed6c2;
  --danger: #ff8a7a;

  /* ── 卡面（2026-10-17 加的）──
     以前每颗按钮都是「一层半透明白 + 一根细边」，排在一起就是一片灰方块，
     看着愣。现在统一成一套玻璃面：上亮下暗的渐变 + 一道顶部高光 + 一点点外阴影，
     选中的那颗换成实心渐变 + 一圈外发光。
     规矩只有一条：琥珀 = 正在用的那一个（正在播的线路、正在播的那一集），
     青色 = 网盘那一类。 */
  --surface-1: linear-gradient(180deg, rgba(255, 255, 255, .075), rgba(255, 255, 255, .028));
  --surface-2: linear-gradient(180deg, rgba(255, 255, 255, .055), rgba(255, 255, 255, .016));
  --sheen: inset 0 1px 0 rgba(255, 255, 255, .08);
  --hair: rgba(255, 255, 255, .09);
  --amber-grad: linear-gradient(180deg, #ffd074, #f0a92f);
  --teal-grad: linear-gradient(180deg, #78e9d8, #33b4a1);
  --glow-amber: 0 10px 26px -12px rgba(245, 184, 75, .9);
  --glow-teal: 0 10px 26px -12px rgba(78, 214, 194, .85);

  --r-xl: 30px;
  --r-lg: 24px;
  --r-md: 20px;

  /* 结构尺寸 */
  --top-h: 104px;
  --rail-w: 320px;
  --pad: 18px;
  --gap: 14px;
  --poster-w: 242px;      /* 搜索结果、分类网格的海报 */
  --poster-row-w: 380px;  /* 首页内容行的海报：一屏只有一行，所以放得更大 */
  --row-h: 88px;      /* 次要按钮、胶囊条 */
  --field-h: 104px;   /* 搜索框、主按钮 */

  /* 字号阶梯：车机上没有「小字」这一档，最小的也 26px */
  --fs-xs: 26px;      /* 海报角标 */
  --fs-sm: 30px;      /* 卡片名、状态文字、说明 */
  --fs-md: 34px;      /* 正文、按钮、输入框 */
  --fs-lg: 44px;      /* 行标题 */
  --fs-xl: 52px;      /* 页面标题 */
  --fs-nav: 36px;     /* 导航文字 */
  --fs-btn: 36px;     /* 按钮文字 */
  --fs-clock: 48px;   /* 时间 */

  --font: "MiSans", "HarmonyOS Sans SC", "Noto Sans SC", "Source Han Sans SC",
          "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  line-height: 1.3;
}
/* 字号只写在 body 上：写到 html 上会被后面的规则盖掉，而且根元素里的 1rem
   会解析成浏览器默认的 16px，所有尺寸都会比设计值小。 */
body { font-size: var(--fs-md); }

button, input, a { font: inherit; color: inherit; }
button { cursor: pointer; border: 0; background: none; }
.hidden { display: none !important; }
/* .chip / .btn 都是 inline-flex，会盖掉浏览器默认的 [hidden]，这里显式兜底 */
[hidden] { display: none !important; }

/* 车机上滚动条只会碍事：焦点导航会把目标自动滚进视野，不需要拖拽条 */
* { scrollbar-width: none; }
*::-webkit-scrollbar { width: 0; height: 0; }

/* 焦点环：触控、键盘、遥控器共用一套，始终清晰可见 */
:focus { outline: none; }
:focus-visible,
.kbd :focus {
  outline: 6px solid var(--amber);
  outline-offset: 4px;
  border-radius: var(--r-md);
}

.app {
  height: 100%;
  display: flex;
  flex-direction: column;
  background:
    radial-gradient(circle at 92% 0%, rgba(245, 184, 75, .07), transparent 30%),
    radial-gradient(circle at 0% 100%, rgba(78, 214, 194, .055), transparent 34%),
    var(--bg);
}

/* ── 顶部状态条 ──
   时间、网络、账号、登录、诊断全在左边，右边不放任何要点的东西。 */
.statusbar {
  flex: 0 0 var(--top-h);
  display: flex;
  align-items: center;
  gap: 26px;
  padding: 0 22px;
  border-bottom: 1px solid var(--line);
}

.clock {
  font-size: var(--fs-clock); font-weight: 900; letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
}

/* 状态是纯文字 + 一个小圆点，不做成胶囊按钮——那看着就像网页导航栏 */
.stat {
  display: inline-flex; align-items: center; gap: 12px;
  color: var(--muted); font-size: var(--fs-sm);
  white-space: nowrap;
}
.led {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--teal); box-shadow: 0 0 14px rgba(78, 214, 194, .85);
  flex: 0 0 auto;
}
.led.off { background: var(--danger); box-shadow: 0 0 14px rgba(255, 138, 122, .8); }

.grow { flex: 1 1 auto; }

/* 顶栏的两个操作紧跟在账号后面，都落在左手区 */
.topbar-actions { display: flex; align-items: center; gap: 14px; }

.chip {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 80px;
  padding: 0 38px;
  border: 1px solid var(--line); border-radius: 999px;
  background: rgba(255, 255, 255, .06);
  color: var(--text-2); font-size: var(--fs-md); font-weight: 700;
  text-decoration: none; white-space: nowrap;
}
/* 未登录时的「登录」是顶栏唯一要立刻点的东西，做成实心主按钮 */
.chip.primary {
  background: var(--amber); border-color: var(--amber); color: var(--amber-ink);
  font-weight: 800;
}

/* 「绑定夸克」照电脑版那颗：青色描边胶囊。
   没绑的时候外面套一圈会呼吸的描边（和电脑版同一个手法），
   一眼看得出「高清原盘还差这一步」；两项都办完了就转成静态青色，不再抢注意力。 */
.chip.qk {
  position: relative;
  color: var(--teal);
  border-color: rgba(78, 214, 194, .42);
  background: rgba(78, 214, 194, .13);
}
.chip.qk.on {
  color: #dffcf3;
  border-color: rgba(78, 214, 194, .5);
  background: rgba(78, 214, 194, .2);
}
.chip.qk.todo::after {
  content: ''; position: absolute; inset: -3px; border-radius: inherit;
  pointer-events: none;
  border: 3px solid rgba(78, 214, 194, .9);
  animation: qk-breath 3s ease-in-out infinite;
}
@keyframes qk-breath {
  0%, 100% { opacity: .1; box-shadow: 0 0 0 0 rgba(78, 214, 194, 0); }
  50% { opacity: .85; box-shadow: 0 0 26px -4px rgba(78, 214, 194, .7); }
}

/* 图标按钮：只有图形，没有边框和底色 */
.icon-btn {
  width: 80px; height: 80px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  color: var(--muted);
}
.icon-btn svg {
  width: 42px; height: 42px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.icon-btn:active { transform: scale(.94); }

/* ── 主体：左边一条控制带 + 右边内容 ── */
.shell { flex: 1 1 auto; min-height: 0; display: flex; }

/* 导航是离手最近的区域，单独做成一条控制带（底色 + 右边线）。
   六个入口都 104px 高，图标 56px、文字 36px —— 一眼能认，伸左手就够到。 */
.rail {
  flex: 0 0 var(--rail-w);
  display: flex; flex-direction: column; justify-content: center;
  gap: 8px;
  padding: 14px 16px;
  overflow: hidden;
  border-right: 1px solid var(--line);
  background: linear-gradient(90deg, rgba(255, 255, 255, .055), rgba(255, 255, 255, .015));
}

.nav {
  width: 100%;
  min-height: 104px;
  padding: 0 22px;
  border-radius: var(--r-lg);
  display: flex; align-items: center; gap: 20px;
  color: var(--text-2);
  transition: background .15s ease, color .15s ease, transform .15s ease;
}
.nav svg {
  width: 56px; height: 56px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.nav b { font-size: var(--fs-nav); font-weight: 800; letter-spacing: .02em; }
.nav.on { color: var(--amber-ink); background: var(--amber); }
.nav:active { transform: scale(.97); }

.stage {
  flex: 1 1 auto; min-width: 0; min-height: 0;
  position: relative;
}

.page {
  position: absolute; inset: 0;
  padding: var(--pad);
  display: flex; flex-direction: column;
  gap: var(--gap);
  min-height: 0;
  overflow: hidden;
}

/* ── 首页 ──
   没有首屏横幅：一进来就是一行 380 宽的大海报，一屏正好一行，
   往下滑（或按方向键）才是下一行。 */
.page-home { padding: var(--pad); }

/* ── 按钮 ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 14px;
  min-height: var(--row-h);
  padding: 0 36px;
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  background: rgba(255, 255, 255, .08);
  color: var(--text); font-size: var(--fs-btn); font-weight: 800;
  transition: background .15s ease, transform .15s ease;
}
.btn.primary { background: var(--amber); border-color: var(--amber); color: var(--amber-ink); }
.btn svg { width: 42px; height: 42px; fill: currentColor; }
.btn:active { transform: scale(.97); }
.btn[disabled] { opacity: .5; }

/* ── 内容行 ── */
.rows {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; gap: 28px;
  overflow-y: auto;
}
.row-block { flex: 0 0 auto; display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.row-head { display: flex; align-items: baseline; gap: 16px; }
.row-head h3 { margin: 0; font-size: var(--fs-lg); font-weight: 800; line-height: 1.05; letter-spacing: .01em; }

.row-scroll {
  display: grid; grid-auto-flow: column;
  /* 首页这行用大号海报：一屏正好一行，看得清也点得准 */
  grid-auto-columns: var(--poster-row-w);
  gap: 18px;
  overflow-x: auto; overflow-y: hidden;
}
/* 加载占位撑满整块内容区，别让首页先闪一条矮的出来 */
.row-skel {
  flex: 1 1 auto; min-height: 0; border-radius: var(--r-lg);
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .015));
}

/* ── 海报卡 ──
   首页内容行 380 × 570，搜索和分类网格 242 × 363（都是 2:3），下面一行 32px 片名。
   年份、评分、集数收成海报角上的角标，卡片下面不再挂第二行小字——车机上那一行根本看不清。 */
.poster-card {
  display: flex; flex-direction: column; gap: 10px;
  border: 0; padding: 0; text-align: left;
  background: none;
  transition: transform .15s ease;
}
.poster-card:active { transform: scale(.98); }
.poster-card .img {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  aspect-ratio: 2 / 3;
  background: linear-gradient(145deg, #1d2630, #0e1318);
}
.poster-card .img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.poster-card .nm {
  font-size: 32px; font-weight: 700; line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tag-tr {
  position: absolute; left: 10px; top: 10px;
  min-height: 44px; padding: 0 18px;
  /* 角标里的字可能很长（「第20260731期上纯享」），到边就省略号，别顶出海报 */
  display: block; line-height: 44px;
  max-width: calc(100% - 20px);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  border-radius: 999px; font-size: var(--fs-xs); font-weight: 800;
  background: rgba(0, 0, 0, .74); color: var(--text-2);
}
.tag-rate { color: var(--amber); right: 10px; left: auto; }
.poster-card .play-ov {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(0, 0, 0, .34); opacity: 0;
  transition: opacity .15s ease;
}
.poster-card:focus-visible .play-ov, .poster-card:focus .play-ov { opacity: 1; }
.play-ov svg { width: 76px; height: 76px; fill: var(--amber); }

/* 「最近播放」卡：海报底边一条进度，和左上角「看到第几集」配着看，
   一眼就知道这集还剩多少。算不出时长的片子不画这条。 */
.poster-card .prog {
  position: absolute; left: 0; right: 0; bottom: 0; height: 10px;
  background: rgba(0, 0, 0, .6);
}
.poster-card .prog i { display: block; height: 100%; background: var(--amber); }

/* ── 搜索页 ──
   四块从上到下：输入行 / 热词或加载更多 / 结果数 / 结果网格。
   搜索键排在输入框左边：主操作落在最左侧、够手够得到，
   输入框吃掉剩下的宽度，整行填满不留空档。 */
.page-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto auto auto minmax(0, 1fr);
  gap: var(--gap) 16px;
}
.page-search .search-bar { grid-column: 1 / -1; grid-row: 1; }
.page-search #hotChips { grid-column: 1 / -1; grid-row: 2; }
.page-search .result-head { grid-column: 1 / -1; grid-row: 3; }
.page-search .grid { grid-column: 1 / -1; grid-row: 4; }
.page-search .more-wrap { grid-column: 2; grid-row: 2; align-self: center; }

/* 出了结果就把热词收起来、把「加载更多」挪到那一行的开头：
   搜索结果才是主角，热词只是没搜之前的引子。 */
.page-search:has(#results .poster-card) #hotChips { display: none; }
.page-search:has(#results .poster-card) .more-wrap { grid-column: 1; justify-self: start; }

.search-bar { display: flex; gap: 16px; align-items: stretch; }
.search-bar input {
  /* 输入框吃掉整行剩下的宽度，右边不留空档 */
  flex: 1 1 auto; min-width: 0;
  min-height: var(--field-h);
  padding: 0 32px;
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  background: var(--panel); color: var(--text);
  font-size: 38px;
}
.search-bar input::placeholder { color: var(--muted); }
.search-bar .btn { min-height: var(--field-h); font-size: 38px; }

.chips { display: flex; flex-wrap: wrap; gap: 14px; }
.chips button {
  min-height: var(--row-h);
  padding: 0 34px;
  border: 1px solid var(--line); border-radius: 999px;
  background: rgba(255, 255, 255, .05);
  color: var(--text-2); font-size: var(--fs-md); font-weight: 700;
  white-space: nowrap;
  transition: background .15s ease, color .15s ease;
}
.chips button.on { color: var(--amber); border-color: rgba(245, 184, 75, .42); background: var(--amber-soft); }
/* 网盘线路用青色和采集线路区分；选中时仍回到统一的琥珀色主状态。 */
.chips button.pan {
  color: var(--teal);
  border-color: rgba(78, 214, 194, .4);
  background: rgba(78, 214, 194, .12);
}
.chips button.pan.on {
  color: var(--amber-ink);
  border-color: var(--amber);
  background: var(--amber);
}
.chips button.pan.loading,
.chips button.pan.error {
  color: var(--muted);
  border-color: var(--line);
  background: rgba(255, 255, 255, .04);
}
.chips button.pan.error {
  color: var(--danger);
  border-color: rgba(255, 138, 122, .35);
}

/* 单行横滚的胶囊条：热词和筛选都用它，几十个选项也只占一行 */
.chips.scroll-row {
  flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
  align-items: center;
}
.chips.scroll-row button { flex: 0 0 auto; }
.chips button.toggle { color: var(--amber); border-color: rgba(245, 184, 75, .4); background: var(--amber-soft); }

/* 结果数这行是纯信息，居中：不用手去够，居中最醒目 */
.result-head {
  color: var(--text-2); font-size: var(--fs-sm); line-height: 1.0;
  min-height: 30px; text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.grid {
  min-height: 0;
  display: grid;
  /* 列宽写死：不写 1fr 的话列会被拉宽，海报跟着变高，一行就装不下了 */
  grid-template-columns: repeat(auto-fill, var(--poster-w));
  justify-content: start;
  gap: 22px 18px;
  align-content: start;
  overflow-y: auto;
}
/* 「加载更多」靠左，不做居中：居中的按钮离操作员最远 */
.more-wrap { display: flex; justify-content: flex-start; align-self: start; }

/* ── 分类页 ──
   标题和筛选并排一行，省下来的高度全给海报。 */
.page-cat {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: var(--gap) 18px;
}
.page-cat .cat-head { grid-column: 1; grid-row: 1; align-self: center; }
.page-cat #catFilters { grid-column: 2; grid-row: 1; }
.page-cat .grid { grid-column: 1 / -1; grid-row: 2; }
.page-cat .more-wrap { grid-column: 1; grid-row: 3; }

.cat-head h2 { margin: 0; font-size: var(--fs-xl); font-weight: 800; line-height: 1.0; white-space: nowrap; }
.cat-filters { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.cat-filter-row { display: flex; align-items: center; gap: 16px; min-width: 0; }
.cat-filter-row .lbl { color: var(--muted); font-size: var(--fs-sm); min-width: 96px; flex: 0 0 auto; }

/* ── 选集页 ──
   点开一张卡片就到这里。三段从上到下：片子本身（海报 + 片名 + 信息 + 返回/播放）、
   线路条、选集网格。线路只有一条时整条不显示，把高度全留给选集。
   一屏三行选集，长剧靠焦点滚动，不再加「加载更多」多占一次按键。 */
.page-detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto auto minmax(0, 1fr);
  /* 行距比别的页紧一档：选集要正好放下三行，多出来的都是白给的空档 */
  gap: 12px;
}

.detail-head { grid-row: 1; display: flex; align-items: flex-start; gap: 24px; min-width: 0; }
.detail-poster {
  flex: 0 0 auto; width: 150px; aspect-ratio: 2 / 3;
  border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--line);
  background: linear-gradient(145deg, #1d2630, #0e1318);
}
.detail-poster img { width: 100%; height: 100%; object-fit: cover; display: block; }
.detail-meta { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.detail-meta h2 {
  margin: 0; font-size: var(--fs-xl); font-weight: 800; line-height: 1.05;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.detail-sub {
  color: var(--muted); font-size: var(--fs-sm); min-height: 30px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 两个动作贴在信息下面，跟海报下沿对齐：左边返回、右边播放，都在左手区 */
.detail-actions { display: flex; flex-wrap: wrap; gap: 14px; margin-top: auto; }

/* 线路这一块，和网页版同一个逻辑：先挑类别（稳定版 / 高清原盘），再挑这一类里的线路。
   摆法是两行（2026-10-17 改回来的）：上面一行是类别分段控件 + 右边的条数，
   下面一行才是这一类里的具体线路，横着排、排满一行自动换下一行（多行，不是左右一条）。
   为什么不并成一行（类别在左、线路在右横着铺）：并起来看着整，但线路多的时候
   右边那串会被屏幕切掉一截，得横着滑才知道还有几条 —— 车机上没人会去滑。
   两行排开，12 条线路一眼全在，不用滑也不用猜；类别那行右边写「N 条线路」，
   不留一大截空白。多出来的一行高度从选集网格里出（网格本来就能滚）。 */
.detail-lines-row {
  grid-row: 2;
  display: flex; flex-direction: column; align-items: stretch; gap: 10px;
  min-width: 0;
}
.detail-tabs-row { display: flex; align-items: center; gap: 16px; min-width: 0; }
.detail-lines-count {
  margin-left: auto; min-width: 0;
  color: var(--muted); font-size: var(--fs-sm); line-height: 1.1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 类别键做成一个分段控件：外面一个内凹的凹槽（暗底 + 内阴影），
   里面两块选中的是凸的（渐变 + 外发光）。一凹一凸，一眼分得清
   「这是一组里选了一个」，而不是两颗并排的独立按钮。
   留白收过两档（2026-10-17）：上下 80 → 70 → 62、左右 26 → 20 → 16，字号 34/26 → 30/23。
   键与键之间、键与凹槽之间的间距一点没动（还是 6 / 5）——用户要的是「按钮别那么大，
   间距照旧」，所以只收里面的留白，不动间隙。 */
.line-tabs {
  flex: 0 0 auto;
  display: inline-flex; align-items: stretch; gap: 6px;
  padding: 5px;
  border: 1px solid var(--line); border-radius: 22px;
  background: rgba(0, 0, 0, .36);
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .5);
}
.line-tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px;
  min-height: 62px;
  padding: 0 16px;
  border: 1px solid transparent; border-radius: 17px;
  background: none;
  color: var(--text-2);
  text-align: center;
  transition: background .18s ease, color .18s ease, box-shadow .18s ease;
}
.line-tab b { font-size: 30px; font-weight: 800; line-height: 1.05; }
.line-tab small { font-size: 23px; font-weight: 600; color: var(--muted); line-height: 1.05; }
.line-tab.on {
  background: var(--amber-grad); color: var(--amber-ink);
  box-shadow: var(--sheen);
}
.line-tab.on small { color: rgba(23, 17, 10, .7); }
.line-tab[data-line-type="pan"].on { background: var(--teal-grad); color: #04231f; }
.line-tab[data-line-type="pan"].on small { color: rgba(4, 35, 31, .7); }

/* 具体线路：横着排、排满一行自动换下一行（多行，不是左右横滑），
   整块最多占两行高，再多就在块里往下滚。
   一颗胶囊里两段字：粗体源名 + 淡一号的说明（见 app.js 的 linePillParts）。
   2026-10-17 又收一档：上下 56 → 48、左右 22 → 16、字号 30/26 → 27/22，
   胶囊之间的间距（14）一点没动。收完之后 12 条线路两行排得下，不用滚也不用猜。 */
.detail-lines {
  align-content: flex-start;
  max-height: 128px;
  overflow-x: hidden; overflow-y: auto;
}
.detail-lines button {
  display: inline-flex; align-items: baseline; gap: 10px;
  min-height: 48px; padding: 0 16px;
  font-size: 27px; font-weight: 700;
}
.detail-lines button b { font-size: 27px; font-weight: 800; line-height: 1; }
.detail-lines button small { font-size: 22px; font-weight: 600; line-height: 1; opacity: .72; }
/* 两段字各自到边就省略号：网盘源名可能很长（「小虎 | 夸克网盘 · 第1-40集」），
   宁可截断也不要顶出卡片 */
.detail-lines button b, .detail-lines button small,
.play-side #pLines button b, .play-side #pLines button small {
  min-width: 0; overflow: hidden; text-overflow: ellipsis;
}
/* 排不下的时候底边化一道渐隐，一眼看出「下面还有」（和播放页的换源同一套记号） */
.detail-lines.has-more-y {
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 20px), transparent 100%);
  mask-image: linear-gradient(180deg, #000 calc(100% - 20px), transparent 100%);
}

/* 线路卡片：玻璃面 + 顶部高光。正在用的那条是实心琥珀 + 外发光，
   和选集里「正在播」的那一集同一套语言。 */
.detail-lines button {
  border: 1px solid var(--hair);
  background: var(--surface-1);
  box-shadow: var(--sheen);
  transition: background .18s ease, color .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.detail-lines button.on {
  color: var(--amber-ink); border-color: transparent;
  background: var(--amber-grad);
  box-shadow: var(--glow-amber), var(--sheen);
  font-weight: 800;
}
.detail-lines button.pan {
  color: var(--teal);
  border-color: rgba(78, 214, 194, .32);
  background: linear-gradient(180deg, rgba(78, 214, 194, .2), rgba(78, 214, 194, .07));
}
.detail-lines button.pan.on {
  color: var(--amber-ink); border-color: transparent;
  background: var(--amber-grad);
  box-shadow: var(--glow-amber), var(--sheen);
}
.detail-lines button.pan.loading,
.detail-lines button.pan.error {
  color: var(--muted);
  border-color: var(--line);
  background: rgba(255, 255, 255, .04);
  box-shadow: none;
}
.detail-lines button.pan.error {
  color: var(--danger);
  border-color: rgba(255, 138, 122, .35);
}

/* 网盘资源的两层（和网页版 sourceBarHTML 的「高清原盘」同一套）：
   第一层是来源（夸克盘搜 4个可用）+「＋ 再搜一个」，
   第二层是「可用资源」，每个来源下的独立分享各一颗。
   说明条是 div，占满一整行把 flex 换行，同时不会被方向键选中。 */
.detail-lines.pan-layout { max-height: 208px; }
.detail-lines .pan-sub-label {
  flex: 1 0 100%;
  display: flex; align-items: center;
  min-height: 26px;
  color: var(--muted);
  font-size: 22px; font-weight: 700; letter-spacing: .02em;
}
.detail-lines button.pan-provider {
  color: var(--teal);
  border-color: rgba(78, 214, 194, .32);
  background: linear-gradient(180deg, rgba(78, 214, 194, .2), rgba(78, 214, 194, .07));
}
.detail-lines button.pan-provider.on {
  color: var(--amber-ink); border-color: transparent;
  background: var(--amber-grad);
  box-shadow: var(--glow-amber), var(--sheen);
}
.detail-lines button.pan-provider small { opacity: .8; }
.detail-lines button.pan-provider.on small { color: rgba(23, 17, 10, .7); }
.detail-lines button.pan-more {
  color: var(--amber);
  border-color: rgba(245, 184, 75, .4);
  background: var(--amber-soft);
}
.detail-lines button.pan-variant {
  color: var(--teal);
  border-color: rgba(78, 214, 194, .32);
  background: linear-gradient(180deg, rgba(78, 214, 194, .2), rgba(78, 214, 194, .07));
}
.detail-lines button.pan-variant.on {
  color: var(--amber-ink); border-color: transparent;
  background: var(--amber-grad);
  box-shadow: var(--glow-amber), var(--sheen);
}
/* 来源后面那格状态字（正在展开高清原盘… / 其他高清来源仍在搜索…）：
   和按钮同高但不参与方向键，只报进度。 */
.detail-lines .pan-status {
  display: inline-flex; align-items: center;
  min-height: 48px; padding: 0 8px;
  color: var(--muted); font-size: 22px; font-weight: 700;
  white-space: nowrap;
}

/* 选集那行标题：左边一根琥珀亮条，和左栏「换源 / 选集」两个小标题同一套记号 */
.eps-head {
  grid-row: 3;
  display: flex; align-items: center; gap: 10px;
  color: var(--text); font-size: var(--fs-sm); font-weight: 800; line-height: 1.1;
  min-height: 26px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.eps-head::before {
  content: ''; flex: 0 0 auto;
  width: 8px; height: 20px; border-radius: 999px;
  background: var(--amber-grad);
  box-shadow: 0 0 14px rgba(245, 184, 75, .5);
}
.eps-head:empty::before { opacity: 0; }

.eps-grid {
  grid-row: 4; min-height: 0;
  display: grid;
  /* 列宽写死：不写 1fr 的话列会被拉宽，按钮跟着变高，一行就装不下了 */
  grid-template-columns: repeat(auto-fill, 180px);
  justify-content: start;
  align-content: start;
  gap: 12px;
  overflow-y: auto;
}

/* 选集按钮：单行文字居中。名字太长到边就省略号，不换行——
   换行会让同一行的按钮高低不齐，方向键移动时看着乱跳。 */
.ep-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 88px; padding: 0 14px;
  border: 1px solid var(--hair); border-radius: 18px;
  background: var(--surface-1);
  box-shadow: var(--sheen);
  color: var(--text-2); font-size: var(--fs-md); font-weight: 700;
  transition: background .18s ease, color .18s ease, box-shadow .18s ease;
}
.ep-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 当前选中的那一集：实心琥珀 + 一颗 ▶，和「继续播放」同一个颜色，
   一眼看得出「按下去要播的就是它」 */
.ep-btn.on {
  background: var(--amber-grad); border-color: transparent;
  color: var(--amber-ink); font-weight: 800;
  box-shadow: var(--glow-amber), var(--sheen);
}
.ep-btn.on::before { content: '▶'; font-size: 22px; line-height: 1; }

/* ── 空态与提示 ──
   靠左，不居中：居中的提示和按钮离操作员最远。 */
.empty {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 16px; padding: 32px 0 32px 8px;
  color: var(--muted); font-size: var(--fs-md); text-align: left;
}
.empty b { color: var(--text); font-size: 38px; }

/* 未登录时的登录入口：做成容器里的直接子按钮，方向键能聚焦到 */
.empty-cta { border: 0; background: none; font: inherit; color: inherit; cursor: pointer; }
.empty-cta em {
  font-style: normal; margin-top: 14px;
  min-height: 112px; display: inline-flex; align-items: center;
  padding: 0 52px; border-radius: 999px;
  background: var(--amber); color: var(--amber-ink);
  font-size: 38px; font-weight: 800;
}

/* ── 车机内登录页 ──
   整屏盖住，一屏只做一件事。卡片贴左不居中：操作员的手在左边。
   卡片用网格排版，输入框和按钮都是它的直接子元素，方向键能一路走过去。 */
.login {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: flex-start;
  background: rgba(4, 6, 9, .96);
  padding: var(--pad) var(--pad) var(--pad) 56px;
}
.login-card {
  width: min(1140px, 100%);
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 14px 18px;
  padding: 34px 40px 38px;
  border: 1px solid var(--line-strong); border-radius: var(--r-xl);
  background: linear-gradient(180deg, #161d24, #0e1319);
}
.login-card h2 { grid-column: 1 / -1; margin: 0; font-size: 60px; font-weight: 900; line-height: 1.05; }
.login-note { grid-column: 1 / -1; margin: 0 0 6px; color: var(--muted); font-size: var(--fs-md); }

.field-lbl { grid-column: 1 / -1; color: var(--muted); font-size: var(--fs-sm); margin-top: 6px; }
.login-card input {
  grid-column: 1 / -1;
  min-height: 116px;
  padding: 0 32px;
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  background: var(--panel); color: var(--text);
  font-size: 40px; letter-spacing: .02em;
}
.login-card input::placeholder { color: #66717d; }

.login-err { grid-column: 1 / -1; margin: 0; min-height: 34px; color: var(--danger); font-size: var(--fs-md); }
.login-card .btn { min-height: 112px; font-size: 38px; }
#loginBtn { grid-column: 1; }
#loginCancel { grid-column: 2; }

/* ── 绑定夸克 · 高清扫码 CDN ──
   和电脑版同一件事：两张码，① 网盘登录 ② 高清 CDN 直连授权，用同一个夸克账号。
   车机上二维码要离眼睛 60~80cm 还能扫，所以码开得比电脑版（224）大一圈到 280。
   整屏只做这一件事，卡片贴左不居中（操作员的手在左边）。 */
.bind {
  position: fixed; inset: 0; z-index: 62;
  display: flex; align-items: center; justify-content: flex-start;
  background: rgba(4, 6, 9, .97);
  padding: var(--pad) var(--pad) var(--pad) 56px;
}
.bind-card {
  display: grid; justify-items: start; gap: 16px;
  width: fit-content; max-width: 100%;
  padding: 28px 34px 32px;
  border: 1px solid var(--line-strong); border-radius: var(--r-xl);
  background: linear-gradient(180deg, #161d24, #0e1319);
}
.bind-head h2 { margin: 0; font-size: 52px; font-weight: 900; line-height: 1.05; }
.bind-summary { margin: 8px 0 0; color: var(--muted); font-size: var(--fs-sm); }
.bind-summary.ok { color: var(--teal); }
.bind-qrs { display: flex; gap: 22px; align-items: stretch; }
.bind-qr {
  display: grid; justify-items: center; gap: 10px;
  padding: 16px 20px 18px;
  border: 1px solid var(--hair); border-radius: var(--r-lg);
  background: var(--surface-2); box-shadow: var(--sheen);
}
.bind-qr h3 { margin: 0; font-size: var(--fs-md); font-weight: 800; }
/* 二维码一律白底：深色底上反色码手机扫不出来 */
.qr-box {
  width: 300px; height: 300px;
  display: grid; place-items: center; padding: 10px;
  border-radius: var(--r-md);
  background: #fff; color: #10151a;
}
.qr-box img { width: 100%; height: 100%; display: block; }
.qr-wait { color: #6b757e; font-size: var(--fs-sm); }
.qr-note {
  margin: 0; min-height: 30px; max-width: 300px;
  color: var(--muted); font-size: var(--fs-xs); text-align: center; line-height: 1.25;
}
.qr-note.ok { color: var(--teal); }
.qr-note.err { color: var(--danger); }
.bind-card > .btn { min-height: 100px; }

/* 提示条弹在屏幕正下方居中：这是纯信息，不用手去够，
   居中一眼就能看到，也不跟左边的操作区挤在一起 */
.toast {
  position: fixed; left: 50%; bottom: 40px;
  transform: translateX(-50%);
  padding: 24px 44px; border-radius: var(--r-md);
  background: rgba(9, 12, 16, .97); border: 1px solid var(--line-strong);
  color: var(--text); font-size: 36px; z-index: 50;
  animation: toast-in .16s ease-out;
}
@keyframes toast-in {
  from { opacity: 0; transform: translate(-50%, 14px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

/* ── 播放 ──
   整屏盖住，按 3 : 7 分：左边 30% 一条控制栏（标题、六个动作键、状态、换源、选集），
   右边 70% 全是画面。
   画面为什么能吃满这 70%：这块屏 2092 × 820，16:9 的画面按整屏高度算正好
   1458 宽 ≈ 70%。所以只要没有横条压在画面上方，画面就一点黑边都不留 ——
   六个动作键因此收进左栏当标题行，仍在屏幕最上方，只是不横跨画面。
   画面用原生控件（controls playsinline），车机上手指直接点。
   加载和出错写在左栏的状态卡里，不盖画面、不改播放器尺寸。 */
.player {
  position: fixed; inset: 0; z-index: 40;
  display: flex; flex-direction: column;
  background: #000;
}
.play-body { flex: 1 1 auto; min-height: 0; display: flex; align-items: stretch; }

/* 左栏 30%：窄，所以每一块都做成有底色 + 描边的卡片，
   标题行左边一条竖着的琥珀亮条，右边跟一个计数，一眼分得清是「换源」还是「选集」。 */
.play-side {
  flex: 0 0 30%; min-width: 0;
  display: flex; flex-direction: column; gap: 8px;
  padding: 9px 14px 9px;
  background: linear-gradient(180deg, #0e141a, #121821 58%, #0a0f14);
  border-right: 1px solid var(--line);
  overflow: hidden;
}
.play-stage { flex: 1 1 auto; min-width: 0; height: 100%; background: #000; display: flex; }
#pVideo { width: 100%; height: 100%; background: #000; outline: none; object-fit: contain; }
#pVideo:focus-visible { box-shadow: inset 0 0 0 4px var(--amber); }

/* 标题 + 六个动作键。键排成 3 × 2：一行三颗，图标在左、文字在右，
   左栏 628 宽正好一格 198 宽，手指点得准，也不用把左栏撑高。 */
.play-head { flex: 0 0 auto; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
/* 片名一行、副题一行，两行都居中：左栏窄，居中之后两边留白一样多，
   比「左边顶着、右边空一大截」看着稳。 */
.play-meta {
  min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 2px;
  text-align: center;
}
.play-title {
  max-width: 100%; font-size: 38px; font-weight: 900; line-height: 1.1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.play-sub {
  max-width: 100%; color: var(--muted); font-size: var(--fs-xs); line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.play-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.pbtn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 74px; padding: 0 8px;
  border: 1px solid var(--line-strong); border-radius: 18px;
  background: var(--surface-1);
  box-shadow: var(--sheen);
  color: var(--text);
  transition: background .15s ease, transform .15s ease;
}
.pbtn b { font-size: 28px; font-weight: 800; line-height: 1; white-space: nowrap; }
.pbtn svg {
  width: 32px; height: 32px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.pbtn:active { transform: scale(.97); }
/* 「全屏」是这六颗里最该一眼看到的一颗：实心琥珀，和「继续播放」同一个颜色 */
#pFull {
  background: var(--amber-grad); border-color: transparent; color: var(--amber-ink);
  box-shadow: var(--glow-amber), var(--sheen);
}
.pbtn[disabled] { opacity: .35; }

/* 状态卡：左边一颗指示灯（等流琥珀闪、出错红、正常青），右边两行字。
   第二行空着时用 visibility 留白，出字收字都不让下面的卡片上下跳。 */
.play-status {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 12px;
  padding: 7px 14px;
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  background: var(--surface-2);
  box-shadow: var(--sheen);
}
.play-status .dot {
  flex: 0 0 auto; width: 14px; height: 14px; border-radius: 50%;
  background: var(--teal); box-shadow: 0 0 12px rgba(78, 214, 194, .8);
}
.play-status.busy .dot {
  background: var(--amber); box-shadow: 0 0 12px rgba(245, 184, 75, .85);
  animation: dot-pulse 1.1s ease-in-out infinite;
}
.play-status.error .dot { background: var(--danger); box-shadow: 0 0 12px rgba(255, 138, 122, .8); }
@keyframes dot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .2; } }
.play-status-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.play-status-main {
  font-size: 30px; font-weight: 700; color: var(--text-2); line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.play-status.busy .play-status-main { color: var(--amber); }
.play-status.error .play-status-main { color: var(--danger); }
.play-status-hint {
  min-height: 26px;
  font-size: 24px; color: var(--muted); line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.play-status-hint:empty { visibility: hidden; }

/* 左栏里的两块（换源 / 选集）：玻璃面卡片，顶部一道高光、底下一点外阴影，
   在整块深色底上能看出是一张「卡」，不是一片贴上去的灰。 */
.side-block {
  flex: 0 0 auto; min-width: 0;
  display: flex; flex-direction: column; gap: 6px;
  padding: 8px 12px 10px;
  border: 1px solid var(--hair); border-radius: 22px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .045), rgba(255, 255, 255, .012)), rgba(8, 12, 17, .55);
  box-shadow: var(--sheen), 0 18px 36px -28px #000;
}
.side-block-eps { flex: 1 1 auto; min-height: 0; }
.side-head { display: flex; align-items: center; gap: 10px; min-height: 20px; }
.side-tag {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 27px; font-weight: 800; line-height: 1.1; color: var(--text); white-space: nowrap;
}
.side-tag::before {
  content: ''; flex: 0 0 auto;
  width: 8px; height: 20px; border-radius: 999px;
  background: var(--amber-grad);
  box-shadow: 0 0 14px rgba(245, 184, 75, .5);
}
.side-count {
  margin-left: auto; min-width: 0;
  display: flex; align-items: center; gap: 10px;
  font-size: 24px; color: var(--muted);
  white-space: nowrap; overflow: hidden;
}
.side-count > span { overflow: hidden; text-overflow: ellipsis; }
/* 「正在播 第3集」是这一块里唯一要一眼看到的字，单独给它琥珀色和一颗 ▶ */
.side-count .side-live { color: var(--amber); font-weight: 700; }
.side-count .side-live::before { content: '▶'; font-size: 18px; margin-right: 6px; }

/* 换源：两颗类别键做成一个分段控件（同一个凹槽里两块），比两颗独立方框看着整。
   凹槽内凹、选中那块外凸，选中态按类别上色：稳定版琥珀、高清原盘青色。
   控件按内容撑开、靠左，不铺满整条 —— 铺满的话两颗键各自几百像素宽，
   字挤在中间、两边全是空，正是「留空太大」的来源。
   2026-10-17 又收一档：左右留白 18 → 13 → 11、上下 52 → 44 → 40，字号 28/24 → 23/19；
   键与键之间、键与凹槽之间的间距一点没动（还是 6 / 5）。 */
.play-side .line-tabs {
  display: inline-flex; align-self: flex-start;
  gap: 6px; padding: 5px;
  border: 1px solid var(--line); border-radius: 18px;
  background: rgba(0, 0, 0, .36);
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .5);
}
.play-side .line-tab {
  min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  min-height: 40px; padding: 0 11px;
  border: 1px solid transparent; border-radius: 14px;
  background: none; color: var(--text-2); text-align: center;
  transition: background .18s ease, color .18s ease, box-shadow .18s ease;
}
.play-side .line-tab b { font-size: 23px; font-weight: 800; line-height: 1.05; }
.play-side .line-tab small { font-size: 19px; font-weight: 600; color: var(--muted); line-height: 1.05; }
.play-side .line-tab.on {
  background: var(--amber-grad); color: var(--amber-ink);
  box-shadow: var(--glow-amber), var(--sheen);
}
.play-side .line-tab.on small { color: rgba(23, 17, 10, .7); }
.play-side .line-tab[data-line-type="pan"].on { background: var(--teal-grad); color: #04231f; box-shadow: var(--glow-teal), var(--sheen); }
.play-side .line-tab[data-line-type="pan"].on small { color: rgba(4, 35, 31, .7); }

/* 具体线路：一行排满自动换行的胶囊（多行），不再一行一条、也不再左右横滑。
   一颗胶囊里两段字：粗体源名 + 淡一号的说明（和选集页同一套，见 linePillParts）。
   左栏 576 宽一行放得下四颗，12 条线路三行排开，一屏全在，不用滑也不用猜。
   2026-10-17 收一档：上下 46 → 42、左右 16 → 13、字号 25/20 → 23/18，
   胶囊之间的间距（6）一点没动。块高按三行留（144），正常片子一律不出滚动条；
   真有二十几条线路时才在块里往下滚，底边一道渐隐提示下面还有。 */
.play-side #pLines {
  display: flex; flex-wrap: wrap;
  align-items: baseline; align-content: flex-start;
  gap: 6px;
  max-height: 144px;
  overflow-x: hidden; overflow-y: auto;
}
.play-side #pLines button {
  flex: 0 0 auto;
  max-width: 100%;
  min-width: 0; min-height: 42px; padding: 0 13px;
  display: inline-flex; align-items: baseline; justify-content: center; gap: 8px;
  border-radius: 999px;
  font-size: 23px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-align: center;
}
.play-side #pLines button b { font-size: 23px; font-weight: 800; line-height: 1; }
.play-side #pLines button small { font-size: 18px; font-weight: 600; line-height: 1; opacity: .7; }
/* 高清原盘的来源组头：和网页版播放器 grouped 排法一致（来源名 + N个资源），
   整行占满，不参与方向键（focusableItems 只认直接子元素里的 button/a/input）。 */
.play-side #pLines .p-pan-group {
  flex: 1 0 100%;
  display: flex; align-items: center; gap: 8px;
  min-height: 24px;
  color: var(--muted); font-size: 19px; font-weight: 700;
}
.play-side #pLines .p-pan-group b { font-size: 20px; font-weight: 800; color: var(--teal); }
.play-side #pLines .p-pan-group small { font-size: 17px; font-weight: 600; opacity: .8; }
.play-side #pLines button.on { font-weight: 800; }
.play-side #pLines button.on::before { content: '▶'; font-size: 17px; }
/* 线路多了会往下滚，底边化一道渐隐，一眼看出「下面还有」 */
.play-side #pLines.has-more-y {
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 18px), transparent 100%);
  mask-image: linear-gradient(180deg, #000 calc(100% - 18px), transparent 100%);
}

/* 选集：四列等宽的方格，正在播的那一颗实心琥珀 + 一个 ▶。
   整块只在内部滚动，不出现滚动条（车机上滚动条既难看又没用）。 */
.play-side #pEps {
  flex: 1 1 auto; min-height: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  align-content: start; gap: 8px;
  overflow-y: auto;
}
.play-side #pEps .ep-btn {
  min-width: 0; min-height: 68px; padding: 0 6px; border-radius: 15px; font-size: 28px;
  transition: background .15s ease, transform .15s ease;
}
.play-side #pEps .ep-btn.on::before { font-size: 19px; }
.play-side #pEps .ep-btn:active { transform: scale(.96); }
.play-side #pLines button:active { transform: scale(.97); }
/* 左栏格子密，全局那圈 6px + 4px 偏移会蹭到隔壁，这里收一档到 4px + 3px */
.play-side :focus-visible,
.kbd .play-side :focus {
  outline-width: 4px; outline-offset: 3px;
}

/* 全屏是两层一起进：.theater 版面（左栏收起来，画面吃满视口）+ 向系统要原生全屏
   （屏幕全屏，浏览器自己的地址栏/标签栏/状态栏一起让开）。
   播放器本身是 position: fixed; inset: 0，视口多大「吃满」就是多大；
   画面是 object-fit: contain、舞台用 flex 撑满，等比铺满不会拉变形，
   这里没有一处写死像素宽度，换一块更大或更小的浏览器窗口也不用另排一套。
   顶上浮一条小窄栏（快退 / 快进 / 退出全屏），保证进去以后还退得出来；
   Esc / 系统手势关掉系统全屏时，app.js 的 fullscreenchange 会把版面这一层一起收回来。 */
.play-fs-bar { display: none; }
.player.theater .play-side { display: none; }
.player.theater .play-fs-bar {
  display: flex; gap: 12px;
  position: absolute; top: 14px; right: 20px; z-index: 2;
  padding: 8px; border-radius: var(--r-md);
  background: rgba(0, 0, 0, .58);
  /* 进全屏后这条栏只亮 3 秒就淡出，不长期压着画面右上角；
     屏幕上一动（点一下、按方向键）再亮 3 秒，见 app.js 的 showFsBar。
     淡出时 pointer-events 一起关掉，免得点到看不见的按钮。 */
  opacity: 0; pointer-events: none;
  transition: opacity .22s ease;
}
.player.theater.fs-bar-on .play-fs-bar { opacity: 1; pointer-events: auto; }
.play-fs-bar .btn { min-height: 76px; font-size: 30px; padding: 0 22px; }

/* ── 兜底 ──
   这个页面只在 2092 × 820 上用（车机和 Mac 上的「车机屏幕」app 都锁死这个视口）。
   万一被人拿普通浏览器打开，整体等比缩小显示，不让它挤爆。 */
@media (max-width: 1900px), (max-height: 780px) {
  body { zoom: .72; }
  .app { width: 2092px; height: 820px; }
  .login, .bind, .toast { position: absolute; }
}
