/* User reference: deepseek_html_20260924_e099b3.html.
   Scope includes the overview's shell; navigating away restores existing pages. */
.ec-shell:has(#page-dashboard:not(.hidden)) {
  --side-bg: #fff; --side-bg-raised: #fff; --side-bg-hover: #f8fafc;
  --side-bg-active: #eff6ff; --side-line: #e2e8f0; --side-text: #475569;
  --side-text-strong: #1e293b; --side-text-dim: #94a3b8;
  --accent: #2563eb; --accent-on-dark: #2563eb;
  --content-bg: #f5f7fa; --ink-1: #1e293b; --ink-2: #475569; --ink-3: #94a3b8;
}
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-sidebar { border-color: #e2e8f0; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-brand-mark { background: #2563eb; border: 0; color: #fff; box-shadow: 0 2px 5px #2563eb20; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-item.is-active { color: #2563eb; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-item[data-page="dashboard"] { background: #eff6ff; color: #2563eb; font-weight: 600; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-item[data-page="dashboard"] .ec-ico { color: #2563eb; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-item.is-active::before { left: auto; right: -12px; top: 4px; bottom: 4px; width: 3px; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-item i.ec-ico { color: #64748b; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-item.is-active i.ec-ico { color: #2563eb; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-item:hover i.ec-ico { color: #2563eb; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-side-avatar { background: #2563eb; color: #fff; border: 0; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-badge { background: #eff6ff; color: #2563eb; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-nav-badge.is-danger { background: #ef4444; color: #fff; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-crumb strong { color: #1e293b; font-size: 17px; }
.ec-shell:has(#page-dashboard:not(.hidden)) .ec-crumb strong i { color: #2563eb; }
#mainContent:has(> #page-dashboard:not(.hidden)) { background: #f5f7fa !important; }
#page-dashboard.ec-overview { background: none; max-width: 1720px; margin-inline: auto; font-variant-numeric: tabular-nums; }
#page-dashboard.ec-overview::before, #page-dashboard .ec-card::after, #page-dashboard .ec-kpi::after { display: none; }
#page-dashboard .ec-section { margin-bottom: 20px; }
#page-dashboard .ec-page-head { align-items: center; margin-bottom: 16px; z-index: 5; gap: 16px; }
#page-dashboard .ec-head-inline { gap: 8px; flex-wrap: wrap; }
#page-dashboard .ec-page-title { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); }
#page-dashboard .ec-mkt-window { font-size: 12px; padding: 0; border: 0; color: #94a3b8; }
#page-dashboard .ec-info-i { font-size: 12px; color: #94a3b8; }
#page-dashboard .ec-info-wrap:focus-within .ec-info-pop { display: block; opacity: 1; visibility: visible; }
#page-dashboard .ec-info-pop { font-size: 12px; line-height: 1.8; }
#page-dashboard :is(a, button, summary, [tabindex]):focus-visible { outline: 2px solid #2563eb; outline-offset: 3px; border-radius: 4px; }
#page-dashboard .ov-data-status { position: relative; flex-shrink: 0; }
#page-dashboard .ov-data-status summary { display: flex; align-items: center; gap: 7px; list-style: none; cursor: pointer; font-size: 12px; color: #64748b; }
#page-dashboard .ov-data-status summary::-webkit-details-marker { display: none; }
#page-dashboard .ov-data-status summary .fa-chevron-down { font-size: 9px; }
#page-dashboard #dash-freshness { position: absolute; right: 0; top: calc(100% + 12px); width: 280px; padding: 18px; border: 1px solid #e2e8f0; background: #fff; border-radius: 10px; box-shadow: 0 12px 32px #0f172a14; }
#page-dashboard .ec-fresh { padding: 0; margin: 0; border: 0; gap: 12px; }
#page-dashboard .ec-fresh-k, #page-dashboard .ec-fresh-v { font-size: 12px; }

/* Same compact, white KPI treatment as the supplied reference. */
#page-dashboard .ec-kg { gap: 20px; grid-template-columns: repeat(4, minmax(0, 1fr)); }
#page-dashboard .ec-kpi { padding: 20px; min-height: 128px; background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; box-shadow: 0 1px 2px #0f172a05; transition: box-shadow .15s; }
#page-dashboard .ec-kpi:hover { transform: none; border-color: #e2e8f0; box-shadow: 0 4px 12px #0f172a07; }
#page-dashboard .ec-kpi-k { font-size: 13px; font-weight: 500; letter-spacing: 0; color: #64748b; }
#page-dashboard .ec-kpi-v { margin-top: 10px; color: #1e293b; font-family: 'Inter', system-ui, sans-serif; font-size: 27px; line-height: 1.25; font-weight: 700; letter-spacing: -.6px; }
#page-dashboard .ec-kpi-f { font-size: 11px; color: #94a3b8; margin-top: 7px; white-space: normal; line-height: 1.6; gap: 4px; align-items: baseline; }
#page-dashboard .ec-kpi-f i { color: #94a3b8; font-size: 10px; flex: none; }
#page-dashboard .ec-kpi-sp { display: none; }
#page-dashboard .ec-delta { font-size: 11px; font-weight: 600; border-radius: 99px; padding: 2px 7px; gap: 3px; }
/* up / down 自第 20 轮起全站统一（:root 的 --delta-*），此处不再覆盖 ——
   原先这里是「涨绿跌红」，靠文件末尾那段才被翻成涨红跌绿，两段互相打架。 */
#page-dashboard .ec-delta.flat { background: #f1f5f9; color: #94a3b8; }
#page-dashboard .ec-delta i { font-size: 9px; }

/* Reference hierarchy: attention + stores, products + traffic. */
#page-dashboard .ov-command-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.8fr); gap: 20px; }
#page-dashboard .ov-pair-grid, #page-dashboard .ov-bottom-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
#page-dashboard .ov-sales-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 20px; }
#page-dashboard .ec-card { background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; box-shadow: 0 1px 2px #0f172a05; min-width: 0; overflow: hidden; }
#page-dashboard .ec-card-head { padding: 18px 20px 12px; min-height: 49px; border: 0; gap: 10px; }
#page-dashboard .ec-card-head h4 { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: #334155; }
#page-dashboard .ec-card-head h4 > i { font-size: 13px; }
#page-dashboard .ov-icon-blue { color: #3b82f6; }
#page-dashboard .ov-icon-amber { color: #f59e0b; }
#page-dashboard .ov-icon-cyan { color: #06b6d4; }
#page-dashboard .ov-icon-purple { color: #8b5cf6; }
#page-dashboard .ec-subunit { color: #94a3b8; font-size: 10px; background: #f8fafc; border: 0; border-radius: 4px; padding: 2px 5px; font-weight: 400; }
#page-dashboard .ec-card-head .hint, #page-dashboard .ec-btn-ghost { color: #2563eb; font-size: 11px; font-weight: 400; }
#page-dashboard .ec-card-head :is(a, button):hover { text-decoration: underline; background: none; }
#page-dashboard .ec-card-pad { padding: 4px 20px 18px; }
#page-dashboard .ec-badge-n { background: #f1f5f9; color: #94a3b8; font-size: 10px; }
#page-dashboard .ec-issue-list { max-height: 184px; overflow-y: auto; }
#page-dashboard .ec-issue-quiet { padding: 12px 0; font-size: 12px; color: #94a3b8; line-height: 1.8; }
#page-dashboard .ec-issue-quiet strong { display: block; font-weight: 500; color: #64748b; font-size: 13px; margin-bottom: 3px; }
#page-dashboard .ec-issue-quiet b { font-weight: 400; color: #64748b; }
#page-dashboard .ec-issue { padding: 10px; margin-bottom: 8px; border: 0; border-left: 3px solid #fbbf24; border-radius: 5px; background: #fffbeb80; }
#page-dashboard .ec-issue:has(.high) { border-left-color: #ef4444; background: #fff1f280; }
#page-dashboard .ec-issue-dot { width: 6px; height: 6px; }
#page-dashboard .ec-issue-t { font-size: 12px; white-space: normal; line-height: 1.6; }
#page-dashboard .ec-issue-d { font-size: 11px; color: #94a3b8; }
#page-dashboard .ov-task-area { margin: 0 20px 18px; padding-top: 12px; border-top: 1px solid #f1f5f9; }
#page-dashboard .ov-task-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; color: #64748b; }
#page-dashboard .ov-task-head a { color: #2563eb; font-size: 11px; }
#page-dashboard #dash-aiwork { padding-top: 7px; max-height: 150px; overflow-y: auto; }
#page-dashboard #dash-aiwork .ec-issue-quiet { padding: 0; font-size: 11px; }
#page-dashboard .ec-prog-row { grid-template-columns: minmax(0, 1fr) auto; gap: 8px; padding: 2px 0; }
#page-dashboard .ec-prog-t { font-size: 11px; }
#page-dashboard .ec-prog-s { color: #3b82f6; padding: 2px 6px; background: #eff6ff; border-radius: 4px; font-size: 10px; }
#page-dashboard .ec-prog-s.is-waiting { color: #b7791f; background: #fffbeb; }
#page-dashboard .ec-prog-s.is-failed { color: #e05260; background: #fff1f2; }

/* Store ranking, backed by the current store scope. */
#page-dashboard .ec-quote-head, #page-dashboard .ec-quote { display: grid; grid-template-columns: minmax(0, 1fr) 72px 76px 64px; gap: 14px; align-items: center; }
#page-dashboard .ec-quote-head { padding: 0 20px 8px; border: 0; color: #94a3b8; font-size: 10px; }
#page-dashboard .ec-quotes { padding: 0 12px 12px; }
#page-dashboard .ec-quote { padding: 8px; border-radius: 8px; border: 1px solid transparent; cursor: default; }
#page-dashboard .ec-quote:first-child { background: #f8fafc; border-color: #f1f5f9; }
#page-dashboard .ec-quote:hover { background: #f8fafc; }
#page-dashboard .ec-quote-name { font-size: 12px; font-weight: 500; color: #475569; display: flex; align-items: center; min-width: 0; gap: 9px; }
#page-dashboard .ov-store-rank { color: #94a3b8; font-size: 12px; width: 15px; flex: none; font-weight: 700; }
#page-dashboard .ec-quote:first-child .ov-store-rank { color: #f59e0b; }
#page-dashboard .ov-store-label { overflow: hidden; text-overflow: ellipsis; }
#page-dashboard .ec-quote-name em { font-size: 10px; font-style: normal; color: #94a3b8; margin-left: 5px; }
#page-dashboard .ov-store-rate { font-size: 11px; color: #94a3b8; text-align: right; }
#page-dashboard .ec-quote-v { font-size: 13px; color: #334155; font-weight: 600; text-align: right; }
#page-dashboard .ec-quote .ec-delta { font-size: 10px; padding-inline: 5px; }
#page-dashboard .ec-contrib { margin: 0 20px 16px; padding: 10px 0 0; border: 0; border-top: 1px solid #f1f5f9; border-radius: 0; box-shadow: none; background: none; }
#page-dashboard .ec-contrib:empty { display: none; }
#page-dashboard .ec-contrib-head { font-size: 10px; margin-bottom: 7px; color: #94a3b8; }
#page-dashboard .ec-contrib-head > span:first-child { font-weight: 400; color: #94a3b8; }
#page-dashboard .ec-contrib-bar { height: 5px; border-radius: 3px; gap: 2px; }
#page-dashboard .ec-contrib-legend { gap: 3px 12px; font-size: 10px; color: #94a3b8; margin-top: 7px; }
#page-dashboard .ec-contrib-legend em { width: 5px; height: 5px; }
#page-dashboard .ec-contrib-note { font-size: 10px; color: #a3afbd; margin-top: 5px; }
#page-dashboard .ov-contribution { margin: 0 20px 16px; border-top: 1px solid #f1f5f9; }
#page-dashboard .ov-contribution summary { padding-top: 9px; list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; color: #94a3b8; font-size: 10px; }
#page-dashboard .ov-contribution summary::-webkit-details-marker { display: none; }
#page-dashboard .ov-contribution summary i { font-size: 8px; }
#page-dashboard .ov-contribution[open] summary i { transform: rotate(180deg); }
#page-dashboard .ov-contribution .ec-contrib { margin: 0; border: 0; padding-top: 10px; }
#page-dashboard .ov-contribution:has(.ec-contrib:empty) { display: none; }

/* Product list and traffic tiles mirror the reference; no invented product labels. */
#page-dashboard .ov-product-columns { display: grid; grid-template-columns: minmax(0, 1fr) 44px 68px; gap: 12px; color: #94a3b8; font-size: 10px; padding: 0 0 7px; }
#page-dashboard .ov-product-columns > span:not(:first-child) { text-align: right; }
#page-dashboard .ec-rank-row { display: grid; grid-template-columns: 18px minmax(0, 1fr) 44px 68px; gap: 12px; padding: 10px 0; border: 0; cursor: default; }
#page-dashboard .ec-rank-i { width: 18px; color: #94a3b8; font-size: 11px; font-weight: 600; }
#page-dashboard .ec-rank-row:first-child .ec-rank-i { color: #2563eb; }
#page-dashboard .ec-rank-n { font-size: 12px; color: #475569; font-weight: 400; }
/* 商品行带平台标识：商品日报也分京东/天猫，标出来才不会被误读成单平台口径 */
#page-dashboard .ec-rank-n { display: flex; align-items: center; gap: 6px; min-width: 0; }
#page-dashboard .ec-rank-n .ov-item-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#page-dashboard .ec-rank-n em { flex: none; font-style: normal; font-size: 10px; color: #94a3b8; }
#page-dashboard .ec-rank-s { font-size: 11px; text-align: right; color: #94a3b8; }
#page-dashboard .ec-rank-v { font-size: 12px; font-weight: 550; color: #334155; text-align: right; }
#page-dashboard .ec-qchips { margin-top: 10px; gap: 5px; }
#page-dashboard .ec-qchip { background: #f8fafc; border: 0; border-radius: 4px; padding: 4px 6px; font-size: 10px; color: #94a3b8; box-shadow: none; }
#page-dashboard .ec-qchip b { color: #64748b !important; font-weight: 500; }
#page-dashboard .ec-card-foot { border-color: #f1f5f9; margin-top: 12px; padding-top: 10px; font-size: 10px; color: #94a3b8; line-height: 1.6; gap: 6px; }
#page-dashboard .ov-traffic-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
#page-dashboard .ov-traffic-tile { background: #f8fafc; border-radius: 8px; text-align: center; padding: 13px 10px; min-width: 0; }
#page-dashboard .ov-traffic-tile > span { display: block; font-size: 11px; color: #94a3b8; }
#page-dashboard .ov-traffic-tile > b { display: block; font-size: 22px; line-height: 1.4; color: #1e293b; font-weight: 700; margin-top: 4px; }
#page-dashboard .ov-traffic-tile > small { display: block; font-size: 10px; color: #94a3b8; margin-top: 2px; }
#page-dashboard .ov-traffic-track { height: 5px; border-radius: 9px; background: #e2e8f0; overflow: hidden; margin-top: 12px; }
#page-dashboard .ov-traffic-track > i { display: block; height: 100%; background: var(--source-color); border-radius: 9px; }

/* Secondary boards keep the same language and retain their own data periods. */
#page-dashboard .ec-chart-tags { font-size: 10px; gap: 10px; color: #94a3b8; }
#page-dashboard .ec-chart-tags b { font-weight: 500; color: #64748b; }
#page-dashboard .ov-chart-legend { display: flex; gap: 16px; align-items: center; margin: 3px 0 12px; font-size: 10px; color: #94a3b8; }
#page-dashboard .ov-chart-legend > span { display: flex; align-items: center; gap: 6px; }
#page-dashboard .ov-chart-legend > span:last-child { margin-left: auto; }
#page-dashboard .ov-chart-legend i { width: 14px; height: 2px; background: #3b82f6; }
#page-dashboard .ov-chart-legend > span:nth-child(2) i { height: 0; background: none; border-top: 2px dashed #cbd5e1; }
#page-dashboard .ec-chart-pad:has(#dash-trend-wrap.hidden) .ov-chart-legend { display: none; }
#page-dashboard #dash-trend-wrap { height: 210px; }
#page-dashboard .ec-chart-x { margin-top: 7px; font-size: 10px; color: #94a3b8; }
#page-dashboard .ec-aud { gap: 22px; padding-top: 10px; }
#page-dashboard .ec-aud-top { grid-template-columns: 96px minmax(0, 1fr); gap: 20px; }
#page-dashboard .ec-aud-bars { gap: 20px; }
#page-dashboard .ec-aud-bk { font-size: 11px; color: #94a3b8; margin-bottom: 7px; }
#page-dashboard .ec-aud-bk b { font-size: 12px; color: #334155; font-weight: 600; }
#page-dashboard .ec-aud-dc b { font-size: 22px; color: #1e293b; }
#page-dashboard .ec-aud-bar { height: 6px; }
#page-dashboard .ec-aud-tiles { gap: 10px; }
#page-dashboard .ec-aud-tile { background: #f8fafc; padding: 12px 10px; border-radius: 8px; box-shadow: none; text-align: center; }
#page-dashboard .ec-aud-tile b { font-size: 18px; color: #334155; font-weight: 600; }
#page-dashboard .ec-aud-tile span { font-size: 10px; color: #94a3b8; margin-top: 5px; }
#page-dashboard #audience-note { font-size: 10px; color: #94a3b8; }
#page-dashboard .ec-lrow { padding: 10px 0; border-bottom: 1px solid #f1f5f9; }
#page-dashboard .ec-lrow-k { font-size: 12px; color: #64748b; }
#page-dashboard .ec-lrow-v { font-size: 17px; font-weight: 600; color: #334155; text-align: right; }
#page-dashboard .ec-lrow-v em { display: block; margin: 3px 0 0; font-size: 10px; color: #94a3b8; }
#page-dashboard .ec-lrow.is-stack .ec-lrow-v { font-size: 13px; }
#page-dashboard .ec-lrow.is-stack .ec-lrow-v em { display: inline; margin-left: 4px; }
#page-dashboard .ec-lrow-bar { background: #f1f5f9; height: 4px; margin-top: 8px; }
#page-dashboard .ec-lrow-bar > i { background: #60a5fa !important; }
#page-dashboard .ec-gap { background: #f8fafc; box-shadow: none; border-radius: 6px; color: #94a3b8; font-size: 11px; line-height: 1.7; }
#page-dashboard .ec-gap i { color: #94a3b8; }

@media (max-width: 1250px) {
  #page-dashboard .ec-kg, #page-dashboard .ov-command-grid, #page-dashboard .ov-pair-grid, #page-dashboard .ov-sales-grid, #page-dashboard .ov-bottom-grid { gap: 14px; }
  #page-dashboard .ec-kpi { padding: 16px; }
  #page-dashboard .ec-kpi-v { font-size: 24px; }
  #page-dashboard .ec-kpi-top { flex-wrap: wrap; gap: 4px; }
  #page-dashboard .ov-command-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); }
  #page-dashboard .ec-quote-head, #page-dashboard .ec-quote { grid-template-columns: minmax(0, 1fr) 68px 60px; gap: 8px; }
  #page-dashboard .ov-store-rate, #page-dashboard .ec-quote-head > span:nth-child(2) { display: none; }
  #page-dashboard .ec-card-head, #page-dashboard .ec-card-pad { padding-inline: 16px; }
  #page-dashboard .ec-aud-top { grid-template-columns: 84px minmax(0, 1fr); gap: 10px; }
  #page-dashboard .ec-aud-donut, #page-dashboard .ec-aud-donut svg { width: 84px; height: 84px; }
  #page-dashboard #audience-note { display: none; }
}
@media (max-width: 1000px) {
  #page-dashboard .ec-kg { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #page-dashboard .ov-command-grid, #page-dashboard .ov-pair-grid, #page-dashboard .ov-sales-grid, #page-dashboard .ov-bottom-grid { grid-template-columns: 1fr; }
  #page-dashboard .ec-quote-head, #page-dashboard .ec-quote { grid-template-columns: minmax(0, 1fr) 72px 76px 64px; gap: 12px; }
  #page-dashboard .ov-store-rate, #page-dashboard .ec-quote-head > span:nth-child(2) { display: block; }
}
@media (max-width: 600px) {
  #mainContent:has(> #page-dashboard:not(.hidden)) { padding: 14px; }
  #page-dashboard .ec-section { margin-bottom: 14px; }
  #page-dashboard .ec-kpi { padding: 14px 12px; }
  #page-dashboard .ec-kpi-k { font-size: 12px; }
  #page-dashboard .ec-kpi-v { font-size: 23px; }
  #page-dashboard .ec-kpi-f { font-size: 10px; }
  #page-dashboard .ec-mkt-window { font-size: 10px; }
  #page-dashboard .ov-data-status summary { font-size: 11px; }
  #page-dashboard .ov-data-status summary .fa-database { display: none; }
  #page-dashboard .ec-quote-head, #page-dashboard .ec-quote { grid-template-columns: minmax(0, 1fr) 64px 58px; gap: 7px; }
  #page-dashboard .ov-store-rate, #page-dashboard .ec-quote-head > span:nth-child(2) { display: none; }
  #page-dashboard .ec-quote-name { gap: 5px; }
  #page-dashboard .ec-quote-name em { display: none; }
  #page-dashboard .ov-product-columns { grid-template-columns: minmax(0, 1fr) 38px 60px; gap: 8px; }
  #page-dashboard .ec-rank-row { grid-template-columns: 14px minmax(0, 1fr) 38px 60px; gap: 8px; }
  #page-dashboard .ov-traffic-grid { gap: 8px; }
  #page-dashboard .ov-traffic-tile { padding: 12px 7px; }
  #page-dashboard .ov-traffic-tile > b { font-size: 20px; }
  #page-dashboard .ec-info-pop { width: min(310px, 82vw); left: -190px; }
}
/* 2026-09-24 第 8 轮：流量按平台分栏。
   京东与天猫的「一级来源」是两套互不相容的分类体系（京东=站内场域/站外渠道，
   天猫=经营优势/主动回访/付费推广），混在一起求和再算占比没有意义 ——
   所以每个平台一组，各自 100%，不跨平台相加。 */
#page-dashboard .ov-traffic-pf + .ov-traffic-pf { margin-top: 16px; padding-top: 14px; border-top: 1px solid #f1f5f9; }
#page-dashboard .ov-traffic-pf-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; min-width: 0; }
#page-dashboard .ov-traffic-pf-head > b { flex: none; font-size: 12px; font-weight: 600; color: #334155; }
#page-dashboard .ov-traffic-pf-head > span { font-size: 10px; color: #94a3b8; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#page-dashboard .ov-traffic-pf-head > em { margin-left: auto; flex: none; font-style: normal; font-size: 11px; color: #64748b; }

/* ==========================================================================
   2026-09-25 第 9 轮：按用户当轮反馈迭代（全部**追加**，不改上面已固化的规则）
   ① 店铺表现的框太长 → 主区改成左右**等宽**两列，它不再是占 1.8fr 的最宽框；
   ② 版式顺序：左列 销售走势 → 待关注 → 商品 TOP5；右列 店铺表现 → 流量全景 → 人群结构；
   ③ 涨红跌绿（A 股 / 生意参谋口径），只在经营总览页生效；
   ④ 销售走势改成按店铺堆积面积：细而淡的色带 + 一行图例。
   ========================================================================== */

/* ①② 主区两列栅格 */
#page-dashboard .ov-board-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start; }
#page-dashboard .ov-col { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
/* 走势卡要给色带留高度；210px 装 30 天堆积带偏挤 */
#page-dashboard #dash-trend-wrap { height: 250px; }

/* ③ 涨跌色：★ 第 20 轮起全站统一为「涨红跌绿」，唯一定义在 ec-shell.css 的 :root。
   原先这里还有 4 条覆盖（up / down / up.bad / down.good），
   是因为当时全站默认「涨绿跌红」、只有总览页要反过来；
   现在默认值本身就是涨红跌绿，这 4 条与全局逐字相同 → 删除，
   避免再出现「同一页两段配色互相打架」——
   这正是「同权重规则、后出现者胜」那类坑：谁在后面谁说话。 */

/* ④ 走势图例（JS 动态生成，每店一个色块；不再用固定的「支付金额 / 3 日均线」图标） */
#page-dashboard .ov-chart-legend { flex-wrap: wrap; gap: 7px 14px; margin-bottom: 4px; }
#page-dashboard .ov-chart-legend > b { display: inline-flex; align-items: center; gap: 6px; font-weight: 400; font-size: 10px; color: #64748b; }
#page-dashboard .ov-chart-legend > b > i { width: 9px; height: 9px; border-radius: 2px; flex: none; }
#page-dashboard .ov-chart-legend > b.ov-lg-ma > i { height: 0; border-radius: 0; background: none; border-top: 1.5px dashed #cbd5e1; width: 12px; }
#page-dashboard .ov-chart-legend > b.ov-lg-total { margin-left: auto; color: #94a3b8; }
#page-dashboard .ov-chart-legend > b.ov-lg-total em { font-style: normal; color: #334155; font-weight: 600; }

/* 人群结构：等专用数据源，不拿别的口径顶替 */
#page-dashboard .ov-pending { background: #f8fafc; border: 1px dashed #e2e8f0; border-radius: 8px; padding: 16px 14px; color: #94a3b8; font-size: 11.5px; line-height: 1.85; text-align: center; }
#page-dashboard .ov-pending > i { display: block; font-size: 20px; color: #cbd5e1; margin-bottom: 8px; }
#page-dashboard .ov-pending > b { display: block; color: #64748b; font-size: 12.5px; font-weight: 600; margin-bottom: 3px; }

@media (max-width: 1250px) {
  #page-dashboard .ov-board-grid { gap: 14px; }
  #page-dashboard .ov-col { gap: 14px; }
  #page-dashboard #dash-trend-wrap { height: 230px; }
}
/* 窄屏先变单列：两列时走势图与店铺表都会被压到不能读 */
@media (max-width: 1080px) {
  #page-dashboard .ov-board-grid { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
  #page-dashboard #dash-trend-wrap { height: 200px; }
  #page-dashboard .ov-chart-legend > b.ov-lg-total { margin-left: 0; }
}

@media (prefers-reduced-motion: reduce) { #page-dashboard * { transition: none !important; } }

/* ==================================================================
   第 11 轮（2026-09-25）· 侧栏配色全局对齐经营总览
   ------------------------------------------------------------------
   背景：总览的浅色侧栏皮肤原先用 `.ec-shell:has(#page-dashboard:not(.hidden))`
   限定作用域 —— 一旦切到别的页面，:has() 不成立，侧栏立刻退回 ec-shell.css
   的深黑（--side-bg:#121417、激活项白字 + #818cf8 淡紫图标）。用户要求
   「左侧的导航栏颜色都要跟经营总览的对齐」。
   做法：把**侧栏用到的那几个设计变量**与构件规则从「总览页专属」提升为
   「全局 .ec-shell」，取值与总览落地的那套完全一致（白底 + #2563eb 蓝 accent）。
   边界：只提升侧栏相关变量（--side-* 与 --accent-on-dark），
   不动 --content-bg / --accent / --ink-*，也不动顶栏 .ec-crumb —— 避免波及
   其它页面已经调好的内容区观感。
   位置：必须写在文件末尾（同权重后出现者胜，用来压过 ec-shell.css 的深色定义）。
   注意：只改变量不够 —— `#sidebar.ec-sidebar { border-right-color:#000 }` 是
   硬编码，变量管不到，必须用同级或更高权重显式覆盖（见下第 2 条）。
   ================================================================== */
.ec-shell {
  --side-bg: #fff; --side-bg-raised: #fff; --side-bg-hover: #f8fafc;
  --side-bg-active: #eff6ff; --side-line: #e2e8f0; --side-text: #475569;
  --side-text-strong: #1e293b; --side-text-dim: #94a3b8;
  --accent-on-dark: #2563eb;
}
/* 2. 侧栏右边框：#000 是硬编码，变量改不动它，需要显式覆盖 */
.ec-shell #sidebar.ec-sidebar { border-right-color: #e2e8f0; }
/* 3. 品牌标 / 头像 / 徽标：深色版的深底在白底侧栏里会变成脏色块，统一成蓝色系 */
.ec-shell .ec-sidebar .ec-brand-mark { background: #2563eb; border: 0; color: #fff; box-shadow: 0 2px 5px #2563eb20; }
.ec-shell .ec-sidebar .ec-side-avatar { background: #2563eb; color: #fff; border: 0; }
.ec-shell .ec-sidebar .ec-nav-badge { background: #eff6ff; color: #2563eb; }
.ec-shell .ec-sidebar .ec-nav-badge.is-danger { background: #ef4444; color: #fff; }
/* 4. 菜单项三态：常态灰、悬停加深、激活蓝；激活条从「左侧」改到「贴侧栏右缘」 */
.ec-shell .ec-sidebar .ec-nav-item i.ec-ico { color: #64748b; }
.ec-shell .ec-sidebar .ec-nav-item:hover { color: #1e293b; }
.ec-shell .ec-sidebar .ec-nav-item:hover i.ec-ico { color: #2563eb; }
.ec-shell .ec-sidebar .ec-nav-item.is-active { color: #2563eb; }
.ec-shell .ec-sidebar .ec-nav-item.is-active i.ec-ico { color: #2563eb; }
.ec-shell .ec-sidebar .ec-nav-item.is-active::before {
  left: auto; right: -12px; top: 4px; bottom: 4px; width: 3px; background: #2563eb;
}
/* 5. 折叠分组的箭头/图标：深色版的 #6f7784 在白底上偏灰，提亮一档 */
.ec-shell .ec-sidebar .ec-nav-subtoggle .chevron { color: #94a3b8; }
.ec-shell .ec-sidebar .ec-side-ctx i { color: #94a3b8; }
.ec-shell .ec-sidebar .ec-side-logout { color: #94a3b8; }
.ec-shell .ec-sidebar .ec-side-logout:hover { color: #2563eb; }

/* ==================================================================
   第 12 轮（2026-09-25）· 店铺对比页对齐经营总览的视觉语言
   ------------------------------------------------------------------
   背景：用户反馈「店铺对比页还不够细致，页面风格向着经营总览对齐」，
   并要求「要有几个维度的排名」。
   做法：总览那套皮肤的作用域全是 `#page-dashboard`，别的页面拿不到。
   本轮**不改 `#page-dashboard` 的任何规则**（那会影响已定稿的总览页），
   而是把同一套设计语言在 `#page-storesCompare` 下重写一份：
     灰底 #f5f7fa 内容区 → 白卡 12px 圆角 → 13/27px 字级 → tabular-nums → 发丝线分隔。
   位置：仍写在文件末尾（本文件是最后一个加载的样式表，覆盖力最强）。
   涨跌色：**保持全站默认的涨绿跌红**，本页不套总览那套「涨红跌绿」——
   两页口径不同时改色号会让同一份数字在两个页面显示成相反的颜色，先不动。
   ================================================================== */

/* 1. 页面骨架：灰底 + 白卡才是总览的层次来源；容器宽度与字号对齐 */
#mainContent:has(> #page-storesCompare:not(.hidden)) { background: #f5f7fa !important; }
#page-storesCompare {
  max-width: 1720px; margin-inline: auto;
  font-variant-numeric: tabular-nums;
}
#page-storesCompare .ec-section { margin-bottom: 20px; }
#page-storesCompare .ec-page-head { align-items: center; margin-bottom: 16px; gap: 16px; flex-wrap: wrap; }
#page-storesCompare .ec-head-inline { gap: 8px; flex-wrap: wrap; align-items: baseline; }
#page-storesCompare .ec-page-title { font-size: 17px; font-weight: 600; color: #1e293b; }
#page-storesCompare .sc-window { font-size: 12px; padding: 0; border: 0; color: #94a3b8; font-weight: 400; }
#page-storesCompare .ec-info-i { font-size: 12px; color: #94a3b8; }
#page-storesCompare .ec-info-wrap:focus-within .ec-info-pop { display: block; opacity: 1; visibility: visible; }
#page-storesCompare .ec-info-pop { font-size: 12px; line-height: 1.85; }
#page-storesCompare :is(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid #2563eb; outline-offset: 3px; border-radius: 4px;
}

/* 2. 卡片与卡片头：与总览同一套规格 */
#page-storesCompare .ec-card {
  background: #fff; border: 1px solid #e2e8f0; border-radius: 12px;
  box-shadow: 0 1px 2px #0f172a05; min-width: 0; overflow: hidden;
}
#page-storesCompare .ec-card-head { padding: 18px 20px 12px; min-height: 49px; border: 0; gap: 10px; }
#page-storesCompare .ec-card-head h4 { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: #334155; }
#page-storesCompare .ec-card-head h4 > i { font-size: 13px; }
#page-storesCompare .ec-card-head .hint { color: #2563eb; font-size: 11px; font-weight: 400; }
#page-storesCompare .ec-card-head :is(a, button):hover { text-decoration: underline; background: none; }
#page-storesCompare .ec-card-pad { padding: 4px 20px 18px; }
#page-storesCompare .ec-subunit {
  color: #94a3b8; font-size: 10px; background: #f8fafc; border: 0;
  border-radius: 4px; padding: 2px 5px; font-weight: 400;
}
#page-storesCompare .ec-badge-n { background: #f1f5f9; color: #94a3b8; font-size: 10px; }
#page-storesCompare .sc-ico-blue { color: #3b82f6; }
#page-storesCompare .sc-ico-amber { color: #f59e0b; }
#page-storesCompare .sc-ico-cyan { color: #06b6d4; }
#page-storesCompare .sc-ico-purple { color: #8b5cf6; }

/* 3. 店铺排行：块状卡 ×4（第 15 轮从「一行一店」改回）
   直接沿用总览的 KPI 卡规格：标签行（名次徽章 + 店名 + 环比胶囊）→ 27px 金额
   → 占比条 → 灰脚注 → 底纹折线。四张卡等宽并排，一眼看高度差就有排序感。 */
#page-storesCompare .ec-kg { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; }
#page-storesCompare .sc-rank {
  padding: 20px; min-height: 128px; background: #fff; border: 1px solid #e2e8f0;
  border-radius: 12px; box-shadow: 0 1px 2px #0f172a05; transition: box-shadow .15s;
}
#page-storesCompare .sc-rank:hover { box-shadow: 0 4px 12px #0f172a07; }
#page-storesCompare .ec-kpi-top { display: flex; align-items: center; gap: 7px; min-width: 0; }
#page-storesCompare .ec-kpi-top .ec-delta { margin-left: auto; flex: none; }
#page-storesCompare .sc-rank-no {
  width: 18px; height: 18px; flex: none; border-radius: 5px; font-size: 11px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  background: #f1f5f9; color: #94a3b8; font-variant-numeric: tabular-nums;
}
#page-storesCompare .sc-rank-no.is-1 { background: #fef3c7; color: #b45309; }
#page-storesCompare .sc-rank-no.is-2 { background: #eef2f6; color: #64748b; }
#page-storesCompare .sc-rank-no.is-3 { background: #ffedd5; color: #c2410c; }
#page-storesCompare .sc-rank-name {
  font-size: 13px; font-weight: 500; color: #64748b;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
#page-storesCompare .sc-rank .ec-kpi-v {
  display: block; margin-top: 10px; color: #1e293b;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 27px; line-height: 1.25; font-weight: 700; letter-spacing: -.6px;
}
#page-storesCompare .sc-share {
  height: 5px; border-radius: 3px; background: #f1f5f9; overflow: hidden; margin-top: 10px;
}
#page-storesCompare .sc-share > i { display: block; height: 100%; border-radius: 3px; }
/* 真实 0（本窗口 0 成交）占比 0 → 条宽 0，这家店在卡里就「消失」了；
   给一根 3px 短桩说明「有这家店、占比就是 0」。缺字段仍是 0 宽 + 无短桩，
   两者靠脚注（「占全场 0.0%」vs「占比不可算」）区分 —— 宁缺勿 0 与真实 0 不能混。 */
#page-storesCompare .sc-share > i.is-zero { min-width: 3px; }
#page-storesCompare .sc-rank-f {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 2px; margin-top: 7px; font-size: 11px; color: #94a3b8;
  white-space: normal; overflow: visible;
}
#page-storesCompare .sc-rank-f > em { font-style: normal; color: #64748b; font-weight: 500; }
#page-storesCompare .sc-spark { display: block; width: 100%; height: 30px; margin: 8px 0 0; }
#page-storesCompare .ec-delta { font-size: 11px; font-weight: 600; border-radius: 99px; padding: 2px 7px; gap: 3px; }
#page-storesCompare .ec-delta i { font-size: 9px; }

/* 4. 两行并排（第 15 轮用户指定）
   ① 差异诊断（左）| 指标对比（右）② 转化漏斗 | 新老买家结构。
   比「三张各占整宽」省掉近一半高度；等宽两列，最窄档塌成单列（见文末响应式）。 */
#page-storesCompare .sc-duo {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px; align-items: start;
}
#page-storesCompare .sc-col { display: flex; flex-direction: column; gap: 20px; min-width: 0; }

/* 5. 指标对比：9 个指标的页签（第 14 轮替换掉「36 根条画在一张图里」的版本）
   页签切换只换 class，条长用 CSS 宽度 —— 不重建 DOM、不起 Chart.js 实例，
   所以「点击就变」是真的零延迟。 */
#page-storesCompare .sc-tabbar {
  display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 14px;
}
#page-storesCompare .sc-tab {
  appearance: none; border: 1px solid #e2e8f0; background: #fff;
  border-radius: 7px; padding: 5px 11px; cursor: pointer;
  font-size: 11.5px; font-weight: 500; color: #64748b; line-height: 1.6;
  transition: background .12s, color .12s, border-color .12s;
}
#page-storesCompare .sc-tab:hover { color: #2563eb; border-color: #bfdbfe; background: #f8fbff; }
#page-storesCompare .sc-tab.is-on {
  background: #2563eb; border-color: #2563eb; color: #fff; font-weight: 600;
}
#page-storesCompare .sc-cmp-row {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) minmax(0, 2.1fr) auto 40px;
  align-items: center; gap: 12px; padding: 9px 0;
}
#page-storesCompare .sc-cmp-row + .sc-cmp-row { border-top: 1px solid #f8fafc; }
#page-storesCompare .sc-cmp-row.is-na { opacity: .55; }
#page-storesCompare .sc-cmp-no {
  width: 20px; height: 20px; border-radius: 6px; font-size: 11px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  background: #f1f5f9; color: #94a3b8; font-variant-numeric: tabular-nums;
}
#page-storesCompare .sc-cmp-no.is-1 { background: #fef3c7; color: #b45309; }
#page-storesCompare .sc-cmp-no.is-2 { background: #eef2f6; color: #64748b; }
#page-storesCompare .sc-cmp-no.is-3 { background: #ffedd5; color: #c2410c; }
#page-storesCompare .sc-cmp-shop {
  font-size: 12px; color: #334155;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#page-storesCompare .sc-cmp-track {
  display: block; height: 14px; border-radius: 4px; background: #f1f5f9; overflow: hidden;
}
#page-storesCompare .sc-cmp-track > i { display: block; height: 100%; border-radius: 4px; }
/* 真实 0（本窗口 0 成交）留一根短桩 —— 与「字段缺失不画」区分开 */
#page-storesCompare .sc-cmp-track > i.is-zero { min-width: 3px; }
#page-storesCompare .sc-cmp-v {
  font-size: 12.5px; font-weight: 600; color: #1e293b; text-align: right;
  min-width: 68px; font-variant-numeric: tabular-nums;
}
#page-storesCompare .sc-cmp-tagbox { text-align: right; }
#page-storesCompare .sc-cmp-tag {
  font-style: normal; font-size: 9px; padding: 1px 4px; border-radius: 3px;
  white-space: nowrap;
}
#page-storesCompare .sc-cmp-tag.is-best { background: #eff6ff; color: #2563eb; }
#page-storesCompare .sc-cmp-tag.is-worst { background: #fff7ed; color: #c2410c; }
#page-storesCompare .sc-cmp-empty { padding: 14px 0; font-size: 12px; color: #94a3b8; line-height: 1.85; }

