/* ===========================================================================
   responsive.css — 手机端自适应的**唯一所有者**（2026-10-18 新增）

   # 为什么单独一份，而不是每页各写 @media

   实测（2026-10-18）：13 个生产页面里**11 个有 viewport 但零媒体查询**，
   只有 console.html / ops.html 各有一条，且那条只做「栅格降列」、
   断点还定在 940/1080px —— 真机（375~430px）下栅格降完仍会横向溢出。

   ⚠️ 漏改**不报错**：viewport 在、页面能访问，只是手机上不能用。
   这正是「有声明、无实现」——比完全没有更危险。

   ⇒ 与 app.css / doc-head 同一个理由：**一份文件、全部引用**。
   改一次对 13 个页面同时生效，也不会有某一页被漏掉。

   # 断点为什么是这三个

   · 1080px — 平板横屏 / 小笔记本：双栏还放得下，但已挤
   · 768px  — 平板竖屏：导航必须折叠
   · 480px  — 手机：所有多栏必须单栏，表格必须横向滚动而不是撑破布局

   ⚠️ 480 那一档**不能省**：真机主流宽度 375~430px，
   少了它所有 `display:grid` 的多列都会挤成一条缝。

   # 加载方式

   · /responsive.css   —— webui 静态页（经 webui 的 static 处理器）
   · publicpage 用内联 <style>，见 internal/publicpage/responsive.go
   =========================================================================== */

/* --- 1. 盒模型兜底 ------------------------------------------------------
   绝大多数「手机上横向溢出」的根因不是某个元素太宽，
   而是 `width:100% + padding + border` 算出了超过视口的宽度。
   这一条一次性解决大部分情况，且**不需要动任何页面的样式**。 */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
*, *::before, *::after {
  box-sizing: border-box;
}

