* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background-color: #f5f5f5;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* HOME */
.lottery-card {
	transition: all 0.3s;
	min-height: 320px;    /* 增加卡片高度 */
	padding: 24px;
	text-align: left;
	max-width: 100%;
}
.lottery-card:hover {
  transform: translateY(-6px);
}

/* ---- 主页彩种卡片：文字层级 ----
   改造前整张卡片只有两种颜色（标签 #333、值继承正文黑）而且五行字一样大 ——
   「一等奖」和「开奖日期」看起来一样重，扫一眼分不出重点，糊成一片黑。

   现在按三层拉开：
     标签    12px #6b7280（灰）          —— 只做引导，不抢视线
     值      14px #111827 + 等宽数字     —— 多张卡片的日期/金额能对齐成一列
     一等奖  20px #e41e2b（同前区球色）  —— 整张卡片唯一的重音
   标签在左、值在右，由 .lottery-info 的 space-between 分栏（值是匿名弹性项，
   所以模板里标签写成 <strong>、值包成 .lottery-value，不再用冒号分隔）。

   ★ 12px 是硬下限，不是随手取的：浏览器的最小字号设置会把更小的字顶回 12px
     （见 §11.16），写 11px 在真机上等于没写。层级靠颜色/字重/字号三档拉开，
     不靠「更小」。 */
.lottery-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
}
.lottery-head i {
  color: #e41e2b;
  font-size: 19px;
}
.lottery-head h3 {
  font-size: 19px;
  font-weight: 700;
  color: #0f172a;
  letter-spacing: -0.01em;
}
.lottery-code {
  margin-left: auto;              /* 与下面右对齐的值在同一条视线上 */
  padding: 2px 8px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #475569;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
}
.lottery-info {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 6px 0;
  font-size: 14px;
}
.lottery-info strong {
  font-size: 12px;
  font-weight: 500;
  color: #6b7280;
}
.lottery-value {
  font-size: 14px;
  font-weight: 600;
  color: #111827;
  font-variant-numeric: tabular-nums;
}
/* 一等奖：整卡唯一的重音。上面一条细线把它和「号码区」分开。 */
.lottery-info--prize {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid #eef2f6;
}
.lottery-info--prize .lottery-value {
  font-size: 20px;
  font-weight: 700;
  color: #e41e2b;
  letter-spacing: -0.01em;
}
.lottery-numbers {
  display: flex;
  /* ★ 必须换行。这里原来是 nowrap 的单行 flex，号码一多就横向顶穿卡片：
     Pick 10 开 20 个号 = 20×32px + 19×8px = 792px，而 lg 三列下卡片净宽只有
     约 352px（max-w-7xl 1280 − padding − 两个 gap ÷ 3 − 卡片 padding）。
     加了 wrap 之后**任何号码数都不会再溢出**，这条是兜底；
     下面的 is-many 只是让它别换得那么参差。 */
  flex-wrap: wrap;
  gap: 8px;
  margin: 6px 0 14px;
}
.lottery-number {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 14px;
  color: white;
}
/* 号码多的彩种（现在只有 Pick 10，20 个号）换成小一号的球：
   32px + 8px 间距在 352px 净宽里一行只放得下 7 个 → 20 个要换 7/7/6 三行，参差；
   24px + 6px 一行放 11 个 → 两行就够，且行内对齐。
   字号 12px 是下限：再小会被浏览器的「最小字号」顶回 12px，球就绷了。 */
.lottery-numbers.is-many {
  gap: 6px;
}
.lottery-numbers.is-many .lottery-number {
  width: 24px;
  height: 24px;
  font-size: 12px;
}
.lottery-number.front {
  background: #e41e2b;
}
.lottery-number.back {
  background: #0066cc;
}
/* 取不到值的行（福彩3D 的一等奖两行）：退成浅灰，且**压回普通字号** ——
   否则一等奖那行会是一个 20px 的红色破折号，比有数的彩种还抢眼。 */
.lottery-info.is-empty .lottery-value {
  font-size: 14px;
  font-weight: 500;
  color: #cbd5e1;
}
.lottery-empty {
  font-size: 14px;
  color: #6b7280;
  margin: 8px 0;
}
.lottery-link {
  font-size: 14px;
  font-weight: 600;
  color: #e41e2b;
}
.lottery-link:hover {
  color: #b91c1c;
}

/* Table Tab Switch */
.tab-nav {
  display: flex;
  border-bottom: 1px solid #e5e7eb;
  margin-bottom: 20px;

  /* ★ 2026-09-17 **上半场加过** `position: sticky; top: 4rem; z-index: 40; background: #fff`
     （当时用户希望滚到长表格底部还能切页签）。**当天即按用户要求撤销**：条子一直压在
     内容上方，滚动时正文从它背后走 —— 用户要的其实是「人已经在底部了，就地能切一下」，
     所以改成在**页面底部再放一条页签**（见下面 .tab-nav-bottom、lottery.html 的 tab_nav 宏）。
     ★ **别再吸回来**：tools/check_frontend_i18n.js 有一条判据专门钉住「.tab-nav 不 sticky」。
     详见 docs/design.md §11.75（当时的记录）与 §11.76（撤销的原因）。 */
}

.tab-item {
  padding: 12px 24px;
  cursor: pointer;
  font-weight: 500;
  color: #4b5563;
  border-bottom: 3px solid transparent;
}

.tab-item.active {
  color: #B91C1C;
  border-color: #B91C1C;
}

.tab-content {
  display: none;
}

.tab-content.active {
  display: block;
}

/* 底部那条页签（lottery.html 的 tab_nav 宏第二次调用，2026-09-17 用户要求）：
   与顶部那条**同一组**页签，只差位置在内容之后 —— 读到长表格底部时就地能切，
   不用先把页面拉回顶部。
   指示线翻到上边（贴着内容那一侧）：同样是 3px 边 + 24px padding + 一行文字，
   所以两条条子的高度逐像素一致，来回切时内容不会上下跳。
   ★ 这一块**必须写在 .tab-nav 之后**：.tab-nav-bottom 与 .tab-nav 同优先级（0,1,0），
     靠源序取胜 —— 写在前面的话 border-bottom:none / margin-bottom:0 会**静默失效**
     （底部条子多出一条通栏灰线 + 20px 空档）。判据里有源序那条盯着。 */
.tab-nav-bottom {
  border-top: 1px solid #e5e7eb;
  border-bottom: none;
  margin-top: 20px;
  margin-bottom: 0;
}
.tab-nav-bottom .tab-item {
  border-bottom: none;
  border-top: 3px solid transparent;
}
/* ★ 这条**不是**多余的：上面那句 `border-top: … transparent` 与既有的
   `.tab-item.active { border-color: #B91C1C }` 是**同优先级**（0,2,0），后写的赢 ——
   上面那句在后，会把选中态的边框颜色重新压成透明（红线就不见了；文字还是红的，
   所以看着像"样式有点怪"而不是"坏了"）。
   这里用多一级的 `.tab-nav-bottom .tab-item.active`（0,3,0）把它扳回来。 */
.tab-nav-bottom .tab-item.active {
  border-color: #B91C1C;
}

/* Full width table container */
.table-container {
  width: 100%;
  overflow-x: auto;
  overflow-y: auto;
  position: relative;
  margin: 0;
  padding: 0;
}

table {
  width: 100%;
  border-collapse: collapse;
  background: #fff;
}

thead th {
  background: /*#B91C1C;*/ #B91C1C;
  color: #fff;
  padding: 14px 16px;
  text-align: left;
  font-weight: 600;
  white-space: nowrap;
  border-right: 1px solid #e0e0e0;
}

thead th:last-child {
  border-right: none;
}

tbody td {
  padding: 12px 16px;
  border-bottom: 1px solid #f0f0f0;
  border-right: 1px solid #f5f5f5;
  white-space: nowrap;
}

tbody td:last-child {
  border-right: none;
}

tbody tr:nth-child(even) {
  background-color: #fdf7f7;
}

tbody tr:hover {
  background-color: #ffebee;
}

thead {
  position: sticky;
  top: 0;
  z-index: 10;
}
/* 分布图表格样式 */
#fenbuTable th,
#fenbuTable td {
  text-align: center;
  vertical-align: middle;
  background: #B91C1C;
  color: #fff;
  padding: 4px 1px;
  font-size: 11px;
  white-space: nowrap;
  border: 1px solid #e0e0e0;
}

#fenbuTable thead th,
#fenbuTable tfoot th {
  font-weight: 600;
}

/* 分布表的第一列（引导列）：中国彩种是期号，美站是开奖日期（美站没有期号，
   只有日期，见 profiles.py 的 show_period）。两列除了宽度之外观感要完全一致，
   共用一个规则；美站在 .dist-compact 里另给宽度。
   这里必须显式改底色：上面 `#fenbuTable th, #fenbuTable td` 给所有单元格铺的是
   **表头红**（#B91C1C），不覆盖就会得到一个红底的日期格。 */
#fenbuTable td.col-period,
#fenbuTable td.col-date {
  background: #fafafa;
  color: #162e51;
  font-weight: bold;
  font-size: 11px;
  width: 48px;
}

/* 美站的日期列比期号宽：6 位数字（260911）11px 下约 36.7px，而期号只有 5~7 位。
   .dist-compact 的 td 横向 padding 是 0，56px 对字体回退也留了余量。

   字号比中国站的期号列（11px）小一档：那 11px 是配「5~7 位期号 + 48px 列宽」定的，
   而这里的整张表（95 列、格宽 14~26px、球内字号约 6px、列号约 10px）是另一套密度，
   日期列是这张表的坐标轴之一，跟着表走而不是跟着期号列走。
   10px 下 6 位数字约 33.4px，56px 列宽余量仍然充足。

   字号走 zoom 而不是直接写 10px：用户常用浏览器带「最小字号」设置，会把它夹取回 12px
   （见 docs/design.md 11.16），那样写 10px 和写 11px 看起来完全一样。
   zoom 产生的缩放不受夹取影响 —— 80px × 0.125 在任何环境下都是 10px。
   两个环境实测一致（默认 / minimumFontSize=12，均 10px、墨迹 41.75px、列宽 42.75px）。

   80px 不是「想显示多大」，是配合 zoom 的中间量：必须远高于常见的最小字号下限
   （Chrome 上限 24px），否则一样会被夹取。改目标字号时两个数要同时改。

   th 与 td 都要写：表头是 <th class="col-date">，只写 td 会让表头留在上面那条
   11px 上 —— 结果是「表头比它管的内容还大」。 */
#fenbuTable.dist-compact th.col-date,
#fenbuTable.dist-compact td.col-date {
  width: var(--dist-lead-w);
  font-size: 80px;
  zoom: 0.125;
}

#fenbuTable .front-dist,
#fenbuTable .back-dist {
  text-align: center;
  padding: 2px 0;
}

#fenbuTable th.back-dist {
  background: #1e3a8a;
}

#fenbuTable .dist-cell {
  width: 20px;
  max-width: 24px;
  height: 24px;
  background: #fff;
  color: #999;
  border: 1px solid #e0e0e0;
  font-size: 11px;
}

/* 紧凑密度：号码范围大的彩种（Powerball 69 列、Mega Millions 70 列）。
   每格一列，整表近 95 列，按原样式约 2185px 宽，前区自己就要滚动才能看全。
   中国彩种前区最多 35 列，不加此类，本块完全不生效。

   注意 width 必须配 box-sizing:border-box：原来只写 width:20px，在默认的
   content-box 下还要叠加 padding 与边框，实际约 24px（上面那句 max-width:24px
   就是这个失真的补丁），压缩时不能重蹈覆辙。

   格宽走 --dist-cell-w 变量，由 lottery.js 实测容器宽度后写进 table 的 style：

   - dist-wide（**前区列数在 15px 兜底格宽下会超出可视区**的彩种，条件写在
     lottery.html）：格宽 = 可视宽 / 前区列数，前区正好铺满可视区。带后区的
     （Powerball / Mega Millions / NY Lotto）后区整体落到右侧，靠底部横向滚动条看；
     无后区的（Pick 10 的 80 列）则整张表一屏铺满、不必滚动。
   - 兜底 15px：容器 1056px（min(1152px,视口) − 两侧内边距）下 70 列 = 1050px，
     仍不溢出，所以即使 JS 没跑到也不会退回「要横向滚动才看得全前区」。
     字号与球径同样按格宽等比算，格宽变了不会出现字撑破格子。 */