/* 6. 多维画像：一店一张小雷达并排（小倍数）。同尺、不叠加，
   所以四张图可以直接横向比「谁的面更鼓」。 */
#page-storesCompare .sc-radar-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px;
}
#page-storesCompare .sc-radar-cell { min-width: 0; }
#page-storesCompare .sc-radar-box { position: relative; height: 268px; }
#page-storesCompare .sc-radar-cap {
  margin-top: 8px; padding-top: 8px; border-top: 1px solid #f1f5f9;
  text-align: center; line-height: 1.6;
}
#page-storesCompare .sc-radar-cap > b {
  display: block; font-size: 11.5px; font-weight: 600; color: #334155;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#page-storesCompare .sc-radar-cap > span {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 2px;
  font-size: 11px; color: #94a3b8;
}
#page-storesCompare .sc-radar-cap em { width: 8px; height: 8px; border-radius: 2px; flex: none; }
#page-storesCompare .sc-note-line {
  margin: 10px 0 0; padding-top: 10px; border-top: 1px solid #f1f5f9;
  font-size: 11.5px; line-height: 1.85; color: #64748b;
}
#page-storesCompare .sc-note-line b { font-weight: 600; color: #334155; }

/* 7. 差异诊断：沿用总览「待关注」的 issue 语言（左侧 3px 色条 + 淡底） */
#page-storesCompare .ec-issue {
  padding: 10px; margin-bottom: 8px; border: 0;
  border-left: 3px solid #fbbf24; border-radius: 5px; background: #fffbeb80;
}
#page-storesCompare .ec-issue:last-child { margin-bottom: 0; }
#page-storesCompare .ec-issue.is-alert { border-left-color: #ef4444; background: #fff1f280; }
#page-storesCompare .ec-issue.is-ok { border-left-color: #3b82f6; background: #eff6ff80; }
#page-storesCompare .ec-issue-t { display: block; font-size: 12px; line-height: 1.65; color: #475569; white-space: normal; }
#page-storesCompare .ec-issue-t > b { display: inline-block; margin-right: 7px; font-size: 11px; font-weight: 600; color: #334155; }
#page-storesCompare .ec-issue-quiet { padding: 12px 0; font-size: 12px; color: #94a3b8; line-height: 1.85; }
#page-storesCompare .ec-issue-quiet strong { display: block; font-weight: 500; color: #64748b; font-size: 13px; margin-bottom: 3px; }

/* 8. 转化漏斗：三段同轨嵌套（绝对定位左对齐、宽度递减），看起来就是收窄的喇叭口
   第 14 轮改「标签行 + 轨道」两行式：卡片从半屏宽变 1/3 屏宽后，
   单行布局会把轨道挤到 200px 以内，喇叭口的层次就看不出来了。 */
#page-storesCompare .sc-fn-row { display: block; padding: 9px 0; }
#page-storesCompare .sc-fn-row + .sc-fn-row { border-top: 1px solid #f8fafc; }
#page-storesCompare .sc-fn-top {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 6px;
}
#page-storesCompare .sc-fn-shop {
  font-size: 11.5px; color: #475569;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#page-storesCompare .sc-fn-track {
  position: relative; display: block; height: 10px; border-radius: 5px;
  background: #f1f5f9; overflow: hidden;
}
#page-storesCompare .sc-fn-track > i { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 5px; }
/* 三段同轨嵌套，颜色由浅到深 —— 段与段之间要能看出分界，
   否则「加购 → 支付」这一小截会被前两段吃掉，看不出漏斗收窄。 */
#page-storesCompare .sc-fn-track > .s1 { background: #dbeafe; }
#page-storesCompare .sc-fn-track > .s2 { background: #93c5fd; }
#page-storesCompare .sc-fn-track > .s3 { background: #2563eb; }
#page-storesCompare .sc-fn-v {
  font-size: 11px; font-weight: 600; color: #334155; flex: none;
  font-variant-numeric: tabular-nums;
}
#page-storesCompare .sc-na { font-size: 11px; color: #cbd5e1; flex: none; }

/* 9. 新老买家结构：一根堆叠条，左新右老。同样是两行式。 */
#page-storesCompare .sc-mix-row { display: block; padding: 9px 0; }
#page-storesCompare .sc-mix-row + .sc-mix-row { border-top: 1px solid #f8fafc; }
#page-storesCompare .sc-mix-top {
  display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px;
}
#page-storesCompare .sc-mix-shop {
  font-size: 11.5px; color: #475569; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#page-storesCompare .sc-mix-v {
  margin-left: auto; flex: none; font-size: 11px; font-weight: 600; color: #334155;
}
#page-storesCompare .sc-mix-n {
  flex: none; font-size: 10.5px; color: #94a3b8; font-variant-numeric: tabular-nums;
}
#page-storesCompare .sc-mix-bar { display: flex; height: 10px; border-radius: 5px; overflow: hidden; background: #f1f5f9; }
#page-storesCompare .sc-mix-bar > .is-new { background: #2563eb; }
#page-storesCompare .sc-mix-bar > .is-old { background: #cbd5e1; }

/* 10. 全场构成：复用总览的贡献条语言，但去掉卡片内边距（它已经在卡里了） */
#page-storesCompare .sc-contrib { margin: 0; padding: 0; border: 0; background: none; box-shadow: none; }
#page-storesCompare .ec-contrib-head {
  display: flex; justify-content: space-between; gap: 10px;
  font-size: 10px; color: #94a3b8; margin-bottom: 7px;
}
#page-storesCompare .ec-contrib-head > span:last-child { color: #334155; font-weight: 600; }
#page-storesCompare .ec-contrib-bar {
  display: flex; gap: 2px; height: 8px; border-radius: 4px; overflow: hidden; background: #f1f5f9;
}
#page-storesCompare .ec-contrib-bar > i { display: block; height: 100%; }
#page-storesCompare .ec-contrib-legend {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin-top: 10px; font-size: 10.5px; color: #475569;
}
#page-storesCompare .ec-contrib-legend > span { display: inline-flex; align-items: center; gap: 6px; }
#page-storesCompare .ec-contrib-legend em { width: 8px; height: 8px; border-radius: 2px; flex: none; }
#page-storesCompare .ec-contrib-legend b { font-weight: 600; color: #334155; }
#page-storesCompare .ec-contrib-note { margin-top: 8px; font-size: 10px; color: #a3afbd; }

/* 11. 脚注（各卡的补充说明）
   第 14 轮删掉了原来的 10 列指标对比表与日走势图 —— 指标数据已收进上面的页签，
   走势用户这轮先不要。表格与走势的样式随之移除。 */
#page-storesCompare .sc-foot { margin: 12px 0 0; font-size: 10.5px; color: #94a3b8; line-height: 1.8; }
#page-storesCompare .sc-foot b { font-weight: 500; color: #64748b; }

/* 12. 响应式：先收 KPI 卡与并排行，再塌成单列 */
@media (max-width: 1250px) {
  #page-storesCompare .ec-kg { gap: 14px; }
  #page-storesCompare .sc-rank { padding: 16px; }
  #page-storesCompare .sc-rank .ec-kpi-v { font-size: 24px; }
  #page-storesCompare .sc-duo { gap: 14px; }
  #page-storesCompare .sc-col { gap: 14px; }
  #page-storesCompare .ec-card-head, #page-storesCompare .ec-card-pad { padding-inline: 16px; }
  #page-storesCompare .sc-radar-grid { gap: 10px; }
  #page-storesCompare .sc-radar-box { height: 238px; }
  #page-storesCompare .sc-cmp-row { gap: 10px; }
}
@media (max-width: 1080px) {
  /* 并排行先塌成单列：两列各半宽时，指标对比的 9 个页签会折成 3 行、差异诊断也会挤 */
  #page-storesCompare .sc-duo { grid-template-columns: 1fr; }
  #page-storesCompare .sc-radar-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  #page-storesCompare .ec-kg { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
  #page-storesCompare .sc-radar-grid { grid-template-columns: 1fr; }
  /* 窄屏下条与「优/弱」徽章留不住，先让位给店名与数值 */
  #page-storesCompare .sc-cmp-row { grid-template-columns: 20px minmax(0, 1fr) auto; }
  #page-storesCompare .sc-cmp-tagbox { display: none; }
  #page-storesCompare .sc-mix-n { display: none; }
}
@media (max-width: 600px) {
  #mainContent:has(> #page-storesCompare:not(.hidden)) { padding: 14px; }
  #page-storesCompare .ec-kg { grid-template-columns: 1fr; }
  #page-storesCompare .sc-rank { padding: 14px 12px; }
}