/* --- 2. 窄屏基线 ------------------------------------------------------ */
@media (max-width: 768px) {
  body {
    /* 别让长 URL / 长英文词把页面撑宽——这是手机上最常见的横向溢出源 */
    overflow-wrap: break-word;
    word-break: break-word;
  }

  /* 长链接/长串（域名、token、query）单独处理：允许在任意处断行 */
  a, code, pre, .mono, .url, .domain {
    overflow-wrap: anywhere;
    word-break: break-word;
  }

  /* 横向滚动容器（如代码块、宽表格）必须自己滚动，而不是把整页撑宽 */
  pre, .table-wrap, .scroll-x {
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* 表格：窄屏下改成可横向滚动，而不是压缩到不可读。
     ⚠️ 真机实测（2026-10-18，375px demands 页 scroll=667）证明这里**不能**
     加 `white-space: nowrap`：表格的最小内容宽度一旦超过容器，
     `overflow-x:auto` 的元素本身仍会被撑宽（它是最小宽度内容的父级），
     于是横向滚动变成了「撑宽整页」，正是我们要消灭的现象。
     ⇒ 表格内容允许折行；确实需要宽表格的页面自己套 .table-wrap。 */
  table {
    max-width: 100%;
    overflow-wrap: anywhere;
  }

  /* ⚠️⚠️ 2026-10-19 的一次误判记录（**没有改任何规则，只记教训**）：
     我曾据「表格盒 323px / scrollWidth 383px / 所有祖先 overflow:visible」
     断定那 60px「DOM 里在、屏幕上没有、滚不到」，还据此加了 .table-wrap。
     **错了** —— 第 6 节那条 `table { display:block; overflow-x:auto }`
     让**表格自己就是滚动容器**。实测：
         tbl.scrollWidth 383 > tbl.clientWidth 323  ⇒ selfScrollable
         tbl.scrollLeft = 60 后，末列右缘由 409 → 349（落入 375 视口）
     ⇒ 错的不是设计，是我的**验证方法**：只看了祖先链的 overflow，
        从没测过「这个元素自己能不能滚」。

     ⇒ 判据（下次直接用）：判断一段内容是否「不可达」，
        **必须**在该元素自身上测 `scrollWidth > clientWidth`，
        而不是看它祖先的 overflow。两者结论可以相反。 */
}

/* --- 3. 多栏栅格降列 ---------------------------------------------------
   覆盖项目里实际用到的类名（grid / grid.two / con-grid / cards 等）。
   ⚠️ 用 `minmax` 的 auto-fit 更稳：它不需要知道有几列，
   容器窄了就自动变单列，宽了就自动多列。 */
@media (max-width: 1080px) {
  .grid.two,
  .con-grid,
  .grid-2 {
    grid-template-columns: 1fr !important;
  }
}

@media (max-width: 768px) {
  .grid,
  .grid.two,
  .grid-3,
  .grid-4,
  .con-grid,
  .cards,
  .stat-grid {
    grid-template-columns: 1fr !important;
  }

  /* flex 容器同样要竖排（横排是手机上第二常见的溢出源） */
  .row,
  .flex,
  .toolbar,
  .actions {
    flex-direction: column;
    align-items: stretch;
  }
}

/* --- 3.5 结果页标签行（2026-10-19 修，公网 375px 实测） -------------------
   实测：四个 tab 被 flex 收缩到 25 / 44 / 76 / 124 px，「Online」拦腰断成
   「Onlin|e」，「Auto delivery」折成两行，整行高 67px。
   根因不是「屏太窄」，是两条规则叠加：
     ① button 继承了 body 的 `word-break: break-word`（见第 2 节）——
        它允许在**词中间**断行，于是按钮的 min-content 塌成约两字符宽；
     ② flex 默认 `flex-shrink: 1` —— 容器一挤，按钮就朝那个塌掉的
        min-content 收缩，标签随之拦腰断。
   ⇒ 修法：禁收缩（flex:none，按钮取自然宽度）+ 禁断词（word-break:normal，
   保留 overflow-wrap:break-word 给俄语等超长标签在词边界折行的兜底）
   + 整钮换行（flex-wrap:wrap）。排不开就换行，而不是把每个钮压扁——
   四个筛选钮没有多到需要横滚，藏起来一个比多一行更糟。 */
@media (max-width: 768px) {
  .res .tabs .in {
    flex-wrap: wrap;
  }
  .res .tabs .in button {
    flex: none;
    word-break: normal;
    overflow-wrap: break-word;
  }
}

/* --- 3.6 结果页标签行：手机档 2×2 网格（2026-10-19 修，375px 实测） ---------
   §3.5 修掉「Onlin|e」拦腰断之后，四个钮改回自然宽度 ⇒ 第三个钮之后
   折行，「Multi-channel payment 17」**独占一行**（用户 2026-10-19 截图 1：
   「为何会有这种换行？」）。根因是物理宽度：375px 视口减去左右各 12px
   内边距只剩 351px，而四个钮加计数徽章在 13px 字号下要约 400px ——
   **不是 bug，是放不下**。
   ⇒ 三条候选路的取舍：
     · 缩字号到 11px + 压间距 ⇒ 342px，仍差一丝，且 11px 低于可读下限；
     · 横滚 ⇒ 把「藏起来一个钮」换成「藏起来一行」，与用户「一屏看完」的
       要求正面冲突；
     · **2×2 网格** ⇒ 全部可见、字号不缩、不横滚，代价是多一行（约 44px）。
   ⇒ 选网格。同时把 tabs 钮从第 4 节 `button{font-size:16px!important}`
   里豁免：那条规则防的是**输入框**被 iOS 自动放大页面，筛选钮不是输入框，
   没有缩放问题，16px 只会把四个钮撑得更放不下。
   ⚠️ 网格态改视觉语言：去掉下划线指示器（网格里每个单元格各画一条下划线
   会很怪），激活态用实底 pill —— 与「筛选 chip」的既有认知一致。 */
@media (max-width: 480px) {
  .res .tabs { border-bottom: 0; }
  .res .tabs .in {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 10px;
  }
  .res .tabs .in button {
    font-size: 13px !important;      /* 盖过第 4 节的 16px 输入框规则 */
    min-height: 0 !important;        /* 盖过第 4 节的 44px */
    padding: 9px 4px !important;
    border-bottom: 0 !important;
    background: var(--brand-soft);
    border-radius: 8px;
    text-align: center;
  }
  .res .tabs .in button.on {
    background: var(--brand);
    color: #fff;
  }
  .res .tabs .in button.on .n { color: rgba(255, 255, 255, 0.85); }
}

/* --- 4. 手机档：控件加大到可点 ----------------------------------------- */
@media (max-width: 480px) {
  /* 表单控件：手机上 14px 以下会被 iOS 自动放大页面 */
  input, select, textarea, button {
    font-size: 16px !important;   /* < 16px 会触发 iOS Safari 自动缩放 */
    max-width: 100%;
  }

  /* 按钮与链接给足点击面积（44px 是主流建议值） */
  button, .btn, .ctl button {
    min-height: 44px;
    padding: 10px 16px;
  }

  /* ⚠️ 圆形图标钮是上面 min-height 的受害者（2026-10-19 公网 375px 实测）：
     `.sbox .go` 34×34 → 34×44、`.settings .gear` 38×38 → 38×44、
     `.tipbtn` 18×18 → 18×44 —— 全被抻成竖椭圆，用户截图即此形变。
     圆钮改 44×44 正方形：触摸目标不降，形状不失真。
     选择器特异度必须高于 `button, .btn, .ctl button` 才压得掉 min-height。 */
  .sbox .go,
  .settings .gear,
  .tipbtn {
    width: 44px;
    height: 44px;
    min-height: 0;
    padding: 0;
  }

  /* 摘要行：计数文本独占第一行，[?] 与排序控件共享第二行。
     不这么做，flex 逐项换行会把「?」单独甩到一行左边缘（2026-10-19 截图）。
     「?」刻意**不**随排序控件右移：它的浮层宽 min(520px, 88vw)，
     只有锚在行左缘时向右展开才不出视口（实测浮层右缘 358 < 375）。 */
  .res .count #countline {
    flex-basis: 100%;
  }

  /* 隐藏元素用显式类，不用 nth-child 猜 */
  .hide-on-mobile {
    display: none !important;
  }
}

