:root{
  --primary:#2563EB; --primary-hover:#1D4ED8; --primary-light:#EFF6FF;
  --green:#10B981; --green-light:#ECFDF5;
  --red:#EF4444; --red-light:#FEF2F2;
  --ink:#1F2937; --sub:#6B7280; --muted:#9CA3AF;
  --line:#E5E7EB; --bg-alt:#F9FAFB; --bg:#F3F4F6; --card:#FFFFFF;
  --shadow:0 1px 3px rgba(16,24,40,.06),0 1px 2px rgba(16,24,40,.04);
  --shadow-h:0 8px 24px rgba(16,24,40,.12);
}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,"PingFang SC","Microsoft YaHei",system-ui,sans-serif;
  background:var(--bg);color:var(--ink);line-height:1.5;-webkit-font-smoothing:antialiased}
.wrap{max-width:1480px;margin:0 auto;padding:24px 28px 64px}

/* header */
header{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:18px}
h1{font-size:22px;font-weight:700;letter-spacing:-.3px}
h1 .tag{font-size:11px;font-weight:600;color:#fff;background:var(--primary);
  padding:2px 8px;border-radius:6px;vertical-align:middle;margin-left:8px}
.header-left{display:flex;align-items:center;gap:14px;min-height:38px}   /* 两页标题行同高（含/不含期下拉都对齐）*/
.dc-select{font:inherit;font-size:13px;font-weight:600;color:var(--primary);
  border:1px solid var(--primary);border-radius:9px;padding:8px 14px;
  background:var(--primary-light);cursor:pointer;outline:none}
.dc-select:focus{box-shadow:0 0 0 2px rgba(37,99,235,.2)}
.sub{color:var(--sub);font-size:13px;margin-top:3px}

/* controls */
.controls{background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:12px 14px;box-shadow:var(--shadow);margin-bottom:16px;position:sticky;top:0;z-index:20;
  display:flex;flex-direction:column;gap:8px}
.ctrl-row{display:flex;gap:10px;align-items:flex-start}
.ctrl-left{display:flex;gap:10px;flex-wrap:wrap;align-items:center;flex:1;min-width:0}
.ctrl-right{display:flex;gap:10px;align-items:center;flex-shrink:0;margin-left:auto}
.numgroup{display:contents}   /* PC 透明(display:contents);手机端(≤768px)激活成整行 flex,见下方 media */
.controls input,.controls select{font:inherit;font-size:13px;border:1px solid var(--line);
  border-radius:9px;padding:8px 11px;background:var(--bg-alt);color:var(--ink);outline:none}