#fenbuTable.dist-compact {
  --dist-cell-w: 15px;
  /* 引导列（日期列）的宽度。lottery.js 的 fitFrontCells() 从这里读，
     算前区格宽时把它从容器宽度里扣掉 —— 定义只此一处，别在 JS 里再写一份。 */
  --dist-lead-w: 56px;
}

#fenbuTable.dist-compact th,
#fenbuTable.dist-compact td {
  padding: 2px 0;
}

#fenbuTable.dist-compact .dist-cell {
  box-sizing: border-box;
  width: var(--dist-cell-w);
  min-width: var(--dist-cell-w);
  max-width: var(--dist-cell-w);
  height: calc(var(--dist-cell-w) + 2px);
  padding: 0;
  /* 间隔数字的字号。上限由「最长的间隔数字必须塞得下」定：实际数据里后区最大见过
     151（3 位），3 位数字宽约 1.668em，格内可用宽 = 格宽 − 2px 边框，
     取 0.42 时 1.668×0.42w ≤ w−2 对 w ≥ 7px 恒成立（本彩种 w≈15px），余量很宽。
     实际取更小的 0.42 是为了观感：95 列的小格子里数字要退成底纹，不能抢球。 */
  font-size: calc(var(--dist-cell-w) * 0.42);
}

/* 表头/表尾的列号（1…69/70）。它们和间隔数字**共用 .dist-cell 类**
   （见 lottery.js 里生成 <th class="dist-cell">），上面那条 0.42 会把列号一起缩到
   6px 上下 —— 列号是这张表的坐标轴，缩小了就没法读数，必须单独给字号。
   列号只有 1~2 位，宽度约束比间隔数字松得多：两位数字的墨迹宽约 1.274em
   （实测 Arial 下 "09" 的墨迹/字号 = 1.274），格内可用宽 = 格宽 − 1px 右边框，
   取 0.72 时 1.274×0.72 = 0.917w ≤ w−1 对 w ≥ 12px 恒成立（本彩种 w≈15px）。
   0.72 也是「两位数列号仍然塞得下」的最大档，再大就要啃到相邻格子。
   注意上面 1.274 是**常规字重**的墨迹比；加粗会宽到 1.392，两位数列号（如 "10"）
   就正好顶到 15.3px > 格宽 15.3px，和相邻格子粘在一起 —— 所以下面必须去掉加粗。 */
#fenbuTable.dist-compact th.dist-cell {
  font-size: calc(var(--dist-cell-w) * 0.72);
  /* 列号默认继承 thead th 的 font-weight:600，而本机字体只有 Regular/Bold 两档，
     600 会被浏览器落到 Bold（半粗体在这套字体里不存在）。分布表 95 列、格宽只有
     15px，列号是这张表的坐标轴：加粗换来的「醒目」不如把它关掉换来的 1.2px 呼吸
     余量重要，观感上也和间隔数字同一档，不与号码球抢注意力。 */
  font-weight: 400;
}

/* 球内数字。圆是圆的：两位数字的墨迹在字顶/字底处比中腰窄一圈，取 0.62 倍格宽时
   单边只剩约 0.5px，看着像被圆啃掉一角。但光按「放得下」缩小还不够 —— 0.5 倍时
   单边余量虽涨到 1.8px，比例仍有 0.575（球径的占比），这么小的圆里看着还是「满」。
   真正的参照是本机中国站的球：18px 球配 11px 字（球径的 0.61），但那是大球，
   同样比例放到 13px 的球上就挤了 —— 小尺寸要靠更小的比例补偿。
   现取 0.42 倍格宽（球径的 0.50、约 6.4px）：墨迹宽约 8.2px，而球在字顶/字底那个
   高度的宽度是 2×√(6.5² − (0.36×6.42)²) ≈ 12.2px，两侧各余约 2px，放得下。
   档位沿革：0.62 → 0.5 → 0.42 → 0.38 →（观感偏小）0.42。0.38 那轮是我按「可读
   下限」推的，实际显示偏小，以观感为准调回来；再往上到 0.5 就会重新出现「满」。
   字重降到 400：6px 上下还加粗会糊成一团，反而显得更大更满。
   注：写 600 没用 —— 系统字体通常没有 semibold，浏览器会直接取 bold。
   以上算术是按球径 13px 推的（当时没有日期列，格宽 15px）。11.20 加了日期列后，
   fitFrontCells 要从容器宽里多扣 56px，最窄视口（~1104px，容器 1056px）下
   格宽降到 14.26px（Mega Millions 70 列）、球径 12.26px —— 比上面假设的小 6%，
   数字字号跟着降到约 6.0px。档位结论不变（仍是 0.42），但"13px 球"这个前提不再精确。 */
#fenbuTable.dist-compact .number-ball {
  width: calc(var(--dist-cell-w) - 2px);
  height: calc(var(--dist-cell-w) - 2px);
  font-size: calc(var(--dist-cell-w) * 0.42);
  font-weight: 400;
  /* 球的外圈。base 的球是给「选号区」26px 大球设计的 border:2px solid #e0e0e0
     —— 大球上是一道细边，缩到 13px 就占了直径的 15%，红球外面像套了个浅色圆环。
     这里收细到 1px，只留一道收边；底下的填充仍是 .selected.front 的红色渐变。 */
  border-width: 1px;
}

/* 间隔数字的颜色：所有彩种通用，比原来继承的 .dist-cell #999 再淡一档，
   让这层数字退成底纹、不跟号码球抢注意力。号码球自带 color:#fff，不受影响。 */
#fenbuTable .miss-num {
  color: #c0c0c0;
}

/* 勾选「隐藏间隔累计数字」：只隐去间隔数字，号码球与格子尺寸全部保留。
   用 visibility 而非 display:none —— 后者会让单元格塌陷，整表的列宽跟着变。 */
#fenbuTable.hide-interval .miss-num {
  visibility: hidden;
}

#fenbuTable thead tr:nth-child(2) th,
#fenbuTable tfoot tr:nth-child(1) th {
  background: #B91C1C;
  color: #fff;
}

#fenbuTable thead tr:nth-child(2) th.back-dist-cell,
#fenbuTable tfoot tr:nth-child(1) th.back-dist-cell {
  background: #1e3a8a;
  color: #fff;
}

#fenbuTable .number-ball {
  display: inline-flex;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  color: #fff;
  font-weight: 700;
  font-size: 11px;
  margin: 0;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}

/* 统计版表格样式 */
#statsTable thead th {
  background: #B91C1C;
  color: #fff;
  padding: 8px 5px;
  font-weight: 600;
  font-size: 12px;
  text-align: center;
  white-space: nowrap;
  border-right: 1px solid #e0e0e0;
}

#statsTable tbody td {
  text-align: center;
  vertical-align: middle;
  padding: 6px 4px;
  border-bottom: 1px solid #f0f0f0;
  border-right: 1px solid #f5f5f5;
  white-space: nowrap;
  font-size: 12px;
}

#statsTable td:first-child {
  font-size: 12px;
  font-weight: bold;
}

#statsTable .col-front,
#statsTable .col-back {
  white-space: nowrap;
}

#statsTable .number-ball {
  display: inline-flex;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  color: #fff;
  font-weight: 700;
  font-size: 13px;
  margin: 0 2px;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}

/* 表格里的「加载中… / 加载失败…」占位行（统计表 + 分布表共用）。
   标记由 lottery.js 的 tablePlaceholderRow() 生成。

   ★ 一律**左对齐**，刻意不居中（2026-09-18 用户报「移动端看不到」）。
     这个 td 用 colspan 横跨整张表，而两张表都比手机屏宽（分布表在桌面也宽）：
     `text-align: center` 居中的是**整张表**的中点，不是可视区的中点 —— 文字被摆到
     可视区右边之外，屏幕上只剩一条空行，看着像卡死了。左对齐落在第一列，屏幕多窄都看得见。

   ★ 选择器必须带 `#statsTable` / `#fenbuTable`，纯类选择器压不过基础规则：
     `#statsTable tbody td { text-align: center }` 的特异性是 (1,0,2)，
     `.table-loading` 只有 (0,1,0) —— 光加类不会生效（本项目已经栽过一次同类问题，
     见 §11.76 里 `.combo-stats` 那条注释）。带 ID 后是 (1,1,1)，与文件位置无关。 */
#statsTable td.table-loading,
#fenbuTable td.table-loading {
  text-align: left;
  padding: 16px 14px;
  background: #fff8f8;      /* 淡红底：让这一条在满屏空行里看得出来 */
  white-space: normal;      /* 别继承表里的 nowrap —— 窄屏上「加载失败: <长报错>」要能折行 */
}

/* spinner 与文字用 flex 对齐，不靠 td 的 line-height ——
   否则圆圈会被文字基线带得忽高忽低。呼吸动画让「还在动」这件事一眼可见，
   比原来一行静止的灰字明显得多。 */
.table-loading-inner {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  font-weight: 600;
  color: #B91C1C;           /* 站点红，比原来的 gray-400 醒目 */
  animation: loadingPulse 1.5s ease-in-out infinite;
}

/* 旋转的圈：border 三边浅、一边红 */
.table-loading-spin {
  flex: none;
  width: 15px;
  height: 15px;
  border: 2px solid #f3c9c9;
  border-top-color: #B91C1C;
  border-radius: 50%;
  animation: loadingSpin 0.7s linear infinite;
}

@keyframes loadingSpin { to { transform: rotate(360deg); } }

@keyframes loadingPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* 失败态：不转、不呼吸 ——「加载失败」是**终态**，
   还在动就等于在说「还在试」，那是在骗人。所以只保留左对齐与淡红底。 */
.table-loading.is-error .table-loading-inner {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  /* ★ 与 .number-ball.ball-flash 那条同一个道理，但结论相反：
     闪球那里「动」本身就是要传达的信息（看这里！），所以留了一个只提亮不缩放的替代动画；
     这里「还在加载」由文字「加载中…」自己说清楚了，动只是加强 ——
     整段停掉**不丢任何信息**，所以直接停。 */
  .table-loading-inner,
  .table-loading-spin {
    animation: none;
  }
}

/* 线条覆盖层 */
.line-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 999;
  transform: translateZ(0);
}

/* 操作栏样式 */
.operation-bar {
  background-color: #f8f9fa;
  border: 1px solid #e9ecef;
  border-radius: 8px;
  padding: 15px;
  margin-bottom: 20px;
}

.operation-bar h3 {
  margin-top: 0;
  margin-bottom: 10px;
  color: #162e51;
  font-size: 16px;
  font-weight: 600;
}

.operation-bar .options {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
}

.operation-bar label {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

/* ---------------------------------------------------------------- 首号折线的号码选择面板 */

/* 这一条 position:relative 是**必须**的，不是可有可无的：
   .operation-bar 和 .options 都没有定位，若这里也不写，下面绝对定位的面板会一路上溯到
   自己在 DOM 里的**后面**那个 .table-container（它是 position:relative），
   面板于是跑进表格的坐标系，位置整个错掉。 */
.line-picker {
  position: relative;
}

/* 下面这一组里的 `.multi-picker-*` 是**过滤对话框**里的多选下拉（奇偶比 / 分区比）。
   外观与折线的选择面板完全一样，所以不复制规则体，直接把类名并进同一个选择器组 ——
   改一处两边都生效，也免得两份样式慢慢漂开。两者的差异只有面板的定位方式（见 .multi-picker-panel）。 */
.line-picker-toggle,
.multi-picker-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  font-size: 14px;
  line-height: 1.2;
  color: #162e51;
  background-color: #fff;
  border: 1px solid #ced4da;
  border-radius: 6px;
  cursor: pointer;
}