/* --- 4.5 计数区与提示条：手机档整理（2026-10-19 修，375px 实测） -----------
   **计数区**（用户截图 2：「这也是错乱的」）：§4 让计数文本独占第一行后，
   「?」与「Sort by」被 `.count` 的 `justify-content: space-between` 甩到
   第二行的**两端** —— 一个在左缘、一个在右缘，中间隔着整个视口，
   看起来像两个互不相干的控件。修法：手机档把主轴对齐改成 flex-start，
   两者紧邻成组（都是「这一屏怎么看」的视图控件，本来就是一伙）。
   amber pill（「First 50 returned · …」）折行时去掉 7px 左缩进，
   与计数文本左缘对齐。

   **提示条**（用户截图 3：「这段内容还是太多，太伤害用户体验」）：
   合规提示是《反电信网络诈骗法》第三十条的**法定义务**，第一句
   （提示 + 警示法律责任）一句不能少；第二句「本页由程序自动索引公开网页
   生成，仅供参考」是**我们自己的声明**，不是法条要求的内容 ——
   9 种语言的译文都已把它包进 `<span class="notice-opt">`（见 i18n.js），
   手机档隐藏。桌面保持全文。隐藏后剩法定义务那一句，11.5px 下 375px 实测
   **3 行 / 66px**（修复前两段全显是 4 行 / 113px）—— 3 行是这句话的物理下限，
   不是没修干净。 */
@media (max-width: 480px) {
  .res .count {
    justify-content: flex-start;
    gap: 2px 10px;
  }
  .res .count .trunc { margin-left: 0; }

  .notice {
    font-size: 11.5px;
    line-height: 1.45;
    padding: 7px 11px;
  }
  .notice .notice-opt { display: none; }
}

/* --- 5. 导航与页脚（publicpage 常用） ----------------------------------- */
@media (max-width: 768px) {
  nav .nav-links,
  .nav-links {
    flex-wrap: wrap;
    gap: 10px 14px;
  }

  footer .foot-links {
    flex-wrap: wrap;
    gap: 8px 16px;
  }

  /* 页面主标题在大屏是大字号，手机上要降下来，否则一行放不下 */
  h1 { font-size: 22px !important; line-height: 1.3; }
  h2 { font-size: 18px !important; line-height: 1.35; }
}