/* ==================================================================
   ★ 第 16 轮 · 销售分析（#page-anSales）· 基础件
   ------------------------------------------------------------------
   视觉规格对齐「经营总览 / 店铺对比」，而且刻意**不另造一套**：
     - 数据状态卡、各店铺表、历史明细表、页签、说明折叠全部沿用既有组件类；
   第 17 轮把「5 张 KPI 卡 + 独立趋势图」换成了多维看板，原来那 6 条
   .sa-kg / .sa-kpi* 规则随 DOM 一并删除（留着就是死规则）；
   看板自己的规则见文件末尾「第 17 轮」那一段。
   ================================================================== */

/* ★ 第 20 轮：这里原来有一整块「各店铺当日表现表 / 历史销售明细表」的样式
   （.sa-shop-card / .sa-table / .sa-td-date / .sa-td-days / .sa-na-cell / .sa-hist-head），
   随那两个板块一起删除（已用「CSS 类名 ↔ JS 输出」集合差确认 JS 侧再无输出）。
   现在每张走势图下面挂的是 .sa-tbl*，规格见文件末尾「第 20 轮」那一段。
   ⚠ 紧跟着的 .sa-tabbar / .sa-tab 是**活的**（工具条上的粒度页签），别跟着删。 */
#page-anSales .sa-tabbar { display: inline-flex; gap: 4px; padding: 2px; background: #f1f5f9; border-radius: 8px; }
#page-anSales .sa-tab {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  border-radius: 6px; padding: 4px 14px; font-size: 11.5px; font-weight: 500;
  color: #64748b; line-height: 1.7; transition: background .12s, color .12s;
}
#page-anSales .sa-tab:hover { color: #2563eb; }
#page-anSales .sa-tab.is-on { background: #fff; color: #2563eb; font-weight: 600; box-shadow: 0 1px 2px #0f172a0f; }
/* .sa-foot / .sa-table-wrap 随「历史销售明细」一起删除（第 20 轮） */
/* ★ 当前**不可达**：/api/sales-report 只在显式给了 start+end 且窗口过窄时才回 autoNote，
   而第 19 轮起销售分析页的窗口跟着粒度走、不传 start/end，所以这段永远不会显示。
   保留是因为后端字段还在、语义仍然成立 —— 哪天本页重新加回区间入口就直接能用。
   删之前先确认 `saUrl()` 里还是只传 grain。 */
#page-anSales .sa-auto-note {
  display: flex; align-items: center; gap: 7px; margin-bottom: 12px;
  padding: 7px 11px; border-radius: 8px; background: #f8fbff; border: 1px solid #e3edfb;
  font-size: 11px; color: #5b708c;
}
#page-anSales .sa-auto-note > i { color: #7ba7e0; }

/* 销售异常：标题 + 描述两行，底部一个「去待办事项处理」（本页不放 AI 任务入口） */
#page-anSales .sa-exc-row { display: flex; align-items: flex-start; gap: 10px; padding: 9px 0; border-bottom: 1px solid #f4f7fa; }
#page-anSales .sa-exc-row:last-of-type { border-bottom: 0; }
#page-anSales .sa-exc-main { min-width: 0; flex: 1; }
#page-anSales .sa-exc-t { font-size: 12.5px; font-weight: 500; color: #1e293b; }
#page-anSales .sa-exc-d { margin-top: 3px; font-size: 11.5px; line-height: 1.6; color: #94a3b8; }
#page-anSales .sa-exc-more { margin-top: 10px; padding-top: 10px; border-top: 1px solid #f1f5f9; font-size: 11.5px; }
#page-anSales .sa-exc-more a { color: #2563eb; }

/* （第 20 轮删除）这里原本有一条只服务 .sa-hist-head 的 @media 600 —— 目标板块已删。
   本页真正的响应式仍集中在文件末尾，那才是唯一该出现 @media 的地方。 */

/* ==================================================================
   ★ 第 17 轮 · 销售分析 · 多维看板（#page-anSales）
   ------------------------------------------------------------------
   老板给了一个 A 股量化系统的「看盘工作台 · 多图网格」做参照，要「多维看板的感觉」，
   同时明确「不要改变现在的颜色」——所以**只借骨架，不借配色**：
   下面这一整段用的仍是本页原来的浅色 + 蓝主色，没有一个色值来自参照物。

   骨架三件套：
     ① .sa-status  顶部数据状态（数据日期 / 距今 / 口径 / 覆盖 / 最新一日合计）
     ② .sa-work > .sa-panel（左栏清单） + .sa-main（右栏）
     ③ .sa-main > .sa-bar（工具条） + .sa-grid > .sa-cell ×N
        ★ 第 18 轮把 ③ 整体换成了「.sa-mpanel（指标多选）+ .sa-sheets > .sa-sheet ×N
        （一店一张表）」，原来的 .sa-grid / .sa-cell / .sa-legend / .sa-mrow / .sa-plus
        都随 DOM 一起删掉了。当前定义见文件末尾「第 18 轮」那一段。

   ⚠ 两处容易翻车的地方，改的时候留意：
     - 左栏是 sticky 吸顶的，**自身可滚动**（max-height + overflow-y），
       这样右边的表格滚到哪，左栏的店铺列表都还在。
     - 「网格列数 / --sa-cols」那套机制**第 18 轮已整体作废**（右侧不再有网格），
       别再照旧注释去改；现在右侧列数 = 勾选指标数 + 1，由 JS 决定，CSS 不参与。
   ================================================================== */

/* ---- 通用小件 ---- */
#page-anSales .sa-flex { flex: 1 1 auto; min-width: 0; }
#page-anSales .sa-sep { width: 1px; height: 16px; flex: none; background: #e8edf4; margin: 0 2px; }

/* ---- ① 顶部数据状态 ---- */
#page-anSales .sa-status { margin-bottom: 16px; }
#page-anSales .sa-strow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
#page-anSales .sa-strow2 { margin-top: 12px; padding-top: 12px; border-top: 1px solid #f1f5f9; gap: 26px; }
#page-anSales .sa-dot { width: 8px; height: 8px; flex: none; border-radius: 50%; background: #cbd5e1; }
#page-anSales .sa-dot.is-ok { background: #10b981; box-shadow: 0 0 0 3px #10b9811f; }
#page-anSales .sa-dot.is-warn { background: #f59e0b; box-shadow: 0 0 0 3px #f59e0b1f; }
#page-anSales .sa-stdate { font-size: 13.5px; font-weight: 650; color: #1e293b; font-variant-numeric: tabular-nums; }
#page-anSales .sa-stsub { font-size: 11.5px; color: #94a3b8; font-variant-numeric: tabular-nums; }
#page-anSales .sa-stnote { margin-top: 9px; font-size: 10.5px; line-height: 1.7; color: #b3bdcc; }
#page-anSales .sa-kv { display: inline-flex; align-items: baseline; gap: 7px; }
#page-anSales .sa-kv > i { font-style: normal; font-size: 11.5px; color: #94a3b8; }
#page-anSales .sa-kv > b { font-size: 17px; font-weight: 680; color: #1e293b; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
#page-anSales .sa-kv .ec-delta { transform: translateY(-1px); }

/* ---- ② 看板：左栏 + 右栏 ----
   ★ 这块是**定高工作台**，不是普通两栏：左栏店铺列表从头排到尾，
     右侧一店一张表（4 家 × 30 期）会很高 —— 让它们各自自然高会在右下方留一大片空白。
     参照物就是这么做的（height: calc(100vh - Npx) + 两栏各自内部滚动），照搬：
       · 高度取 min(视口推导, 780px)：视口很高时不至于把工作台拉成一根长条；
       · 左栏自己滚（店铺再多也不影响布局）；表格区自己滚（加满列也不会撑破）。
     ⚠ 表格区不能设 `overflow: hidden`：它靠 flex:1 + min-height:0 吃满剩余空间，
       写死高度或裁掉溢出会在底部留白/把表切掉。 */
#page-anSales .sa-work {
  display: flex; align-items: stretch; gap: 14px;
  height: min(calc(100vh - 300px), 780px);
  min-height: 460px;
}
#page-anSales .sa-panel {
  flex: 0 0 268px; width: 268px; height: 100%;
  background: #fff; border: 1px solid #e6e8ec; border-radius: 12px;
  overflow-y: auto;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04);
}
#page-anSales .sa-search { padding: 10px 10px 6px; position: sticky; top: 0; background: #fff; z-index: 2; border-radius: 12px 12px 0 0; }
#page-anSales .sa-search input {
  width: 100%; box-sizing: border-box;
  border: 1px solid #e2e8f0; border-radius: 8px; background: #f8fafc;
  padding: 6px 10px; font-size: 12px; color: #334155; outline: none;
  transition: border-color .12s, background .12s;
}
#page-anSales .sa-search input:focus { border-color: #93b4f5; background: #fff; box-shadow: 0 0 0 3px #2563eb14; }
#page-anSales .sa-search input::placeholder { color: #b3bdcc; }
#page-anSales .sa-tip { padding: 2px 12px 9px; font-size: 10px; line-height: 1.7; color: #aab4c2; }
#page-anSales .sa-lists { padding: 0 6px 10px; }
#page-anSales .sa-side-empty { padding: 18px 8px; text-align: center; font-size: 11.5px; color: #a8b4c7; }

#page-anSales .sa-group { border-radius: 8px; }
#page-anSales .sa-group + .sa-group { border-top: 1px solid #f1f5f9; padding-top: 4px; margin-top: 4px; }
#page-anSales .sa-ghead {
  display: flex; align-items: center; gap: 6px; padding: 6px 8px;
  border-radius: 7px; cursor: pointer; user-select: none;
  font-size: 12px; font-weight: 620; color: #4a5260;
}
#page-anSales .sa-ghead:hover { background: #f6f8fb; color: #1e293b; }
/* ★ 左栏/指标列表的分组标题**不可折叠**（JS 里一律带 `is-static`）——
   第 17/18 轮那套折叠机（`.sa-group.is-fold` + `.sa-mgcaret` 旋转 +
   指标多选面板的 `.sa-mgroup/.sa-mghead/.sa-mgrows`）已随各自 DOM 一起删掉。
   现在整份样式表里不该再出现 `sa-mg` 前缀的类。 */
#page-anSales .sa-gname { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#page-anSales .sa-gcount {
  margin-left: auto; flex: none; font-size: 10px; font-weight: 500; color: #94a3b8;
  background: #f1f5f9; border-radius: 20px; padding: 0 6px; line-height: 16px;
}
/* ★ 第 26 轮补齐：`.sa-rows` 是左栏指标分组内的行容器，但**从第 19 轮起就没有
   对应规则** —— 第 25 轮类名自查里它落在「无样式类」清单里，当时只处理了
   sa-report-x，把它漏了（那一版 missing 只打印、不参与 FAIL，所以没拦住）。 */
#page-anSales .sa-rows { display: flex; flex-direction: column; }

#page-anSales .sa-main { flex: 1 1 auto; min-width: 0; height: 100%; display: flex; flex-direction: column; }

/* ---- ③ 工具条 ---- */
#page-anSales .sa-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; margin-bottom: 10px;
  background: #fff; border: 1px solid #e6e8ec; border-radius: 10px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04);
}
#page-anSales .sa-bar-lab { font-size: 11px; color: #94a3b8; }
#page-anSales .sa-bar .sa-tabbar { padding: 2px; }
#page-anSales .sa-bar .sa-tab { padding: 3px 10px; font-size: 11px; }

#page-anSales .sa-ge-big { font-size: 14px; font-weight: 650; color: #64748b; }
#page-anSales .sa-ge-tip { margin-top: 10px; text-align: center; font-size: 11.5px; line-height: 2; color: #a8b4c7; }


/* ==================================================================
   ★ 第 19 轮 · 销售分析改成「每店一张走势图」（#page-anSales）
   ------------------------------------------------------------------
   老板把第 18 轮的形态推翻了一半，原话：
     「我要的是图表，左侧是指标不是店铺。右上角的 09-25 ~ 09-25 / 全部店铺 去掉。」

   三个拍板（AskUserQuestion）：
     · 右侧形态 = 一个店铺一张走势图（4 家店 4 张），悬停出同环比
     · 时间范围 = 跟着粒度走（日 近 30 天 / 周 近 26 周 / 月 近 12 个月 / 年 全部）
     · 左栏指标 = 单选（点一个，4 张图同时换成它）

   所以这一轮把第 18 轮的「左栏店铺列表 + 右侧一店一表」换成了：
     · 左栏  .sa-panel-metrics > .sa-group > .sa-mrow ×23    指标列表（单选）
     · 右侧  .sa-bar（只剩粒度）+ .sa-charts > .sa-chart ×N  每店一张走势图
     · 悬停  用 Chart.js 原生 tooltip（值 / 环比 / 同比 三行），第 18 轮那套
             HTML 浮层（.sa-hover / .sa-tip-*）随「一店一表」一起删掉了

   ⚠ 四条容易翻车的：
     ① 定高工作台（.sa-work，第 17 轮定的）沿用：**.sa-charts 不写死高度** ——
        它靠 flex:1 + min-height:0 吃满剩余空间，写死就会在底部留白。
     ② 图卡里的画布走**固定高度**（.sa-chart-b 190px），**不能**让卡片高度去 1fr ——
        画布尺寸跟父级高度算、父级又跟画布变，用 1fr 会来回抖。
     ③ 左栏 `.sa-mrow` 是 `<button>`：必须 `width:100%` + `box-sizing:border-box`
        + `font-family:inherit`，否则行宽不自洽、字体变成浏览器默认的宋体。
     ④ 顶栏那两件（日期控件 / 店铺作用域）在本页隐藏，用的是 `.ec-shell:has(...)`
        —— 与第 11 轮提升侧栏皮肤同一手法，作用域跟着「当前显示的页」走。
   ================================================================== */

/* ---- ① 左栏：指标列表（单选） ---- */
/* 分组标题在指标列表里只是个「规模 / 效率」的标签，不可折叠 → 去掉手型与 hover */
#page-anSales .sa-ghead.is-static { cursor: default; }
#page-anSales .sa-ghead.is-static:hover { background: none; color: #4a5260; }
#page-anSales .sa-panel-metrics { padding-bottom: 8px; }
#page-anSales .sa-mrow {
  display: flex; align-items: center; gap: 6px;
  width: 100%; box-sizing: border-box;
  text-align: left; cursor: pointer; font-family: inherit;
  padding: 5px 8px; border: 0; border-radius: 7px; background: none;
  font-size: 12px; color: #475569;
  transition: background .12s, color .12s;
}
#page-anSales .sa-mrow:hover { background: #f6f8fb; color: #1e293b; }
#page-anSales .sa-mrow.is-on { background: #2563eb; color: #fff; font-weight: 600; }
#page-anSales .sa-mrow.is-on .sa-mrow-v { color: #fff; }
#page-anSales .sa-mrow.is-on .sa-low { color: #fde3b3; }
/* 销售日报里没有这个字段的指标：仍可点（点了会看到「为什么是空的」的说明），
   但要一眼看出它和别的指标不一样，不能让人以为是自己没找到数据 */
#page-anSales .sa-mrow.is-na { opacity: .45; }
#page-anSales .sa-mrow.is-na.is-on { opacity: .75; }
#page-anSales .sa-mrow-n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#page-anSales .sa-mrow-v {
  flex: none; font-size: 11.5px; font-weight: 620; color: #334155;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
#page-anSales .sa-mrow .ec-delta { flex: none; font-size: 10px; }

/* ---- ② 工具条上的「当前指标」 ---- */
#page-anSales .sa-bar-cur {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12px; font-weight: 620; color: #1e293b;
}
#page-anSales .sa-bar-cur > i {
  font-style: normal; font-size: 10px; font-weight: 500; color: #94a3b8;
}

/* ---- ③ 右侧：每个店铺一张走势图 ----
   一屏 4 张，auto-fit 网格：宽了 2 列、窄了 1 列，不需要 JS 参与。
   grid-auto-rows: min-content —— 行高由卡片内容决定，别让它去抢剩余空间。 */
#page-anSales .sa-charts {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
  grid-auto-rows: min-content;
  align-content: start;
  padding-right: 2px;
}
#page-anSales .sa-chart {
  display: flex; flex-direction: column;
  background: #fff; border: 1px solid #e6e8ec; border-radius: 12px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04);
  padding: 10px 12px 6px;
}
#page-anSales .sa-chart-h {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; row-gap: 4px;
  margin-bottom: 8px;
}
#page-anSales .sa-chart-dot { width: 8px; height: 8px; flex: none; border-radius: 50%; }
#page-anSales .sa-chart-nm {
  max-width: 210px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px; font-weight: 650; color: #1e293b;
}
#page-anSales .sa-chart-v {
  font-size: 14.5px; font-weight: 680; color: #0f172a;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
#page-anSales .sa-chart-d {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11px; color: #94a3b8; white-space: nowrap;
}
#page-anSales .sa-chart-d > i { font-style: normal; }
#page-anSales .sa-chart-d .ec-delta { font-size: 10.5px; }
/* 画布固定高度：见文件头 ⚠② */
#page-anSales .sa-chart-b { position: relative; height: 190px; min-height: 0; }
#page-anSales .sa-chart-b canvas { display: block; }
#page-anSales .sa-chart-f {
  display: flex; align-items: center; gap: 8px;
  padding-top: 5px; margin-top: 2px; border-top: 1px solid #f6f9fc;
  font-size: 10px; color: #b3bdcc; font-variant-numeric: tabular-nums;
}
#page-anSales .sa-chart-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 100%; text-align: center; font-size: 11.5px; color: #a8b4c7;
}
#page-anSales .sa-chart-empty > i {
  margin-top: 6px; font-style: normal; font-size: 10px; line-height: 1.6; color: #cbd5e1;
  max-width: 260px;
}
#page-anSales .sa-charts-empty { padding: 60px 0; text-align: center; }

/* ---- ④ 越低越好标记（↓）----
   第 18 轮的浮层徽章随浮层一起删了，这里只剩左栏与工具条上的一个小箭头：
   做成带框的小标签在 268px 的窄栏里会把指标名挤没，一个箭头足够。 */
#page-anSales .sa-low {
  flex: none; margin-left: 2px; font-style: normal; font-weight: 700;
  font-size: 10px; line-height: 1; color: #d97706;
}

/* ---- ⑤ 顶栏的「日期范围」与「店铺作用域」在销售分析页隐藏 ----
   老板要求：「右上角的 09-25 ~ 09-25 / 全部店铺 去掉」。
   本页窗口**跟着粒度走**（日/周/月/年各有默认期数），本来就不需要日期控件；
   而 /api/sales-report 不在 EC_SCOPED_APIS 里，店铺作用域对本页从不起作用 ——
   控件留在那儿只会让人以为「这里能按店铺筛」，是误导。
   其余 16 个页面照旧（它们仍以顶栏日期为唯一时间入口）。 */