.line-picker-toggle:hover,
.multi-picker-toggle:hover { border-color: #162e51; }

/* 分布页的刷新按钮：跳过前端的 60 秒缓存强制回源（见 lottery.js 的 FENBU_TTL_MS）。
   代码是从 .line-picker-toggle 抄的，只是没有文字、padding 略窄 —— 操作栏那一行
   美站已经排满，多一点宽度就会换行。 */
.dist-refresh {
  display: flex;
  align-items: center;
  padding: 5px 10px;
  font-size: 14px;
  line-height: 1.2;
  color: #162e51;
  background-color: #fff;
  border: 1px solid #ced4da;
  border-radius: 6px;
  cursor: pointer;
}

.dist-refresh:hover:not(:disabled) { border-color: #162e51; }

/* 请求期间禁用。转圈由 Font Awesome 的 fa-spin 负责，这里只压一下颜色，
   免得连点叠出几个并发请求。 */
.dist-refresh:disabled { cursor: default; color: #8a94a6; }

/* 有勾选时按钮换个色：面板收起后，光看按钮也得知道「这个条件正在生效」 */
.line-picker-toggle.active,
.multi-picker-toggle.active {
  border-color: #162e51;
  background-color: #e7eefc;
  font-weight: 600;
}

/* 面板默认靠 Tailwind 的 .hidden 收起来（与 base.html 的 mobileMenu 同一套做法），
   类摘掉就是普通块级元素 —— 所以这里**不要**写 display，写了会和 .hidden 抢。 */
.line-picker-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  /* 分布表的 thead 是 sticky、z-index:10（见下方 #fenbuTable 那段）。面板向下探出时
     正好压在表头上，不抬起来就被表头盖住。 */
  z-index: 900;
  width: 250px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #ced4da;
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
}

.line-picker-group + .line-picker-group { margin-top: 8px; }

.line-picker-title {
  margin-bottom: 5px;
  font-size: 12px;
  font-weight: 600;
  color: #6c757d;
}

/* 选项是球位（第 1~N 球），一区最多 7 项，三列两行就排完了。
   限高滚动留着是兜底：万一以后有 pick 数很大的彩种，不至于把面板拖成一长条。
   两组**各自**滚动而不是整个面板滚，免得后区被前区推走。 */
.line-picker-list,
.multi-picker-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
  gap: 2px 6px;
  max-height: 200px;
  overflow-y: auto;
}

.line-picker-item,
.multi-picker-item {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: #162e51;
  white-space: nowrap;
  cursor: pointer;
}

.line-picker-item input,
.multi-picker-item input {
  margin: 0;
  cursor: pointer;
}

.line-picker-item.on,
.multi-picker-item.on { font-weight: 600; }

/* 「清空」：折线那两个下拉（第 1~N 球）与过滤对话框里那 5 个多选下拉**形态一致** ——
   都是面板内部、列表下面的整宽按钮（2026-09-16~17 期间多选那份曾被挪到下拉按钮右侧，
   行内形态是 `.multi-picker-row .multi-picker-clear` 覆盖出来的，2026-09-17 已删）。
   所以下面这组是它们**共同**的基样式，不再有第二份行内形态。 */
.line-picker-clear,
.multi-picker-clear {
  width: 100%;
  margin-top: 8px;
  padding: 4px;
  font-size: 12px;
  color: #162e51;
  background-color: #f1f3f5;
  border: 1px solid #ced4da;
  border-radius: 6px;
  cursor: pointer;
}

.line-picker-clear:hover,
.multi-picker-clear:hover { background-color: #e2e6ea; }

/* ------------------------------------------------- 过滤对话框里的多选下拉（奇偶比 / 分区比） */

/* 容器。.form-group 是 flex 行（标签 80px + 控件），这里 flex:1 顶掉原来的
   `.form-group select { flex: 1 }`；min-width:0 不加的话长文案会把容器撑破
   （flex 项默认 min-width:auto）。 */
.multi-picker {
  flex: 1;
  min-width: 0;
  /* 浮层面板的定位祖先（与 .line-picker 同一个理）。 */
  position: relative;
}

/* 下拉按钮。
   ★ 2026-09-17 起它**独占**这一行（「清空」挪回面板里了，原来外面还套一层
     `.multi-picker-row`）。那个 wrapper 连同行内形态的覆盖一起删掉了。
   ★ 靠 `width: 100%` 占满，**不能**像原来那样靠父元素是 flex + `flex: 1`。
     这里踩过一个坑，值得记下：<button> 即使写了 `display: flex` 也**不**像 <div> 那样
     「块级元素自动填满」—— Chrome 对表单控件保留 shrink-to-fit（fit-content），
     实测 dlt 那一行：文案是「不限」时按钮只有 **53px**（右边留一大片空白），勾 6 项后
     才长到 237px。原来那份 `flex: 1` 能生效，是因为外面那层 `.multi-picker-row` 是
     flex 容器；wrapper 一删，它就完全不管用了（这一版的截图里 5 个下拉宽窄不一）。
     `width: 100%` 是 §11.64 之前的老写法，现在「清空」不在行内了，正好还是它。
     箭头仍由 justify-content: space-between 推到最右；文案的省略由
     `.multi-picker-text` 的 overflow:hidden 负责，不需要 min-width:0。 */
.multi-picker-toggle {
  width: 100%;
  justify-content: space-between;
}

/* 收起时按钮上的文案可能是两个比值（"3:2, 2:3"）。宽度不够就省略，
   完整选中值挂在 title 上（lottery.js 的 renderLabel 写），悬停可见。 */
.multi-picker-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ★ 2026-09-16 起**改成浮层**（内联展开 → 绝对定位），用户要求：
   「下拉的时候保持窗口大小不变，只是遮盖住下面的内容」。
   原来的取舍（§11.55）是内联展开 —— 面板把对话框撑高，理由是「浮层会盖住
   取消/确定，还要额外的『点外部收起』逻辑」。那条理由现在**已经过期**：
   ①「点外部收起」在 §11.64 前后就加上了（lottery.js 里共享的 document 监听），
   ② 对话框从 3 条条件长到 6 条之后，「展开哪一条，对话框就跳高一次」本身就是
      最刺眼的那件事 —— 每点一次下拉，整张对话框在屏幕上重新排一次。
   ★ 盖住的东西（下面的条件行、必要时连底部按钮一起）：这是**要的行为**，
     不是副作用 —— 面板是临时浮层，点一下别处或再点一次按钮就收回去。
   ★ 收起状态仍靠 Tailwind 的 .hidden，所以这里**不要写 display**（写了会和 .hidden 抢，
     与 .line-picker-panel 同一个理）。 */
.multi-picker-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  /* 宽度跟着下拉按钮那一行 —— 2026-09-17 起那一行**只有按钮自己**（「清空」挪回面板内部），
     所以这里 width:100% 就是按钮的宽度。面板里的选项网格
     （`.multi-picker-list` 是 repeat(auto-fill, minmax(70px,1fr))）和面板底部的
     「清空」都需要这一整宽。 */
  width: 100%;
  /* 盖住**后面那些行**：它们是普通流里的非定位元素，定位 + z-index 就压得住。
     900 是照 .line-picker-panel 抄的（那里是为了压过分布表 sticky 表头的 z-index:10）。
     对话框本身是 z-index:1000 的 fixed 遮罩，面板在它内部，不参与外面的层叠。 */
  z-index: 900;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #ced4da;
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
}

/* 向下放不下时朝**上**开（lottery.js 的 placePanel 决定加不加这个类）。
   ★ 为什么需要它：最下面那几行（「重号」）向下开时会盖住底部「取消 / 确定」——
     那是完成流程的核心按钮，被临时浮层盖住会让人以为「得先把面板关掉才能确定」。
     而这几行**上方**的空间反而富余得多（上面摞着 5 行）。
     两边都放不下才走限高 + 列表滚动（内联样式，见 placePanel）。 */
.multi-picker-panel.drop-up {
  top: auto;
  bottom: calc(100% + 6px);
}

/* 面板展开后 .form-group 会变成很高的 flex 行（align-items:center 是 .form-group 定的），
   左侧标签会被吊在高块的正中间、随开合上下漂。改成顶对齐，再用 padding-top 让它和
   按钮里的文字落在同一条基线上（≈ 按钮的 5px padding + 1px 边框）。
   几何上的验证在 tools/check_picker_stats.js（真浏览器量中线差）。 */
.form-group-multi {
  align-items: flex-start;
}

.form-group-multi > .form-label {
  padding-top: 6px;
}

/* ★ 窄屏（真机 390px）下这一行会挤爆 —— 2026-09-16 探针 (6) 抓到的真缺陷：
   一行里有四个东西（标签 96px + 下拉 + 行内「清空」+ 右侧提示），「重号」那一行
   还多一句英文提示 "vs. latest draw"（88px）。实测下拉被压到 107px（其余四行 205px），
   里面**文案区只剩 6px** —— 连退化成「6 items」也放不下，被省略号吃光，
   按钮看上去是空的（美站 390px 下就是这样，中文站提示只有 72px，侥幸没崩）。
   给下拉一个**下限宽度**：一行放不下时由 flex-wrap 把提示挤到下一行，
   提示自己占满整行、不截断；宽屏下三项仍在一行，与原来逐字一致（桌面实测 520px 内容区
   里放得下 96+324+88）。
   下限取 150px 的依据：下拉按钮里的**退化文案**「6 items」(59px) + 按钮内边距与箭头(~37px)
   + 面板左右 padding(20px) ≈ 116 —— 也就是「至少还放得下最长的退化文案」，再留点余量。
   ★ 2026-09-17 起「清空」挪回面板**内部**，不再参与这一行的宽度（§11.64 挪出去时
     这条下限里还含着它的 ~52px），150 这个数**没改**：宽屏下三项仍在一行、与原来逐字一致，
     动它就得把桌面那一轮几何（工具里的 labelFit / dlgHeights）整套重量一遍，没必要。 */
.form-group-multi {
  flex-wrap: wrap;
}

.form-group-multi .multi-picker {
  min-width: 150px;
}

/* 选号器样式 */
.selector-area {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px;
  margin-bottom: 20px;

  /* 从底部那条页签切到「选号器」、且还没产生组合时，lottery.js 的 scrollToSelectorArea()
     会把这里以 block:'start' 滚进视野（用户 2026-09-19 要求）。顶栏是 sticky 的
     （base.html:60 的 <header>，内层 h-16），占掉视口最上面 64px —— 不留边距的话
     前区标题（.number-area 的 h3）刚好压在它下面，看着就是「滚过头了」。
     ★ 4rem = h-16 = 64px，与顶栏高度是**同一个数**：顶栏改高度，这里跟着改。
     ★ scroll-margin-* 只影响 scrollIntoView / 锚点跳转，平时对布局零影响。 */
  scroll-margin-top: 4rem;
}

.number-area {
  background-color: #f8f9fa;
  border-radius: 8px;
  padding: 15px;
}

.number-area h3 {
  text-align: center;
  margin-top: 0;
  margin-bottom: 15px;
  color: #162e51;
  font-size: 18px;
  font-weight: 600;
}

.number-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
  /* 号码格里没有任何**值得选中**的文字，只有号码球。这里再声明一次是为了
     堵住「选区不落在球上、而落在球的容器上」那条路 —— 球的 user-select: none
     只保证从球上按下不起选区，起不到别的。详见 .number-ball 里那段。 */
  user-select: none;
  -webkit-user-select: none;
}