.controls input:focus,.controls select:focus{border-color:var(--primary);background:#fff}
.controls .search{min-width:180px;max-width:300px}
.ctrl-left select{min-width:80px;max-width:200px;flex:0 1 auto;overflow:hidden;text-overflow:ellipsis}
.controls .sep{width:1px;height:24px;background:var(--line);flex-shrink:0}
/* 上传新数据入口（跳转上传页 upload.yunxi.io，新标签打开）*/
.btn-upload{display:inline-flex;align-items:center;gap:6px;font:inherit;font-size:13px;font-weight:600;
  color:var(--primary);background:#fff;border:1px solid var(--primary);border-radius:9px;
  padding:8px 16px;cursor:pointer;transition:.15s;text-decoration:none;align-self:center}
.btn-upload:hover{background:var(--primary);color:#fff}
.btn-upload.active{background:var(--primary);color:#fff}   /* 当前所在页高亮（如收藏夹页的"收藏夹"按钮）*/
.brand-home{color:inherit;text-decoration:none}            /* 标题兼作"回看板"链接，样式同纯文字 */
.brand-home:hover{opacity:.82}
.seg{display:inline-flex;border:1px solid var(--line);border-radius:9px;overflow:hidden}
.seg button{font:inherit;font-size:13px;font-weight:500;border:none;background:var(--bg-alt);color:var(--sub);
  padding:5px 14px;line-height:18px;cursor:pointer;transition:.15s}   /* 中度压缩：按钮 28px(line-height18+padding5×2)、seg 外框 30px，与筛选控件齐平（原 8px→35.5px 偏高） */
.seg button.on{background:var(--primary);color:#fff}
.count{font-size:13px;color:var(--sub);font-weight:500;white-space:nowrap}
.chip-clear{font-size:12px;color:var(--primary);cursor:pointer;border:none;background:none;font-weight:600}
.sort-dir-btn{font-size:14px;font-weight:700;width:28px;height:28px;line-height:28px;text-align:center;border:1px solid var(--line);border-radius:6px;background:var(--card);cursor:pointer;color:var(--primary);padding:0}
.sort-dir-btn:hover{background:var(--primary-light)}
.controls .fl{font-size:12px;color:var(--sub);font-weight:600;white-space:nowrap}
.controls .rng{width:62px;padding:8px 8px}
.controls .dash{color:var(--sub);font-weight:600}

/* 统一顶栏 head：标题/导航行 + 筛选器排 整体吸顶（sticky）。
   bg 盖住下方滚动内容，z-index 压过卡片；padding-bottom 把"内容不被 head 挡住"的间距落在 head 内。*/
/* ===================== 三层通用 Head（全站:主看板/收藏夹/分析）===================== */
.head{position:sticky;top:0;z-index:50;margin-bottom:18px;border-radius:14px;overflow:hidden;
  border:1px solid var(--line);box-shadow:var(--shadow);background:#fff;
  transition:transform .28s ease,opacity .2s ease;will-change:transform}
/* Head 滚动隐藏:一旦滚动即整块上移隐藏,回到顶部才恢复(JS 加/去 .hd-hide) */
.head.hd-hide{transform:translateY(-108%);opacity:0;pointer-events:none}
/* 回到顶部按钮:固定右下角,滚动约一屏后浮现 */
.back-to-top{position:fixed;right:22px;bottom:22px;z-index:60;width:44px;height:44px;border-radius:50%;
  border:1px solid var(--line);background:#fff;color:var(--primary);box-shadow:var(--shadow-h);cursor:pointer;
  display:flex;align-items:center;justify-content:center;opacity:0;transform:translateY(12px);pointer-events:none;
  transition:opacity .2s ease,transform .2s ease}
.back-to-top svg{width:22px;height:22px}
.back-to-top.show{opacity:1;transform:translateY(0);pointer-events:auto}
.back-to-top:hover{background:var(--primary);color:#fff;border-color:var(--primary)}
/* 通用跑马灯:box 溢出时 inner 来回滚动(JS 给 box 加 .is-marquee + 设 --shift) */
@keyframes uiMarquee{0%,14%{transform:translateX(0)}86%,100%{transform:translateX(var(--shift))}}
/* 卡片渠道/地区:过长换行显示(已取消跑马灯滚动) */
.chans{flex-wrap:wrap;overflow:visible}
.ch{flex:0 1 auto;min-width:0;max-width:100%;white-space:normal}
.foot .left .region{flex:0 1 auto;min-width:0;max-width:100%;white-space:normal}
/* 第一层 · 标题栏（薄、居中、深浅背景自然分层，无分隔线）*/
.head-title{display:flex;justify-content:center;align-items:center;gap:8px;background:#fff;padding:4px 16px}
.head-title-txt{font-family:'Noto Sans SC',-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;
  font-size:13px;font-weight:700;letter-spacing:3px;color:#111827}   /* 标题 +1px：12→13 */
/* 云熙 logo：放大镜 + 内部蓝色上扬箭头，置于「独立站选品分析系统」标题左侧。
   做成 data-URI 背景图写在 CSS 一处 —— index / favorites / analysis 三页共用同一个
   .head-title-txt，改这里三页自动都有，零 HTML 改动（与本文件里日历图标同一路数）。
   ⚠️ 只取图形部分、不含 "yunxi" 手写体：标题栏高度只有 ~26px，手写体缩到 5px 高不可读。
   颜色与现有设计对齐：镜圈/手柄 #111827（= .head-title-txt 的字色），箭头 #2563EB（= --primary，
   与「内部版」徽标同色）。SVG 里的 # 必须写成 %23，否则被当成片段标识符、整张图不显示。 */
.head-title-txt::before{
  content:"";display:inline-block;width:20px;height:20px;
  vertical-align:-5px;margin-right:5px;   /* 5px + 字距 3px ≈ 视觉 8px，与 .head-title 的 gap 一致 */
  background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='none'%3E%3Cpath d='M21.8 21.8 29 29' stroke='%23111827' stroke-width='4.2' stroke-linecap='round'/%3E%3Ccircle cx='13.4' cy='13.4' r='10.6' stroke='%23111827' stroke-width='3.4'/%3E%3Cpath d='M7.6 16.8 10.9 11.9 13.9 14.6 18.6 8.2' stroke='%232563EB' stroke-width='2.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M15.1 8.2 18.6 8.2 18.6 11.7' stroke='%232563EB' stroke-width='2.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center/contain;
}
.head-tag{font-size:10px;font-weight:700;color:#4B5563;background:#E5E7EB;border-radius:5px;padding:2px 7px;letter-spacing:0}   /* 徽章 蓝底白字→浅灰底(#E5E7EB=--line)深字(#4B5563)，对比≈6:1，取自本文件既有灰系 */
/* 第二层 · 模块导航（全站一致）*/
.head-nav{display:flex;justify-content:space-between;align-items:center;gap:14px;flex-wrap:wrap;background:#fff;padding:2px 16px}
.nav-modules{display:flex;align-items:center;flex-wrap:wrap}
.nav-mod{display:inline-flex;align-items:center;gap:8px;height:34px;padding:0 15px;border-radius:10px;
  font-size:15px;font-weight:700;color:#4B5563;text-decoration:none;cursor:pointer;
  background:transparent;border:1px solid transparent;transition:.15s}
.nav-mod .nav-num{display:inline-flex;align-items:center;justify-content:center;width:21px;height:21px;border-radius:50%;
  font-size:12px;font-weight:700;color:#4B5563;background:transparent;border:1.5px solid #CBD1DA;flex-shrink:0}
.nav-mod:hover{background:#F3F4F6}   /* tab hover 用筛选框下拉 hover 同款浅灰 #F3F4F6（= .head .controls select:hover 196行，同值）；去掉原 #E7EAF0 边框，与下拉 hover 一样纯底色反馈、两行悬停成一套。🔴 激活态由下一行 .nav-mod.is-active（同特异性、后声明者胜）覆盖 → 蓝底白字不受影响 */
.nav-mod.is-active{background:#2563EB;color:#fff;box-shadow:0 2px 8px rgba(37,99,235,.28)}
.nav-mod.is-active .nav-num{background:#fff;color:#2563EB;border-color:#fff}
/* 模块连接符:纯装饰(三模块平级、非流程步骤);三连粗角标 ❯❯❯ */
.nav-sep{color:#A6ADB8;font-size:20px;letter-spacing:1px;margin:0 16px;user-select:none}
.nav-actions{display:flex;align-items:center;gap:10px;position:absolute;top:var(--head-actions-top);right:16px;z-index:2}   /* top 由 :root 的 --head-actions-top 控（下移量），建议 4-10px */
/* ↑ 上传/退出：绝对定位钉右上角。containing block = .head 的 position:sticky（已是定位值，不必也不许加 position:relative）。
   脱离 nav 行布局流 → nav 行塌到只剩 tab 高。右缘 16px 与原 .head-nav padding-right 对齐。窄屏恢复 static（见 media）。 */
.nav-act{display:inline-flex;flex-direction:column;align-items:center;gap:2px;padding:6px;border-radius:10px;   /* 去文字后收紧为方形图标钮：18图标+6×2=30px */
  font:inherit;font-size:11px;font-weight:600;line-height:1.1;text-decoration:none;cursor:pointer;
  background:transparent;border:1px solid transparent;transition:.15s}
.nav-act svg{width:18px;height:18px;display:block}   /* 图标化：20→18px（去文字后图标为唯一元素）*/
.nav-act-upload{color:#8A93A0}   /* 默认与退出统一：灰字、无底、无边（去掉原蓝底 #E9F1FF / 蓝字）*/
.nav-act-upload:hover{color:#2563EB;background:#E9F1FF;border-color:#BBD0FF}   /* hover 与退出同形式(色+底+边)，换蓝色系（#2563EB/#E9F1FF/#BBD0FF 均本文件既有）*/
.nav-act-logout{color:#8A93A0}
.nav-act-logout:hover{color:#DC2626;background:#FEF2F2;border-color:#F7C9C9}   /* 退出 hover 红系（原样，作为上传 hover 的参照形式）*/
/* 🔴 键盘可见焦点（不只做 hover）：上传蓝框、退出红框，各自呼应 hover 色 */
.nav-act-upload:focus-visible{outline:2px solid #2563EB;outline-offset:1px}
.nav-act-logout:focus-visible{outline:2px solid #DC2626;outline-offset:1px}
/* 第三层 · 筛选器（白底；各页放各自筛选器）*/
.head .controls,.head .tabs-row{background:#fff;border:none;border-radius:0;box-shadow:none;position:static;margin:0}
.head .controls{padding:10px 16px 11px;display:flex;flex-direction:column;gap:var(--head-row-gap)}
.head .tabs-row{padding:10px 16px 0;margin:0}
/* 第三层控件统一:高34px、圆角9px */
.head .controls input,.head .controls select,.head .who-btn{height:34px;border-radius:9px;
  border:1px solid #E3E6EA;color:#374151;background:#fff;font-size:13px;padding:6px 10px}
.head .controls .rng{width:66px;padding:6px 8px}
.head .controls .search{height:34px}
.head .controls .chip-clear,.head .controls .sort-dir-btn{height:34px;border-radius:9px}
/* 数据期下拉:第三层打头、蓝色强调 + 日历图标 */
.head .dc-select{height:34px;border-radius:9px;font-weight:600;color:#1D4ED8;background:#F5F8FF;border:1px solid #BBD0FF;
  padding:6px 10px 6px 30px;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='%231D4ED8' stroke-width='2' stroke-linecap='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cpath d='M16 2v4M8 2v4M3 10h18'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:9px center}

/* 期数下拉「精确 10 行 + 超出滚动」（主看板 #dcsel / 收藏页 #fperiod 共用一份）。
   期×渠道组合已有 35 个，原生 select 展开后长到铺满屏幕；而原生下拉的弹出层是
   浏览器/系统画的、CSS 完全够不到（给 select 加 max-height 只会压扁收起态那个框）。
   appearance:base-select（Chromium 135+）把弹出层交还给 CSS，于是能精确控制到行。
   ⚠️ 必须包在 @supports 里：不支持的浏览器连 option{height:32px} 都读不到，
      直接回退成原生下拉——功能完全正常，只是没有 10 行限制。
   ⚠️ 行高写死 32px 而非靠内容撑：328 能被 32 整除，第 11 行才会干净地切在边界外；
      若用 line-height:normal，不同系统字体会让"10 行"变成 9.6 或 10.4 行，露半行更难看。
   零 JS 改动：select 的 add()/value/change/selectedOptions 全部原样可用。 */
@supports (appearance: base-select) {
  /* ⚠️ 两边都要设：只给 select 设，弹出层仍是原生渲染、会忽略下面的 max-height
     （表现为 option 的配色行高生效、但下拉照样铺满整屏）。picker 也必须进入 base 模式。 */
  .dc-select, .dc-select::picker(select),
  #fperiod,  #fperiod::picker(select) { appearance: base-select; }

  .dc-select::picker(select), #fperiod::picker(select){
    max-height:328px;              /* 10 行 × 32px + 上下 padding 4px×2 */
    overflow-y:auto;
    padding:4px 0;
    border:1px solid #BBD0FF;border-radius:10px;background:#fff;
    box-shadow:0 8px 24px rgba(15,23,42,.14);
  }
  .dc-select option, #fperiod option{
    height:32px;line-height:32px;  /* 固定行高，勿改成 auto，见上方说明 */
    padding:0 12px;font-size:13px;
    /* 🔴 未选中 option 与按钮看齐：文字 #4B5563 + 字重 600（按钮 .dc-select/#fperiod = #4B5563/600）。
       原为 700 且未设 color → 继承回退成黑 #000，与按钮 600 灰不一致；现显式钉 #4B5563/600。
       #fperiod 无 .dc-select 类，否则继承 .controls select 的 400，故在共享规则里直接钉、两页一致。
       选中项 :checked（下一行）仍 #0C447C/700 + ✓ → 未选灰、选中深蓝加粗，清楚区分。不用 !important、不动收起态。 */
    color:#4B5563;font-weight:600;
    display:flex;align-items:center;
  }
  .dc-select option:hover,  #fperiod option:hover  {background:#F5F8FF}
  .dc-select option:checked,#fperiod option:checked{background:#EFF6FF;color:#0C447C;font-weight:700}   /* 选中项文字改与按钮同色 #0C447C(实测 rgb 12,68,124)；浅蓝底 #EFF6FF 保留作"这行选中"提示 */
  /* ::picker-icon（base-select 自带的下拉箭头）【保留不隐藏】。原打算隐藏它以避让
     .head .dc-select 的日历背景图，但实测那张图【本来就没在显示】——第 115 行的
     `.head .controls select`(0,3,1) 特异性高于第 121 行的 `.head .dc-select`(0,2,0)，
     把 background-image 覆成了 initial（既有问题，与本次改动无关）。
     既然没有图标可撞，隐藏箭头只会让下拉【失去唯一的展开指示】；且实测宽度
     隐藏=80px / 保留=89.7px / 原生=95.2px —— 保留也更接近原来的尺寸。 */
}

/* ═══════════ Head 视觉改造 · 筛选栏无边框风格（选品+收藏两页共用）═══════════
   🔴 特异性：现有 .head .controls input/select 是 (0,3,1)、.head .dc-select (0,2,0) 会压新样式，
      故新规则一律 .head .controls 作用域(≥(0,3,1))且排在旧规则之后 → 特异性+顺序双覆盖（当年日历图标就是栽在这）。
   🔴 base-select 两个 (#dcsel/#fperiod) 绝不 appearance:none——只去边框、期数深蓝、箭头走 ::picker-icon。
   🔴 字重 spec I：未设 600 / 已设·期数 700 / 标签·计数·分段·清空 500。
      （Windows 实测：中文 600≈700，已筛选区分靠颜色+底色；期数/数字是拉丁，600/700/500 三档有效） */
.head .controls{padding:7px 14px}

/* —— 下拉：去边框 + hover 淡底 + focus 描边（base-select 与原生共同底子）—— */
.head .controls select{
  height:30px;border:0;background:transparent;color:#4B5563;
  font-size:13px;font-weight:600;border-radius:6px;
  padding:0 26px 0 9px;cursor:pointer;transition:background-color .12s}
.head .controls select:hover{background-color:#F3F4F6}
.head .controls select:focus{outline:2px solid #B5D4F4;outline-offset:0}
/* 原生 6 个（排除 base-select 两个）：appearance:none + 背景图 chevron（描边非实心，右 6px 居中，不重复）。
   🔴 修①：appearance:none 的 select 会被【最宽 option】撑开（加载后选项变长 → 收起态被拉很宽、文字与箭头中间大空）。
      field-sizing:content 让它按【当前选中值】自适应（Chromium 123+，本浏览器 base-select 135+ 必支持）；
      max-width 兜住超长选中值、overflow+ellipsis 截断，保证收起态始终紧凑、加载中/加载后一致。 */
.head .controls select:not(.dc-select):not(#fperiod){
  appearance:none;-webkit-appearance:none;
  field-sizing:content;max-width:170px;overflow:hidden;text-overflow:ellipsis;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='.55'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 6px center}
/* 试：普通 select（非 base-select 的 6 个：L1/L2/L3/渠道/地区/默认排序）弹层 option 字重 → 600，与各自按钮(600)一致。
   🔴 :not(.dc-select):not(#fperiod) 显式排除数据期两个 base-select 弹层，绝不波及它们。
   ⚠️ 原生 select 弹层由浏览器/OS 绘制；getComputedStyle 读得到 ≠ 弹层真渲染出来，需真机肉眼确认。 */
.head .controls select:not(.dc-select):not(#fperiod) option{font-weight:600}
/* 已筛选高亮（JS 加 .is-set）：淡蓝底 + 深蓝字 + 加粗 + chevron 深蓝。
   🔴 base-select Chromium 里 <select> 不吃 background-color、只吃 background-image → 用 linear-gradient
      当填充（叠在 chevron 之下，两层背景）。特异性抬到 (1,4,1) 压过上面原生 chevron 规则 (1,3,1)。 */
.head .controls select.is-set:not(.dc-select):not(#fperiod){
  color:#0C447C;font-weight:700;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%230C447C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='.65'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"),linear-gradient(#E6F1FB,#E6F1FB);
  background-repeat:no-repeat,no-repeat;background-position:right 6px center,0 0;background-size:auto,100% 100%}
/* 🔴 base-select 两个（#dcsel/#fperiod）：保留 base-select，去边框/底色 + 期数深蓝加粗。
   🔴 修①（期数错位）：箭头改用【与原生下拉同款的背景图 chevron】（base-select 吃 background-image，实测），
      位置 calc(100%-6px)、padding-right:26px 与原生 f1 完全一致 → 两套箭头到右缘的距离像素级对齐；
      深蓝 opacity .7 表期数（原生是灰 .55）。同时隐藏 base-select 自带的 ::picker-icon（见下）避免双箭头。
      ⚠️ 只动收起态按钮的箭头，picker(::picker(select) 328px / option 32px / ✓ / ::checkmark)全不受影响。 */
.head .controls .dc-select,.head .controls #fperiod{
  color:#4B5563;font-weight:600;border:0;background-color:transparent;   /* 方案A：按钮与普通下拉(#f1)完全一致——灰 #4B5563 / 600（弹层选中项仍深蓝 #0C447C，见 :checked 规则，不动）*/
  padding:0 26px 0 9px;
  line-height:30px;   /* 修②·数据期文字错位：base-select 按钮不像原生 select 垂直居中选中文字，把它顶到偏上约 5.25px(半行距)；lh=盒高(30) 让行盒撑满按钮→文字回到与原生 f1 同一水平线(实测 relTop 5.25→0.25)。⚠️ option 第160行有显式 line-height:32px，级联"显式胜过继承"挡住此值→弹层 10行/✓/::checkmark/滚动 全不受影响 */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='.55'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:calc(100% - 6px) center}
.head .controls .dc-select:hover,.head .controls #fperiod:hover{background-color:#F3F4F6}
@supports (appearance: base-select){
  #dcsel::picker-icon,#fperiod::picker-icon{display:none}   /* 隐藏自带箭头，改用上面的背景图 chevron（与原生一致）*/
}

/* —— 收藏人 .who-btn（团队夹专属，第三套）：去边框 + chevron，视觉同其他项。⚠️ 只改样式不碰显隐 —— */
.head .controls .who-btn{
  height:30px;border:0;background:transparent;color:#4B5563;font-weight:600;font-size:13px;
  border-radius:6px;padding:0 26px 0 9px;cursor:pointer;transition:background-color .12s;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='.55'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 6px center}
.head .controls .who-btn:hover{background-color:#F3F4F6}
/* button 同 select：不吃 background-color → is-set 填充用 linear-gradient 背景图（叠在 chevron 下）*/
.head .controls .who-btn.is-set{
  color:#0C447C;font-weight:700;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%230C447C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='.65'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"),linear-gradient(#E6F1FB,#E6F1FB);
  background-repeat:no-repeat,no-repeat;background-position:right 6px center,0 0;background-size:auto,100% 100%}

/* —— 搜索框/通用输入容器 .field：去边框 + 浅底填充（#EDEFF2），内放 icon + input —— */
.head .controls .field{
  display:inline-flex;align-items:center;gap:7px;height:30px;
  background:#EDEFF2;border-radius:7px;padding:0 7px;transition:.12s;border:0}
.head .controls .field:focus-within{background:#fff;box-shadow:0 0 0 2px #B5D4F4}
.head .controls .field.is-set{background:#E6F1FB}
.head .controls .field svg{flex:none;opacity:.55}
.head .controls .field.is-set svg{opacity:.85}
.head .controls .field input{
  border:0;background:transparent;outline:0;font-size:13px;font-family:inherit;
  color:#1F2937;width:100%;min-width:0;padding:0;font-weight:600;height:auto}
.head .controls .field.is-set input{color:#0C447C;font-weight:700}
.head .controls .field input::placeholder{color:#9CA3AF;font-weight:400}
/* 🔴 搜索框：字号 12px、静态文案、两页等宽 220px（容长文案≈177.8px + 图标15 + gap7 + padding14 + 缓冲）。
   图标+文字【整组居中】(justify-content:center + input field-sizing 贴合文字)；有值/聚焦 → 靠左 + 文字左对齐
   （输入时从左往右长，不别扭）。纯 CSS 用 :focus-within / :has，无需 JS。⚠️ 只作用搜索框，单量/增长率不变。 */
.head .controls .field.search{width:220px;justify-content:center}
.head .controls .field.search input{
  width:auto;field-sizing:content;max-width:100%;text-align:center;font-size:12px;
  line-height:28px}   /* 🔴 光标加长①：caret 高度由 line-height 派生(Chrome/Blink)，字号锁死 12px 不变；line-height 18→28px 让竖线接近筛选栏内高上限（输入框内高随之 18→28px，仍 <30px 的 .field，不撑破/不变形）。⚠️ 严格 2×≈caret 36px 需 >30px 会顶破 30px 筛选栏，故上限约 28px（见提交说明的可达倍数） */
.head .controls .field.search:focus-within,
.head .controls .field.search:has(input:not(:placeholder-shown)){justify-content:flex-start}
.head .controls .field.search:focus-within input,
.head .controls .field.search:has(input:not(:placeholder-shown)) input{text-align:left}
/* 🔴 去掉②：type=search 输入后出现的浏览器原生一键清空 x（::-webkit-search-cancel-button）——
   纯浏览器 UI、无 JS 依赖；筛选行最右「清空」(#clear) 另有 handler 会清空 #q(app.js:679 的 q.value='')，
   删这个 x 不影响任何 清空/搜索/筛选 逻辑，两页(#q 均 type=search)共用此规则一并生效。 */
.head .controls .field.search input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none;display:none}

/* —— 单量/增长率合并容器 .range（#EDEFF2）+ 内嵌更浅输入槽 .well（#FAFBFC，比外层浅一档）—— */
.head .controls .range{
  display:inline-flex;align-items:center;gap:4px;height:30px;
  background:#EDEFF2;border-radius:7px;padding:0 7px;transition:.12s;border:0;--wellBg:#FAFBFC}
.head .controls .range:focus-within{box-shadow:0 0 0 2px #B5D4F4}
.head .controls .range.is-set{background:#E6F1FB;--wellBg:#F2F8FE}
.head .controls .well{
  display:inline-flex;align-items:center;height:20px;
  background:var(--wellBg);border-radius:4px;padding:0 5px;transition:.12s}
.head .controls .well:focus-within{box-shadow:0 0 0 1px #A9C7EE inset}
/* 🔴 修③：type=number 默认有 spin 上下按钮，吃掉宽度 → "min"/"max" 被截成 "mir"/"ma:"。
   appearance:none + 隐藏 spin 按钮腾出宽度，并把 36px 加宽到 44px 完整显示占位文字。 */
.head .controls .well input{
  appearance:none;-webkit-appearance:none;
  border:0;background:transparent;outline:0;font-size:13px;font-family:inherit;
  color:#1F2937;width:44px;text-align:center;padding:0;font-weight:600;height:auto}
.head .controls .well input::-webkit-inner-spin-button,.head .controls .well input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
.head .controls .well.w2 input{width:34px}
.head .controls .well input::placeholder{color:#9CA3AF;font-weight:400}
.head .controls .range.is-set .well input{color:#0C447C;font-weight:700}
.head .controls .range .tilde,.head .controls .range .op,.head .controls .range .unit{
  color:#9CA3AF;font-size:12px;user-select:none;flex:none}
.head .controls .range.is-set .tilde,.head .controls .range.is-set .op,.head .controls .range.is-set .unit{color:#0C447C;opacity:.7}

/* —— 标签 .fl / 计数 / 分段控件：字重 500（spec I 微标签档）—— */
.head .controls .fl{font-size:12px;color:#9CA3AF;white-space:nowrap;font-weight:500;margin:0 2px}
.head .controls .count{font-weight:500}
.head .controls .seg button{font-weight:600;display:inline-flex;align-items:center;justify-content:center;gap:6px}   /* 卡片/表格·个人夹/团队夹 加粗 500→600（选中/未选中共用，.on 不覆写字重）*/
.head .controls .seg svg{flex:none}

/* —— 清空 .chip-clear：深蓝字 500 + filter-off 图标 + hover 淡蓝底 + 无筛选失效态 —— */
.head .controls .chip-clear{
  border:0;background:transparent;color:#0C447C;font-weight:500;font-size:12px;
  height:26px;display:inline-flex;align-items:center;gap:5px;padding:0 9px;border-radius:6px;
  cursor:pointer;transition:.12s;white-space:nowrap;width:auto;min-width:0}
.head .controls .chip-clear svg{flex:none}
/* 🔴 button 不吃 background-color（实测同 select/who-btn）→ hover 淡蓝底用 linear-gradient 兜底 */
.head .controls .chip-clear:hover{background-image:linear-gradient(#E6F1FB,#E6F1FB)}
.head .controls .chip-clear.is-off{color:#D1D5DB;cursor:default;pointer-events:none;background:transparent}

/* —— J. 两排之间的底部间距：分隔线已移除；行距现由 --head-row-gap 统一控制，此处 padding-bottom 归 0 —— */
.head .controls>.ctrl-row:first-child{padding-bottom:0}

/* ============ head 紧凑 · 两个可调变量（都在下面 :root 一处，改数字即可微调）============
   --head-row-gap   ：筛选行↔搜索行的行距（越小搜索行越贴上；默认 5px，别设 0）。
   --head-right-lift：右侧三组整体上抬量（transform，默认 7px）。分组：
        ① 上传/退出 = .nav-actions（三页，含 analysis）
        ② 计数+卡片/表格 = 筛选行 .ctrl-right
        ③ 个人夹/团队夹 = 收藏页搜索行 .ctrl-right
   🔴 lift 用 transform（不参与布局 → head 总高/行高/四处锁死不受扰动；负 margin 才会扰动，故不用）。
   🔴 上抬上限（压行距后重测）：三组共用一个变量、一起等量上移 → ②↔① 恒 11px、③↔② 恒 5px（实测 5/7/8px 均不变、
      不会相撞）；唯一真上限是 ① 升到与标题文字齐平 = 8px（再高 ① 被 .head 的 overflow:hidden 裁切，绝对硬顶 32px）。
      故 MAX=8px，取 85% ≈ 7px（① 距标题仍留 1px、距裁切 25px）。
   ⚠️ 调法：只改下面 :root 里这两个数字（调大更紧凑/更高，① 别超 8px 免得压到标题）。窄屏(≤768)上抬已归零。 */
:root{--head-row-gap:5px; --head-right-lift:7px; --head-actions-top:7px}
/* --head-right-lift 现只作用 ②③（① 上传/退出已改绝对定位、不再参与上抬） */
.head .controls>.ctrl-row:first-child>.ctrl-right,
.head .controls>.ctrl-row:nth-child(2)>.ctrl-right{
  transform:translateY(calc(-1 * var(--head-right-lift)))}
@media(max-width:768px){   /* 窄屏 head 紧凑：上传/退出钉右上 + 图标缩小 */
  :root{--head-right-lift:0px}
  .head-nav .nav-actions{position:absolute;top:4px;right:10px;gap:6px}
  .nav-act{padding:3px;border-radius:8px}
  .nav-act svg{width:15px;height:15px}
}

/* 🔴 手机端(≤768px) head 两处紧凑（仅窄屏，PC 端不变；用的都是 Safari 安全属性） */
@media(max-width:768px){
  /* ① 选品/收藏/分析 三 tab 一行不换行：缩 tab 间距/箭头/字号 */
  .nav-modules{flex-wrap:nowrap;white-space:nowrap}
  .nav-mod{padding:0 8px;gap:4px;font-size:13px}
  .nav-mod .nav-num{width:18px;height:18px}
  .nav-sep{margin:0 4px;font-size:13px}
  /* ② 手机端：筛选只留图标(去文字)；个人/团队/卡片/表格 保留图标+文字、缩框让五者一行
     (第0步实测 375px 下五钮共 282px < 可用 345px、不换行)。功能不变，仅视觉。 */
  .btn-tx{display:none}                                    /* 默认隐藏文字 → 筛选按钮只剩图标 */
  .filter-toggle{padding:6px 9px;gap:2px}
  .head .controls .seg button .btn-tx{display:inline}      /* seg 四钮(个人/团队/卡片/表格)恢复文字 */
  .head .controls .seg button{padding-left:7px;padding-right:7px;font-size:12px;gap:3px}   /* 缩框 + 字号 13→12 */
  .head .controls .seg svg{width:12px;height:12px}         /* 图标 13→12 略缩 */
}

/* cards */
.grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
/* 修改①：段分隔线（.seg-sep / #tableview tr.seg-sep）已删除——各期首尾相接、无视觉边界，
   期数与边界只由顶部总计"已加载N期·筛选后X/共Y个"体现。对应 JS 的 cardSepHTML/tableSepHTML 也已删。 */
/* 滚动自动加载（第③步）：sentinel(观察触发点) + 状态区(加载中/失败重试/末期/上限)。JS 创建 #loadMoreWrap 插在两视图之后。 */
#loadMoreWrap{display:flex;flex-direction:column;align-items:center;padding:8px 0 44px}
#loadSentinel{width:1px;height:1px}   /* 观察哨兵：极小不占视觉；靠 rootMargin 提前触发 */
#loadMoreStatus{min-height:20px;font-size:13px;font-weight:500;color:var(--sub);
  display:flex;align-items:center;gap:10px;padding:10px 0}
#loadMoreStatus.lm-idle{display:none}                 /* 静默态：不占位 */
#loadMoreStatus.lm-loading{color:var(--primary)}
#loadMoreStatus.lm-end{color:var(--muted)}
#loadMoreStatus.lm-error{color:var(--red)}
#loadMoreStatus .lm-retry{font:inherit;font-size:13px;font-weight:600;color:var(--primary);
  background:var(--primary-light);border:1px solid var(--primary);border-radius:8px;padding:5px 16px;cursor:pointer;transition:.15s}
#loadMoreStatus .lm-retry:hover{background:var(--primary);color:#fff}
.card{background:var(--card);border:1px solid var(--line);border-radius:14px;overflow:hidden;
  box-shadow:var(--shadow);transition:.16s;display:flex;flex-direction:column;position:relative}
.card:hover{box-shadow:var(--shadow-h);transform:translateY(-2px)}
.card-img{width:100%;aspect-ratio:1/1;overflow:hidden;position:relative;background:var(--line);
  display:flex;align-items:center;justify-content:center;cursor:pointer;color:inherit}
.card-img:hover{opacity:.95}
.card-img img{width:100%;height:100%;object-fit:cover;display:block}
.card-img .initial{font-size:36px;font-weight:800;color:#fff;opacity:.9}
.card-img .l1tag{position:absolute;bottom:0;left:0;right:0;font-size:10px;font-weight:600;
  background:rgba(0,0,0,.45);color:#fff;padding:2px 5px;text-align:center;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;z-index:2}
.card-sib-overlay{position:absolute;bottom:10px;right:10px;display:flex;gap:6px;z-index:3;
  opacity:0;transform:scale(.8);transition:opacity .2s ease,transform .2s ease;pointer-events:none}
.card-img:hover .card-sib-overlay{opacity:1;transform:scale(1);pointer-events:auto}
.card-sib-overlay a{display:block;width:40px;height:40px;border-radius:8px;overflow:hidden;
  border:2px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,.25);transition:.2s;cursor:pointer}
.card-sib-overlay a:hover{transform:scale(1.1);border-color:var(--primary)}
.card-sib-overlay .sib-ph{width:100%;height:100%;display:flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:700;color:var(--sub);background:var(--line)}
.card-sib-overlay a img{width:100%;height:100%;object-fit:cover}
.card-img .swap-overlay{position:absolute;inset:0;opacity:0;transition:opacity .3s ease;
  display:flex;align-items:center;justify-content:center;pointer-events:none;z-index:1;background:var(--line)}
.card-img .swap-overlay.show{opacity:1}
.card-img .swap-overlay .initial{font-size:36px}
.card-fav{position:absolute;top:8px;right:8px;z-index:4;
  width:40px;height:40px;border-radius:50%;background:rgba(255,255,255,.85);
  border:none;cursor:pointer;font-size:18px;line-height:1;color:var(--muted);
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 1px 4px rgba(0,0,0,.15);transition:.15s}
.card-fav:hover{transform:scale(1.15);background:#fff}
.card-fav.active{color:var(--primary)}
.card-body{padding:10px 12px 0;flex:1;display:flex;flex-direction:column;gap:5px}
.pname{font-size:14px;font-weight:600;line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;
  -webkit-box-orient:vertical;overflow:hidden}
.crumbs{font-size:11px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.metrics{display:flex;gap:0;margin-top:4px;align-items:stretch}
.m{flex:1;border-radius:8px;padding:6px 8px;text-align:center;min-width:0;background:var(--bg-alt)}
.m .k{font-size:10px;color:var(--sub);font-weight:500}
.m .v{font-size:15px;font-weight:700;line-height:1.2;color:var(--ink)}
.m.hl .v{color:var(--primary)}
.m .v.gpos{font-size:13px;color:var(--green)}
.m .v.gneg{font-size:13px;color:var(--red)}
.sparkline-wrap{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:4px 6px;min-width:0;background:var(--bg-alt);border-radius:8px}
.sparkline-wrap .k{font-size:10px;color:var(--sub);font-weight:500;margin-bottom:1px}
.chans{display:flex;gap:5px;flex-wrap:wrap;padding:0 12px;margin-top:4px}
.ch{font-size:10px;font-weight:600;padding:2px 7px;border-radius:6px;background:var(--primary-light);color:var(--primary)}
.region{font-size:11px;font-weight:600;color:var(--sub)}
.foot{padding:9px 12px;margin-top:auto;border-top:1px solid var(--line);display:flex;align-items:center;
  justify-content:space-between;gap:8px}
.foot .left{display:flex;align-items:center;gap:10px;min-width:0}
.price{font-size:15px;font-weight:700}
.visit-sm{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;
  border-radius:8px;border:1px solid var(--line);background:#fff;cursor:pointer;transition:.15s;
  text-decoration:none;color:var(--primary);flex-shrink:0}
.visit-sm:hover{background:var(--primary-light);border-color:var(--primary)}
.visit-sm svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.adbtn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;
  border-radius:8px;border:1px solid var(--line);background:#fff;cursor:pointer;transition:.15s;flex-shrink:0}
.adbtn:hover{background:var(--primary-light);border-color:#1877F2}
.adbtn svg{display:block}
td.thcell{width:62px;padding:6px 8px;position:relative}
td.thcell img{width:50px;height:50px;object-fit:cover;border-radius:8px;background:var(--bg);display:block}
td.thcell .ph{width:50px;height:50px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:var(--sub);font-weight:700;font-size:16px;background:var(--line)}
.hover-big{display:none;position:absolute;z-index:100;left:calc(100% + 4px);top:calc(100% - 10px);
  width:300px;height:300px;border-radius:12px;overflow:hidden;
  box-shadow:0 8px 32px rgba(0,0,0,.25);border:3px solid #fff;background:var(--line);pointer-events:none}
td.thcell .hover-big img{width:100%;height:100%;object-fit:cover;border-radius:0}
.hover-big .ph-big{width:100%;height:100%;display:flex;align-items:center;justify-content:center;
  font-size:48px;font-weight:800;color:var(--sub);opacity:.9}
td.thcell:hover .hover-big{display:block}
/* favorite */
.fav-btn{background:none;border:none;cursor:pointer;font-size:18px;padding:2px;transition:.15s;line-height:1;color:var(--muted)}
.fav-btn:hover{transform:scale(1.2)}
.fav-btn.active{color:var(--primary)}
td.favcell{text-align:center;width:50px;padding:6px 8px}
th.favcell-head{text-align:center;width:50px;padding:6px 8px;font-size:12px}
th.favcell-head .fav-btn{font-size:16px}
/* sparkline */
td.sparkcell{padding:6px 8px;width:80px;text-align:center}
/* siblings */
td.sibcell{padding:6px 8px;vertical-align:middle}
.sib-thumbs{display:flex;gap:5px}
.sib-thumbs a{display:block;width:40px;height:40px;border-radius:8px;overflow:visible;
  border:1px solid var(--line);transition:.15s;position:relative}
.sib-thumbs a img{border-radius:8px}
.sib-thumbs a:hover{transform:scale(1.1);box-shadow:0 2px 8px rgba(0,0,0,.2)}
.sib-thumbs .sib-ph{width:100%;height:100%;display:flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:700;color:var(--sub);background:var(--line)}
.sib-thumbs a img{width:100%;height:100%;object-fit:cover}
.sib-thumbs a .sib-hover-big{display:none;position:absolute;z-index:100;left:calc(100% + 4px);top:calc(100% - 8px);
  width:300px;height:300px;border-radius:10px;overflow:hidden;
  box-shadow:0 6px 24px rgba(0,0,0,.25);border:2px solid #fff;background:var(--line);pointer-events:none}
.sib-thumbs a .sib-hover-big img{width:100%;height:100%;object-fit:cover;border-radius:0}
.sib-thumbs a .sib-hover-big .ph-big{width:100%;height:100%;display:flex;align-items:center;
  justify-content:center;font-size:36px;font-weight:800;color:var(--sub);opacity:.9}
.sib-thumbs a:hover .sib-hover-big{display:block}
/* inline ad icon */
.adbtn-sm{display:inline-flex;align-items:center;vertical-align:middle;margin-left:4px;opacity:.7;transition:.15s}
.adbtn-sm:hover{opacity:1}
/* copy toast */
.copy-toast{position:fixed;top:20px;left:50%;transform:translateX(-50%);
  background:var(--ink);color:#fff;padding:8px 18px;border-radius:8px;font-size:13px;font-weight:600;
  box-shadow:0 4px 16px rgba(0,0,0,.2);z-index:999;opacity:0;transition:opacity .2s;pointer-events:none}
.copy-toast.show{opacity:1}

/* table —— overflow 用 visible（不建滚动上下文），表头 sticky 才能吸到"视口"顶部实现冻结表头 */
.tablewrap{background:var(--card);border:1px solid var(--line);border-radius:14px;overflow:visible;box-shadow:var(--shadow)}
table{width:100%;border-collapse:collapse;font-size:13px}
th,td{padding:10px 12px;text-align:left;border-bottom:1px solid var(--line);vertical-align:middle}
/* 冻结表头:滚动时表头行固定在视口顶(此时 head 已滚动隐藏，顶部只此一条，不打架) */
th{background:var(--bg-alt);font-weight:600;font-size:12px;color:var(--sub);position:sticky;top:0;z-index:15;
  cursor:pointer;user-select:none;white-space:normal;min-width:50px}
th:hover{color:var(--primary)}
th.sorted{color:var(--primary);background:var(--primary-light)}
th.sort-desc::after{content:' ↓';font-size:11px}
th.sort-asc::after{content:' ↑';font-size:11px}
th.num{font-size:11px;text-align:center;padding:8px 6px;min-width:60px}
tbody tr:hover{background:var(--bg-alt)}
td.num{text-align:center;font-variant-numeric:tabular-nums;font-weight:600;padding:8px 6px}
td a{color:var(--primary);text-decoration:none}
td a:hover{text-decoration:underline}
td.namecell{white-space:normal;max-width:180px;min-width:100px;line-height:1.35}
td.namecell a{color:var(--ink);font-weight:600;text-decoration:none}
td.namecell a:hover{color:var(--primary);text-decoration:underline}
td.catcell{white-space:normal;max-width:160px;min-width:80px;line-height:1.35;color:var(--ink)}
td.encell{white-space:normal;max-width:180px;min-width:100px;font-size:12px;color:var(--sub);line-height:1.35;
  cursor:copy;position:relative}
td.encell:hover{color:var(--ink);background:var(--bg-alt)}
.clamp2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* channel + region dual-row in table */
td.chancol,td.regioncol{padding:8px 6px;vertical-align:middle;min-width:80px}
.chan-stack,.region-stack{display:flex;flex-direction:column;gap:3px}
.chan-row,.region-row{font-size:12px;font-weight:600;white-space:normal}
.chan-row .cname{color:var(--primary)}
.chan-row .cval,.region-row .rval{color:var(--sub);font-weight:500;margin-left:3px}
.region-row .rname{color:var(--ink)}

/* 收藏页的 .fav-empty / .fav-loading 原本定义在 favorites.html 自己的内联 <style> 里
   （padding:50px、无 font-size），与主看板这里的 60px + 15px 不一致 —— 同一个产品两页两副样子。
   已把那条内联规则删掉、并入这里，两页加载/空状态从此同源。
   ⚠️ 内联 <style> 排在 style.css 之后、同特异性会覆盖它，所以必须删源头才生效，光改这里没用。 */
.empty,.fav-empty{text-align:center;padding:60px 20px;color:var(--sub)}
.hidden{display:none!important}
.loading,.fav-loading{text-align:center;padding:60px 20px;color:var(--sub);font-size:15px}
/* 两页的加载容器初始留空，只在 JS 写入「加载中…」或「加载失败：…」时才现身。
   :empty 让空的时候不占那 120px 上下留白——否则静态骨架屏会被凭空推下去一大截。 */
.loading:empty,.fav-loading:empty{display:none}
@media(max-width:1100px){.grid{grid-template-columns:repeat(2,1fr)}}

/* ── 筛选折叠 ── */
.filter-toggle{display:none}
.filter-badge{display:none}

@media(max-width:768px){
  .wrap{padding:12px 10px 48px}
  .controls{padding:10px 12px;gap:6px}

  /* 第一行：筛选按钮 + count + 卡片/表格；下拉默认隐藏，展开时两列显示 */
  .controls>.ctrl-row:first-child{flex-wrap:wrap}
  .controls>.ctrl-row:first-child .ctrl-left{display:none}
  .controls.filter-open>.ctrl-row:first-child .ctrl-left{
    display:flex;flex-wrap:wrap;gap:8px;flex-basis:100%;order:10}
  .controls.filter-open>.ctrl-row:first-child .ctrl-left select{
    flex:1 1 calc(50% - 4px);min-width:0;max-width:none}
  .controls.filter-open>.ctrl-row:first-child .ctrl-left select#frg{flex:1 1 100%}

  .filter-toggle{display:inline-flex;align-items:center;gap:4px;
    font:inherit;font-size:13px;font-weight:600;color:var(--primary);
    background:var(--primary-light);border:1px solid var(--primary);
    border-radius:9px;padding:7px 12px;cursor:pointer;white-space:nowrap;
    flex-shrink:0;transition:.15s}
  .filter-toggle:hover{background:var(--primary);color:#fff}
  .filter-toggle-icon{width:14px;height:14px;flex-shrink:0}
  .filter-chevron{width:14px;height:14px;flex-shrink:0;transition:transform .3s ease}
  .filter-toggle[aria-expanded="true"] .filter-chevron{transform:rotate(180deg)}

  .filter-badge{display:inline-flex;align-items:center;justify-content:center;
    background:var(--primary);color:#fff;font-size:11px;font-weight:700;
    min-width:18px;height:18px;border-radius:9px;padding:0 5px;margin-left:2px}
  .filter-badge:empty{display:none}

  /* 折叠面板：下拉 + 搜索/单量/排序 */
  .filter-panel{display:flex;flex-direction:column;gap:8px;
    max-height:500px;opacity:1;overflow:hidden;
    transition:max-height .3s ease,opacity .2s ease,padding .3s ease;
    padding-top:6px}
  .filter-panel.collapsed{max-height:0;opacity:0;pointer-events:none;padding-top:0}

  /* 面板内下拉两列排列 */
  .filter-panel .ctrl-row{flex-wrap:wrap}
  .filter-panel .ctrl-left{gap:8px}
  .filter-panel .ctrl-left select{flex:1 1 calc(50% - 4px);min-width:0;max-width:none}
  .filter-panel .search{min-width:0;max-width:67%;flex:1 1 100%}   /* 搜索框 67% 靠左(选品页) */

  .grid{grid-template-columns:repeat(2,1fr);gap:10px}
}

/* 手机端(≤768px)：隐藏商品计数 + 收藏页第二行随筛选折叠 */
@media(max-width:768px){
  .count{display:none}
  .controls>.ctrl-row:nth-child(2) .ctrl-left{display:none}
  .controls.filter-open>.ctrl-row:nth-child(2) .ctrl-left{display:flex;flex-wrap:wrap;gap:8px;flex-basis:100%}
  .controls.filter-open>.ctrl-row:nth-child(2) .ctrl-left .search{min-width:0;max-width:67%;flex:1 1 100%}
}

/* 手机端(≤768px)：筛选框两列 grid + 缩窄 width + field-sizing */
@media(max-width:768px){
  .head .controls.filter-open>.ctrl-row:first-child .ctrl-left{
    display:grid;grid-template-columns:repeat(2, 22%);justify-content:start;column-gap:4px;row-gap:8px}
  .head .controls.filter-open>.ctrl-row:first-child .ctrl-left select:not(.dc-select):not(#fperiod){
    field-sizing:fixed;width:100%;min-width:0;max-width:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .head .controls.filter-open>.ctrl-row:first-child .ctrl-left #fperiod,
  .head .controls.filter-open>.ctrl-row:first-child .ctrl-left .dc-select{
    field-sizing:fixed;width:100%;min-width:0;max-width:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .head .controls .field.search input{overflow:hidden;text-overflow:ellipsis}
}

/* 手机端(≤768px)：卡片地区行跑马灯——溢出裁剪 + 内层滚动动画(@keyframes uiMarquee 见76行) */
@media(max-width:768px){
  .foot .left .region{overflow:hidden;white-space:nowrap}
  .region .region-in{display:inline-block}
  .region.is-marquee .region-in{animation:uiMarquee linear infinite alternate;will-change:transform}
}

/* 手机端(≤768px)：numgroup 单量组激活成整行 flex(两页共用) */
@media(max-width:768px){
  .filter-panel .numgroup,
  .controls.filter-open>.ctrl-row:nth-child(2) .ctrl-left .numgroup{
    display:flex;flex-wrap:wrap;align-items:center;gap:8px;flex-basis:100%}
}

/* 加载条（ui.js 的 UI.bar 控制，三页共用）。
   🔴 必须只动 transform / opacity —— 这两个属性的过渡跑在【合成器线程】，所以 render()
      同步阻塞主线程 0.8~1.3 秒期间进度条照常走；换成 width/left 会归主线程管、当场冻住。
      已实测确认：切最大一期(3239 条)时蓝条在阻塞期间仍顺畅推进。
   🔴 位置从窗口顶端改到【筛选栏下边沿】(.in-controls) 后，动画属性一个没变，仍是
      transform:scaleX + will-change:transform,opacity —— 合成器资格取决于"动画的是哪个属性"
      与"能否提升独立图层"，与 position 是 fixed 还是 absolute 无关。
   颜色用 var(--primary)（#2563EB，站内主蓝），不引入新色。 */
.head .controls{position:relative}          /* 给贴边的 #uiprog 当定位上下文；不改布局 */
#uiprog{position:fixed;top:0;left:0;right:0;height:2px;z-index:9999;pointer-events:none;
  background:var(--primary);transform:scaleX(0);transform-origin:0 50%;
  opacity:0;will-change:transform,opacity}
#uiprog.in-controls{position:absolute;top:auto;bottom:0;z-index:30}
#uiprog.on{opacity:1}

/* 第④步：期数下拉里【已加载期】显示 ✓ 前缀。用 ::before 而非改 option.textContent——
   实测 base-select 下 ::before 只在展开的 picker 里出现，不进收起态按钮（按钮保持"0722 PP"干净）。
   JS(markLoadedOptions) 给已加载期的 option 加 data-loaded。 */
/* 🔴 文字左缘对齐：给【所有】option 预留固定宽 ✓ 位（有无 ✓ 文字左缘都一致）。
   #dcsel 原生 ::checkmark 已抑制(下方)，✓ 走自定义 ::before：空位默认 content:""，已加载期覆为 "✓"。 */
#dcsel option::before{content:"";flex:none;width:1.15em;text-align:center;color:#0C447C;font-weight:700}   /* ✓ 色改与按钮同款深蓝 #0C447C(原 var(--primary)=#2563EB)；固定宽 1.15em 对齐不动 */
#dcsel option[data-loaded]::before{content:"✓"}
/* #fperiod 用原生 ::checkmark 作【选中】指示：给它固定宽 → 选中/未选中都占同宽 gutter → 文字左缘对齐。
   只钉宽度，不碰 content/颜色/含义（仍是"当前选中期"的勾）。 */
#fperiod option::checkmark{width:1.15em;text-align:center;color:#0C447C}   /* ✓ 与按钮/选中文字同色 #0C447C；固定宽 1.15em 对齐不动 */
/* 修改①：隐藏 base-select 自带的 ::checkmark。它只画在 option:checked（当前选中期）上，会与上面
   data-loaded 的 ::before ✓ 在【选中且已加载】那一项撞成两个勾。选中态已由 option:checked 的蓝底+
   加粗表示（本文件第 165 行），不需要这个额外的勾。仅限 #dcsel——#fperiod 无 data-loaded 机制、
   其 ::checkmark 是唯一选中指示，保留不动。 */
#dcsel option::checkmark{display:none}

/* 骨架屏（UI.skeleton）。靠 renderCards/renderTable 的 innerHTML 覆盖自动消失，无需移除逻辑。
   shimmer 用 transform:translateX —— 同样是合成器驱动，render 阻塞期间照常流动。 */
@keyframes ui-shimmer{to{transform:translateX(100%)}}
.sk{position:relative;overflow:hidden;background:#EEF0F3;border-radius:6px}
.sk::after{content:"";position:absolute;inset:0;transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.65),transparent);
  animation:ui-shimmer 1.4s infinite;will-change:transform}
.sk-card{background:var(--card);border:1px solid var(--line);border-radius:14px;
  overflow:hidden;padding:0 0 12px}
.sk-card .sk-img{aspect-ratio:1/1;border-radius:0}
.sk-card .sk-line{height:12px;margin:10px 12px 0}
.sk-row td{padding:10px 6px}
.sk-row .sk-line{height:12px}

/* 卡片⇄表格按钮的忙碌态（UI.busy）。
   🔴 转圈用 transform:rotate + will-change —— 与顶部加载条同一个道理，动画交给合成器线程，
      render() 阻塞主线程那 0.8~1.3 秒里它照常转。
   文字用 color:transparent 让位给转圈，并 transition:none 让它【瞬间】消失——.seg button 上
   那条 transition:.15s 是 all，color 归主线程管，render 一阻塞就会把淡出冻在半透明状态。
   被点的按钮总是先被加上 .on（蓝底），故默认用白色转圈；:not(.on) 兜底给主蓝色。 */
@keyframes ui-spin{to{transform:rotate(360deg)}}
.seg button.is-busy{position:relative;color:transparent;transition:none}
.seg button.is-busy::after{content:"";position:absolute;top:50%;left:50%;
  width:13px;height:13px;margin:-7px 0 0 -7px;border-radius:50%;
  border:2px solid rgba(255,255,255,.4);border-top-color:#fff;
  animation:ui-spin .6s linear infinite;will-change:transform}
.seg button.is-busy:not(.on)::after{border-color:rgba(37,99,235,.25);border-top-color:var(--primary)}