.ec-shell:has(#page-anSales:not(.hidden)) #dateRangeWrapper,
.ec-shell:has(#page-anSales:not(.hidden)) #storeDropdownWrapper,
/* ★ 第 26 轮：商品分析页也隐藏这两件 —— 本页按店铺分组看全部店铺，
   顶栏切单店会让分组失去意义（要单店用左栏的店铺 chip）。 */
.ec-shell:has(#page-anGoods:not(.hidden)) #dateRangeWrapper,
.ec-shell:has(#page-anGoods:not(.hidden)) #storeDropdownWrapper,
/* ★ r108：流量分析页同样隐藏这两件（老板：「右上角那个可以直接去掉了，不然重复了」）——
   本页工具栏有自己的日期选择器，列头有自己的按平台店铺切片器；而 /api/flow-view
   根本不读顶栏的店铺作用域（它用 picks），这两个控件留在顶栏只会误导。
   注意：本文件用 :has() 按页判定，切页自动生效/恢复，不依赖 js 重建顶栏。 */
.ec-shell:has(#page-anTraffic:not(.hidden)) #dateRangeWrapper,
.ec-shell:has(#page-anTraffic:not(.hidden)) #storeDropdownWrapper { display: none !important; }

/* ==================================================================
   ★ 第 20 轮 · 每店图下挂明细表 + 底部 AI 指标分析（#page-anSales）
   ------------------------------------------------------------------
   老板原话：
     「下方应该有对应的表格类型的数据。比如选到支付金额到月的，那么每个表格
       对应下面应支付金额数据然后是固定窗口大小 可以滚轮撒查看的，每个支持
       单独的导出，这样各店铺当日表现和历史销售明细 · 日期（合计口径）
       这个项目可以删掉了，底部就放一些AI智能的指数分析。」
     「上升用红色，下跌用绿色，整个表都是这样。」
       → 涨跌色已提到 ec-shell.css 的 :root（--delta-*），全站唯一源，本页不再覆盖。

   两件事：
     ① .sa-tblwrap —— 走势图卡片里追加的「同一家店 × 同一个指标」逐期明细，
        固定窗口高（.sa-tblscroll）+ 内部滚轮，右上角自带「导出」只导本店。
     ② .sa-ai —— 销售日报的内容（事实由后端规则引擎算，模型只改写措辞）。
        第 25 轮起只出现在弹窗里（外壳见文件末尾 ③ `.sa-report-mask`），
        页面上只剩「生成销售日报」一个入口按钮（`.sa-ai-entry`）。

   ⚠ 两套颜色别读混：
       · 走势图与明细表里的胶囊 → 吃 :root 的 --delta-*，**表达方向**（涨红跌绿）
       · AI 日报里的「好 / 注意 / 异常 / 口径」 → 表达**结论性质**（好坏），
         所以这一块刻意不放涨跌胶囊，配色也不复用 --delta-*。

   ★ 第 21 轮（老板原话）：「AI分析应该是日报的格式，用于配合未来我们增加
     定时发送日报的功能」→ 底部那块由「一列结论」改成**日报版式**
     （报头 / 正文 / 脚注，见 .sa-ai-rp / .sa-ai-blk / .sa-ai-foot），
     结构与文案全部来自后端 report，前端只排版。
   ★ 第 24 轮（老板原话）：「AI助理日报，总结不需要 / 底下的数据总结 AI 建议应该是
     1/2/3 这种长文字的 / 数据总结应该是对数据的总结，而不是一顿乱说。就是让人一眼
     知道我们的日报有哪些内容 / 多一些图标做总结。」
     → 删掉顶部「总结」（摘要）块；「数据总结」「AI 建议」改**有序编号列表**
       （编号跨分节连续），每条 = 等级图标 + 一句完整的长文字，分节标题带图标。
     同轮还删掉了工具条右侧那段窗口说明（.sa-bar-note）——
     窗口与期数改由日报报头承载。
   ★ 第 25 轮（老板原话）：「销售日报 以弹窗的形式。点击生成销售日报，然后弹出
     销售日报 弹窗可以生成 发送邮件」
     → 日报整块从「页面底部内嵌」搬进**居中大弹窗**；页面只剩一个入口按钮。
       弹窗工具条 = 重新生成 / 生成 PDF / 发送邮件（老板没勾「目标设置」）。
       外壳在文件末尾 ③；里面这 106 条 `.sa-ai-*` 规则**作用域一并从
       `#page-anSales` 换成 `#sa-report-mask`** —— 弹窗挂在 body 上，
       前缀不改就是「弹窗能开、日报全裸、控制台无错」的静默样式失效。
   ================================================================== */

/* ---- ① 每张走势图下方的明细表 ---- */
#page-anSales .sa-tblwrap { margin-top: 8px; padding-top: 7px; border-top: 1px solid #f1f5f9; }
/* 窄屏让「导 出」与期数说明换行，别把表名挤没 —— 直接写进主规则，不另造 @media */
#page-anSales .sa-tblh { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 0 2px 5px; min-width: 0; }
#page-anSales .sa-tblh > b {
  font-size: 11px; font-weight: 600; color: #475569;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#page-anSales .sa-tbln { font-size: 10px; color: #a8b4c7; white-space: nowrap; }
#page-anSales .sa-tblexp { flex: none; padding: 2px 9px; font-size: 10.5px; line-height: 1.7; }
/* ★ 定高 + 内部滚动 = 老板要的「固定窗口大小、可以滚轮查看」。
   overscroll-behavior:contain 让滚到底时不要把整页也带着滚。
   200px ≈ 6 行（行高约 27px + 表头 28px）—— 实测 160px 只露 5 行，
   看一周数据要滚两次，略挤；再高就会把上面的走势图顶出工作台可视区。 */
#page-anSales .sa-tblscroll {
  max-height: 200px; overflow: auto; overscroll-behavior: contain;
  border: 1px solid #eef2f7; border-radius: 8px;
}
/* ★ overflow 用 auto（同时管两个方向）而不是 overflow-y:auto：
   四列在窄列里（≤1180px 时列宽可低到 300px）会顶到 ~320px，
   只写 overflow-y 就会横向顶破卡片。给表格一个最小宽度，
   让列挤到极限时交给容器出横向条，而不是把版面撑坏
   （核验里的横向溢出探针会跳过 overflow 为 auto/scroll 的元素，正好对应这里）。 */
#page-anSales .sa-tbl { width: 100%; min-width: 288px; border-collapse: separate; border-spacing: 0; font-size: 11.5px; }
#page-anSales .sa-tbl thead th {
  position: sticky; top: 0; z-index: 1;
  font-size: 10px; font-weight: 400; color: #94a3b8; background: #fbfdfe;
  padding: 6px 6px; border-bottom: 1px solid #eef2f7; white-space: nowrap; text-align: left;
}
#page-anSales .sa-tbl thead th.num { text-align: right; }
#page-anSales .sa-tbl thead th > i { font-style: normal; color: #b6c0cf; }
/* 单元格左右 padding 压到 6px：月粒度的第 5 列「天数」在 338px 宽的卡片里
   只差 ~14px 就能放下（实测容器 352 / 可用 338），压一压就不用出横向滚动条。 */
#page-anSales .sa-tbl tbody td { padding: 5px 6px; border-bottom: 1px solid #f6f8fb; white-space: nowrap; }
#page-anSales .sa-tbl tbody tr:last-child td { border-bottom: 0; }
#page-anSales .sa-tbl tbody tr:hover td { background: #fafbfc; }
#page-anSales .sa-tbl tbody td.num { text-align: right; font-variant-numeric: tabular-nums; }
#page-anSales .sa-tdt { color: #64748b; font-variant-numeric: tabular-nums; }
#page-anSales .sa-tdd { color: #94a3b8; font-variant-numeric: tabular-nums; }

/* ---- ② 「销售日报」的内容（第 25 轮起只出现在弹窗里）----
   结构（第 24 轮定稿的七块，一个字没改）：
       报头（刊物 · 期次 · 指标 / 谁·多细·看多长）
         → 关键数据（4 个数字格）
           → 累计与达成（本月 / 本年 × 目标 / 完成率）
             → 图表（窗口内逐期走势 + 最新一期各店对比）
               → 数据（最新一期各店明细表）
                 → 数据总结（分节 + 编号 1/2/3… 跨节连续）
                   → 其它板块（预留）
                     → AI 建议（同样编号）
                       → 脚注。
   ★ 结构、数字、文案全部来自后端 report，前端只排版；定时发送日报用的是
     同一份 report 渲染出的纯文本（接口 text 字段），两边不会跑偏。
   ★ 作用域是 `#sa-report-mask`（弹窗外壳）而不是 `#page-anSales`：
     弹窗挂在 document.body 上，前缀写错这 106 条规则会**全部静默失效**。
   ★ 弹窗本身已经是一张白卡，所以这里只给内边距，不再套底纹 / 边框 / 阴影。 */
#sa-report-mask .sa-ai { padding: 16px 18px 18px; }

/* 报头：一条 2px 下划线把它和正文分开，读起来像一份文档的开头 */
#sa-report-mask .sa-ai-rp { padding: 0 2px 9px; border-bottom: 2px solid #eef2f7; }
#sa-report-mask .sa-ai-rp-h {
  display: block; font-size: 14px; font-weight: 700; color: #0f172a;
  letter-spacing: .2px; word-break: break-word;
}
#sa-report-mask .sa-ai-rp-m { margin-top: 4px; font-size: 11px; color: #94a3b8; word-break: break-word; }

/* ★ 第 24 轮：顶部「总结」（摘要）块整块删掉（老板：「AI助理日报，总结不需要」）。
   原来这条规则给摘要加了浅蓝底纹；现在摘要不再渲染，规则一并删除。 */

/* ---- 数据总结 / AI 建议 = 有序编号列表 ----
   老板原话：「底下的数据总结 AI 建议应该是 1/2/3 这种长文字的 /
             数据总结应该是对数据的总结，而不是一顿乱说。就是让人一眼知道
             我们的日报有哪些内容。/ 多一些图标做总结。」
   → 每个分节先出一个带图标的**小标题**，节内条目排成 1/2/3；
     编号**跨分节连续**（前端用 <ol start> 给），一眼数得清一共几个点；
     每条 = 等级图标（替代原来的色块 pill）+ 加粗要点 + 描述，
     连起来读是一段完整的长文字。空分节后端不出现，前端也不出空壳。 */
#sa-report-mask .sa-ai-sums { margin-top: 2px; }
#sa-report-mask .sa-ai-sg { margin-top: 13px; }
#sa-report-mask .sa-ai-sg:first-child { margin-top: 0; }
#sa-report-mask .sa-ai-sgh {
  display: flex; align-items: center; gap: 6px;
  padding: 0 2px 6px; border-bottom: 1px solid #eef2f7;
  font-size: 12px; font-weight: 600; color: #334155;
}
#sa-report-mask .sa-ai-sgh > i { font-size: 11px; color: #94a3b8; }
#sa-report-mask .sa-ai-ol {
  margin: 8px 0 0; padding-left: 28px; list-style: decimal;
  font-size: 12px; line-height: 1.95; color: #334155;
}
#sa-report-mask .sa-ai-ol > li { padding: 3px 0 3px 3px; word-break: break-word; }
#sa-report-mask .sa-ai-ol > li::marker { font-size: 11.5px; font-weight: 600; color: #94a3b8; }
#sa-report-mask .sa-ai-oli { margin-right: 6px; font-size: 10px; color: #94a3b8; }
/* 结论性质色（好 / 注意 / 异常 / 口径）—— 与涨跌方向色是两套语义，勿混用 */
#sa-report-mask .sa-ai-ol > li.is-good .sa-ai-oli { color: #067647; }
#sa-report-mask .sa-ai-ol > li.is-warn .sa-ai-oli { color: #b54708; }
#sa-report-mask .sa-ai-ol > li.is-risk .sa-ai-oli { color: #b42318; }
#sa-report-mask .sa-ai-ol > li.is-info .sa-ai-oli { color: #475569; }
/* 要点与描述之间的全角空格**由渲染层直接写进 DOM**（第 24 轮踩过：
   CSS 伪元素 content 在 innerText / PDF 提取里读不到，看着有、实际没有）。 */
#sa-report-mask .sa-ai-olt { font-weight: 600; color: #1e293b; }
#sa-report-mask .sa-ai-old { color: #64748b; }
#sa-report-mask .sa-ai-ola { color: #1e293b; }
#sa-report-mask .sa-ai-olf { color: #94a3b8; }
/* 脚注：数据来源与口径纪律（不推算 / 缺失不填 0）。
   虚线上边框 —— 让「报告正文到此为止」一眼可辨。 */
#sa-report-mask .sa-ai-foot {
  margin-top: 12px; padding-top: 9px; border-top: 1px dashed #e8eef5;
  font-size: 10.5px; line-height: 1.8; color: #a8b4c7; word-break: break-word;
}
#sa-report-mask .sa-ai-notes {
  margin: 10px 0 0; padding: 9px 12px 9px 26px; border-radius: 8px;
  background: #fbfcfd; border: 1px solid #eef2f7;
  font-size: 10.5px; line-height: 1.9; color: #94a3b8; list-style: disc;
}
#sa-report-mask .sa-ai-notes > li { margin-left: 2px; }

/* ---- 第 22 轮：日报的功能块（总结 / 关键数据 / 图表 / 分析 / 数据）----
   报头下面是五个带小标题的功能块，读起来才像一份日报而不是一列结论。 */
#sa-report-mask .sa-ai-blk { margin-top: 14px; }
#sa-report-mask .sa-ai-blk-h {
  display: flex; align-items: center; gap: 6px;
  margin-bottom: 8px; padding-bottom: 5px; border-bottom: 1px solid #eef2f7;
  font-size: 12px; font-weight: 600; color: #334155;
}
#sa-report-mask .sa-ai-blk-h > i { color: #94a3b8; font-size: 11px; }
/* 「数据总结」块里的分节自己还有一条下划线，块标题就不再画第二条，免得双线夹着 */
#sa-report-mask .sa-ai-blk-h + .sa-ai-sums { margin-top: 0; }
#sa-report-mask .sa-ai-blk-h + .sa-ai-sums > .sa-ai-sg:first-child > .sa-ai-sgh {
  border-bottom: 0; padding-top: 2px;
}

/* 关键数据：4 个数字格 */
#sa-report-mask .sa-ai-kpi { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
#sa-report-mask .sa-ai-kpic {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
  padding: 10px 12px; border-radius: 8px;
  background: #f8fafc; border: 1px solid #eef2f7;
}
#sa-report-mask .sa-ai-kpl { font-size: 10.5px; color: #94a3b8; }
#sa-report-mask .sa-ai-kpv {
  font-size: 17px; font-weight: 700; color: #0f172a;
  letter-spacing: .2px; word-break: break-word;
}
/* 环比的涨跌胶囊在格子里要放大到主数字的体量（颜色仍取全站唯一源） */
#sa-report-mask .sa-ai-kpic .ec-delta { font-size: 15px; font-weight: 700; }
#sa-report-mask .sa-ai-kps { font-size: 10px; color: #b6c1d1; word-break: break-word; }

/* 图表：两张并排；窄了由末尾的媒体查询落到一列 */
#sa-report-mask .sa-ai-charts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
#sa-report-mask .sa-ai-chart {
  min-width: 0; padding: 9px 10px 4px; border-radius: 8px;
  background: #fff; border: 1px solid #eef2f7;
}
#sa-report-mask .sa-ai-chart-h {
  display: flex; align-items: baseline; gap: 6px;
  font-size: 11.5px; font-weight: 600; color: #475569;
}
#sa-report-mask .sa-ai-chart-h > i { font-style: normal; font-size: 10px; color: #b6c1d1; }
#sa-report-mask .sa-ai-chart-b { position: relative; height: 156px; min-height: 0; margin-top: 4px; }
#sa-report-mask .sa-ai-chart-b canvas { display: block; }

/* 数据：最新一期各店明细（表会横向滚动，故不参与页面级的溢出断言） */
#sa-report-mask .sa-ai-tblwrap { overflow-x: auto; overscroll-behavior: contain; }
#sa-report-mask .sa-ai-tbl { width: 100%; font-size: 11.5px; }
#sa-report-mask .sa-ai-tbl th { white-space: nowrap; }
#sa-report-mask .sa-ai-td-n { color: #334155; white-space: nowrap; }
#sa-report-mask .sa-ai-tbl .ec-delta { font-size: 10.5px; }
#sa-report-mask .sa-ai-tblf { margin-top: 6px; font-size: 10px; color: #b6c1d1; word-break: break-word; }


/* ============================================================
   第 23 轮：日报的操作条 + 累计与达成 + 其它板块（预留）+ AI 建议 + 设置面板
   ------------------------------------------------------------
   老板原话：「日报不止有当月数据还有全月数据，KPI功能完成率等情况，然后针对日报
   可以一键生成PDF。然后又发送邮件的功能。分析更多的先是针对数据的总结。最后才是AI建议：
   你就相当于要发给领导看的一个销售日报。…预留一些给商品、流量、内容、推广、人群…
   相当于日报板块跟其他的页面是通的，其他数据补齐了 生成日报PDF然后自动发送邮件。」
   ★ 本块**追加在文件末尾的 @media 之前** —— 媒体查询必须留在最末尾（第 19 轮教训）。
   ============================================================ */

/* 卡片右上角的三个动作按钮（目标 / 生成 PDF / 发送邮件） */
#sa-report-mask .sa-ai-act { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
#sa-report-mask .sa-ai-act .hint { margin-right: 2px; }
#sa-report-mask .sa-ai-act .ec-btn { height: 26px; padding: 0 9px; font-size: 11.5px; }
#sa-report-mask .sa-ai-act .ec-btn[disabled] { opacity: .5; cursor: not-allowed; }

/* 卡片内的设置面板：空着的时候完全不占高度 */
#sa-report-mask .sa-ai-panel { padding: 0; }
#sa-report-mask .sa-ai-panel:empty { display: none; }
#sa-report-mask .sa-ai-pmsgs { padding: 11px 14px 0; }
#sa-report-mask .sa-ai-pmsg { font-size: 11.5px; line-height: 1.7; padding: 7px 10px; border-radius: 7px; word-break: break-word; }
#sa-report-mask .sa-ai-pmsg.is-ok { background: #ecfdf3; color: #067647; }
#sa-report-mask .sa-ai-pmsg.is-err { background: #fef3f2; color: #b42318; }

#sa-report-mask .sa-ai-fm {
  margin: 11px 14px 4px; border: 1px solid #e2e8f0; border-radius: 9px;
  padding: 12px 13px; background: #fbfdff;
}
#sa-report-mask .sa-ai-fmh { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600; color: #1e293b; margin-bottom: 10px; }
#sa-report-mask .sa-ai-fmh > i { color: #2563eb; font-size: 12px; }
#sa-report-mask .sa-ai-fmh > span { font-weight: 400; font-size: 10.5px; color: #94a3b8; }
#sa-report-mask .sa-ai-fmx {
  margin-left: auto; border: 0; background: transparent; color: #94a3b8;
  cursor: pointer; font-size: 12px; padding: 2px 5px; border-radius: 5px;
}
#sa-report-mask .sa-ai-fmx:hover { color: #475569; background: #f1f5f9; }
#sa-report-mask .sa-ai-fmrows { display: grid; gap: 9px; }
#sa-report-mask .sa-ai-fmgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px; }
#sa-report-mask .sa-ai-fld { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
#sa-report-mask .sa-ai-fld.wide { margin-top: 9px; }
#sa-report-mask .sa-ai-fld > span { font-size: 10.5px; color: #64748b; }
#sa-report-mask .sa-ai-fld > input {
  height: 31px; border: 1px solid #dbe3ec; border-radius: 7px; padding: 0 9px;
  font-size: 12px; color: #1e293b; background: #fff; min-width: 0; width: 100%;
}
#sa-report-mask .sa-ai-fld > input:focus { outline: 0; border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,.1); }
#sa-report-mask .sa-ai-chk { display: flex; align-items: center; gap: 6px; margin-top: 10px; font-size: 11.5px; color: #475569; }
#sa-report-mask .sa-ai-fma { display: flex; align-items: center; gap: 9px; margin-top: 11px; flex-wrap: wrap; }
#sa-report-mask .sa-ai-fmm { font-size: 11px; color: #64748b; word-break: break-word; }
#sa-report-mask .sa-ai-fmn {
  margin-top: 10px; padding-top: 9px; border-top: 1px dashed #e8edf4;
  font-size: 10.5px; line-height: 1.8; color: #94a3b8;
}
#sa-report-mask .sa-ai-fmn b { color: #64748b; font-weight: 600; }

/* 「累计与达成」：本月 / 本年两张卡（累计值 + 同比 + 目标 + 完成率 + 进度条） */
#sa-report-mask .sa-ai-cum { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
#sa-report-mask .sa-ai-cumc {
  border: 1px solid #e8edf4; border-radius: 9px; padding: 11px 13px;
  background: #fcfdff; min-width: 0;
}
#sa-report-mask .sa-ai-cumh { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
#sa-report-mask .sa-ai-cumh > b { font-size: 12.5px; color: #1e293b; }
#sa-report-mask .sa-ai-cumh > span { font-size: 10px; color: #94a3b8; white-space: nowrap; }
#sa-report-mask .sa-ai-cumv { margin-top: 4px; font-size: 21px; font-weight: 700; color: #0f172a; letter-spacing: -.2px; }
#sa-report-mask .sa-ai-cumr { margin-top: 2px; font-size: 11px; color: #64748b; }
#sa-report-mask .sa-ai-cumr .ec-delta { font-size: 11px; }
#sa-report-mask .sa-ai-cumt { margin-top: 7px; font-size: 11.5px; color: #334155; line-height: 1.7; }
#sa-report-mask .sa-ai-cumt > b { font-size: 13px; }
#sa-report-mask .sa-ai-cumj {
  font-size: 10px; padding: 1px 6px; border-radius: 5px;
  background: #f1f5f9; color: #64748b; white-space: nowrap;
}
#sa-report-mask .sa-ai-cumc.is-ok .sa-ai-cumj { background: #ecfdf3; color: #067647; }
#sa-report-mask .sa-ai-cumc.is-no .sa-ai-cumj { background: #fef3f2; color: #b42318; }
#sa-report-mask .sa-ai-cumb { height: 6px; border-radius: 4px; background: #eef2f7; margin-top: 8px; overflow: hidden; }
#sa-report-mask .sa-ai-cumb > i { display: block; height: 100%; border-radius: 4px; background: #2563eb; }
/* ★ 达标 / 未达标 —— 结论性质色，与同一张卡的 .sa-ai-cumj 标签、编号列表项
   （.sa-ai-ol > li）的 is-good / is-risk 是同一套色，
   **故意不复用 --delta-up-fg / --delta-down-fg**
   （那对是「涨 / 跌」的方向语义；混用会让页面出现第二个取色真源，
     将来改变量时这里会静默保持旧色）。 */
#sa-report-mask .sa-ai-cumc.is-ok .sa-ai-cumb > i { background: #067647; }
#sa-report-mask .sa-ai-cumc.is-no .sa-ai-cumb > i { background: #b42318; }
#sa-report-mask .sa-ai-cume { margin-top: 7px; font-size: 10.5px; color: #b45309; }
#sa-report-mask .sa-ai-cumn { margin-top: 6px; font-size: 10.5px; color: #94a3b8; }
#sa-report-mask .sa-ai-cumf { margin-top: 9px; font-size: 10.5px; color: #b6c1d1; }

/* 「其它板块（预留）」：商品 / 流量 / 内容 / 推广 / 人群 */
#sa-report-mask .sa-ai-pbs { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 9px; }
#sa-report-mask .sa-ai-pb {
  border: 1px dashed #d7dee8; border-radius: 8px; padding: 9px 10px;
  background: #fbfcfe; min-width: 0;
}
#sa-report-mask .sa-ai-pb > b { display: block; font-size: 12px; color: #334155; }
#sa-report-mask .sa-ai-pb > em {
  display: inline-block; margin-top: 3px; font-style: normal; font-size: 10px;
  padding: 1px 6px; border-radius: 5px; background: #fffaeb; color: #b54708;
}
#sa-report-mask .sa-ai-pb > span { display: block; margin-top: 5px; font-size: 10px; line-height: 1.6; color: #94a3b8; }
#sa-report-mask .sa-ai-pb.is-ready { border-style: solid; border-color: #cfe3f7; background: #f7fbff; }
#sa-report-mask .sa-ai-pbf { margin-top: 9px; font-size: 10.5px; line-height: 1.75; color: #b6c1d1; }

/* 「AI 建议」：日报最后一块，所有行动项集中在这里（也是编号列表）。
   ★ 用中性灰蓝 + 左侧强调条，刻意**不用绿色** —— 免得与涨跌方向色（跌绿）混淆。 */
#sa-report-mask .sa-ai-ol.is-adv {
  margin-top: 2px; padding: 3px 12px 3px 32px;
  border: 1px solid #e8edf4; border-left: 3px solid #2563eb;
  border-radius: 8px; background: #fcfdff;
}
#sa-report-mask .sa-ai-ol.is-adv > li { padding: 8px 0; border-bottom: 1px solid #f1f5f9; }
#sa-report-mask .sa-ai-ol.is-adv > li:last-child { border-bottom: 0; }
#sa-report-mask .sa-ai-advn { margin-top: 8px; font-size: 10.5px; line-height: 1.75; color: #b6c1d1; }

/* ---- ③ 销售日报的入口条 + 日报弹窗（第 25 轮）----
   老板原话：「销售日报 以弹窗的形式。点击生成销售日报，然后弹出销售日报
   弹窗可以生成 发送邮件」
             「销售日报 放在最上面 保证 商品分析/流量分析/内容分析/推广分析/人群分析
               顶部都有一个一样的东西。」
     · `.sa-ai-entry`  —— **六个分析页共用**的入口条（销售/商品/流量/内容/推广/人群），
        统一挂在各页**页头正下方**（「放在最上面」）。
        ★ 因为跨页共用，所以**不带页面作用域**（写成 `#page-anSales .sa-ai-entry`
          就只有销售页有样式，另外五页的入口会全裸 —— 和日报那次同一个坑）。
        ★ 位置从「页面底部」改成「页头正下方」：上边距交给 `.ec-page-head` 自带的
          `margin-bottom: 14px`，这里只补下边距，不叠两层。
     · `.sa-report-mask` —— 弹窗外壳。做法与项目里既有的「创建 AI 任务」弹窗同款：
        遮罩 fixed inset-0 + 白色圆角卡 + 头部固定 / 正文内部滚动，
        z-index 320（与那个弹窗同级，保证盖住侧栏与顶栏）。
     · 正文用 flex + min-height:0 撑着：日报很长（有图有表），
        必须让 `.sa-report-b` 自己滚，而不是把整张卡片顶出视口。
     · 宽 1120px + max-width:100%：桌面是「居中大弹窗」，
        窄屏自然退成全宽（外壳两侧留 24px，见 @media）。 */