/* --- 6. 运行时注入的组件（2026-10-18 真机实测后补） ------------------------
   这三类是 `refresh.js` 在运行时注入样式的，**源码 CSS 里搜不到**，
   所以上面几档都没有覆盖到它们。真机 375px 实测溢出清单：

     div.rfs / span.rfs-age right=493   console / dashboard / demands / ops
     button.on               right=424
     div.wrap                right=1180  dashboard
     div.card                right=777   ops
     table thead / tr        right=667   demands

   ⚠️ 为什么不能靠「加一条更晚的规则」解决：refresh.js 是在
   `document.head` 里**动态插入** <style> 的，插入时机在本文件之后，
   同一特异度下**后插入的胜出**。所以这里必须用 `!important`
   才能盖住 refresh.js 注入的 `white-space:nowrap`。
   ⇒ 判据是 scripts\width-probe.py 的实测输出，不是「看起来够了」。 */
@media (max-width: 768px) {
  /* 刷新状态条：一行放不下就换行，不要把整页撑宽。
     ⚠️ `.rfs` 实际挂在 `HEADER.topbar` 内（实测 dashboard/console/
     demands/ops 四页皆然），而 topbar 自身是 nowrap 的 flex 行
     ⇒ 只给 `.rfs` 设 max-width 无用（它相对的是 518px 宽的父级）。
     ⇒ 必须连父容器一起放开。 */
  .topbar,
  header.topbar {
    flex-wrap: wrap !important;
    white-space: normal !important;
    min-width: 0 !important;
    max-width: 100% !important;
  }

  .rfs {
    flex-wrap: wrap !important;
    white-space: normal !important;
    min-width: 0 !important;
    max-width: 100% !important;
    gap: 6px 10px !important;
  }

  .rfs .rfs-age {
    white-space: normal !important;
    overflow-wrap: anywhere;
  }

  .ltag {
    white-space: normal !important;
    overflow-wrap: anywhere;
  }

  /* 容器：`max-width` **管不住 `min-width`**。实测 dashboard 页
     `.wrap { max-width:1720px; min-width:1180px }` ⇒ 元素被硬撑到
     1180px，把整页宽度顶开。所以窄屏下必须 min-width:0。
     ⚠️ 2026-10-19：此处原写有第二个选择器 `*-wrap`——**它不是合法选择器**
     （既非类型选择器也非类选择器）。Chrome 的容错恢复恰好保留了同一规则里
     的 `.wrap`，所以量起来「生效」；换一个严格解析器就会整条规则作废。
     已删除。原意若是给 `.table-wrap` 之类兜底，应显式写类名——
     而 `.table-wrap` 目前无任何页面使用（2026-10-19 grep 证实）。 */
  .wrap {
    max-width: 100% !important;
    min-width: 0 !important;
    padding-left: 12px !important;
    padding-right: 12px !important;
  }

  /* 卡片与大块同理：内部若有固定宽度子元素，卡片本身也会被撑开 */
  .card,
  .panel {
    max-width: 100% !important;
    min-width: 0 !important;
  }

  /* 表格：窄屏下改成**自身横向滚动**，而不是压缩到不可读。
     ⚠️ 这里三行缺一不可（2026-10-18 真机 375px 逐条试出来的）：
       · display:block —— 没有它，表格是 `display:table`，浏览器按内容
         的最小宽度给它布局，滚动容器退化为普通块，nowrap 直接把整页撑宽；
       · overflow-x:auto —— 提供滚动；
       · **不能有 white-space:nowrap** —— 实测 demands 页 thead/tr 到 667px。
         加了它，即使有 display:block + overflow-x:auto，表格的最小内容
         宽度仍会超过容器，而它本身就是那个滚动容器 ⇒ 横向滚动变成撑宽整页。 */
  table {
    display: block !important;
    max-width: 100% !important;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    white-space: normal !important;
  }
}