.number-ball {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  cursor: pointer;
  transition: all 0.3s ease;
  border: 2px solid #e0e0e0;
  background: #f0f0f0;
  color: #333;
  font-size: 16px;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  /* iOS Safari：长按会弹「拷贝/查询」气泡。必选手势就是长按（见 lottery.js 的
     LONG_PRESS_MS），不关掉它，用户按到 500ms 先看到的是系统菜单。 */
  -webkit-touch-callout: none;
  /* 长按拖到球外时有些引擎会把球本身拖起来（HTML5 拖拽）—— 号码球没有可拖的语义。 */
  -webkit-user-drag: none;
  /* 双击缩放。**不是**为了必选手势（触屏上双击早就不是必选了），是因为
     `auto` 下浏览器把「在球上连点两下」当成缩放手势，会改视口、也会让系统
     去识别长按 —— 球是纯点击目标，用 manipulation：保留单指滚动/双指缩放，
     去掉双击缩放这一种。
     ★ 不要写成 none：那会连**单指滚动**一起关掉，号码格占满整屏，
       手机上就再也滚不动页面了。 */
  touch-action: manipulation;
}

.number-ball:hover {
  transform: scale(1.1);
}

.number-ball.selected.front {
  background: linear-gradient(135deg, #e41e2b, #c41e2b);
  color: white;
}

.number-ball.selected.back {
  background: linear-gradient(135deg, #0066cc, #004499);
  color: white;
}

.number-ball.front.must-select {
  background: linear-gradient(135deg, #9333ea, #7e22ce);
  color: white;
  border: 2px solid #9333ea;
  box-shadow: 0 0 10px rgba(147, 51, 234, 0.5);
}

.number-ball.back.must-select {
  background: linear-gradient(135deg, #ff7f00, #ff4500);
  color: white;
  border: 2px solid #ff7f00;
  box-shadow: 0 0 10px rgba(255, 127, 0, 0.5);
}

/* 「预演」之后分布表末尾那行的球**依次闪一下**（用户 2026-09-17：点完预演跳到分布页，
   「显示的时候一开始这些号码都『闪烁』一下，然后再正常显示」）。

   类由 lottery.js 的 flashPreviewBalls 加/摘，**错开的延迟**按第几颗球用内联
   animation-delay 给（不是 :nth-child —— 球只落在部分格子里，「第 k 颗球」与
   「第 k 个格子」不是一回事，见那个函数的注释）。

   ★ 时长 200ms 与 lottery.js 的 FLASH_MS 是**同一个数**，改一处要改两处：
     摘类的定时器按它算，写小了动画播到一半就被摘掉（闪到一半就停）。
   ★ 这里放心动 transform：.number-ball 的 `transition: all 0.3s ease` 拖不慢它 ——
     动画进行期间 transition 不生效（animation 覆盖 transition）。 */
@keyframes ballFlash {
  0%   { transform: scale(1);    filter: brightness(1); }
  45%  { transform: scale(1.15); filter: brightness(1.55); }
  100% { transform: scale(1);    filter: brightness(1); }
}

.number-ball.ball-flash {
  animation: ballFlash 200ms ease-out;
}

/* 用户把系统设成「减少动态效果」时：**只提亮、不缩放**。
   「看这里」这个信息还是要给，去掉的只是运动那一半 —— 整段动画一起关掉的话，
   这个功能对这些人等于不存在。 */
@keyframes ballFlashFlat {
  50% { filter: brightness(1.55); }
}

@media (prefers-reduced-motion: reduce) {
  .number-ball.ball-flash {
    animation: ballFlashFlat 400ms ease-out;
  }
}

.count-display {
  text-align: center;
  font-weight: bold;
  color: #162e51;
  margin-bottom: 10px;
}

/* 「必选」的手势说明（picker.must_hint）。字号 12px 是**下限**，不要往下调：
   用户浏览器把 <12px 顶回 12px，写了 11px 在他机器上反而更大（design.md §11.16）。 */
.picker-hint {
  font-size: 12px;
  color: #8a94a6;
  margin: 0 0 12px;
}

.action-buttons {
  display: flex;
  justify-content: center;
  gap: 15px;
  margin-bottom: 20px;
}

.action-button {
  padding: 10px 30px;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
}

.action-button.confirm {
  background: #B91C1C;
  color: #fff;
  border: 1px solid #B91C1C;
}

.action-button.confirm:hover {
  background: #991b1b;
  transform: translateY(-2px);
}

.action-button.clear {
  background: #fff;
  color: #B91C1C;
  border: 1px solid #B91C1C;
}

.action-button.clear:hover {
  background: #fef2f2;
  transform: translateY(-2px);
}

.action-button:disabled {
  background: #e5e7eb;
  color: #9ca3af;
  border: 1px solid #e5e7eb;
  cursor: not-allowed;
  transform: none;
}

.action-button.copy {
  background: #1e3a8a;
  color: #fff;
  border: 1px solid #1e3a8a;
}

.action-button.copy:hover {
  background: #1e40af;
  transform: translateY(-2px);
}

.action-button.filter {
  background: #65a30d;
  color: #fff;
  border: 1px solid #65a30d;
}

.action-button.filter:hover {
  background: #78350f;
  transform: translateY(-2px);
}

/* Dialog Styles */
.dialog {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

/* 宽度 2026-09-16 从固定 400px 改成 min(560px, 92vw)。
   ★ 为什么必须调大：过滤对话框从 3 条条件变成了 6 条（加了 AC值 / 连号 / 重号），
     而标签在英文界面里更长（"Consecutive" ≈ 85px），400px 里留给控件的只剩两百出头，
     多选面板展开后选项列会挤成一列。
   ★ 用 min() 而不是只写 560px：窄屏（手机 375px）上 92vw=345px，对话框自动跟着缩，
     不必再加一条媒体查询。92vw 而不是 100vw —— 留 8% 让背后的遮罩看得见，
     不然全屏对话框和「页面本来就长这样」分不出来。
   ★ max-width 保留 90%：它是给**别的**对话框用的（本文件里 .dialog-content 是共用的），
     与 width 里的 92vw 不冲突 —— 两者取小，手机上仍是 90%（比 92vw 更保守一点）。
   ★ 这里**不写** max-height / overflow：高度策略由 .dialog-fullscreen / .dialog-scroll
     两个类管，由 lottery.js 的 fitFilterDialog() 按内容量出来再加（顺序：自然撑开 →
     全屏 → 最后才滚动）。默认两样都没有 = 内容多高就多高。 */
.dialog-content {
  background-color: white;
  border-radius: 8px;
  padding: 20px;
  width: min(560px, 92vw);
  max-width: 90%;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

/* 放不下时给 .dialog-content 加的第一道：放大到几乎整屏。
   ★ 用 max-height + 100vh 而不是 height：内容矮的时候它不该被拉高（会离出大片空白）。
   ★ 96vh 与 lottery.js 里 DIALOG_FULLSCREEN_RATIO = 0.96 是**同一个数**：
     那边用它决定「要不要加这个类」，这边用它决定「加到多高」。改一处必须改另一处，
     否则会出现「判定该全屏、全屏后还是差几个像素」这种看着像没生效的状态。 */
.dialog-fullscreen {
  max-height: 96vh;
}

/* 最后一道：全屏之后仍然放不下，才允许滚动。
   ★ 这是**兜底**，不是常规路径 —— 用户 2026-09-16 明确要求「窗口不要滚动」。
     真滚起来说明条件多到一屏放不下了，那时能滚也比被裁掉强（被裁掉的条件点不着、
     且完全看不出少了东西）。 */
.dialog-scroll {
  overflow-y: auto;
}

.dialog-content h3 {
  margin-top: 0;
  margin-bottom: 20px;
  color: #162e51;
  text-align: center;
}

.dialog-body {
  margin-bottom: 20px;
}

.form-group {
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
}

/* ★ 必须是**直接子元素**选择器，不能写回 `.form-group label`（后代选择器）：
   奇偶比 / 分区比的多选下拉（.multi-picker-*）里，每个选项本身就是 <label>，
   一条后代选择器会把它们统统压成 80px 宽，面板里选项挤成一列 —— 而且看着像「本来就该这样」。
   2026-09-15 改成多选时踩到过。 */
.form-group > .form-label {
  display: inline-block;
  /* ★ 2026-09-16 实测修正：原来是**定宽 80px**，为英文 "Consecutive" 改成 96px
     （当时的估算：「14px 粗体约 85px」）。真浏览器量出来**实际是 116px** ——
     96px 的盒子装不下，文字溢出 20px、盖到右边下拉框上 10px（中文标签只有 66px，
     所以**中文站一直看不到这条，只有美站会**）。
     ★ 改成「内容多宽就多宽，但不少于 96px」：短标签（"Sum:" / 所有中文标签）仍是 96px、
     保持左对齐；只有真装不下的那一个自己变宽（代价是**它自己那一行**的控件右移，
     不是全局右移）。估出来的数字不可靠，这条要的是「装得下」而不是某个具体宽度。
     ★ 别改回定宽 —— 定宽只在**恰好量过的那种译文**上是对的，加一个更长的词就静默重叠，
     而重叠是探针 check_picker_stats.js 里新加的那条判据在盯的。 */
  width: max-content;
  min-width: 96px;
  flex: 0 0 auto;
  font-weight: 600;
  color: #333;
  margin: 0;
}

.form-group select {
  flex: 1;
  padding: 8px;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  font-size: 14px;
}

/* 「运算符 + 数字 + 区间提示」这种条件行：和值 / 方差 / 跨度 三行共用。
   ★ 2026-09-16 从 id 选择器（select#sumFilterOp / #sumFilterValue / .sum-range-hint）
     改成**类选择器** —— 加第二、三行时 id 版本没法复用（只能复制三份规则，
     而复制出去的那份以后改不到）。类和值的关系写在模板的注释里。
   ★ 改完和值那一行的几何必须逐字不变：探针 check_picker_stats.js 在盯
     「运算符下拉与数字输入框等高（36/36）」与「这一行不换行、不越界」。 */

/* 运算符那个下拉必须**退出上面那条 `.form-group select { flex: 1 }`**：
   否则它和输入框都抢着撑满，一行放不下（对话框宽度固定），
   会被挤成两行或把提示顶出去。 */
.form-group .filter-op {
  flex: 0 0 auto;
  width: 88px;
}

/* 输入框的外观抄上面 select 的三条（padding/border/radius/font-size），
   两者并排时边框与字号必须一致，否则一眼看得出是两套控件。 */
.form-group .filter-value {
  flex: 1;
  padding: 8px;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  font-size: 14px;
  min-width: 0;        /* 没有它会撑破 flex 容器（number input 有默认最小宽度） */
  /* 高度显式对齐左边的 select：两者 padding/border/font-size 完全相同，
     但 select 的内容盒是 18px、number input 是 21px（实测 36px vs 39px），
     并排时底下会差 3px。写死 36px 而不是去调 padding —— 改 padding 会连带
     改变文字基线位置，对比更难对齐。 */
  height: 36px;
}

.form-group .filter-value:disabled {
  background: #f5f5f5;
  color: #999;
}

/* 该彩种的理论区间提示（和值如 dlt 15~165；方差/跨度由 stats.py 的 *_bounds 推导）。
   ★ 对跨度是满区间，对方差只是外包围 —— 见 design.md §11.69。
   字号写 12px 是**下限**，不能再小：浏览器有「最小字号」钳制，写 11px 会被顶回 12px。 */
.form-group .range-hint {
  flex: 0 0 auto;
  font-size: 12px;
  color: #6b7280;
}

/* 「重号」那一行右边的小字（"与最新一期比"），完整口径说明挂在它的 title 上。
   ★ 字号 12px 是**下限**，与上面那条同一个理由（浏览器最小字号会顶回 12px）。
   ★ flex: 0 0 auto + 允许换行：这一行比别的行多一个元素（标签 + 多选 + 小字），
     560px 下放得下；窄屏放不下时它宁可整体掉到第二行，也不要被压成两三个字一行。
   ★ 颜色用 #6b7280（与提示同色）而不是正文色：它是**限定条件**，不是第三个选项，
     混在正文里会让人以为可以点。 */
.form-group .filter-hint {
  flex: 0 0 auto;
  font-size: 12px;
  color: #6b7280;
  white-space: nowrap;
}

/* --------------------------------------------------- 回溯验证那一行 + 结果块（2026-09-17）
   对话框最下面一行：「回溯验证: [最近 100 期 ▾] [开始验证]」，结果出在行下面那一块小字里。
   和值/方差/跨度那三行是「运算符 + 数字」，这一行是「选择框 + 按钮」——
   共用 .filter-op 的 88px 不够（中文「最近 100 期」6 个字就 84px），所以单独给宽度。
   ★ 2026-09-18 从**定宽 112px** 改成 max-content：112px 是估出来的，实测**装不下**，
     下拉框里的「最近 200 期」被截掉一截（用户报的就是这个）。
     量法（探针里可复现）：原生的下拉箭头是**内置的**，它占的宽度浏览器不会明说，
     但在页面内能自己标定 —— 造一个同类的 select、width:max-content，
     它比文字多出来的那部分就是箭头（本机实测 20.4px，几组不同文字量出来的值一致）。
     于是「装得下」的条件是：文字 + 左右内边距 16 + 边框 2 + 箭头 20.4。
     中文「最近 200 期」真机约 74~84px（14px 字号，3 个汉字 + 3 个数字 + 2 个空格），
     即需要 112~122px —— 定宽 112px 正好卡在门槛上，字体稍宽就被切。
     ★ 改成 max-content 就是让浏览器自己算这个和：文字换成英文/别的译文、字号调整，
       它都跟着变，不存在「估出来一个数、换个语言就静默切字」的老问题
       （和上面 .form-label 那次修正同一个理由）。
     ★ flex 从 .filter-op 的 0 0 auto 改成 0 1 auto + min-width: 0：**允许它收缩**。
       极窄屏（< 350px）这一行本来就放不下，定死不让缩的结果是控件被顶出对话框右边界；
       允许收缩则会退化成「下拉框里的字短一截」——难看，但不越界，对话框也不横滚。 */
.form-group .backtest-n {
  width: max-content;
  flex: 0 1 auto;
  min-width: 0;
}

/* 按钮外观抄 .dialog-footer button（:1331-1339）+ #filterCancel 的次要配色，
   但**必须自带类**：footer 那两条规则用的是 id 选择器（`#filterCancel`），
   换到别处就失效了。 */
.backtest-run {
  flex: 0 0 auto;
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  background-color: #e5e7eb;
  color: #374151;
}

.backtest-run:hover {
  background-color: #d1d5db;
}

.backtest-run:disabled {
  opacity: 0.6;
  cursor: default;
}

/* 结果块：结论行 / 分项行 / 小字注，各占一行（.backtest-line），每行自己折行。
   ★ 不用 .filter-hint 那个类：它是给「跟在一个控件后面的小字」用的（flex:0 0 auto +
     white-space: nowrap），而这里是**整块多行文本**，必须允许折行。
   ★ 它是 .dialog-body 的普通块级子节点（那个容器不是 flex），所以不写 flex。
   ★ 字号 12px 是**下限**，与上面两条同一个理由（浏览器最小字号会钳回 12px）。 */
.backtest-out {
  font-size: 12px;
  line-height: 1.55;
  color: #6b7280;
  margin: -4px 0 12px;
}

.backtest-out .backtest-line + .backtest-line {
  margin-top: 2px;
}

/* 过期态（条件改了、结果还没重算）：整块变淡 + 顶上多一行说明（那行由 JS 插进来）。
   ★ 只变淡**不隐藏**：用户改完条件往往正是要跟上一次的数字比，藏起来等于白算。
     变淡 + 说明行一起，才既留了信息又不会被当成当前条件的结论。 */
.backtest-out[data-state="stale"] {
  opacity: 0.55;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

.dialog-footer button {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
}

.dialog-footer #filterCancel {
  background-color: #e5e7eb;
  color: #374151;
}

.dialog-footer #filterOK {
  background-color: #e41e2b;
  color: white;
}

.dialog-footer #filterOK:hover {
  background-color: #c41e2b;
}

.combinations-container {
  margin-top: 20px;
  width: 100%;
}

.combinations-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-top: 15px;
}

/* 手机/平板的断点。**只放这一处 768px 的块** —— 同一个断点散成两个块，以后有人加第三条规则
   到其中之一时，没人看得出还有另一半。
   ★ 块的位置在文件后段，但 CSS 不看位置看「同优先级下后写的胜」，
     所以这里能覆盖上面 700 行附近的 .selector-area / .combinations-grid 基础规则。 */
@media (max-width: 768px) {
  /* 前区 / 后区改**上下**排（用户 2026-09-15 报「左右并列太狭长」）。
     原来两栏 1fr 1fr：375px 手机上每栏只剩约 165px，扣掉 .number-area 的 15px 内边距
     和 12px 间隔，号码格 50px 一排只能排 **2 个** —— dlt 前区 35 个号要 18 行、约 1100px，
     中间夹着的后区也在同一行里陪着长，整块又窄又长。
     改成 1fr 后同一台机器能排 4 个，前区 9 行、约 560px，宽度也用满了。
     gap 一并从 30px 收到 16px：横向间距变成纵向间距后 30px 会显得很空。 */
  .selector-area {
    grid-template-columns: 1fr;
    gap: 16px;
  }

  .combinations-grid {
    grid-template-columns: 1fr;
  }

  /* 组合行里那段统计：窄屏放它**在任意位置折行**（桌面仍是 nowrap 单行，见
     .combination-item .combo-stats）。
     ★ 为什么必须这么做（2026-09-17 加方差/跨度之后实测出来的）：
       .combo-stats 是 nowrap + flex: none —— 它的**最小宽度就等于整段文字宽度**，
       加了两段之后 pick_10（英文，最长的一彩种）那一段是 325px，
       而 390px 屏上一行只有 299px 可用。nowrap 让 flex-wrap 也压不下去它，
       于是它顶宽了网格轨道（1fr 的 auto 下限 = 内容最小宽度）：
       页面滚动宽 407 > 视口 390，整页横向滚动（改之前是 390 = 390，不溢出）。
       改成 normal 后最小的不可折单元降到「最长的一个词」，轨道不再被顶宽。
     ★ 折行的代价可接受：这是 12px 的灰色说明文字，折成两三行只影响观感，
       不影响可读性；而横向整页滚动是明确的故障。
     ★ 选择器多写一层 `.combinations-list` 是**为了特异性，不是为了结构**：
       基础规则 `.combination-item .combo-stats` 在这个块**后面**（文件下半段），
       两者同特异性 (0,2,0) 时「后写的胜」，块内这条会输 —— 实测被盖掉过一次
       （页面照样 407 > 390）。(0,3,0) 与文件位置无关，稳定胜出。
     ★ 同时要允许它**收缩**（基础规则是 flex: none = 不收缩）：white-space: normal
       只让文字能折，flex 项的宽度仍取 max-content（325px），放不进这一行就溢出到列表外
       —— 实测 pick_10 的**列表内部**因此多出 15px 横向滚动（scroll 355 / client 340）。
       min-width: 0 让它在窄屏被压到可用宽度（299px）并在内部折行。
       这两条只在窄屏生效：桌面端 708px 的行宽放得下 325px 的一段，保持不折行的单行。
     ★ 2026-09-17 起它住在 .combo-meta 里、第二行还带 55px 缩进（与号码左缘对齐），
       窄屏可用宽度因此再少 55px → 折行更早发生。这是「与号码对齐」的代价，
       折的仍是 12px 灰色说明文字，**接受**（用户选的就是这个方案）。 */
  .combinations-list .combination-item .combo-stats {
    white-space: normal;
    flex-shrink: 1;
    min-width: 0;
  }

  /* ------------------------------------------------ 窄屏收起「预演」按钮（2026-09-19）
     用户 2026-09-19 报：「移动浏览下，号码组合后的 2 个按钮，删除按钮被挤到了下一行」。
     实测（tools/check_picker_stats.js 的「行首三行」，390px）——
       一行可用 299px = 列表 340 - 左右内边距 41；第一行要放
       序号 40 + 3 个间距 45 + 号码 + 两颗按钮 52 = 137 + 52 + 号码。
       号码本身：powerball 174、dlt / ny_lotto 202、pick_10 273px。
     结论：**号码超过 110px 就放不下两颗按钮**，也就是除了 4~5 个号的彩种，其余全都放不下 ——
     所以窄屏下「按钮掉到第二行」不是某个彩种的偶发，而是这一行的常态。
     ★ 收起哪一颗：预演。理由不是「它次要」，而是**它在窄屏另有出路**（见下），
       而删除没有 —— 删除被折到第二行时，用户点到的可能还是上一行的号码。
     ★ 代价与出路：预演 = 把这组号码投放到统计表/分布表的末行（setPreview）。
       窄屏上统计表本来就要横向滚动（见 .table-container 与 fitFrontCells），
       「投放到末行」在手机上看不见效果，这个按钮在窄屏的价值本来就接近 0。
       桌面（>768px）一切照旧，按钮还在。
     ★ 只隐藏**显示**：DOM 与 click 绑定都留着（bindPreview 扫的是 .preview-btn），
       所以 JS 一行都不用改；将来要换别的入口（例如点号码）也不用重建这颗按钮。
     ★ 实测（探针同一条判据）：隐藏后 序号 40 + 间距 + 号码 202 + 间距 + 删除 26 = 288px
       （间距在本块下面收到了 10px，理由见那条注释），390px 下放得下；pick_10 那 273px 的号码仍然放不下，
       它的第一行是「序号 + 号码」、删除键在第二行 —— 10 个两位数在 299px 里本来就不可能
       再塞下一个按钮（273 + 40 + 10 = 323 > 299，连序号都快挤不下），那条不属于这条规则能治的。
     ★ 选择器多一层 .combinations-list 是**为了特异性，不是为了结构**（与上面 .combo-stats
       那条同一个理由）：基础规则 `.combination-item .preview-btn` 在本块**后面**，
       两者都是 (0,2,0) 时「后写的胜」—— 实测第一版就写成了 `.combination-item .preview-btn`，
       按钮照样显示（探针原样报 26px）。加一层到 (0,3,0) 就与文件位置无关。 */
  .combinations-list .combination-item .preview-btn {
    display: none;
  }

  /* 窄屏把行内间距从 15px 收到 10px：只为给删掉预演键之后的那 1px 余量留条活路。
     隐藏预演键之后，7 个号码的行（dlt / ny_lotto，号码 202px）第一行需要
     序号 40 + 间距 15×2 + 号码 202 + 删除 26 = 298px，而 390px 屏上一行只有 299px ——
     装是装下了，但只多 1px，真机字体（iOS/Android 的 sans 各不相同）差几个像素就再折回去。
     收到 10px 后是 288/299px，余量 11px。
     ★ 第二行的缩进 `padding-left: calc(--seq-w + --item-gap)` 与号码左缘用的是同一个变量，
       所以改完仍然逐行对齐（探针的「第二行对齐 0px」在盯这一条）。
     ★ 选择器带 .combinations-list 仍然是**为了特异性**：基础规则里 --item-gap 定义在
       `.combination-item` 上，而它在文件里位于本块**之后**（同见上面 .preview-btn 那条）。 */
  .combinations-list .combination-item {
    --item-gap: 10px;
  }

  /* ------------------------------------------------ 过滤对话框的横向预算（2026-09-18）
     用户 2026-09-18 报的两条：和值那一行「Sum 后的下拉框太宽、后面的数字框显示不全」，
     以及回溯验证的期数下拉框显示不全。量出来是**横向预算**的问题，不是控件的问题 ——
       一行的可用宽度 = 对话框宽 - 40（左右各 20 内边距）= 0.9×视口 - 40，
       375px 的手机上**只有 298px**。
     固定开销：标签 96 + 三个 10px 间距 + 运算符下拉 88 + 区间提示（和值 48 / 方差 64 / 跨度 33）。
     留给数字框的因此只剩：和值行 35px（375px 屏）～22px（360px 屏）；方差行在 360px 屏上
     内边距就把整个框吃满 —— 内容区 **0px**，一个数字都看不见（探针现在会报这一条）。
     数字框里的字是被**裁掉**的，不是换行：number 输入框永远单行，所以屏幕越窄丢的位数越多。
     ★ 下面两条是把**本来就不需要那么宽**的地方收回来，让给数字框：
       · 标签：中文最长的是「奇偶比:」约 46px、「AC值:」约 36px。96px 那个下限是给英文站的
         "Consecutive"（真机量出来 116px）留的。窄屏压到 64px 仍然装得下**所有**中文标签。
         ★ 只压 min-width，不动 width: max-content —— 长标签照样自己变宽、不会重叠
         （定宽才会，见上面基础规则里那次踩坑）。代价是英文站窄屏下各行控件不再左右对齐，
         那是次要问题，装不下才是主问题。
       · 运算符下拉：选项就「不限」「<」「≤」「=」「≥」「>」六个，最宽的「不限」两个汉字
         约 28px，加内边距 16 + 边框 2 + 原生箭头约 20 = 66px 就够。88px 里那 22px 是白扔的。
         和上面 .backtest-n 一样用 max-content 让浏览器自己算，不写死数。
     ★ 改完实测（探针量的**数字框内容区**，即扣掉左右各 8px 内边距）：
         360px 屏 和值 69 / 方差 54 / 跨度 84px（check_picker_stats.js 的「360px 横向预算」那行）。
         ★ 这几个数是 headless 量的：它**没装中文字体**，「不限」那两个字比真机窄约 10px，
           于是运算符下拉窄 10px、数字框相应**宽** 10px —— 真机上应减去这 10px 看
           （约 58 / 43 / 73px）。三行各自区间里的最长取值（165 / 254.0 / 34）都还装得下，
           最紧的是方差那行的「254.0」（约 40px）。
         ★ 为什么要专门说这一条：这台机器上跑的探针**看不见**真机那 10px 的差距，
           所以「装得下」这条判据在这里只是**下界**（NARROW_PROBE 的注释里也写了）。
           真机那条靠的是 max-content 让浏览器自己算，而不是这里量出来的某个数。
     ★ 这些数**互相耦合**：一行里谁多占 10px 就是同行的数字框少 10px。改任何一条都要重跑
       check_picker_stats.js —— 它现在会逐行报「数字框装不下自己的最长取值」。 */
  .form-group > .form-label {
    min-width: 64px;
  }

  .form-group .filter-op {
    width: max-content;
  }

  /* ★ 2026-09-18 第二轮（美站实测）：上面两条把中文站救回来了，**英文布局还不够**。
     同一套判据跑美站（powerball）报了两条「控件里的字被裁」：
       · 方差行的数字框内容区只剩 22px —— 美站区间是 2~1061.8，最长取值 6 个字符
         （约 47px，加内边距 16 + 边框 2 = 65px）；英文标签 "Variance:" 又比「方差:」宽 39px。
       · 回溯验证的期数下拉被压到 123px，而 "Last 200 draws" 要 145px（中文「最近 200 期」只要 99px）。
     这两条在 375/390px 上一样有，不是 360px 才冒出来的 —— 英文布局一行的固定开销比
     中文站多约 100px（标签 +39、期数下拉 +46、区间提示 +8），390px 那档只是不查数字框宽度。
     ★ 办法不是再找一个更小的数写死，而是**让放不下的东西掉到第二行** ——
       这在本文件里是 2026-09-16 就定下的先例（上面 .form-group-multi 那条：
       「给下拉一个下限宽度：一行放不下时由 flex-wrap 把提示挤到下一行，
        提示自己占满整行、不截断」）。这里照抄同一个形状：
       · .form-group 允许折行：一行放不下时，多出来的那个元素整体掉到第二行。
         条件行里掉下去的是区间提示（「2~1061.8」），回溯验证那行掉下去的是按钮。
         美站 360px 下因此变成「Variance: [Any ▾] [数字框 104px]」+ 第二行「2~1061.8」，
         期数下拉那行变成「Backtest: [Last 200 draws ▾]」+ 第二行「[Run]」。
       · 数字框给下限 9ch：`ch` 是「0 的宽度」，字号/字体/译文一变它自己跟着变，
         不存在「估一个像素数、换个语言就静默裁字」（基础规则里 .form-label 和
         .backtest-n 两次踩的都是这个）。9ch 在 border-box 下约 76px（含内边距 16 + 边框 2）
         → 内容区约 60px，装得下最长取值「1061.8」（约 47px）。
         ★ 这个下限只决定**什么时候折行**：真折了行，数字框拿到的是整行的剩余宽度
           （美站 360px 实测 104px），下限不再是它的实际宽度。
     ★ 两条规则**只给英文布局**（html[lang="en"]，由 base.html 按 site_language 写死）：
       · 中文站不缺这几十像素 —— 它一行 284px，方差行的固定开销 213px（标签 64 + 运算符 55 +
         提示 64 + 三个间距 30），数字框拿 71px，装「254.0」（40px）够用，**没有折行的理由**。
       · 先写成全局规则试过（中文站也跟着走）：实测**中文站方差那一行被顶成两行**
         （数字框 54 → 127px，区间提示掉到第二行）—— 在公开站上改了没人要的版式。
       · 而且「中文站在真机上折不折」在这台机器上**论证不了**：headless 没装中文字体，
         中文标签/提示比真机窄约 10px（第一轮那段写着），也就是中文站的余量在这里是**虚高**的。
         靠一个刚好卡在两站之间的数（实测窗口只有 60~71px）来分流，真机上随时翻车。
         按语言分流不依赖任何量出来的数，只依赖「英文文案更宽」这个事实。
     ★ 改完实测（check_picker_stats.js 的「360px 横向预算」那行）：
         美站 和值 66 / 方差 104 / 跨度 81px，期数下拉 145/145px，对话框 658px·不滚动；
         中文站 和值 69 / 方差 54 / 跨度 84px，一行都没折、与改动前逐字一致。 */
  html[lang="en"] .form-group {
    flex-wrap: wrap;
  }

  html[lang="en"] .form-group .filter-value {
    min-width: 9ch;
  }

  /* ------------------------------------------------ 首页博客轮播：一屏一张、开吸附、收箭头
     窄屏一屏摆不下 4 张：360px 的屏每张只剩 78px，统计图缩到那个宽度，坐标轴上的刻度
     就成了一条糊线。所以窄屏**一屏一张**（手指横滑翻页）—— 卡片的版面（图上文下）
     不用改，它在两种宽度下是同一套，这里改的只是「一屏几张」。
     窄屏的翻页动作是**手指横滑**，箭头既占地方、点击区又只有 36px，圆形指示点
     已经足够指明位置。
     ★ 一屏一张时才开吸附：吸附点就是每一张卡。桌面一屏 4 张时不开（见 2035 行那段
       基础规则里的说明）。
     ★ 选择器多一层 `.home-blog` 是**为了特异性，不是为了结构**：基础规则在本块
       **后面**（文件末尾那段），同特异性时「后写的胜」，块内这条会输 ——
       与 1447 行藏预演键、1460 行窄屏行内间距是同一个形状。
       这里还有一层用得上：`.home-blog-track--n1`~`--n3` 只有一层类，
       `.home-blog .home-blog-track` 两层，正好盖过它（窄屏就是 1 张，与篇数无关）。 */
  .home-blog .home-blog-track {
    --cols: 1;
  }

  .home-blog .home-blog-viewport {
    scroll-snap-type: x mandatory;      /* 滑到一半松手，自动落回整张 */
  }

  .home-blog .home-blog-slide {
    scroll-snap-align: start;
  }

  .home-blog .home-blog-arrow {
    display: none;
  }
}

.combinations-column {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.button-group {
  width: 100%;
  max-width: 100%;
  display: flex;
  gap: 10px;
  box-sizing: border-box;
  padding: 0;
  /* 20 是「组合列表 → 按钮」的间距，而且**必须写在这里**：
     .combinations-list 自己的 margin-bottom 是 0（见那块）。
     ★ 这一块原来是 `margin-top: 20px;` 和 `margin: 0;` **同时存在**，后者胜 ——
     于是 margin-top 实际是 0，按钮紧贴号码区域（2026-09-14 用户报的就是这个）。
     同一个块里写两条互相矛盾的简写/长写，读代码的人只会看见前面那条。
     现在合成一条 `margin: 20px 0 0`：上 20，左右 0，下 0。 */
  margin: 20px 0 0;
}

.button-group .action-button {
  flex: 1;
  max-width: 100%;
  box-sizing: border-box;
}

.combinations-container h3 {
  text-align: center;
  margin-top: 0;
  margin-bottom: 15px;
  color: #162e51;
  font-size: 16px;
  font-weight: 600;
}

/* ★ 这个选择器**只能有一块**。原来有两块（另一块写着 margin-bottom: 20px），
   而本块的 `margin: 0` 是后者、胜出 —— 于是那个 20px **从来没有生效过**，
   列表与下面按钮之间的间距实际是 0（按钮紧贴号码区域）。
   现在两块合成一块，间距由 .button-group 的 margin-top 承担（见那一块）。 */
.combinations-list {
  height: 400px;
  width: 100%;
  max-width: 100%;
  margin: 0;
  overflow-y: auto;
  border: 1px solid #e9ecef;
  border-radius: 4px;
  background-color: #f8f9fa;
  /* scrollbar-gutter: stable —— 这个列表是**定高 400px + 内容动态生成**的，
     没生成组合时没有滚动条、生成后才有。不留槽的话，滚动条一出现就吃掉约 15px
     内容宽度，整行内容横向跳一下（而且行内那个删除按钮正好贴过去）。
     保留槽位 = 有没有滚动条都是同样的宽度，位置不跳。
     不认识这个属性的浏览器直接忽略，退化成原来的行为，不会坏。 */
  scrollbar-gutter: stable;
}

/* 一行 = 序号 | 号码 | 删除（第一行）+ 统计（第二行）。宽度是这个列表的稀缺资源。
   ★ flex-wrap: wrap 是**故意的**，而且与旧版相反：
   旧版是「统计段 nowrap + 号码列 flex:1 被压扁 → 宁可挤压号码也不换行」，
   实测的后果是号码**在号码中间断行**（"04 05 06" 折成两行），整行照样变高，
   而且号码读起来断成两截 —— 也就是那次要修的现象。
   现在：号码列 nowrap（绝不拆开），统计段**固定独占第二行**（见 .combo-meta）。
   号码永远完整，统计段也不再跟号码抢第一行的宽度。 */
.combination-item {
  /* 序号列宽与行内间距：**只在这里定义一次**。第二行的缩进就是这两个量之和
     （见 .combo-meta 的 padding-left），对齐靠的就是它精确等于「序号列宽 + gap」——
     数字写两遍必然漂移（与 #fenbuTable.dist-compact 的 --dist-cell-w 同一个理由）。 */
  --seq-w: 40px;
  --item-gap: 15px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* 右内边距 26 而不是 15：这一行最右边是删除按钮，而列表右侧紧邻滚动条
     （滚动条在 padding box 之外，中间只隔着这里的内边距）。
     15px 时按钮看上去就是**贴着滚动条**的 —— 26px 才留出看得见的间隔。
     左边仍是 15：左边是列表边框，本来就没东西，不需要额外留白。 */
  padding: 12px 26px 12px 15px;
  border-bottom: 1px solid #e9ecef;
  background: #f8f9fa;
  gap: var(--item-gap);
}

.combination-item:last-child {
  border-bottom: none;
}

/* 序号定宽 + 右对齐：定宽让**号码列的起始 x 逐行一致**（1. 与 100. 都对齐），
   右对齐让小数点也成一列，序号与号码之间就只剩 flex gap 那 15px。
   原来左对齐时，宽 40px 里短序号（"1." 约 18px）身后挂着 22px 空档，
   再叠上 15px gap —— 序号和号码之间空出近 40px，这就是「太空」的一半。
   ★ 宽度走 --seq-w：第二行的缩进按同一个变量算，两者不会各写一个数字。 */
.combination-item .seq {
  width: var(--seq-w);
  text-align: right;
  font-weight: bold;
  color: #162e51;
  font-size: 16px;
}

/* 统计段（基础段 + 右列专有的「启用中条件」段）的包裹层。
   ★ 2026-09-17 用户要求：「统计项目多了，一行无法放下，干脆另起一行吧，
     但要保持和号码对齐」——
   它**永远独占第二行**，并用 padding-left 缩进到与 .numbers 的左缘对齐
   （= 序号列宽 --seq-w + 行内间距 --item-gap）。
   ★ order: 1 是这一块的关键：DOM 里它排在删除按钮**之前**（与旧结构一致，
     读屏顺序也还是「号码 → 统计 → 删除」），而 flex 的排版顺序由 order 决定 ——
     不把它排到最后的话，flex 会把它和删除按钮**一起**塞进第二行，
     删除按钮就从第一行右侧掉下去了。
   ★ flex-basis: 100% 保证它在第一行永远排不下 → 必定另起一行；
     全局 `* { box-sizing: border-box }`（本文件第 1-5 行）让 padding 含在这 100% 里，
     所以缩进不会把它顶宽、不会横向溢出。
   ★ 它自己是 flex 容器（wrap）：基础段与追加段之间保留一个行内间距，
     放不下时追加段能自己再折一行（窄屏），与包裹前的行为一致。 */
.combination-item .combo-meta {
  order: 1;
  flex: 0 0 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--item-gap);
  padding-left: calc(var(--seq-w) + var(--item-gap));
}

/* flex-basis 用 auto（不是旧版的 flex:1 = basis 0）：空间不够时，flex 的**换行判据**
   按「号码的实际宽度」算，basis:0 会让它以为号码不占宽度，于是永远不换行、直接压扁。
   nowrap：号码序列内部绝不换行（"01 02 03" 断成两行就是旧版的毛病）。

   ★ flex-grow 是 0（2026-09-17 改，原来是 1）—— 这一行曾经唯一会增长的元素。
   它文字左对齐，于是所有剩余宽度都被它吃进框里，变成号码文字与统计段之间的一大块空白
   （实测 dlt 左列 290px、右列 270px；用户原话：「这些统计信息已经换行了，但是左侧和号码
   之间的距离还是很空的」）。改成 0 之后框宽 = 号码文字宽，统计段紧跟在号码后面
   （只剩父级 flex gap 那 15px），**空白被赶到删除按钮之前** —— 那里看着才是
   「一行左对齐的内容 + 右侧留白」。实测号码→统计：dlt 290px → 15px。
   ★ flex-shrink 仍是 1：极端窄屏下宁可让 nowrap 的号码溢出自己的框，
   也别把它当不可压缩项、把整行顶出横向滚动条。
   ★ text-align 是 left，**这里和旧版相反**（旧版 center，2026-09-14 改）：
   居中时剩余宽度会在号码两侧各撑出一块空白（序号与号码之间空、号码与统计之间也空），
   整个左半边看起来是散的。左对齐让号码就贴着序号（flex-grow=0 之后更是如此）。 */
.combination-item .numbers {
  flex: 0 1 auto;
  font-size: 16px;
  font-weight: bold;
  text-align: left;
  white-space: nowrap;
}

/* 组合后面那组统计（和值 / 奇偶 / 分区 / 方差 / 跨度 / 重号）。
   ★ 它现在住在 .combo-meta（独占第二行的包裹层）里，随包裹层一起排第二行 ——
   见上面 .combo-meta 那一块；这里只管它自己的字号 / 颜色 / 不拆行。
   ★ 字号写 12px 是**下限**，不能再小：浏览器有「最小字号」钳制，写 11px 会被顶回 12px，
   反而不受控（见 docs/design.md 相关记录）。12px 正好是那个下限，渲染结果如所写。
   标签本身已经是缩写（picker.stat_* 键；方差/跨度/重号用统计表的 stat.* 键），
   宽度是第一约束。
   nowrap：它自己内部不拆行 —— 桌面端一整段放得下；窄屏由媒体查询那条改成 normal
   （见 @media (max-width:768px) 里的 .combinations-list .combination-item .combo-stats）。
   flex: none：不许被压缩，宽度只由内容决定。 */
.combination-item .combo-stats {
  flex: none;
  font-size: 12px;
  font-weight: normal;
  color: #6b7280;
  white-space: nowrap;
}

/* 右列（过滤结果）在搬过来的统计段之后**追加**的那一段：只显示当前启用中的
   过滤条件对应的量（AC值 / 连号），见 lottery.js 的 activeStatsHtml()。
   ★ 重号 2026-09-17 起不在这一段里了：它搬进了基础段（两列都显示、口径相同），
     留在这里就是同一行印两个重号。
   ★ 它现在住在 .combo-meta 里（统计段那个独占第二行的包裹层），与基础段同排一行、
     放不下时自己再折一行。flex 从 `0 0 100%`（强制独占整行）改成 none（2026-09-17）：
     独占整行的代价实测有三条：① 第一行号码与统计后面的宽度白空着；
     ② 它自己占一整行，起点在**行的左内容边缘**（序号下方），与上面的号码错开一截；
     ③ 它把删除按钮挤到**第三行**（dlt 右列实测行高 123px = 三行）。
     改成 none 后它跟在基础段后面接着排（dlt 右列 123 → 51px）。
     ★ 上面②那条「与号码错开一截」**现在不成立了**（但保留原文：它解释了当初为什么
       放弃 `0 0 100%`）—— 2026-09-17 起基础段所在的 .combo-meta 会用 padding-left
       缩进到与号码左缘对齐，追加段跟在它后面，左缘自然也对齐。
   ★ 颜色略深一点（#4b5563 vs 统计段的 #6b7280）：它是「为什么这条被留下」，
     比旁边那几个总是显示的统计量更该被看见。 */
.combination-item .combo-stats-extra {
  flex: none;
  color: #4b5563;
}

/* 预演按钮（2026-09-17 加）：把这组号码投放到统计表末行 + 分布表末行。
   尺寸/圆角与 .delete-btn 逐项对齐 —— 两颗按钮挨着站，差 1px 都看得出来。
   蓝色（#2563EB）与红色删除键区分：一个是「看看」，一个是「删掉」。

   ★ margin-left: auto 在**这一颗**上（不在 .delete-btn 上）：两颗都写 auto 的话，
     flex 会把剩余空间**平分**给两个 auto 外边距 → 两颗按钮之间裂开一大块空白。
     谁在前谁负责顶开，删除键跟在它右边紧挨着。 */
.combination-item .preview-btn {
  flex: none;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  background: #2563EB;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
}

.combination-item .preview-btn:hover {
  background: #1d4ed8;
}

/* 删除按钮：26×26 的图标方块。
   原来是「padding 6px 12px + 文字」，英文站是 "Delete"，一个按钮吃掉 60px。
   flex: none 保证它不会被压扁（图标按钮压扁后就是个红点）。

   margin-left: auto 曾在这条上，2026-09-17 加预演按钮时**搬到了 .preview-btn**
   （见上）。留白因此仍然落在号码与按钮之间，只是现在推开的是「预演+删除」这一对，
   删除键不再是最右那个被 auto 顶开的元素，而是紧跟着预演键 —— 视觉上仍是对齐的一列。
   ★ 同日起统计段搬到第二行（.combo-meta + order:1），第一行固定是「序号 + 号码 + 两颗按钮」，
   按钮的位置比从前更稳定：不再随统计段长短而变化。
   （父级 gap 管最小间距，与 auto 外边距不冲突。） */
.combination-item .delete-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  background: #B91C1C;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
}

.combination-item .delete-btn:hover {
  background: #991b1b;
}

/* 过滤结果为空时右列的提示（见 lottery.js 的 doFilter）。
   颜色取 #6b7280（与页面正文同一档灰），字号比组合条目小一号 ——
   它是说明不是内容，不该跟组合条目抢注意力。 */
.filtered-empty {
  padding: 24px 15px;
  text-align: center;
  color: #6b7280;
  font-size: 14px;
  line-height: 1.6;
}

.must-number.front {
  color: #9333ea;
  font-weight: bold;
  text-shadow: 0 0 2px rgba(147, 51, 234, 0.5);
}

.must-number.back {
  color: #ff7f00;
  font-weight: bold;
  text-shadow: 0 0 2px rgba(255, 127, 0, 0.5);
}

.bet-info {
  text-align: center;
  font-weight: bold;
  color: #162e51;
  margin-top: 10px;
}

/* 分区背景色 */
#fenbuTable .front-area-1 {
  background-color: #fff0f0;
}

#fenbuTable .front-area-2 {
  background-color: #f0f5ff;
}