.sa-ai-entry { margin: 0 0 14px; }
.sa-ai-entryin {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  justify-content: space-between;
}
.sa-ai-entryt { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sa-ai-entryt > b { font-size: 13px; font-weight: 650; color: var(--ink-1, #1e293b); }
.sa-ai-entryt > span {
  font-size: 11px; color: #94a3b8; line-height: 1.6; word-break: break-word;
}

.sa-report-mask {
  position: fixed; inset: 0; z-index: 320;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; background: rgba(16, 24, 40, .45);
}
.sa-report {
  display: flex; flex-direction: column;
  width: 1120px; max-width: 100%; max-height: 88vh;
  background: #fff; border-radius: 16px; overflow: hidden;
  box-shadow: var(--shadow-pop, 0 24px 60px rgba(16, 24, 40, .2));
}
.sa-report-h {
  flex: none; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 14px 18px; border-bottom: 1px solid var(--panel-line, #eef2f7);
}
/* 标题 + 状态提示占满左侧，工具条靠右；窄屏靠 flex-wrap 自然折行 */
.sa-report-ht {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.sa-report-hn { font-size: 15px; font-weight: 650; color: var(--ink-1, #1e293b); white-space: nowrap; }
/* ★ min-height:0 不能省：flex 子项默认 min-height:auto，内容再高也不会滚，
   而是把 .sa-report 撑破 88vh —— 日报里有表格和画布，必炸。 */
.sa-report-b { flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; }

/* ---- 响应式（左栏宽度 / 图表列数 / 小屏退回自然高）----
   ★ 本块**必须留在整个文件的最末尾**：媒体查询与主块里的同名规则优先级相同，
     谁在后面谁生效。第 19 轮曾把它放在主块之前 → minmax(300px) 与 1fr 两条全被吃掉。
   第 19 轮：右侧是「每个店铺一张走势图」，列数交给 auto-fit 网格自己塌，
   这里只接管「窄到一栏放不下 → 改纵向堆叠、两栏都退回自然高」。
   （第 17/18 轮的列数机制——内联 --sa-cols 与 @media 两处必须一致——已随网格一起作废。） */
@media (max-width: 1180px) {
  #page-anSales .sa-panel { flex: 0 0 232px; width: 232px; }
  #page-anSales .sa-charts { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
}
/* ≤900px：定高工作台不成立（一栏放不下），改成纵向堆叠、全部自然高 */
@media (max-width: 900px) {
  #page-anSales .sa-work { flex-direction: column; height: auto; min-height: 0; }
  #page-anSales .sa-panel { flex: 0 0 auto; width: 100%; height: auto; max-height: 300px; }
  #page-anSales .sa-main { height: auto; }
  /* ★ 必须写 minmax(0, 1fr) 而不是 1fr：单写 `1fr` 等于 `minmax(auto, 1fr)`，
     轨道最小值会取**内容的最小内容宽**。画布上带着 Chart.js 上一次自适应写下的
     内联 width（比如在 900px 时算出的 774px），于是窄到 700/500 时轨道仍被撑成
     774px → 整页横向溢出（实测 620/460px 下 5 个元素 scrollWidth > clientWidth）。
     给最小值一个 0，轨道就只认容器宽度，画布的 ResizeObserver 随即按新宽度重画。 */
  #page-anSales .sa-charts { height: auto; overflow: visible; grid-template-columns: minmax(0, 1fr); }
  /* 日报的两张图并排时每张只剩 ~300px，横向条形的店名会被挤掉 → 落到一列；
     关键数据 4 格同理落成 2×2 */
  #sa-report-mask .sa-ai-charts { grid-template-columns: minmax(0, 1fr); }
  #sa-report-mask .sa-ai-kpi { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 第 23 轮：累计两张卡并排时每张只剩 ~330px，「目标 x　完成率 y　已达标」会折两行 → 落一列 */
  #sa-report-mask .sa-ai-cum { grid-template-columns: minmax(0, 1fr); }
  #sa-report-mask .sa-ai-pbs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #sa-report-mask .sa-ai-fmgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #sa-report-mask .sa-ai-act { gap: 5px; }
  /* 第 24 轮：编号列表在窄屏收一点左内边距，别把正文挤窄 */
  #sa-report-mask .sa-ai-ol { padding-left: 26px; }
  /* 第 25 轮：日报弹窗在窄屏收紧外留白，把宽度让给内容 */
  .sa-report-mask { padding: 12px; }
  .sa-report { max-height: 92vh; border-radius: 12px; }
  .sa-report-h { padding: 11px 13px; }
  #sa-report-mask .sa-ai { padding: 13px 13px 15px; }
}
@media (max-width: 640px) {
  #page-anSales .sa-strow2 { gap: 14px; }
  #page-anSales .sa-kv > b { font-size: 15px; }
  #page-anSales .sa-chart-nm { max-width: 140px; }
  #sa-report-mask .sa-ai-kpi { gap: 8px; }
  #sa-report-mask .sa-ai-kpv,
  #sa-report-mask .sa-ai-kpic .ec-delta { font-size: 15px; }
  #sa-report-mask .sa-ai-chart-b { height: 140px; }
  /* 第 23 轮：小屏把卡片头的按钮换行、预留板块落两列、设置表单落一列 */
  #sa-report-mask .sa-ai-cumv { font-size: 18px; }
  #sa-report-mask .sa-ai-pbs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #sa-report-mask .sa-ai-fmgrid { grid-template-columns: minmax(0, 1fr); }
  #sa-report-mask .sa-ai-act .ec-btn { height: 25px; font-size: 11px; padding: 0 8px; }
  #sa-report-mask .sa-ai-ol { padding-left: 24px; font-size: 11.5px; }
  #sa-report-mask .sa-ai-ol.is-adv { padding-left: 28px; }
  /* 第 25 轮：手机上弹窗几乎贴边，头部工具条换行、标题缩一档 */
  .sa-report-mask { padding: 8px; }
  .sa-report-h { padding: 10px 11px; gap: 8px; }
  .sa-report-hn { font-size: 14px; }
  #sa-report-mask .sa-ai { padding: 11px 11px 13px; }
}

/* ==================================================================
   ★ 第 27 轮 · 商品分析页（#page-anGoods）
   ------------------------------------------------------------------
   老板原话（本轮 10 条）：
     1、商品分析商品需要加入图片，并且可以手动调整列宽
     2、右上角创建AI任务不要
     3、右侧不要以店铺维度显示商品。只需要上面的筛选按钮即可
     4、整理SKU需要有历史回档的功能，不然点击恢复自动以后，什么手动设置的都没了
     5、支持可以直接不点击整理这个SKU，直接在页面上编辑SKU的属性。
     6、组合成分应该是对应整理SKU的产品名字（但是产品没名字要改成系列）
     7、组合/赠品改成 产品
     8、每个SKU的瓶数可能不一样。比如黄尾袋鼠西拉梅洛*6，那么分别是产品西拉*3梅洛*3
     9、逐月明细需要有同环比。
     10、增加年维度 周 日的颗粒维度。

   ① 骨架照销售分析的多维看板（定高工作台 + 左栏 + 右栏），但**用独立的
      gd-* 类，一行 sa-* 规则都不改** —— 销售分析页已定稿，零回归风险优先。
   ② 与第 26 轮的三处结构变化：
      · 左栏**取消店铺分组**（原来一个店一个 .gd-group）→ 改成一整张平铺表格
        （图片列 + 商品 + 金额 + 瓶数），店铺改成一排 .gd-chip 筛选按钮；
      · 左栏从 268px 加宽到 340px（要放缩略图 + 可拖的列宽）；
      · 新增「就地编辑属性」「历史版本」「列宽拖拽」三套控件。
   ③ 弹窗（SKU 整理）挂在 document.body 上 → **它的规则一律用
      #gd-sku-mask 作用域**。作用域写错的表现是「弹窗能开、数据也对、
      控制台一条错都没有，只是样式全丢」—— 第 25 轮踩过一次，别再来。

   ⚠ 四条容易翻车的：
     · .gd-main 用 overflow-y:auto 整体滚，**不要再写死高度**；
     · 窄屏单列一律 minmax(0, 1fr)（单写 1fr 等于 minmax(auto,1fr)，
       画布内联 width 会把轨道撑破 → 整页横向溢出）；
     · flex 子项要滚必须写 min-height:0（默认 min-height:auto 会把父级撑破）；
     · 本块自带 @media 且追加在文件末尾，**别在它后面再加主规则**
       （同名规则谁在后谁生效，会把 @media 吃掉）。
   ================================================================== */

/* ---- 顶部数据状态：整块已撤（第 30 轮） ----
   ★ 老板原话：「【状态卡截图】这部分不需要」→ 澄清后选定「整块删（含 KPI 行）」。
   .gd-status / .gd-strow / .gd-strow2 / .gd-kvl / .gd-kv / .gd-dot /
   .gd-stdate / .gd-stsub / .gd-stnote / .gd-warn-t 全部随 JS 一起删干净
   —— 留在 CSS 里就是「死规则」，classdiff 会记账。
   只留 .gd-flex：它还被左栏排序行、走势图卡头与 SKU 弹窗共用。 */
#page-anGoods .gd-flex { flex: 1 1 auto; min-width: 0; }

/* 页签（粒度 / 走势指标 / 商品结构 / 弹窗筛选共用） */
#page-anGoods .gd-tabbar { display: inline-flex; gap: 2px; padding: 2px; background: #f1f5f9; border-radius: 8px; }
#page-anGoods .gd-tab {
  border: 0; background: none; border-radius: 6px; padding: 3px 10px;
  font-size: 11.5px; line-height: 17px; color: #64748b; cursor: pointer;
  font-family: inherit; transition: background .12s, color .12s;
}
#page-anGoods .gd-tab:hover { color: #334155; }
#page-anGoods .gd-tab.is-on { background: #fff; color: #2563eb; font-weight: 600; box-shadow: 0 1px 2px rgba(16, 24, 40, .06); }

/* ---- 工作台（定高，两栏各自滚） ---- */
#page-anGoods .gd-work {
  /* 第 28 轮：gap 12 -> 0（中间让位给可拖的分隔条）。
     ★ 第 28 轮修正：这个高度**不再写死**成 900（900 装不下上方 892px 的内容，
     会把逐期明细压到 48px 再裁掉 140px）。静态值只作兜底，真实高度由
     gdFitWork() 按右栏内容量出来；左栏靠 stretch 自动等高。 */
  display: flex; gap: 0; height: 1240px; min-height: 0;
  align-items: stretch;
}
#page-anGoods .gd-panel {
  /* ★ 第 27 轮：268 → 340px（清单变成带缩略图的表格，268 放不下） */
  flex: 0 0 340px; width: 340px; height: 100%; min-height: 0;
  display: flex; flex-direction: column;
  background: #fff; border: 1px solid #e6e8ec; border-radius: 12px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04); overflow: hidden;
}
#page-anGoods .gd-main {
  /* 第 28 轮第 5 条：右栏自己不再整体滚动（原来 overflow-y:auto），
     改成纵向 flex —— 上方内容固定，只有「逐期明细」那一段滚。
     ★ 高度不由自己决定（去掉 height:100%），由 .gd-work 承担，见 gdFitWork()。 */
  flex: 1 1 auto; min-width: 0; min-height: 0;
  display: flex; flex-direction: column; overflow: hidden;
}

/* ---- 左栏：搜索 / 店铺筛选 / 排序 ---- */
#page-anGoods .gd-search { padding: 10px 10px 8px; }
#page-anGoods .gd-search input {
  width: 100%; box-sizing: border-box;
  border: 1px solid #e2e8f0; border-radius: 8px; background: #f8fafc;
  padding: 6px 10px; font-size: 12px; color: #334155; outline: none;
  transition: border-color .12s, background .12s;
}
#page-anGoods .gd-search input:focus { border-color: #93c5fd; background: #fff; }
#page-anGoods .gd-search input::placeholder { color: #a8b3c2; }
#page-anGoods .gd-chips {
  display: flex; flex-wrap: wrap; gap: 5px;
  padding: 0 10px 8px;
}
#page-anGoods .gd-chip {
  display: inline-flex; align-items: center; gap: 4px;
  border: 1px solid #e2e8f0; background: #fff; border-radius: 20px;
  padding: 2px 9px; font-size: 10.5px; line-height: 17px; color: #64748b;
  cursor: pointer; font-family: inherit; transition: background .12s, color .12s, border-color .12s;
}
#page-anGoods .gd-chip b { font-weight: 650; color: #94a3b8; font-variant-numeric: tabular-nums; }
#page-anGoods .gd-chip-p { font-style: normal; font-size: 9px; padding: 0 4px; border-radius: 4px; background: #f1f5f9; color: #94a3b8; }
#page-anGoods .gd-chip:hover { border-color: #cbd5e1; color: #334155; }
#page-anGoods .gd-chip.is-on { background: #2563eb; border-color: #2563eb; color: #fff; }
#page-anGoods .gd-chip.is-on b, #page-anGoods .gd-chip.is-on .gd-chip-p { color: #dbeafe; }
#page-anGoods .gd-chip.is-on .gd-chip-p { background: rgba(255, 255, 255, .18); }
#page-anGoods .gd-sorts {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  padding: 0 10px 8px; margin-bottom: 0;
  border-bottom: 1px solid #f1f5f9;
}
#page-anGoods .gd-sortl { font-size: 10.5px; color: #a8b3c2; }
#page-anGoods .gd-cnt { font-size: 10.5px; color: #a8b3c2; font-variant-numeric: tabular-nums; }
#page-anGoods .gd-sortb {
  border: 0; background: none; border-radius: 6px; padding: 2px 6px;
  font-size: 10.5px; color: #94a3b8; cursor: pointer; font-family: inherit;
  transition: background .12s, color .12s;
}
#page-anGoods .gd-sortb:hover { background: #f1f5f9; color: #334155; }
#page-anGoods .gd-sortb.is-on { background: #eff6ff; color: #2563eb; font-weight: 600; }

/* ---- 左栏：商品清单（第 27 轮起是**一张平铺表格**，不再按店铺分组） ---- */
#page-anGoods .gd-list { flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; }
#page-anGoods .gd-side-empty { padding: 26px 12px; text-align: center; font-size: 12px; color: #a8b3c2; }

/* 表格通用：列宽可控（table-layout:fixed + colgroup），表头右侧有拖拽手柄 */
#page-anGoods .gd-tbl {
  table-layout: fixed; width: 100%;
  border-collapse: separate; border-spacing: 0; font-size: 12px;
}
#page-anGoods .gd-tbl thead th {
  position: relative; text-align: left;
  font-size: 10.5px; font-weight: 600; letter-spacing: .03em; color: #94a3b8;
  padding: 7px 9px; background: #fafbfc;
  border-bottom: 1px solid var(--panel-line); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
#page-anGoods .gd-tbl tbody td {
  padding: 7px 9px; border-bottom: 1px solid var(--panel-line-soft);
  color: var(--ink-2); vertical-align: middle;
  overflow: hidden; text-overflow: ellipsis;
}
#page-anGoods .gd-tbl tbody tr:last-child td { border-bottom: 0; }
#page-anGoods .gd-tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
#page-anGoods .gd-tbl .strong { color: var(--ink-1); font-weight: 600; }
/* 左栏清单的粘性表头（列表自己滚，表头别跟着跑） */
#page-anGoods .gd-ltbl thead th { position: sticky; top: 0; z-index: 2; }
#page-anGoods .gd-ltbl tbody tr { cursor: pointer; transition: background .12s; }
#page-anGoods .gd-ltbl tbody tr:hover td { background: #fafbfc; }
#page-anGoods .gd-ltbl tbody tr.is-on td { background: #eff6ff; }
#page-anGoods .gd-ltbl tbody tr.is-on td:first-child { box-shadow: inset 2px 0 0 #2563eb; }
#page-anGoods .gd-ltbl .gd-cc-nm b { display: block; font-size: 12px; font-weight: 600; color: #1e293b; line-height: 1.45; }
#page-anGoods .gd-ltbl .gd-cc-nm span { display: block; margin-top: 2px; font-size: 10.5px; color: #94a3b8; }
#page-anGoods .gd-ltbl .gd-cc-num { text-align: right; font-variant-numeric: tabular-nums; font-size: 11.5px; color: #475569; }
#page-anGoods .gd-ltbl tbody tr.is-on .gd-cc-num { color: #1d4ed8; font-weight: 620; }
#page-anGoods .gd-cc-img { text-align: center; }

/* 表头文字：一行 + 省略号（第 28 轮：表内列宽拖拽已按老板要求撤掉，手柄样式一并删除） */
#page-anGoods .gd-thin { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; }
body.gd-resizing { cursor: col-resize !important; user-select: none; }
#gd-sku-mask .gd-thin { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; }

/* ---- 商品图片：占位图标垫底，<img> 盖在上面，加载失败就把 img 藏掉 ---- */
#page-anGoods .gd-thumbbox, #gd-sku-mask .gd-thumbbox {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  overflow: hidden; background: #f1f5f9; color: #cbd5e1; flex: none;
}
#page-anGoods .gd-thumbbox > i, #gd-sku-mask .gd-thumbbox > i { font-size: 13px; }
#page-anGoods .gd-thumbbox > img, #gd-sku-mask .gd-thumbbox > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
#page-anGoods .gd-thumb, #gd-sku-mask .gd-thumb { width: 34px; height: 34px; border-radius: 7px; }
#page-anGoods .gd-dimg, #gd-sku-mask .gd-dimg { width: 58px; height: 58px; border-radius: 10px; }
#page-anGoods .gd-dimg > i, #gd-sku-mask .gd-dimg > i { font-size: 19px; }

/* ---- 右栏：头部 ---- */
#page-anGoods .gd-detail { display: flex; flex-direction: column; gap: 12px; padding-right: 2px;
  /* 第 28 轮修正：右栏自己按内容长高（flex:0 0 auto），不再被窗口高度挤压裁切。
     真正提供给容器的高度由 .gd-work 承担，见 gdFitWork()。 */
  flex: 0 0 auto; min-height: 0; height: auto; overflow: visible; }
#page-anGoods .gd-dhead { display: flex; align-items: flex-start; gap: 12px; }
#page-anGoods .gd-dmeta { flex: 1 1 auto; min-width: 0; }
#page-anGoods .gd-dnm { display: block; font-size: 14.5px; font-weight: 650; color: #0f172a; line-height: 1.5; }
#page-anGoods .gd-dtags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }

/* ---- 右栏：属性（只读 / 就地编辑 / 历史） ---- */
#page-anGoods .gd-prop-h { display: flex; align-items: center; gap: 7px; margin-bottom: 9px; flex-wrap: wrap; }
#page-anGoods .gd-prop-h b { font-size: 12.5px; font-weight: 650; color: #334155; }
#page-anGoods .gd-prop-hs { font-size: 11px; color: #a8b3c2; }
#page-anGoods .gd-props {
  /* 第 28 轮第 4 条：三列 -> 两列。产品构成通栏占满第 1 排，其余 5 个字段 2+2+1
     正好排成第 2/3/4 排 —— 这就是老板要的「四排展示」。 */
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px;
  background: #eef2f7; border: 1px solid #eef2f7; border-radius: 10px; overflow: hidden;
}
#page-anGoods .gd-prop { display: flex; flex-direction: column; gap: 3px; padding: 9px 11px; background: #fff; min-width: 0; }
#page-anGoods .gd-prop i { font-style: normal; font-size: 10.5px; color: #94a3b8; }
#page-anGoods .gd-prop b { font-size: 12.5px; font-weight: 620; color: #1e293b; word-break: break-all; }
#page-anGoods .gd-prop-w { grid-column: span 2; }
#page-anGoods .gd-prop-w b { font-weight: 600; color: #334155; line-height: 1.7; }
#page-anGoods .gd-warns {
  margin: 8px 0 0; padding: 8px 10px 8px 26px; list-style: disc;
  background: #fffaeb; border: 1px solid #fedf89; border-radius: 9px;
  font-size: 11px; line-height: 1.8; color: #b54708;
}
/* ★ 第 31 轮：.gd-na（结构行里那个「--」）随结构行一起撤掉 ——
   留着就是死规则，类名自查会记账。 */

/* ---- 右栏：就地编辑表单 ---- */
#page-anGoods .gd-editbox {
  display: flex; flex-direction: column; gap: 10px;
  padding: 11px; border: 1px solid #bfdbfe; border-radius: 10px; background: #f8fbff;
}
#page-anGoods .gd-editrow { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 9px; }
/* 图片地址单独通栏（URL 很长，塞进 1/4 列看不清）—— 第 28 轮第 3 条 */
#page-anGoods .gd-edimg { grid-column: 1 / -1; }
#page-anGoods .gd-editrow label, #page-anGoods .gd-editsec label { display: flex; flex-direction: column; gap: 4px; font-size: 10.5px; color: #94a3b8; }
#page-anGoods .gd-editsec { display: flex; flex-direction: column; gap: 6px; }
#page-anGoods .gd-editl { font-size: 10.5px; color: #94a3b8; }
#page-anGoods .gd-editl b { color: #64748b; font-weight: 600; }
#page-anGoods .gd-edwarn {
  margin-left: 8px; font-style: normal; font-size: 10.5px; color: #b54708;
  background: #fffaeb; border: 1px solid #fedf89; border-radius: 6px; padding: 1px 6px;
}
#page-anGoods .gd-edparts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 5px; }
#page-anGoods .gd-edpart { display: grid; grid-template-columns: minmax(0, 1fr) 62px 28px; gap: 5px; align-items: center; }
#page-anGoods .gd-edit-empty { font-size: 11px; color: #a8b3c2; }
#page-anGoods .gd-editfoot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding-top: 9px; border-top: 1px solid #dbeafe; }
#page-anGoods .gd-editnote { font-size: 10.5px; color: #94a3b8; line-height: 1.7; flex: 1 1 220px; }
#page-anGoods .gd-editnote b { color: #64748b; font-weight: 600; }

/* 输入控件（页面与弹窗共用 → 两个作用域各写一份） */
#page-anGoods .gd-in, #gd-sku-mask .gd-in {
  width: 100%; box-sizing: border-box;
  border: 1px solid #e2e8f0; border-radius: 7px; background: #fff;
  padding: 5px 8px; font-size: 12px; color: #334155; outline: none;
  font-family: inherit; transition: border-color .12s, box-shadow .12s;
}
#page-anGoods .gd-in:focus, #gd-sku-mask .gd-in:focus { border-color: #93c5fd; box-shadow: 0 0 0 3px #93c5fd26; }
#page-anGoods .gd-in-sm, #gd-sku-mask .gd-in-sm { font-size: 11.5px; padding: 4px 7px; }
#page-anGoods .gd-in-xs { font-size: 11.5px; padding: 4px 4px; text-align: center; }

/* ---- 历史版本（页面与弹窗共用） ---- */
#page-anGoods .gd-hist, #gd-sku-mask .gd-hist {
  margin-top: 9px; border: 1px solid #e6e8ec; border-radius: 10px; background: #fff; overflow: hidden;
}
#page-anGoods .gd-hist-h, #gd-sku-mask .gd-hist-h {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 11px; background: #fafbfc; border-bottom: 1px solid #f1f5f9;
}
#page-anGoods .gd-hist-h b, #gd-sku-mask .gd-hist-h b { font-size: 12px; font-weight: 650; color: #334155; }
#page-anGoods .gd-hist-h span, #gd-sku-mask .gd-hist-h span { font-size: 10.5px; color: #a8b3c2; }
#page-anGoods .gd-hist-list, #gd-sku-mask .gd-hist-in { padding: 4px 0; }
#page-anGoods .gd-hist-list, #gd-sku-mask .gd-hist-list { padding: 8px 11px; }
#gd-sku-mask .gd-hist-in { padding: 8px 11px; display: flex; flex-direction: column; gap: 5px; }
#page-anGoods .gd-hist-it, #gd-sku-mask .gd-hist-it {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 6px 0; border-bottom: 1px dashed #f1f5f9;
}
#page-anGoods .gd-hist-it:last-child, #gd-sku-mask .gd-hist-it:last-child { border-bottom: 0; }
#page-anGoods .gd-hist-t, #gd-sku-mask .gd-hist-t { font-size: 11px; color: #64748b; font-variant-numeric: tabular-nums; flex: none; }
#page-anGoods .gd-hist-a, #gd-sku-mask .gd-hist-a {
  font-size: 10px; color: #64748b; background: #f1f5f9; border-radius: 5px; padding: 1px 6px; flex: none;
}
#page-anGoods .gd-hist-d, #gd-sku-mask .gd-hist-d { flex: 1 1 200px; min-width: 0; font-size: 11.5px; color: #334155; line-height: 1.7; }
#page-anGoods .gd-hist-auto, #gd-sku-mask .gd-hist-auto { color: #b54708; font-weight: 620; }
#page-anGoods .gd-hist-none, #gd-sku-mask .gd-hist-none,
#page-anGoods .gd-hist-loading, #gd-sku-mask .gd-hist-loading { font-size: 11px; color: #a8b3c2; }

/* ---- 右栏：KPI 格 ---- */
#page-anGoods .gd-kpis {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px;
  background: #eef2f7; border: 1px solid #eef2f7; border-radius: 10px; overflow: hidden;
}
#page-anGoods .gd-kpi { display: flex; flex-direction: column; gap: 2px; padding: 9px 11px; background: #fff; min-width: 0; }
#page-anGoods .gd-kpi-l { font-size: 10.5px; color: #94a3b8; }
#page-anGoods .gd-kpi-v { font-size: 15px; font-weight: 650; color: #1e293b; font-variant-numeric: tabular-nums; line-height: 1.35; }
#page-anGoods .gd-kpi-f { font-size: 10px; color: #a8b3c2; }

/* ---- 右栏：走势图 ---- */
#page-anGoods .gd-chartcard { border: 1px solid #e6e8ec; border-radius: 12px; background: #fff; overflow: hidden; }
#page-anGoods .gd-chart-h {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; border-bottom: 1px solid #f1f5f9;
}
#page-anGoods .gd-chart-lab { font-size: 12.5px; font-weight: 650; color: #334155; }
#page-anGoods .gd-chart-note { font-size: 10.5px; color: #a8b3c2; }
#page-anGoods .gd-chart-b { height: 190px; padding: 8px 10px 10px; }

/* ---- 右栏：逐期明细（第 9 条：同环比两列） ---- */
#page-anGoods .gd-tblwrap { border: 1px solid #e6e8ec; border-radius: 12px; background: #fff; overflow: hidden;
  display: flex; flex-direction: column; }