/* --- 6.5 公开结果表：窄屏一屏装下五列（2026-10-19 二次修，375px 实测） -----
   第一次修（≤768 全格 nowrap + 自身横滚）解决了域名拦腰断，但把**响应列
   挤出视口**：实测表格内容 496px vs 盒子 351px，末列左缘在 x=422 ——
   用户报「最后一列的响应时间完全检测不出来，wifi 符号也不见了」
   （2026-10-19 截图）。横滚对**表格**是「内容可达」，对**用户**是
   「内容藏起来了」—— 手机上没有人会想到去横滚一张表。

   ⇒ 二次修拆成两档（都经 375px 真机实测）：

   **档 A（≤768px，防拦腰断）**：统计格 nowrap，域名格**只**在 <wbr> 处折行
   （app.js 的 domainLink 在点号后插入 —— 点号是域名里唯一天然的断点）。
   盒子有 450px+ 时五列本来放得下；481~768px 被轻微挤压时长域名在点号
   折成两行，而不是拦腰断在标签中间。

   **档 B（≤480px，紧凑化装进一屏）**：375px 真机实测的组合拳 ——
     · 单元格 padding 10px → 5px（五列共省 50px）
     · 表头允许词内换行（表头不是数据，「Auto delivery」折成两行省约 50px）
     · 字号 12.5 → 11.5px，域名 <b> 13 → 12px
   ⇒ 实测 scrollWidth 351 = clientWidth 351：**零横滚**；50 条结果里
     48 条行高仍是 38px 单行，只有最长域名（23 字符）在点号折成两行。

   ⚠️ 只作用于 `.res .dtable`（公开结果表）。demands 页是 `table.dem`，
   2026-10-18 实测过它加 nowrap 会把整页撑宽（667px），不在本规则内；
   通用 `table { white-space: normal !important }` 对它继续生效。 */
@media (max-width: 768px) {
  .res .dtable td { white-space: nowrap; }
  /* 域名格是唯一允许折行的格，且折只折在 domainLink 插的 <wbr>（点号）处。
     overflow-wrap/word-break 归位是为了压掉第 2 节 `a{overflow-wrap:anywhere}`
     的任意处断行 —— 那条规则正是「gmailw|holesal|e.com」的来源。 */
  .res .dtable td.c-site {
    white-space: normal;
    overflow-wrap: normal;
    word-break: normal;
  }
  .res .dtable a,
  .res .dtable .domain {
    overflow-wrap: normal;
    word-break: normal;
  }
}

@media (max-width: 480px) {
  .res .dtable { font-size: 11.5px; }
  .res .dtable th,
  .res .dtable td {
    padding-left: 4px;
    padding-right: 4px;
  }
  /* 表头可折行 —— 它是标签不是数据；统计格保持单行（数字折行比域名折行更糟，
     档 A 的 nowrap 继续有效，这里只放开表头）。
     ⚠️ 放开折行**必须**同时把 word-break 归位：第 2 节的 `body{break-word}`
     会被 th 继承，于是「delivery」「Response」在窄列里被**词中断开**
     （2026-10-19 探针 P2 实测：delivery→2 行、Response→2 行）。表头只允许
     在空格处折（Auto / delivery），字号再降 0.5px 以保住最长单词。 */
  .res .dtable th {
    white-space: normal;
    word-break: normal;
    overflow-wrap: normal;
    font-size: 11px;
  }
  .res .dtable .c-site b { font-size: 12px; }
}

/* ≤340px（iPhone SE 一代 / 极窄安卓）：五列的**最小内容宽度**加起来约 319px，
   而 320px 视口的表格盒只有 296px —— 物理装不下，且此时任何进一步压缩都会
   牺牲可读性（探针实测 scrollWidth 345 > clientWidth 296）。
   ⇒ 降级：隐藏**域名年龄**列（第 4 列）。选它的理由：
     · 响应列是用户点名要看的（2026-10-19 报「完全检测不出来」）；
     · 自动发货 / 支付通道是成交事实，域名是身份，都不可省；
     · 域名年龄仍然在**档案栏**（点任意一行）里完整可见。
   ⚠️ 这是**极窄屏专属**降级，375/430 两个主流宽度不触发（实测零横滚）。 */
@media (max-width: 340px) {
  .res .dtable th:nth-child(4),
  .res .dtable td:nth-child(4) {
    display: none;
  }
}

/* --- 7. 打印（顺带修一个真问题） -----------------------------------------
   打印时导航/操作按钮应当消失——它们对读者没有意义，
   而留着会浪费纸张并可能造成空白页。 */
@media print {
  nav, footer, .no-print, button, .btn { display: none !important; }
  body { background: #fff !important; color: #000 !important; }
}