#fenbuTable .front-area-3 {
  background-color: #f0fff0;
}

#fenbuTable .back-area-1 {
  background-color: #f0f8ff;
}

#fenbuTable .back-area-2 {
  background-color: #fff0f0;
}

/* 列特定样式 */
.col-period {
  width: 48px;
  background-color: #fafafa;
  font-weight: bold;
  color: #162e51;
  font-size: 11px;
}

.col-date {
  width: 76px;
  background-color: #fafafa;
}

.col-front, .col-back {
  width: auto;
  background-color: #fafafa;
}

/* 统计列样式 */
.stats-col {
  background-color: #f8f9fa;
  font-weight: bold;
  color: #162e51;
  padding: 6px 4px;
}

/* 末尾的「下一期」占位行（可点选号码，见 lottery.js 的 appendEmptyRows）。
   只在第一行画一条虚线与「已开奖」的区段分开 —— 这几行和上面的真实开奖长得一样，
   不划线容易把摆上去的号码误读成已开出的号码。

   这里**不**改底色。原来那条 `.empty-row td { background-color: #f8f9fa }` 从来没生效过：
   分区底色是 `#fenbuTable .front-area-*`（ID 选择器，优先级高于这里的类+元素选择器），
   把灰底整个盖住了。真去灰掉也不好 —— 预演选号时正要看分区，灰掉反而丢信息。 */