#page-anGoods .gd-tblh {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; border-bottom: 1px solid #f1f5f9;
}
#page-anGoods .gd-tblh b { font-size: 12.5px; font-weight: 650; color: #334155; }
#page-anGoods .gd-tbln { font-size: 10.5px; color: #a8b3c2; }
#page-anGoods .gd-tblscroll { flex: 1 1 auto; min-height: 0; max-height: none; overflow: auto; overscroll-behavior: contain; }
#page-anGoods .gd-tblscroll .gd-tbl thead th { position: sticky; top: 0; z-index: 2; }
#page-anGoods .gd-tblfoot { padding: 8px 12px 10px; border-top: 1px solid #f1f5f9; font-size: 10.5px; line-height: 1.8; color: #94a3b8; }
#page-anGoods .gd-tblfoot b { color: #64748b; font-weight: 620; }
#page-anGoods .gd-tdt { white-space: nowrap; font-variant-numeric: tabular-nums; color: #334155; font-weight: 600; }
#page-anGoods .gd-tdt i { display: block; font-style: normal; font-size: 9.5px; font-weight: 400; color: #b6c0cc; }
/* 同环比小签：涨红跌绿 —— 颜色一律走全站唯一真源变量，不写死色值 */
#page-anGoods .gd-dl { font-size: 11px; font-variant-numeric: tabular-nums; font-weight: 600; }
#page-anGoods .gd-dl.up { color: var(--delta-up-fg); }
#page-anGoods .gd-dl.down { color: var(--delta-down-fg); }
#page-anGoods .gd-dl.flat { color: #94a3b8; }
#page-anGoods .gd-dl.is-na { color: #cbd5e1; font-weight: 400; }

/* ---- 右栏：商品结构 ----
   ★ 第 31 轮：.gd-disthead / .gd-distnote（四档页签条）随长列表一起撤掉，
     商品结构改成图表网格，样式见下方「① 商品结构：图表网格」。 */

/* ---- 待确认 / 已确认标记（页面与弹窗共用） ---- */
#page-anGoods .gd-flag, #gd-sku-mask .gd-flag {
  display: inline-flex; align-items: center; flex: none;
  font-size: 10px; line-height: 16px; padding: 0 7px; border-radius: 20px;
  font-weight: 600; white-space: nowrap;
}
#page-anGoods .gd-flag.is-ok, #gd-sku-mask .gd-flag.is-ok { background: #ecfdf3; color: #067647; }
#page-anGoods .gd-flag.is-warn, #gd-sku-mask .gd-flag.is-warn { background: #fffaeb; color: #b54708; }
#page-anGoods .gd-flag.is-auto, #gd-sku-mask .gd-flag.is-auto { background: #f1f5f9; color: #64748b; }
#page-anGoods .gd-flag.is-dirty, #gd-sku-mask .gd-flag.is-dirty { background: #eff6ff; color: #1d4ed8; }

/* ---- 右栏空态 ---- */
#page-anGoods .gd-empty { padding: 70px 20px; text-align: center; color: #a8b3c2; }
#page-anGoods .gd-empty > i { font-size: 26px; color: #cbd5e1; }
#page-anGoods .gd-empty-t { margin-top: 12px; font-size: 13.5px; font-weight: 620; color: #64748b; }
#page-anGoods .gd-empty-s { margin-top: 6px; font-size: 11.5px; line-height: 1.9; color: #a8b3c2; max-width: 420px; margin-left: auto; margin-right: auto; }

/* ---- SKU 整理入口条 + 图片链接格式 ---- */
#page-anGoods .gd-sku-entry { border: 1px solid #dbeafe; background: #f8fbff; }
#page-anGoods .gd-sku-entryin { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
#page-anGoods .gd-sku-entryt { flex: 1 1 320px; min-width: 0; }
#page-anGoods .gd-sku-entryt b { display: block; font-size: 13px; font-weight: 650; color: #1e293b; }
#page-anGoods .gd-sku-entryt span { display: block; margin-top: 3px; font-size: 11px; line-height: 1.7; color: #94a3b8; }
#page-anGoods .gd-sku-prog { font-size: 11.5px; color: #64748b; flex: none; }
#page-anGoods .gd-sku-prog b { color: #1d4ed8; font-weight: 650; font-variant-numeric: tabular-nums; }
#page-anGoods .gd-imgon {
  margin-left: 5px; font-size: 9px; background: #ecfdf3; color: #067647;
  border-radius: 4px; padding: 0 4px; font-weight: 600;
}
#page-anGoods .gd-imgset {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 10px; border-top: 1px dashed #bfdbfe;
}
#page-anGoods .gd-imgset input {
  flex: 1 1 420px; min-width: 0; box-sizing: border-box;
  border: 1px solid #e2e8f0; border-radius: 7px; background: #fff;
  padding: 6px 9px; font-size: 12px; color: #334155; outline: none; font-family: inherit;
}
#page-anGoods .gd-imgset input:focus { border-color: #93c5fd; box-shadow: 0 0 0 3px #93c5fd26; }
#page-anGoods .gd-imgset-n { font-size: 10.5px; color: #a8b3c2; flex: 1 1 100%; line-height: 1.7; }

/* ==================================================================
   SKU 整理弹窗（挂在 body 上 → 作用域一律 #gd-sku-mask）
   ================================================================== */
.gd-sku-mask {
  position: fixed; inset: 0; z-index: 330;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; background: rgba(16, 24, 40, .45);
}
.gd-sku {
  display: flex; flex-direction: column;
  width: 1440px; max-width: 100%; max-height: 88vh;
  background: #fff; border-radius: 16px; overflow: hidden;
  box-shadow: 0 24px 60px rgba(15, 23, 42, .28);
}
.gd-sku-h {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 13px 16px; border-bottom: 1px solid #eef2f7; flex: none;
}
.gd-sku-ht { flex: 1 1 300px; min-width: 0; }
.gd-sku-hn { display: block; font-size: 15px; font-weight: 650; color: #0f172a; }
.gd-sku-ht .hint { display: block; margin-top: 3px; font-size: 11px; line-height: 1.7; color: #94a3b8; }
.gd-sku-act { display: flex; align-items: center; gap: 8px; flex: none; }
.gd-sku-x { width: 30px; height: 30px; padding: 0; justify-content: center; }
/* ★ min-height:0 不能省：flex 子项默认 min-height:auto，内容再高也不会滚，而是把 .gd-sku 撑破 88vh */
.gd-sku-b { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 0 16px 12px; }
.gd-sku-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 0; flex: none;
}
.gd-sku-cnt { font-size: 11.5px; color: #94a3b8; font-variant-numeric: tabular-nums; flex: none; }
.gd-sku-colhint { font-size: 10.5px; color: #cbd5e1; flex: none; }
#gd-sku-mask .gd-search { width: 240px; flex: none; }
#gd-sku-mask .gd-search input {
  width: 100%; box-sizing: border-box;
  border: 1px solid #e2e8f0; border-radius: 8px; background: #f8fafc;
  padding: 6px 10px; font-size: 12px; color: #334155; outline: none;
  transition: border-color .12s, background .12s;
}
#gd-sku-mask .gd-search input:focus { border-color: #93c5fd; background: #fff; }
#gd-sku-mask .gd-search input::placeholder { color: #a8b3c2; }
#gd-sku-mask .gd-tabbar { display: inline-flex; gap: 2px; padding: 2px; background: #f1f5f9; border-radius: 8px; flex: none; }
#gd-sku-mask .gd-tab {
  border: 0; background: none; border-radius: 6px; padding: 3px 10px;
  font-size: 11.5px; line-height: 17px; color: #64748b; cursor: pointer;
  font-family: inherit; transition: background .12s, color .12s;
}
#gd-sku-mask .gd-tab:hover { color: #334155; }
#gd-sku-mask .gd-tab.is-on { background: #fff; color: #2563eb; font-weight: 600; box-shadow: 0 1px 2px rgba(16, 24, 40, .06); }
#gd-sku-mask .gd-flex { flex: 1 1 auto; min-width: 0; }
#gd-sku-mask .gd-sku-tblwrap { flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; }
#gd-sku-mask .gd-sku-tip {
  flex: none; padding-top: 9px; margin-top: 9px; border-top: 1px solid #f1f5f9;
  font-size: 10.5px; line-height: 1.85; color: #94a3b8;
}
#gd-sku-mask .gd-sku-tip b { color: #64748b; font-weight: 620; }
#gd-sku-mask .gd-sku-tipw { color: #b54708 !important; }

/* 弹窗表：列宽可控（table-layout:fixed + colgroup），表头带拖拽手柄 */
#gd-sku-mask .gd-sku-table {
  table-layout: fixed; width: 100%;
  border-collapse: separate; border-spacing: 0; font-size: 12px;
}
#gd-sku-mask .gd-sku-table thead th {
  position: sticky; top: 0; z-index: 2;
  text-align: left; font-size: 10.5px; font-weight: 600; letter-spacing: .03em;
  color: #94a3b8; padding: 8px 9px; background: #fafbfc;
  border-bottom: 1px solid var(--panel-line); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
/* ★ 单元格必须有内边距 —— 第 26 轮这里漏了，文字全贴边（靠量 paddingLeft=0 才抓到） */
#gd-sku-mask .gd-sku-table tbody td {
  padding: 8px 9px; border-bottom: 1px solid var(--panel-line-soft);
  color: var(--ink-2); vertical-align: top; overflow: hidden;
}
#gd-sku-mask .gd-sku-table tbody tr:last-child td { border-bottom: 0; }
#gd-sku-mask .gd-sku-table tbody tr.is-warn td { background: #fffcf5; }
#gd-sku-mask .gd-sku-table .num { text-align: right; font-variant-numeric: tabular-nums; }
#gd-sku-mask .gd-sku-table .gd-cc-img { text-align: center; }
#gd-sku-mask .gd-sku-table .gd-cc-num input { text-align: center; }
#gd-sku-mask .gd-sku-it b { display: block; font-size: 12px; font-weight: 600; color: #1e293b; line-height: 1.45; }
#gd-sku-mask .gd-sku-it i { display: block; margin-top: 2px; font-style: normal; font-size: 10.5px; color: #94a3b8; }
#gd-sku-mask .gd-sku-ser { color: #b6c0cc !important; }
#gd-sku-mask .gd-sku-one { flex: none; }
#gd-sku-mask .gd-sku-histb { flex: none; width: 26px; height: 26px; padding: 0; justify-content: center; }
#gd-sku-mask .gd-sku-histb.is-on { background: #eff6ff; color: #2563eb; }
#gd-sku-mask .gd-cc-st { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
#gd-sku-mask .gd-sku-histtr > td { padding: 0 !important; background: #fafbfc; }
#gd-sku-mask .gd-sku-histtr .gd-hist { margin: 0; border: 0; border-radius: 0; }
#gd-sku-mask .gd-sku-histtr .gd-hist-h { background: #f5f7fa; }

/* 「产品」列：一件里装什么（多款酒各带瓶数 + 赠品） */
#page-anGoods .gd-parts, #gd-sku-mask .gd-parts { display: flex; flex-direction: column; gap: 5px; }
#page-anGoods .gd-part, #gd-sku-mask .gd-part {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) 62px 24px;
  gap: 5px; align-items: center;
}
#page-anGoods .gd-part-t, #gd-sku-mask .gd-part-t {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; line-height: 18px; border-radius: 5px;
  background: #eff6ff; color: #1d4ed8; font-weight: 600;
}
#page-anGoods .gd-part.is-gift .gd-part-t, #gd-sku-mask .gd-part.is-gift .gd-part-t { background: #fef3c7; color: #b54708; }
#page-anGoods .gd-part-x, #gd-sku-mask .gd-part-x {
  border: 0; background: none; color: #cbd5e1; cursor: pointer; font-size: 11px;
  padding: 0; height: 24px; border-radius: 5px; transition: color .12s, background .12s;
}
/* ★ 这里用「异常」语义色 #b42318（好 #067647 / 注意 #b54708 / 异常 #b42318），
   **不能写成涨跌色** —— 删掉一行不是「涨」，写涨色值会造出第二个取色真源
   （_guard-colors.py 规矩一，第 23 轮踩过一次；★ 连注释里都不许出现那个十六进制，
     守则是按整行匹配的）。 */
#page-anGoods .gd-part-x:hover, #gd-sku-mask .gd-part-x:hover { background: #fef2f2; color: #b42318; }
#page-anGoods .gd-parts-f, #gd-sku-mask .gd-parts-f { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
#page-anGoods .gd-part-add, #gd-sku-mask .gd-part-add {
  border: 1px dashed #cbd5e1; background: none; border-radius: 6px;
  padding: 2px 7px; font-size: 10.5px; color: #64748b; cursor: pointer; font-family: inherit;
  transition: border-color .12s, color .12s;
}
#page-anGoods .gd-part-add:hover, #gd-sku-mask .gd-part-add:hover { border-color: #93c5fd; color: #2563eb; }
#page-anGoods .gd-parts-sum, #gd-sku-mask .gd-parts-sum { font-size: 10.5px; color: #94a3b8; font-variant-numeric: tabular-nums; }
#page-anGoods .gd-parts-sum.is-bad, #gd-sku-mask .gd-parts-sum.is-bad { color: #b54708; font-weight: 620; }
#page-anGoods .gd-in-pn, #gd-sku-mask .gd-in-pn { font-size: 11.5px; padding: 4px 7px; }
#page-anGoods .gd-in-pq, #gd-sku-mask .gd-in-pq { font-size: 11.5px; padding: 4px 4px; text-align: center; }
#gd-sku-mask .gd-in-pq:disabled { background: #f8fafc; color: #94a3b8; }
#page-anGoods .gd-side-empty, #gd-sku-mask .gd-side-empty { padding: 26px 12px; text-align: center; font-size: 12px; color: #a8b3c2; }

/* ==================================================================
   ★ 第 28 轮新增（一律追加在本文件最后一段主块；@media 仍在最末尾）
   ================================================================== */

/* ---- 第 1 条：左栏宽度分隔条（老板要的是调「左侧窗口」宽，不是表内列宽） ---- */
#page-anGoods .gd-split {
  flex: 0 0 12px; align-self: stretch; position: relative;
  cursor: col-resize; user-select: none; background: transparent;
}
#page-anGoods .gd-split::before {
  content: ''; position: absolute; top: 8px; bottom: 8px; left: 5px; width: 2px;
  background: #e6e8ec; border-radius: 2px; transition: background .12s;
}
#page-anGoods .gd-split:hover::before, #page-anGoods .gd-split:active::before { background: #2563eb; }
#page-anGoods .gd-split-g {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; gap: 2px; padding: 5px 3px;
  border: 1px solid #e6e8ec; border-radius: 6px; background: #fff;
  opacity: 0; transition: opacity .12s;
}
#page-anGoods .gd-split:hover .gd-split-g { opacity: 1; }
#page-anGoods .gd-split-g i { display: block; width: 6px; height: 1px; background: #94a3b8; }

/* ---- 第 2 条：商品大标题 = 详情页链接 ---- */
#page-anGoods .gd-dlink {
  color: #0f172a; text-decoration: none; border-bottom: 1px solid transparent;
  transition: color .12s, border-color .12s;
}
#page-anGoods .gd-dlink:hover { color: #2563eb; border-bottom-color: #93c5fd; }
#page-anGoods .gd-dlink-ic { margin-left: 5px; font-size: 10px; color: #a8b3c2; vertical-align: middle; }
#page-anGoods .gd-dlink:hover .gd-dlink-ic { color: #2563eb; }

/* ---- 第 4 条：产品（一件里装什么）只读展示：每个产品一条 ---- */
#page-anGoods .gd-pitems { display: flex; flex-wrap: wrap; gap: 5px; }
#page-anGoods .gd-pitem {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 2px 8px; border-radius: 999px;
  background: #eff6ff; color: #1d4ed8; font-size: 11.5px; font-weight: 600;
}
#page-anGoods .gd-pitem em { font-style: normal; font-size: 10.5px; font-weight: 650; color: #2563eb; }
#page-anGoods .gd-pitem.is-gift { background: #fffaeb; color: #b54708; }
#page-anGoods .gd-pitem.is-gift em { color: #b54708; }
#page-anGoods .gd-psum { margin-left: 6px; font-size: 10.5px; color: #94a3b8; font-variant-numeric: tabular-nums; }
#page-anGoods .gd-psum.is-bad { color: #b54708; font-weight: 620; }

/* ---- 第 5 条：右栏里只有「逐期明细」一段滚 ---- */
#page-anGoods .gd-detail > * { flex: 0 0 auto; }
/* 逐期明细：不再是「吃剩余高度」（剩余为负时会被压到 48px），改成固定上限，
   表头 .gd-tblh / 表尾 .gd-tblfoot 固定，只有 .gd-tblscroll 内部滚。 */
#page-anGoods .gd-detail > .gd-tblwrap { flex: 0 0 auto; max-height: 340px; }

/* ==================================================================
   第 29 轮（老板 6 条需求里的 ②③④）
   ================================================================== */

/* ---- 第 30 轮：状态卡整块撤了，第 29 轮这条 .gd-strow2:first-child 兜底也一起撤 ---- */

/* ---- 需求②：左侧商品列不换行（标题行 + 结构行各锁一行，超出省略号） ----
   ★★ 必须用**子选择器 `>`**：结构行里还嵌着 .gd-mini（需求③ 的「图标+数据」块）。
      第一版写成后代选择器 `.gd-cc-nm span`，特异性 (1,2,1) 高于 .gd-mini 的 (1,1,0)
      -> 把内层 .gd-mini 也一起变成 display:block -> 每个产品各占一行，
      结构行反而涨到 51~87px（探针 K4 量高度才抓出来）。 */
#page-anGoods .gd-ltbl tbody td { white-space: nowrap; }
#page-anGoods .gd-ltbl .gd-cc-nm > b,
#page-anGoods .gd-ltbl .gd-cc-nm > span {
  display: block; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---- 需求③：商品结构 = 图标 + 数据 ---- */
#page-anGoods .gd-pitem > i { margin-right: 5px; font-size: 10px; color: #7ea6e8; }
#page-anGoods .gd-pitem.is-gift > i { color: #d97706; }
#page-anGoods .gd-pitem.is-na { background: #f1f5f9; color: #94a3b8; font-weight: 500; }
#page-anGoods .gd-pitem.is-na > i { color: #a8b3c2; }
/* 左栏那行里的图标（同 gdAttrText 的数据，图标版） */
#page-anGoods .gd-mini { display: inline-flex; align-items: center; white-space: nowrap; }
/* 兜底：左栏里那条同样写成高特异性，防止被 .gd-cc-nm 的后代规则打回 block */
#page-anGoods .gd-ltbl .gd-cc-nm .gd-mini { display: inline-flex; align-items: center; white-space: nowrap; }
#page-anGoods .gd-mini > i { margin-right: 3px; font-size: 9.5px; color: #a8b3c2; }

/* ---- 需求④：环比贴在数值右侧（不再单独占一列） ---- */
#page-anGoods .gd-v {
  display: inline-flex; align-items: baseline; justify-content: flex-end;
  gap: 5px; white-space: nowrap; max-width: 100%;
}
#page-anGoods .gd-v b { font-weight: 600; color: var(--ink-1); }
/* 贴在数值右侧的环比小签：.gd-dl-in 由 gdDelta(rate, true) 在运行时拼出来
   （'gd-dl' + ' gd-dl-in'），所以类名集合差脚本抓不到它 —— 已加进该脚本的
   动态拼类名白名单，否则会被假报成「死规则」。 */
#page-anGoods .gd-dl-in { font-size: 10px; font-weight: 620; letter-spacing: -0.01em; }
#page-anGoods .gd-v .gd-dl.is-na { color: #cbd5e1; font-weight: 400; }

/* ==================================================================
   ★ 第 31 轮（老板：商品结构要出图，「你现在显示的东西太长了」）—— 改前先读这里
   ------------------------------------------------------------------
   ① 商品结构 = **图表网格**（第 30 轮那套「图标 + 数据」结构行整块撤掉）。
      老板原话：「商品结构用(图)显示阿！通过日期颗粒，根据每个参数来显示图表阿。
      产品 / 容量 / 系列 / 品牌 / 哪个产品在哪个店铺卖得多这些参数阿！
      你现在显示的东西太长了！」
      → 长列表（四档合计 99 行）换成 5 张**期次堆叠柱状图**：
        系列 / 产品 / 容量 / 品牌 / 系列 × 店铺。
      X 轴 = 期次，跟着顶部粒度条走（日 / 周 / 月 / 年）—— 数据来自服务端
      `timeline`（按当前粒度逐期汇总好的），前端不自己拆期。
      ★ 命名按老板本轮口径：**系列** = 缤纷系列 / 世界系列 …（归一化系列名）；
        **产品** = 一件里装的具体几款酒（西拉 / 梅洛 / 加本力 …），**只统计瓶数**。
   ② 整块状态卡撤掉（含 KPI 行）——见上面 A 段（第 30 轮）。
   ③ 粒度条在工作区最上方：.gd-bar 是 [data-gd-sec="board"] 的第一个孩子、
      在 .gd-work 之上，横跨左栏（商品列表）与右栏（SKU 属性）。
   ⚠ 图表卡用 grid auto-fit 自适应列数，窄屏自然收成一列，
      不需要额外 @media（@media 段本身不许再被后面的主规则盖掉）。
   ================================================================== */

/* ---- ③ 粒度条（工作区最上方，横跨两栏） ---- */
#page-anGoods .gd-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; margin-bottom: 10px;
  background: #fff; border: 1px solid #e6e8ec; border-radius: 10px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04);
}
#page-anGoods .gd-bar-lab { font-size: 11px; color: #94a3b8; }
#page-anGoods .gd-bar .gd-tabbar { padding: 2px; }
#page-anGoods .gd-bar .gd-tab { padding: 3px 12px; font-size: 11.5px; }

/* ---- ① 商品结构：四张专业图（第 34 轮；31 = 图表网格、32 = 维度自动拼接、33 = 交叉矩阵） ----
   老板第 34 轮：「商品结构不一定非要用交叉的方式。你找下网上有什么针对商品分析
   有帮助的专业的图表来用一下看看。」
   一张图只回答一个问题：帕累托 = 哪些是核心 / 四象限 = 该投谁该改谁 / 树图 = 结构长什么样 /
   走势 = 在怎么变。窄屏一列、宽屏两列，帕累托与走势通栏（它们要的是宽度，不是高度）。 */
#page-anGoods .gd-dgrid {
  display: grid; gap: 12px;
  /* ★ 列宽下限 520px 而不是 400：400 在 1600 视口下会排出三列、每列只剩 377px，
     卡头一行放不下就把标题挤成竖排（第 34 轮第一版截图的真实事故）。
     下限给 520 → 无论如何每列都不窄于 520px：宽屏两列、窄屏一列，不会出现三列。 */
  grid-template-columns: repeat(auto-fit, minmax(520px, 1fr));
  align-items: start;
}
/* 通栏：用 1 / -1 而不是 span 2 —— 退化成单列时 span 2 会溢出 */
#page-anGoods .gd-w2 { grid-column: 1 / -1; }
#page-anGoods .gd-dcard {
  min-width: 0; padding: 10px 12px 8px;
  background: #fff; border: 1px solid #eef2f7; border-radius: 10px;
}
#page-anGoods .gd-dcard-h { display: flex; align-items: center; gap: 7px; margin-bottom: 6px; }
/* 档位图标：系列 / 产品 / 容量 / 品牌 / 店铺 */
#page-anGoods .gd-dcard-i {
  flex: none; width: 22px; height: 22px; border-radius: 7px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #eff6ff; color: #2563eb; font-size: 10.5px;
}
#page-anGoods .gd-dcard-h > b {
  flex: none; white-space: nowrap;
  font-size: 12.5px; font-weight: 640; color: var(--ink-1);
}
/* ★ 右侧说明必须**可压缩 + 省略号**：它是 nowrap，若不让它压缩，
   它就会把左边的标题压到 0 宽 —— 标题会一个字一行地竖排下来（真事故）。
   另外 .gd-dcard-h > b 是**子选择器**，只打标题，不会碰到说明里的 <b> 数字。 */
#page-anGoods .gd-dcard-n {
  flex: 0 1 auto; min-width: 0;
  font-size: 10.5px; color: #94a3b8; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
#page-anGoods .gd-dcard-n b { color: #64748b; font-weight: 640; }
/* 画布容器必须有确定高度：maintainAspectRatio:false 下没有高度图就画不出来 */
/* 画布容器必须有确定高度：maintainAspectRatio:false 下没有高度图就画不出来。
   第 34 轮起每张图按自己的形状定高（.gd-b-pa / .gd-b-quad / .gd-b-tm / .gd-b-empty 见下）。 */
#page-anGoods .gd-dcard-b { position: relative; height: 208px; }
#page-anGoods .gd-dgrid-foot {
  margin-top: 11px; padding-top: 9px; border-top: 1px solid #f1f5f9;
  font-size: 11px; line-height: 1.9; color: #94a3b8;
}
#page-anGoods .gd-dgrid-foot > i { margin-right: 5px; color: #a8b3c2; }
#page-anGoods .gd-dgrid-foot b { color: #64748b; font-weight: 620; }