#fenbuTable tbody tr.empty-row-first td {
  border-top: 1px dashed #b8b8b8;
}

/* 统计表末尾的「预演行」（见 lottery.js 的 appendStatsEmptyRow / paintStatsPreview）。
   与分布表那一行同一视觉语言：一条虚线把「拿一注来预演」与「已开奖」分开。
   2026-09-17 起再给它一整行**淡黄底 + 左侧一道红竖条**（用户要求：「这个统计的最后一行，
   要加个特殊样式，以区分历史行」）—— 那一行现在填着期号 / 日期 / 9 个统计值，
   长得和数据行几乎一样，不标出来会被当成一期真实开奖。

   ★ 底色写在 td 上，**不能写在 tr 上**：历史行的底色来自 .col-period / .col-date /
     .stats-col 三个**类**（#fafafa / #f8f9fa），它们作用在 td 上，tr 的背景色会被整个盖住。
     这个坑 §11.74 已经踩过一次（当时那条 `.empty-row td { background-color }` 从来没生效过）。
     `#statsTable tbody tr.empty-row td`（1,0,2）压得过那三个类（0,1,0）。
   ★ 左侧那道红竖条用 box-shadow: inset，**不用 border-left**：border 会把这一格的**内容**
     往右推 3px，而只有第一格被推、后面的格子不推 —— 整行的列就跟表头错开了。
   ★ 只认 #statsTable：分布表那行（`tr.empty-row-first`）不动 —— 它的格底是分区色，
     盖成一片淡黄反而丢信息（预演选号时正要看分区）。 */
#statsTable tbody tr.empty-row td {
  border-top: 1px dashed #b8b8b8;
  background-color: #fffbeb;
}

#statsTable tbody tr.empty-row td:first-child {
  box-shadow: inset 3px 0 0 #B91C1C;
}

/* 分布单元格样式 */
.dist-cell {
  text-align: center;
  vertical-align: middle;
  width: 28px;
  cursor: pointer;
}

/* 分布列样式 */
.front-dist, .back-dist {
  white-space: nowrap;
}
/* ====================== 文章内容 ====================== */
.article-content {
  color: #374151;
  line-height: 1.8;
  font-size: 15px;
}
.article-content h1, .article-content h2, .article-content h3 {
  color: #1f2937;
  font-weight: 700;
  margin: 1.4em 0 0.6em;
}
.article-content h1 { font-size: 1.5em; }
.article-content h2 { font-size: 1.3em; }
.article-content h3 { font-size: 1.1em; }
.article-content p { margin: 0.8em 0; }
.article-content ul, .article-content ol { margin: 0.8em 0; padding-left: 1.5em; }
.article-content ul { list-style: disc; }
.article-content ol { list-style: decimal; }
.article-content blockquote {
  border-left: 4px solid #e41e2b;
  background: #fff5f5;
  padding: 0.6em 1em;
  margin: 1em 0;
  color: #666;
}
.article-content code {
  background: #f3f4f6;
  padding: 0.1em 0.4em;
  border-radius: 4px;
  font-size: 0.9em;
}
.article-content pre {
  background: #1f2937;
  color: #e5e7eb;
  padding: 1em;
  border-radius: 8px;
  overflow-x: auto;
  margin: 1em 0;
}
.article-content pre code { background: transparent; color: inherit; }
.article-content a { color: #e41e2b; text-decoration: underline; }
.article-content img { max-width: 100%; border-radius: 8px; margin: 1em 0; }

/* ====================== 首页博客轮播（一屏 4 张的图上文下小卡） ======================
   `index.html` 那个 #homeBlog 区块的卡片轨道（卡片本身是服务端渲染的），翻页与
   圆形指示点由同一页里**另一段独立**的轮播脚本接管。样式分三层：

     外壳尺寸 / 卡片圆角阴影过渡 → Tailwind 工具类
     滚动盒 / 吸附 / 列数 / 卡片版面（图上文下） → 这里
     圆形点 / 箭头            → 这里（没有对应的工具类）

   ★ 手写规则**不要**和同一元素上的 Tailwind 工具类抢同一个属性：base.html 里
     tailwind.css 排在 style.css **之后**（§8.6），同优先级时 Tailwind 赢 ——
     抢了就是死代码。**卡片上的文字样式因此一个 Tailwind 文字类都没留**
     （模板那边配合着把 `text-gray-*` 这些都撤了）：文字样式本来就只有一处该说，
     留着 `text-gray-800` 只会同属性两边打架、而赢的是它。
   ★ ★ **图是「图」，不是背景** —— 这是这一块改到第五版才定下来的：配图多是**统计图**
     （`app/static/blog/` 下那几张就是带坐标轴和图例的柱状图/直方图）。当背景铺满再压一层
     暗色遮罩，裁掉的那部分就是全部数据。所以这里：
       图占卡片上方一整条（.home-blog-figure）、居中等比完整显示、**绝不裁切**，
       文字在下、浅底深字。任何「图铺满 + 字压上去」的写法都会把这个前提推翻。
   ★ **一屏几张由 `--cols` 决定**（模板按篇数给 `--n1`~`--n4`，窄屏那个块改成 1）。
     卡宽、卡片高度、圆点个数全都从它推出来；脚本那边**不写死**这个数，是从几何量的
     （见 index.html 那段脚本里 perScreen 的说明）。
   ★ 「窄屏版面」**不在这里**，在 1378 行那个唯一的 768px 块里 —— 那里是「窄屏」
     这件事的唯一出处，散成两处以后加规则必漏一处（目前是：一屏一张、开吸附、收起箭头）。 */
.home-blog-track {
  --cols: 4;   /* 一屏几张。窄屏那个块改成 1 */
  display: flex;
  gap: 24px;   /* 两张之间留一道缝：翻页滑过去时看得出是两张，而不是一块在动 */
}

/* 篇数不足 4 时**按实际篇数均分**，不按 1/4 摆：库里今天只有 1~2 篇，照 1/4 摆出来是
   「两张小卡 + 大半行空白」，看着像没加载完。1 篇按 2 篇摆并居中（100% 宽的话图要
   620px 高，一整条灰底）。★ 这个类由模板按篇数给，**不是**媒体查询 —— 判据是篇数不是屏宽。
   ★ `.home-blog-track--n*` 只有一层类，特意低于窄屏块里的 `.home-blog .home-blog-track`：
   窄屏一屏一张是要盖过这里的。 */
.home-blog-track--n1,
.home-blog-track--n2 { --cols: 2; }
.home-blog-track--n3 { --cols: 3; }
.home-blog-track--n1 { justify-content: center; }

.home-blog-viewport {
  /* 一屏摆满外层容器（Tailwind 的 max-w-7xl 给的上限）—— 不另设宽度上限：
     图栏宽 = 容器宽 / 4，1248px 下每张 294px、图 294×147（2:1），统计图看得清。 */
  /* ★ 承重属性：手机上「横滑切页」就是它，JS 一行手势代码都没参与 */
  overflow-x: auto;
  overscroll-behavior-x: contain;     /* 挡 iOS 的边缘返回手势（最左一张往右滑会触发后退） */
  scrollbar-width: none;              /* 已经有圆形指示点了，不要横向滚动条 */
  -webkit-overflow-scrolling: touch;
  /* 上下留一点：overflow-x:auto 会把纵向一并变成裁剪，不留的话卡片阴影被切平。
     左右必须是 0 —— 否则 snap 的落点会偏。 */
  padding: 8px 0;
  /* ★ 吸附**只在窄屏开**（在 1378 行那个块里）：窄屏一屏一张，吸附点就是每张卡；
     桌面一屏 4 张时若每张都吸，手指/触控板滑一下停在「第 2 张挨着左边」，
     一屏里同时露出前一页和后一页的卡，圆点标不出这一格。桌面的落点全交给箭头、
     圆点和自动翻页（都是整页落点）。 */
}
.home-blog-viewport::-webkit-scrollbar { display: none; }

.home-blog-slide {
  /* 一屏 --cols 张：每张 = (100% - (列数-1) 道 24px 缝) / 列数
     —— 等价于 (100% + 24px) / 列数 - 24px；写成后者是为了 calc 里不出现嵌套括号。
     ★ 是 `flex: 0 0 ...`（不许缩），不是只写 flex-basis：溢出本该撑出滚动条，
       能缩的话上下 8 张会被压进一行、横滑就没了。 */
  flex: 0 0 calc((100% + 24px) / var(--cols) - 24px);
  min-width: 0;                     /* 长标题不许把卡片顶宽 */
  display: flex;                    /* 卡片撑满行高（不写 h-full，产物里没有） */
}

/* 卡片的尺寸全在这个 min-height 上：宽度由列宽给，高度只由它定。
   正文再长也顶不高（标题、摘要都是定行数截断的），所以「每张卡一样高」是算出来的、
   不是碰巧 —— 自动轮播换页时高度不跳。 */
.home-blog-card {
  display: flex;
  flex-direction: column;           /* 图上、文下 */
  flex: 1;
  min-width: 0;                     /* 长标题不许把卡片顶宽 */
  min-height: 20rem;                /* 320px：图 147 + 文字三行块 167，正好留一点余量 */
  background: #fff;
  color: #1f2937;
  text-decoration: none;
}

/* 图栏：浅灰底 + 居中，图在里面等比缩到不超出为止（`object-fit: contain`，见 -cover）。
   ★ 比例 2:1 是**跟着配图选的**：现有几张统计图是 1.87~2.36:1，给 2:1 时等比缩完
     短边上剩的灰底最少。
   ★ 用 aspect-ratio 而**不是定高**：卡宽会变（桌面一屏 4 张时 294px、窄屏一屏一张时
     328px、篇数不足 4 时更宽），定高总有一头比例离谱 —— 宽卡会上下都是一大条灰底。
   ★ **不要给这一栏加内边距**：图因此能一直铺到栏的两侧边缘。加了内边距，图就变成
     浅灰框里的一张小图 —— 里外两层留白，看着像没放满。
   ★ 留下的那点灰底是**不裁切的代价**：图的比例和栏的比例对不上，等比缩完必然在短的
     那一边空出来。要它一点都不空，只有 `object-fit: cover` 一条路，而那会把统计图
     裁掉一块（见本段开头 ★ ★ 那条）。 */
.home-blog-figure {
  flex: none;
  aspect-ratio: 2 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f9fafb;
}

.home-blog-cover {
  /* 框就是图栏（2:1），图**按自己的比例缩到框里放得下为止**，短边留灰底。
     ★ 必须是 `contain`：`cover` 会把统计图裁掉一块（坐标轴、图例都是数据）。
     ★ 写死宽高（而不是「auto + only max-*」）是因为框的比例现在是 aspect-ratio 定出来的：
       `max-height: 100%` 要有一个百分比可解析的高度，靠 aspect-ratio 推出来的那个在
       个别浏览器上会被当成不确定值 —— 一旦解析不了，图就按自身原始高度撑出去。
       宽高都给死 + contain，图永远在框里，也不会溢出压到下面的文字。 */
  width: 100%;
  height: 100%;
  object-fit: contain;
  min-width: 0;   /* flex 项默认「不小于自身内容」，不写这条图会按原始宽度把栏顶宽 */
}

.home-blog-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 18px 20px 20px;
  /* ★ 刻意**不**竖向居中：一行 4 张卡并排时，居中的话标题首行会随各自行数错位，
     顶对齐才让 4 张卡的「分类·日期 / 标题 / 摘要」齐在一条线上。 */
}