/* ---------- 第 32 轮：维度自动拼接（芯片行 + 交叉卡双图标） ---------- */
#page-anGoods .gd-dpick {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 11px; padding: 8px 10px;
  background: #f8fafc; border: 1px solid #eef2f7; border-radius: 10px;
}
#page-anGoods .gd-dpick-l {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 620; color: #64748b;
}
#page-anGoods .gd-dpick-l > i { font-size: 11px; color: #94a3b8; }
#page-anGoods .gd-dpick-c { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
#page-anGoods .gd-dchip {
  display: inline-flex; align-items: center; gap: 5px;
  height: 26px; padding: 0 10px; line-height: 1;
  font-family: inherit; font-size: 12px; font-weight: 560; color: #475569;
  background: #fff; border: 1px solid #e2e8f0; border-radius: 999px; cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
#page-anGoods .gd-dchip:hover { border-color: #cbd5e1; color: #334155; }
#page-anGoods .gd-dchip.on { color: #1d4ed8; background: #eff6ff; border-color: #bfdbfe; font-weight: 640; }
#page-anGoods .gd-dchip > i { font-size: 10.5px; }
/* 角标 = 勾选顺序（1 先勾 → 作颜色；2 后勾 → 作横轴） */
#page-anGoods .gd-dchip-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; margin-left: -2px;
  font-size: 9.5px; font-weight: 700; color: #fff;
  background: #2563eb; border-radius: 999px;
}
#page-anGoods .gd-dpick-hint { margin-left: auto; font-size: 10.5px; color: #94a3b8; white-space: nowrap; }
#page-anGoods .gd-dpick-hint > b { color: #64748b; font-weight: 640; }
/* 交叉卡的两个图标并排 —— 就是老板说的「系列 + 产品的图标」。
   ★ 用**同一个元素上的两个类**提高特异性（(1,2,0) > (1,1,0)），
     不用后代选择器：后代选择器会连带打掉内层布局（第 29 轮的坑）。*/
#page-anGoods .gd-dcard-i.gd-i2 { width: auto; min-width: 22px; padding: 0 6px; gap: 3px; }
#page-anGoods .gd-dcard-i.gd-i2 > i { font-size: 9.5px; }

/* ---------- 第 34 轮：四张图各自的版式 ----------
   帕累托要扁宽（12 根柱 + 折线）、四象限要方正（四块地）、树图要满、走势居中。 */
#page-anGoods .gd-b-pa { height: 246px; }
/* 四象限：画布 262 + 下面那条 HTML 图例 */
#page-anGoods .gd-b-quad { height: 262px; }
#page-anGoods .gd-qkey {
  display: flex; flex-wrap: wrap; gap: 4px 14px;
  margin-top: 7px; padding-top: 6px; border-top: 1px solid #f1f5f9;
  font-size: 10.5px; line-height: 1.6; color: #64748b;
}
#page-anGoods .gd-qkey > span { display: inline-flex; align-items: center; gap: 5px; }
#page-anGoods .gd-qkey > span > i {
  flex: none; width: 8px; height: 8px; border-radius: 2px;
}
#page-anGoods .gd-qkey > span > b { color: #334155; font-weight: 640; }
#page-anGoods .gd-qkey > .gd-qkey-n { width: 100%; color: #94a3b8; }
#page-anGoods .gd-b-tm { height: 300px; }
#page-anGoods .gd-b-empty { height: auto; min-height: 232px; display: flex; align-items: center; }

/* ---------- 第 34 轮：结构树图（squarified treemap，纯 HTML） ----------
   ★ 两级都用**绝对定位 + 百分比**：外层相对 .gd-tm（0-100 = 整块画布）、
     内层相对 .gd-tm-gb（0-100 = 该分组扣掉卡头之后的区域）。
     这样内层面积天然跟着外层的实际大小走，不用再算一次像素。
   ★ 内层写不写标签，由 JS 按**估算像素**决定；写不下就不写 ——
     节点是 overflow:hidden，最差的情况是少写一行字，不会破版。 */
#page-anGoods .gd-tm { position: relative; width: 100%; height: 100%; overflow: hidden; }
#page-anGoods .gd-tm-g {
  position: absolute; display: flex; flex-direction: column;
  padding: 2px; border-radius: 6px; overflow: hidden; background: #f8fafc;
  /* ★ 第 41 轮：树图按**固定设计格 620x300** 排（GD_TM_W/GD_TM_H），但 .gd-tm 实际
     是 width:100%，卡片比 620 窄时，卡头那些**固定 px** 的内边距/间距/字号就塞不下了
     （实测 65px 的格子要装 69px 的东西 ⇒ R5/R48 报「元素级越界」）。
     这里把它立成**行内尺寸容器**，好让卡头改用下面的容器单位 cqw 自伸缩。 */
  container-type: inline-size;
}
/* 分组卡头：一行放下「名字 + 值 + 占比」，放不下就把名字省略 */
#page-anGoods .gd-tm-gh {
  flex: none; display: flex; align-items: center;
  /* ★ 第 41 轮：三个长度全部改用**容器单位 cqw**（= .gd-tm-g 宽度的 1%）。
     于是整行宽度 = 0.772 x 容器宽，**恒小于容器宽** —— 任何宽度都不会越界，
     也不用赌字体度量（推演见补丁脚本头注）。字号封顶 10.5px，宽卡片与原来一致。 */
  gap: min(5px, 4cqw); padding: 0 min(5px, 4cqw);
  border-radius: 4px; overflow: hidden; white-space: nowrap;
  font-size: min(10.5px, 13cqw); font-weight: 620;
}
#page-anGoods .gd-tm-gh > b { min-width: 0; overflow: hidden; text-overflow: ellipsis; font-weight: 640; }
#page-anGoods .gd-tm-gh > i {
  flex: none; font-style: normal; opacity: .85; font-variant-numeric: tabular-nums;
}
#page-anGoods .gd-tm-gh > em {
  flex: none; margin-left: auto; font-style: normal; opacity: .7;
  /* ★ 第 41 轮：占比是行内**第二个**定宽项，必须跟主字号一起缩，否则窄格子还是塞不下 */
  font-size: min(9.5px, 12cqw); font-variant-numeric: tabular-nums;
}
#page-anGoods .gd-tm-gb { position: relative; flex: 1 1 auto; min-height: 0; margin-top: 2px; }
#page-anGoods .gd-tm-n {
  position: absolute; overflow: hidden; border-radius: 4px;
  /* ★ 内边距**不许放在节点上**：节点宽是按百分比算出来的，而 border-box 下
     width 不能小于左右 padding 之和 —— 那些只分到 1%~2%（≈2.3px）的极细小格
     会被硬撑成 6px，于是比自己的 .gd-tm-gb 还宽 4px。
     它被外层的 overflow:hidden 挡着，截图上一点看不出来，但「元素级越界」是硬伤
     （R5/R48 就是这么从 PASS 变 FAIL 的）。内边距改放到标签上。 */
  padding: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; line-height: 1.15;
}
#page-anGoods .gd-tm-nl {
  display: block; max-width: 100%; padding: 0 3px; font-size: 10.5px; font-weight: 560;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#page-anGoods .gd-tm-nv {
  display: block; margin-top: 1px; padding: 0 3px; font-style: normal; font-size: 9.5px;
  opacity: .9; font-variant-numeric: tabular-nums;
}

/* ---------- 第 35 轮：流量分析（按平台分栏，绝不跨平台合并） ----------
   ★ 老板红线：「两个平台的流量不能混在一起看」。
     所以版式上就是**并排两栏**，全页没有任何一处把两个平台的数字放进同一个分母。
   ★ 这是第三次踩「按百分比 / 会被压缩的元素上不许挂 padding」：
     .fp-k / .fp-eff-r 都是会被挤窄的格子，内边距给它们没问题（宽度由 grid 定死），
     但 .fp-canvas 只给高度、宽度交给容器 —— Chart.js 的 responsive 要靠它。
   ★ 颜色：本页线条色板 FP_LINE_COLORS 在 JS 里，与四个保留色都拉开了距离；
     这里一个色值都不写死（避免出现第二个色源）。 */
#page-anTraffic .fp-sel {
  border: 1px solid #e2e8f0; background: #fff; color: var(--ink-2);
  border-radius: 8px; padding: 4px 9px; font-size: 12px; font-weight: 560;
  font-variant-numeric: tabular-nums;
}
#page-anTraffic .fp-cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(520px, 1fr));
  gap: 14px; align-items: start;
}
#page-anTraffic .fp-pf,
#page-anTraffic .fp-card {
  border: 1px solid #e8ecf3; border-radius: 12px; background: #fff;
  padding: 13px 14px; box-shadow: 0 1px 2px rgba(15, 23, 42, .04);
}
#page-anTraffic .fp-pf-h { display: flex; align-items: center; gap: 7px; min-width: 0; }
#page-anTraffic .fp-pf-dot { flex: none; width: 9px; height: 9px; border-radius: 3px; }
#page-anTraffic .fp-pf-n { font-size: 14px; font-weight: 650; color: var(--ink-1); }
#page-anTraffic .fp-pf-s { font-size: 11px; color: var(--ink-3); }
#page-anTraffic .fp-pf-t {
  flex: none; margin-left: auto; font-size: 10.5px; font-weight: 620; color: #475569;
  background: #f1f5f9; border-radius: 9999px; padding: 2px 9px; white-space: nowrap;
}
/* 第 41 轮：卡头「一级来源分类体系：…」这行已删（与「?」弹窗①重复）→ 规则同去 */
/* ★ 第 41 轮：5 张**等权**格 → **1 主 + 4 从**。老板：「内容太多了 第一眼看不到重点」。
   主格（访客数）跨两行占左栏、字号 15 → 31；其余四项在右栏排 2×2。
   一屏里两个平台各只有一个大数字，眼睛有落点；数字本身一个没动。 */
#page-anTraffic .fp-kpis {
  display: grid; grid-template-columns: minmax(0, 1.34fr) repeat(2, minmax(0, 1fr));
  grid-template-rows: auto auto;
  gap: 1px; background: #eef2f7; border-radius: 9px; overflow: hidden; margin-top: 9px;
}
#page-anTraffic .fp-k { background: #fff; padding: 7px 8px; min-width: 0; }
#page-anTraffic .fp-k-h {
  /* ★ 第 35 轮修正：原来 label 与环比胶囊同一行（justify-content: space-between），
     5 列网格下单元格只有 ~103px，label 52.5px + 胶囊 48px + gap 4px = 104.5px → 必然溢出
     （R5 判据实测 ovf=18；相邻白底格还会把溢出的胶囊盖掉）。
     改成**两行**（label 一行、胶囊一行）：与字体度量无关，任何宽度下都不溢出。 */
  display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start;
  gap: 1px; font-size: 10.5px; color: var(--ink-3); white-space: nowrap;
}
#page-anTraffic .fp-k-v {
  margin-top: 3px; font-size: 15px; font-weight: 660; color: var(--ink-1);
  font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis;
}
#page-anTraffic .fp-k-f { margin-top: 1px; font-size: 9.5px; color: #94a3b8; white-space: nowrap; }
#page-anTraffic .fp-k-lead {
  grid-row: span 2; display: flex; flex-direction: column; justify-content: center;
  padding: 9px 11px;
}
#page-anTraffic .fp-k-lead .fp-k-h { font-size: 11px; }
#page-anTraffic .fp-k-lead .fp-k-v {
  margin-top: 5px; font-size: 31px; line-height: 1.04; font-weight: 690; letter-spacing: -.5px;
}
#page-anTraffic .fp-k-lead .fp-k-f { margin-top: 3px; font-size: 10px; }
/* ★ 从属格的脚注（口径定义）全部收进「?」弹窗⑧ —— 改定义先改弹窗，别只删正文 */
#page-anTraffic .fp-k:not(.fp-k-lead) .fp-k-f { display: none; }
/* 口径断点 = 数据事实，不是解释 → 用注意色，别混进灰色说明里 */
#page-anTraffic .fp-note-brk { color: #b54708; }
#page-anTraffic .fp-warn {
  display: flex; gap: 6px; margin-top: 8px; padding: 6px 9px;
  border-radius: 7px; background: #fffaeb; border: 1px solid #fde68a;
  color: #b54708; font-size: 11px; line-height: 1.55;
}
#page-anTraffic .fp-warn > i { flex: none; margin-top: 2px; }
#page-anTraffic .fp-ch-t {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin: 12px 0 6px; font-size: 11.5px; color: var(--ink-2);
}
#page-anTraffic .fp-ch-t > b { font-size: 12px; font-weight: 640; color: var(--ink-1); }
#page-anTraffic .fp-ch-t > span { font-size: 10.5px; color: var(--ink-3); }
#page-anTraffic .fp-canvas { position: relative; width: 100%; }
/* ★ 第 42 轮：量效对比那条画布高度规则已随「改 HTML 条」整条撤掉
   —— 规则和类名一起消失（防死规则，见 classdiff 的 GONE42）。
   走势画布 236 -> 148：去掉网格 / 轴线、刻度抽稀之后，原来的高度只剩空白。 */
#page-anTraffic .fp-canvas-trend { height: 148px; margin-top: 8px; }
#page-anTraffic .fp-eff { margin-top: 9px; border-top: 1px solid #f1f5f9; }
#page-anTraffic .fp-eff-r {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 5px 0; border-bottom: 1px solid #f6f8fb;
  font-size: 11px; color: var(--ink-3);
}
#page-anTraffic .fp-eff-r:last-child { border-bottom: 0; }
#page-anTraffic .fp-eff-n { min-width: 74px; font-weight: 620; color: var(--ink-1); }
#page-anTraffic .fp-eff-k b { color: var(--ink-1); font-weight: 620; font-variant-numeric: tabular-nums; }
#page-anTraffic .fp-note { margin-top: 8px; font-size: 10.5px; line-height: 1.65; color: #94a3b8; }
#page-anTraffic .fp-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
/* ★ 选中态用**同一元素上的两个类**（.fp-chip.fp-chip-on）提高特异性，
   不用后代选择器 —— 后代选择器会连带打掉内层布局（第 29 轮的坑）。 */
#page-anTraffic .fp-chip {
  border: 1px solid #e2e8f0; background: #fff; color: var(--ink-2);
  border-radius: 9999px; padding: 3px 13px; font-size: 11.5px; font-weight: 560; cursor: pointer;
}
#page-anTraffic .fp-chip.fp-chip-on { border-color: #4f46e5; background: #eef2ff; color: #4338ca; }

/* ==================================================================
   第 37 轮：口径说明收进「?」（老板：「这种解释 要少点出现 用？带图」）
   ------------------------------------------------------------------
   改前：正文里铺着 6 段 ec-notes，把真正的图挤下去了。
   改后：正文只留工具栏最右一个圆「?」；点开弹窗，弹窗顶部是
         **一张结构示意图**（两平台各自的 100% 环 + 各自一级来源 +
         正中「✕ 不可相加」），下面才是分组文字。
   ★ 图里**不放任何数字**：本期数值一律以卡片为准，图只讲结构 ——
     没有数据源支撑的数一个都不编（口径纪律）。
   ★ 弹窗挂在 #page-anTraffic **里面**，所以选择器一律带
     `#page-anTraffic` 前缀；挂到 body 上这些规则会一条都不生效。
   ================================================================== */
#page-anTraffic .fp-help-btn {
  flex: none; width: 21px; height: 21px; margin-left: 8px; padding: 0;
  border: 1px solid #d8e0ea; background: #fff; color: #475569;
  border-radius: 50%; cursor: pointer; text-align: center;
  font-size: 12px; font-weight: 700; line-height: 19px;
}
#page-anTraffic .fp-help-btn:hover { border-color: #4f46e5; background: #eef2ff; color: #4338ca; }

#page-anTraffic .fp-help-mask {
  position: fixed; inset: 0; z-index: 60; padding: 16px;
  background: rgba(15, 23, 42, 0.34);
  display: flex; align-items: center; justify-content: center;
}
#page-anTraffic .fp-help {
  width: min(860px, 100%); max-height: 88vh; overflow: hidden;
  display: flex; flex-direction: column;
  background: #fff; border-radius: 12px; box-shadow: 0 18px 46px rgba(15, 23, 42, 0.24);
}
#page-anTraffic .fp-help-h {
  flex: none; display: flex; align-items: center; gap: 8px;
  padding: 11px 14px; border-bottom: 1px solid #eef2f7;
}
#page-anTraffic .fp-help-h > b {
  display: flex; align-items: center; gap: 7px; min-width: 0;
  font-size: 14px; font-weight: 650; color: var(--ink-1);
}
#page-anTraffic .fp-help-q {
  flex: none; width: 18px; height: 18px; border-radius: 50%;
  background: #4338ca; color: #fff; text-align: center;
  font-size: 11px; font-weight: 700; line-height: 18px;
}
#page-anTraffic .fp-help-h .ec-btn { margin-left: auto; }
/* flex 子项要滚必须 min-height:0，否则被内容撑开、滚动条永远不出现 */
#page-anTraffic .fp-help-b { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 12px 14px 15px; }
#page-anTraffic .fp-help-sec + .fp-help-sec { margin-top: 11px; }
#page-anTraffic .fp-help-st { margin-bottom: 8px; font-size: 12px; font-weight: 620; color: var(--ink-2); }
#page-anTraffic .fp-help-cols {
  margin-top: 12px; display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px 16px;
}
#page-anTraffic .fp-help-g { min-width: 0; }
#page-anTraffic .fp-help-g > b { display: block; margin-bottom: 2px; font-size: 11.5px; font-weight: 620; color: var(--ink-2); }
#page-anTraffic .fp-help-g > p { margin: 0; font-size: 11px; line-height: 1.7; color: var(--ink-3); }
#page-anTraffic .fp-help-g strong { color: var(--ink-2); font-weight: 620; }

/* ---- 结构示意图 ---- */
#page-anTraffic .fp-fig { padding: 11px 12px 9px; background: #fbfcfe; border: 1px solid #eef2f7; border-radius: 10px; }
#page-anTraffic .fp-fig-row { display: flex; align-items: stretch; gap: 8px; }
#page-anTraffic .fp-fig-col {
  flex: 1 1 0; min-width: 0; padding: 10px 8px;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  background: #fff; border: 1px solid #e8edf4; border-radius: 9px;
}
#page-anTraffic .fp-fig-h { display: flex; align-items: center; gap: 6px; min-width: 0; }
#page-anTraffic .fp-fig-h > b { font-size: 12.5px; font-weight: 650; color: var(--ink-1); }
#page-anTraffic .fp-fig-ring { position: relative; width: 56px; height: 56px; }
#page-anTraffic .fp-fig-ring svg { display: block; width: 56px; height: 56px; }
#page-anTraffic .fp-fig-ring > em {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-style: normal; font-size: 11px; font-weight: 650; color: var(--ink-2);
}
#page-anTraffic .fp-fig-cap { font-size: 10px; color: #64748b; }
#page-anTraffic .fp-fig-chips { display: flex; flex-wrap: wrap; gap: 5px; justify-content: center; }
#page-anTraffic .fp-fig-chip {
  max-width: 100%; padding: 2px 9px; border-radius: 9999px;
  background: #f1f5f9; color: var(--ink-2); font-style: normal; font-size: 11px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#page-anTraffic .fp-fig-x {
  flex: none; width: 104px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 3px; text-align: center;
}
#page-anTraffic .fp-fig-x > b { font-size: 16px; line-height: 1; color: #b54708; }
/* ★ 不折行：96px 时「不可相加」被折成上下两行（实测），中栏加宽到 104px + nowrap 一起上 */
#page-anTraffic .fp-fig-x > span { font-size: 10.5px; font-weight: 600; color: #b54708; white-space: nowrap; }
#page-anTraffic .fp-fig-note { margin: 9px 0 0; font-size: 10.5px; line-height: 1.6; color: #94a3b8; }
#page-anTraffic .fp-fig-note strong { color: var(--ink-2); font-weight: 620; }

/* ==================================================================
   ★ @media 必须留在**本文件最末尾**（同名规则谁在后谁生效）
   ================================================================== */
@media (max-width: 1250px) {
  #page-anGoods .gd-work { flex-direction: column; height: auto; }
  /* !important：左栏宽度存在内联样式里（拖拽后的记忆值），窄屏必须由 CSS 夺回控制权 */
  #page-anGoods .gd-panel { flex: none !important; width: 100% !important; height: 420px; }
  #page-anGoods .gd-split { display: none; }
  #page-anGoods .gd-main { height: auto; overflow: visible; }
  #page-anGoods .gd-detail { height: auto; overflow: visible; }
  #page-anGoods .gd-detail > .gd-tblwrap { max-height: none; }
  #page-anGoods .gd-tblscroll { flex: none; max-height: 260px; }
  #page-anGoods .gd-kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  #page-anGoods .gd-editrow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1080px) {
  #page-anGoods .gd-props { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #page-anGoods .gd-prop-w { grid-column: span 2; }
  .gd-sku { max-height: 92vh; }
  #gd-sku-mask .gd-search { width: 100%; flex: 1 1 100%; }
}
@media (max-width: 900px) {
  #page-anTraffic .fp-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #page-anTraffic .fp-cols { grid-template-columns: minmax(0, 1fr); }
  #page-anGoods .gd-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #page-anGoods .gd-editrow { grid-template-columns: minmax(0, 1fr); }
  .gd-sku-mask { padding: 12px; }
  .gd-sku-h { padding: 11px 13px; }
  .gd-sku-b { padding: 0 13px 10px; }
}
@media (max-width: 640px) {
  #page-anTraffic .fp-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 主格改整宽置顶（否则 2 列下它跨两行，会把后两项挤到第 3 行） */
  #page-anTraffic .fp-k-lead { grid-column: span 2; grid-row: auto; }
  #page-anGoods .gd-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #page-anGoods .gd-props { grid-template-columns: minmax(0, 1fr); }
  #page-anGoods .gd-prop-w { grid-column: span 1; }
  #page-anGoods .gd-dhead { flex-wrap: wrap; }
  .gd-sku-mask { padding: 8px; }
  .gd-sku-h { padding: 10px 11px; gap: 8px; }
  .gd-sku-hn { font-size: 14px; }
  .gd-sku-b { padding: 0 11px 8px; }
}

/* ==================================================================
   第 38 / 39 / 40 轮：店铺维度
   38 轮三张表 → 39 轮三个大图 → 40 轮老板「图太大 太长了 小一点的板块显示。
   太图表化了。要那种网站的感觉」→ **拆成一网格小板块**：

     ① 量效对比 / ② 流量结构 = **HTML 条**（无坐标轴 / 无网格 / 无 canvas 图例，
        数值标在行尾）—— 「图表感」大半来自轴、网格和 canvas 图例这三样，
        条本身留着；行高从 30px 降到 7px+间隙；
     ③ 逐期走势 = 唯一还留 canvas 的（18 期 × 多店折线），高度 220 → 104。
   每个平台卡从 ~620px 降到 ~250px。

   规则：① 全部带 #page-anTraffic 前缀；② **不新增色值** —— 板块底/轨道/文字
   全部走本文件里已有的浅灰与 --ink-*，条色由 JS 用 FP_LINE_COLORS 内联下发
   （那组色已量过与四个保留色的距离），所以这里不可能撞上 涨/跌/未归类/其他；
   ③ 走势图容器必须有**确定高度**：Chart.js 是 responsive + maintainAspectRatio:false，
   父级高度为 auto 时它会一路缩到 0 —— 画布上什么都没有，而断言只看 data 还是全绿。
   ================================================================== */