.home-blog-meta {
  /* ★ 不低于 12px：浏览器的最小字号会把更小的顶回来（§8.5 硬下限） */
  font-size: 13px;
  color: #9ca3af;
  margin-bottom: 8px;
}

.home-blog-title {
  font-size: 18px;
  line-height: 1.35;
  font-weight: 700;
  color: #111827;
  margin-bottom: 8px;
  /* 最多两行：长标题不许把摘要挤出卡片（一行 4 张时卡片很矮） */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.home-blog-summary {
  /* 固定两行（Tailwind 的 `line-clamp-*` 在产物里，但截断行数是版式、跟别的规则
     一处改更省事，所以手写），卡片高度才不会随摘要长短抖。 */
  font-size: 14px;
  line-height: 1.6;
  color: #4b5563;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ★ 这里原来有个「阅读全文 →」的胶囊（`.home-blog-more`），一屏 4 张之后去掉了：
   每张只有 294px 宽，那个胶囊要占掉一行，摘要就只剩一行。整张卡本来就是链接
   （hover 有阴影），不需要第二个提示。
   （`blog.read_more` 这个 i18n 键还在，博客列表页在用。） */

/* 控件默认**不显示**，脚本判出「不止一页」时才挂 is-live 让它出现 ——
   这样脚本没跑起来、或压根装不下第二页时，不会留下点不动的死箭头。 */
.home-blog-nav { display: none; }
.home-blog.is-live .home-blog-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 24px;
}

.home-blog-arrow {
  width: 36px;
  height: 36px;
  padding: 0;
  border: 1px solid #e5e7eb;
  border-radius: 999px;
  background: #fff;
  color: #6b7280;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}
.home-blog-arrow:hover {
  color: #e41e2b;
  border-color: #fecaca;
}

.home-blog-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: #d1d5db;
  cursor: pointer;
}
/* 当前页那个点拉长成小横条：颜色之外再给一个形状线索，不只靠颜色区分 */
.home-blog-dot.is-active {
  width: 20px;
  background: #e41e2b;
}

/* 只有一页时不自播、也不出控件（is-live 不挂）—— 判据是**页数 > 1**，不是篇数 > 1：
   一屏 4 张时 4 篇正好一页，出箭头圆点也没地方可翻。 */