#page-anTraffic .fp-card-shop { display: block; margin-bottom: 12px; }
#page-anTraffic .fp-tiles {
  /* 三个板块**并排**（第 40 轮第二次收敛）。原来量效/结构两列、走势跨整行 ——
     走势一个人吃 177px，上半只 129px，卡下半全是空的。
     auto-fit 在主区宽 1060px 时给 3 列，窄屏自动塌列（不需要额外媒体查询）。 */
  /* 三列**不等宽**：量效对比要装 5 个指标 chip（等比等宽会让第 5 个掉到第二行），
     走势要装 18 期刻度 —— 给它俩多一点。窄屏在末尾 @media 里塌成一列。 */
  display: grid; grid-template-columns: minmax(0, 1.26fr) minmax(0, 1fr) minmax(0, 1.06fr);
  gap: 8px; margin-top: 8px;
}
#page-anTraffic .fp-tile {
  min-width: 0; padding: 7px 10px 8px;
  border: 1px solid #e8ecf3; border-radius: 9px; background: #f1f5f9;
}
#page-anTraffic .fp-tile-h { display: flex; align-items: baseline; gap: 7px; margin-bottom: 5px; }
#page-anTraffic .fp-tile-h > b { font-size: 11.5px; font-weight: 650; color: var(--ink-1); }
#page-anTraffic .fp-tile-h > span { font-size: 10px; color: #94a3b8; }
/* 一行 = 店名 / 轨道 / 数值。固定两侧宽度（不用百分比留白，第 35 轮的坑），
   所以任何容器宽度下轨道都是弹性剩余，不会溢出。 */
#page-anTraffic .fp-rows { display: flex; flex-direction: column; gap: 4px; }
#page-anTraffic .fp-tl { display: flex; align-items: center; gap: 7px; min-width: 0; }
#page-anTraffic .fp-tl-n {
  flex: none; width: 100px; font-size: 10.5px; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#page-anTraffic .fp-tl-bar {
  display: flex; flex: 1 1 auto; min-width: 0; height: 7px;
  border-radius: 9999px; background: #e2e8f0; overflow: hidden;
  /* ★ 第 40 轮修正：段间缝**不再用 gap**。
     gap 会让「各段 100% + (n−1) 个 1px」比轨道宽 1~2px —— 实测天猫结构板块
     185 -> 187 / 189，被全站累积回归 R5 判成「元素内容溢出自身盒子」。
     缝改由下面的 box-shadow 内阴影画：零布局宽度。 */
}
/* 缝 = 1px 内阴影（不参与布局 ⇒ 轨道多宽，各段就正好铺满多宽） */
#page-anTraffic .fp-tl-fill + .fp-tl-fill { box-shadow: inset 1px 0 0 0 #e2e8f0; }
/* ★ flex-shrink 放开：只有「min-width:2px 把极窄段抬起来」的场合才会收缩
   （收缩量 ≤ 2px）；各段之和 = 100% 时没有负剩余空间，**不收缩** ——
   所以渲染出来的段宽仍是 style.width 里的接口真值。 */
#page-anTraffic .fp-tl-fill { display: block; flex: 0 1 auto; height: 100%; min-width: 2px; border-radius: 2px; }
#page-anTraffic .fp-tl-v {
  flex: none; width: 62px; text-align: right; font-size: 10.5px; font-weight: 620;
  color: var(--ink-1); font-variant-numeric: tabular-nums;
}
/* 堆叠板块行尾那个数是**该行各段之和**（满=数据完整、不满=本期有来源缺失），
   属于完整性标记而不是主读数 —— 压小、变灰，别跟量效板块的量数值抢眼。 */
#page-anTraffic .fp-tile[data-fp-tile="stack"] .fp-tl-v {
  width: 48px; font-size: 10px; font-weight: 560; color: var(--ink-3);
}
#page-anTraffic .fp-tl-lg { display: flex; flex-wrap: wrap; gap: 4px 11px; margin-top: 6px; }
#page-anTraffic .fp-tl-lg > span {
  display: inline-flex; align-items: center; gap: 4px; font-size: 10px; color: var(--ink-3);
}
#page-anTraffic .fp-tl-lg > span > i { flex: none; width: 7px; height: 7px; border-radius: 2px; }
/* 榜样式微调：指标 chips 在灰底板块里换成白底，才浮得起来 */
#page-anTraffic .fp-metric { margin-bottom: 7px; }
#page-anTraffic .fp-tile .fp-chip {
  background: #fff; padding: 2px 9px; font-size: 11px;
}
#page-anTraffic .fp-tile .fp-chip.fp-chip-on { background: #eef2ff; }
#page-anTraffic .fp-chips-sub { margin-top: 6px; }
#page-anTraffic .fp-chart-box {
  position: relative; width: 100%; min-height: 80px;
  border: 1px solid #e8ecf3; border-radius: 8px; background: #fff;
  padding: 6px 8px 4px;
}
#page-anTraffic .fp-chart-box > canvas { display: block; }

/* ------------------------------------------------------------------
   第 42 轮 · 来源量效对比：canvas → HTML 双细条
   ------------------------------------------------------------------
   规则与店铺板块那套（.fp-tl-*）**同源**：
     ① 固定两侧宽度（名字列 / 数值列），中间轨道吃弹性剩余 ——
        任何容器宽度下都不会溢出（第 35 轮那个「103px 装 104.5px」的坑）；
     ② **不新增色值**：轨道与文字全部走本文件已有的浅灰与 --ink-*，
        条色（实心填充 / 空心描边）由 JS 内联下发平台色 ——
        那组色已量过与「涨 / 跌 / 未归类 / 其他」四个保留色的距离；
     ③ 空心条用 `border` + `box-sizing:border-box` 画：描边**不参与**宽度计算，
        所以 style.width 里的接口真值就是渲染出来的条长。
   ------------------------------------------------------------------ */
#page-anTraffic .fp-mix { display: flex; flex-direction: column; gap: 7px; }
#page-anTraffic .fp-mx-r { display: flex; align-items: center; gap: 7px; min-width: 0; }
#page-anTraffic .fp-mx-n {
  flex: none; width: 76px; font-size: 10.5px; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#page-anTraffic .fp-mx-b {
  display: flex; flex-direction: column; gap: 3px;
  flex: 1 1 auto; min-width: 0;
}
#page-anTraffic .fp-mx-bar {
  display: flex; flex: none; min-width: 0; height: 5px;
  border-radius: 9999px; background: #e2e8f0; overflow: hidden;
}
#page-anTraffic .fp-mx-fill {
  display: block; flex: 0 1 auto; height: 100%; min-width: 2px; border-radius: 2px;
}
#page-anTraffic .fp-mx-o { background: transparent; border: 1.5px solid; box-sizing: border-box; }
#page-anTraffic .fp-mx-v {
  flex: none; width: 46px; display: flex; flex-direction: column; align-items: flex-end;
  font-size: 10px; line-height: 1.35; font-variant-numeric: tabular-nums;
}
/* 两个数与两条一一对齐：上=访客占比（实心，主读数），下=支付金额占比（空心，次读数） */
#page-anTraffic .fp-mx-v > b { font-weight: 620; color: var(--ink-1); }
#page-anTraffic .fp-mx-v > em { font-style: normal; font-weight: 560; color: var(--ink-3); }

/* ------------------------------------------------------------------
   第 42 轮 · 顶部「销售日报」入口条在流量页收成一行
   ------------------------------------------------------------------
   ★ 只加 `#page-anTraffic` 作用域的覆盖，**绝不改 `.sa-ai-entry` 共享规则本身** ——
     那一条跨六页共用、刻意不带页面前缀（写成无前缀会连带改掉另外五页，
     与第 25 轮那次「作用域写错＝静默全裸」是同一个坑的反面）。
   ------------------------------------------------------------------ */
#page-anTraffic .sa-ai-entry { margin: 0 0 10px; }
#page-anTraffic .sa-ai-entry .sa-ai-entryin {
  padding-top: 8px; padding-bottom: 8px;
  gap: 10px; flex-wrap: nowrap;
}
#page-anTraffic .sa-ai-entry .sa-ai-entryt {
  flex-direction: row; align-items: baseline; gap: 8px; flex: 1 1 auto;
}
#page-anTraffic .sa-ai-entry .sa-ai-entryt > b { flex: none; font-size: 12.5px; }
#page-anTraffic .sa-ai-entry .sa-ai-entryt > span {
  font-size: 10.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#page-anTraffic .sa-ai-entry .ec-btn { flex: none; padding: 4px 11px; font-size: 12px; }

/* ==================================================================
   第 37 轮：口径弹窗的窄屏适配（**追加在文件最末尾** —— 追加的 @media
   仍是最末尾，符合「最后一个 @media 之后不许有顶层规则」这条规矩）
   ================================================================== */
@media (max-width: 900px) {
  #page-anTraffic .fp-fig-row { flex-direction: column; }
  #page-anTraffic .fp-fig-x { width: 100%; flex-direction: row; gap: 7px; }
  #page-anTraffic .fp-help-cols { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  #page-anTraffic .fp-help-mask { padding: 8px; }
  #page-anTraffic .fp-fig-chip { font-size: 10.5px; }
}

/* 第 39 / 40 轮窄屏：第 39 轮那条 .fp-shop-sec-h 已随板块化撤掉（见 _r40-classdiff.py 的
   GONE40），只留指标 chips 换行。.fp-tiles 用 auto-fit minmax(286px,1fr) 自适应列数，
   窄屏自动塌成一列，不需要额外的媒体查询。
   （**仍在文件最末尾** —— 最后一个 @media 之后不许有顶层规则） */
@media (max-width: 900px) {
  #page-anTraffic .fp-metric { flex-wrap: wrap; }
  /* 三列 → 一列：窄屏下 300px 一列是刚好的，但指标 chips 一定会换行，
     所以给板块留出上下间距而不是靠压缩字号硬塞（不赌字体度量）。 */
  #page-anTraffic .fp-tiles { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   ★★★ 第 78 轮（老板 2026-10-26）· 销售分析页清爽化
   --------------------------------------------------------------------------
   老板四条原话（逐字）：
     1、销售异常板块 置顶
     2、所有解释小字隐藏
     3、店铺看板的板块 不设置固定的下限，有多少店铺就显示多少店铺，不需要滚轮跳
     4、自检修复其他需要美观的地方
   （第 1 条是结构改动，在 ec-pages.js 的 renderSalesBoard 里，本文件不管。）
   --------------------------------------------------------------------------
   ★ 第 3 条为什么只拆容器、不碰画布：
     `.sa-work` 是第 17 轮定的**定高工作台**（height: min(calc(100vh - 300px), 780px)
     + min-height: 460px），右侧 `.sa-charts` 靠 flex:1 + 内部滚动吃满剩余空间。
     老板要「有多少店显示多少店、不要滚轮跳」⇒ 把定高整条拆掉，改成自然高：
       .sa-work   height:auto + min-height:0 + align-items:flex-start
       .sa-main   height:auto
       .sa-charts overflow:visible（不再自己滚）
       .sa-panel  height:auto + max-height:none（左栏指标也自然高，避免出现内层滚动）
     ⚠ **不动** `.sa-chart-b` 的 190px —— 画布高度跟容器解耦，改百分比会互相追着变
       （第 19 轮注释里的 ⚠②，踩过一次）。
   ========================================================================== */

/* ---- W1 解释性小字：整条隐藏 ---------------------------------------------- */
/* ★ 用 `.hint` 全量而不是 `.ec-card-head .hint` —— 第一版只写了前一种，
   实测漏掉「销售日报入口条」下面那行（「报表 · 关键数据 · 累计与达成 · …」），
   老板一眼就能看见那行灰字还在。判据也改成「所有 .hint 都不可见」，
   只查 querySelector 的第一个会被「第一个恰好藏了」骗过去。 */
#page-anSales .sa-tip,               /* 左栏「点一个指标，右侧每张图…」 */
#page-anSales .sa-stnote,            /* 状态卡底部「上一行是数据最新一天的合计…」 */
#page-anSales .sa-chart-f,           /* 图卡底部「最新 xx · 30 期 · 环比基期…」 */
#page-anSales .sa-chart-empty > i,   /* 空图下面那行小字 */
#page-anSales .sa-ge-tip,            /* 空态「换一个粒度试试」 */
#page-anSales .sa-exc-d,             /* 异常项下面那行「2026-10-25 支付金额…（健康线 <8%）」
                                        标题里已经有「退款 ¥x，占支付 y%」，这行是重复的解释 */
#page-anSales .sa-gap,               /* 「数据日期为昨天」—— 日期就在它左边，这句是重复解释 */
#page-anSales .sa-ai-entryt > span,  /* 销售日报入口条下面「报头 · 关键数据 · 累计与达成 · …」 */
#page-anSales .hint,                 /* 卡片标题右边所有解释（含入口条下面那行） */
#page-anSales .ec-more { display: none !important; }   /* 底部「走势图、明细表与 AI 助理日报的口径」折叠说明 */

/* ---- W2 销售看板：拆掉定高，有多少店显示多少店 ---------------------------- */
#page-anSales .sa-work { height: auto; min-height: 0; align-items: flex-start; }
#page-anSales .sa-panel { height: auto; max-height: none; overflow: visible; }
#page-anSales .sa-main { height: auto; }
#page-anSales .sa-charts { flex: 0 0 auto; overflow: visible; }

/* ---- W3 保留下来的次要信息：从浅灰提到可读，且卡片间距统一 ---------------- */
#page-anSales .sa-stsub { color: #64748b; }
#page-anSales .sa-bar-lab { color: #64748b; }
#page-anSales .sa-chart-d { color: #64748b; }
#page-anSales .sa-gcount { color: #64748b; }
#page-anSales .sa-tbln { color: #64748b; }   /* 明细表头「16 期 · 2 期无数据 · 最新在前」 */
#page-anSales .sa-status { margin-bottom: 14px; }
#page-anSales .ec-section[data-sa-sec="exc"] { margin-bottom: 14px; }
/* 异常卡置顶后要一眼看出这是「要处理的事」：标题前加一条竖色条 */
#page-anSales .ec-section[data-sa-sec="exc"] .ec-card-head h4 {
  position: relative;
  padding-left: 9px;
}
#page-anSales .ec-section[data-sa-sec="exc"] .ec-card-head h4::before {
  content: '';
  position: absolute; left: 0; top: 50%;
  width: 3px; height: 13px; margin-top: -6.5px;
  border-radius: 2px; background: #f59e0b;
}

/* ==========================================================================
   ★★★ 第 79 轮（老板 2026-10-26 17:22）· 销售分析页三处收口
   --------------------------------------------------------------------------
   ① 异常从独立卡片缩成一排 chip（#sa-exc 挪进 .sa-status 卡内，标题没了）
   ② 左栏 .sa-panel 改成绝对定位：高度由右栏 .sa-main 决定 ⇒ 底边严丝合缝
   ③ 日报入口条本页不再渲染，按钮挂顶栏 #topbarExtra

   ⚠ .sa-chart-b 的 190px 画布高度**依然不许碰**（第 19 轮 ⚠②）。
   ========================================================================== */

/* ---- ① 异常项：一排胶囊，落在状态卡里 ---------------------------------- */
#page-anSales .sa-exc-wrap {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px;
  margin-top: 11px; padding-top: 11px;
  border-top: 1px solid #f1f5f9;
}
#page-anSales .sa-exc-ico { flex: none; font-size: 11px; color: #f59e0b; }
#page-anSales .sa-exc-ico.is-ok { color: #10b981; }
#page-anSales .sa-exc-chip {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
  padding: 3px 9px; border: 1px solid #eef2f7; border-radius: 999px;
  background: #f8fafc; font-size: 11.5px; line-height: 1.55; color: #334155;
  text-decoration: none;
  transition: background .12s, border-color .12s, color .12s;
}
#page-anSales .sa-exc-chip:hover { background: #f1f5f9; border-color: #e2e8f0; color: #1e293b; }
#page-anSales .sa-exc-chip > span {
  max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#page-anSales .sa-exc-dot { flex: none; width: 6px; height: 6px; border-radius: 50%; background: #94a3b8; }
#page-anSales .sa-exc-dot.lv-high { background: #ef4444; }
#page-anSales .sa-exc-dot.lv-mid { background: #f59e0b; }
#page-anSales .sa-exc-dot.lv-low { background: #3b82f6; }
#page-anSales .sa-exc-go { flex: none; font-size: 11.5px; color: #2563eb; text-decoration: none; }
#page-anSales .sa-exc-go:hover { text-decoration: underline; }
#page-anSales .sa-exc-none { font-size: 11.5px; color: #64748b; }

/* ---- ② 左栏跟随右栏：底边对齐 ------------------------------------------
   ★ 必须让左栏**脱离正常流**：只要它还在流里，它自己的内容高度就会把 .sa-work
     撑高 —— 那时不是「左栏跟随右栏」，而是「右栏被左栏拉长」。
     top:0 + bottom:0 把高度完全交给右栏（.sa-main 是唯一在流里的子项）决定；
     左栏内部只让 .sa-lists 滚，搜索框因此常驻顶部（flex column + 固定高头部）。
   ★ 宽度两档沿用原来的 268 / 232，右侧可用宽度一分不差（padding-left = 宽 + 14 的 gap）。 */
@media (min-width: 901px) {
  #page-anSales .sa-work { position: relative; padding-left: 282px; }
  #page-anSales .sa-work > .sa-panel {
    position: absolute; left: 0; top: 0; bottom: 0;
    width: 268px; height: auto; max-height: none;
    display: flex; flex-direction: column;
    overflow: hidden;
  }
  #page-anSales .sa-work > .sa-panel > .sa-lists {
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
  }
}
@media (min-width: 901px) and (max-width: 1180px) {
  #page-anSales .sa-work { padding-left: 246px; }
  #page-anSales .sa-work > .sa-panel { width: 232px; }
}

/* ---- ③ 顶栏的「生成销售日报」按钮 -------------------------------------- */
#topbarExtra .ec-btn > i { font-size: 11.5px; }
/* r79-sales-css */


/* ===================================================================
   2026-11-05 性能补丁（老板反馈：商品分析数据出来后鼠标拖不动）
   原因：538 行 x 15 列的表格 + 全站 246 个 transition，
        鼠标划过每一行都触发重绘；顶栏又是 fixed + backdrop-filter:blur(12px)，
        滚动时每帧重算全屏模糊，低端 GPU 直接卡死。
   =================================================================== */

/* (1) 表格内部不参与鼠标移动引发的过渡（视觉几乎无差异） */
#page-anGoods .gd-list tr,
#page-anGoods .gd-list td,
#page-anGoods .gd-list th,
#page-anGoods .gd-list tbody,
#page-anGoods .gd-list > div {
  transition: none !important;
}

/* (2) 顶栏玻璃模糊降级：背景调成接近不透明，去掉每帧模糊计算 */
.topbar, .topbar-fixed {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  background: rgba(255, 255, 255, 0.97) !important;
}
[data-theme="dark"] .topbar,
[data-theme="dark"] .topbar-fixed {
  background: rgba(11, 17, 32, 0.97) !important;
}
/* r104e-perf */


/* ===================================================================
   2026-11-05 虚拟滚动配套：行高必须固定，否则占位行算不准
   只作用于商品分析左栏列表（.gd-ltbl），不影响其他表格
   =================================================================== */
#page-anGoods .gd-ltbl tbody tr { height: 48px; }
#page-anGoods .gd-ltbl tbody tr > td { height: 48px; overflow: hidden; }
/* 占位行：只有高度，不画边框、不吃 padding */
#page-anGoods .gd-ltbl tbody tr.gd-vpad > td {
  padding: 0 !important;
  border: 0 !important;
  background: none !important;
}
#page-anGoods .gd-ltbl tbody tr.gd-vpad { cursor: default; }
/* r104f-vscroll */


/* ===== 2026-11-05 商品分析分页控件（学 tz：服务端分页） ===== */
#page-anGoods .gd-pager { display: inline-flex; align-items: center; gap: 6px; margin: 0 10px; }
#page-anGoods .gd-pager b { font-size: 11.5px; color: #64748b; font-variant-numeric: tabular-nums; }
#page-anGoods .gd-pgb {
  width: 22px; height: 22px; border: 1px solid #e2e8f0; background: #fff; border-radius: 6px;
  color: #475569; font-size: 10px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
#page-anGoods .gd-pgb:hover:not(:disabled) { background: #f1f5f9; border-color: #cbd5e1; }
#page-anGoods .gd-pgb:disabled { opacity: .4; cursor: default; }
/* r105-pager */


/* ===== 2026-11-06 工具条位置对齐流量分析（标题底到控件顶统一 14px） ===== */
#page-anSales .ec-section[data-sa-sec="bar"] { margin-top: 0 !important; padding-top: 0 !important; }
#page-anSales .ec-section[data-sa-sec="bar"] .sa-bar { margin: 0 !important; }
#page-anGoods .ec-section[data-gd-sec="board"] { margin-top: 0 !important; padding-top: 0 !important; }
#page-anGoods .gd-bar { margin-top: 0 !important; }
/* r106-align */


/* ===== 2026-11-06 修：工具条自带 padding-top:9px，比流量分析多出 10px 间距 ===== */
#page-anSales .sa-bar { padding-top: 0 !important; }
#page-anGoods .gd-bar { padding-top: 0 !important; }
/* r107-barpt */


/* ===== 2026-11-06 工具栏与流量分析完全一致：去掉白卡片外壳，改为扁平 ===== */
#page-anSales .sa-bar,
#page-anGoods .gd-bar {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  border-radius: 0 !important;
  padding: 0 0 14px !important;
  margin-bottom: 0 !important;
  gap: 16px !important;
}
#page-anSales .sa-bar-lab,
#page-anGoods .gd-bar-lab { font-size: 12px !important; color: #8a93a3 !important; }
#page-anSales .sa-rangehint,
#page-anGoods .gd-rangehint { font-size: 12px; color: #8a93a3; margin-left: 4px; white-space: nowrap; }
/* r108-flat */


/* ===== 2026-11-06 销售/商品工具栏：**逐条照搬**流量分析的 fv-* 规则 ===== */
#page-anSales .fv-bar,
#page-anGoods .fv-bar {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 0 0 14px;
}
#page-anSales .fv-grp,
#page-anGoods .fv-grp {
  display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
}
#page-anSales .fv-lab,
#page-anGoods .fv-lab {
  font-size: 12px; color: var(--ink-3); flex: 0 0 auto; white-space: nowrap;
}
#page-anSales .fv-gran,
#page-anGoods .fv-gran {
  display: inline-flex; gap: 2px; padding: 2px;
  background: #eef0f4; border: 1px solid var(--panel-line); border-radius: 9px;
  flex: 0 0 auto;
}
#page-anSales .fv-gb,
#page-anGoods .fv-gb {
  appearance: none; border: 0; background: transparent;
  font: inherit; font-size: 12.5px; color: var(--ink-2);
  height: 26px; min-width: 38px; padding: 0 12px; border-radius: 7px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .12s ease, color .12s ease, box-shadow .12s ease;
}
#page-anSales .fv-gb:hover,
#page-anGoods .fv-gb:hover { background: #e3e7ee; color: var(--ink-1); }
#page-anSales .fv-gb.on,
#page-anGoods .fv-gb.on {
  background: #ffffff; color: var(--ink-1); font-weight: 650;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .12);
}
#page-anSales .fv-range,
#page-anGoods .fv-range {
  font-size: 12px; color: var(--ink-3);
  white-space: nowrap; flex: 0 0 auto; padding-right: 2px;
}
#page-anSales .fv-dp-w,
#page-anGoods .fv-dp-w { position: relative; }
#page-anSales .fv-dp-btn,
#page-anGoods .fv-dp-btn { height: 32px; font-size: 12.5px; min-width: 180px; }
#page-anSales .fv-dp-btn .ec-dp-cv,
#page-anGoods .fv-dp-btn .ec-dp-cv { margin-left: auto; }
/* r109-fvcopy */


/* ===== 2026-11-06 三张店铺卡底部对齐 =====
   原因：.sa-tblscroll 是 max-height（内容不足就矮），.sa-charts 是 grid-auto-rows:min-content
   （每张卡按自己内容撑高）⇒ 三家店的表底参差不齐。改成固定高度 + 卡片等高。 */
#page-anSales .sa-charts { grid-auto-rows: 1fr; }
#page-anSales .sa-chart { height: 100%; }
#page-anSales .sa-tblscroll { height: 212px !important; max-height: 212px !important; }
/* 表头不换行，避免「83 期 · 13 期无数据 · 最新在前」把卡片顶高 */
#page-anSales .sa-tblh { flex-wrap: nowrap; }
#page-anSales .sa-tbln { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* r110-align3 */


/* 2026-11-06 周粒度：鼠标悬停时整周 7 格预览高亮 */
#sa-dp-host .cal-day.wk-hover,
#gd-dp-host .cal-day.wk-hover {
  background: #e8f0ff !important;
  color: #1d4ed8 !important;
  border-radius: 8px;
}
/* r111-wkhover */
