/* ui2-modules.css — per-module class families mapped onto the shared primitives.
 *
 * Each module in this app has its own bespoke class family (mv*, kmm*, zsxq*, src*,
 * bk*, ima* …) — roughly 1,400 rules in styles.css. Restyling each one individually
 * is not the job: what defines the LOOK is the structural chrome (group headers,
 * toolbars, search, badges, buttons, tables, big numbers). Those are mapped here onto
 * the primitives already defined in ui2.css, and card internals inherit the typography.
 *
 * Loaded after ui2.css. Every rule scoped under .ui2.
 */

/* ============================ Market View (mv*) ============================ */
.ui2 .mvHeader{margin-bottom:var(--u2-s3);}
.ui2 .mvToolbar{display:flex;align-items:center;gap:var(--u2-s2);flex-wrap:wrap;padding:0 0 var(--u2-s3);}
.ui2 .mvSearchWrap{position:relative;display:inline-flex;align-items:center;}
.ui2 .mvSearch{
  box-sizing:border-box;height:var(--u2-ctl);
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink);
  border-radius:var(--u2-radius);padding:0 28px 0 30px;
  font:400 var(--u2-fs-sm)/1 inherit;min-width:210px;
}
.ui2 .mvSearch:focus{outline:none;border-color:var(--u2-accent);}
.ui2 .mvSearchIco{color:var(--u2-muted);font-size:13px;}
.ui2 .mvSearchClear{color:var(--u2-muted);background:transparent;border:0;cursor:pointer;}
.ui2 .mvSearchCount{font-size:var(--u2-fs-xs);color:var(--u2-muted);font-variant-numeric:tabular-nums;}

/* group headers -> the quiet section label used everywhere else */
.ui2 .mvGroup{margin-bottom:var(--u2-s4);}
.ui2 .mvGroupTitle{
  font-size:var(--u2-fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.07em;
  color:var(--u2-muted);
}
.ui2 .mvGroupCount,
.ui2 .mvSubCount{
  font-size:10px;font-weight:600;color:var(--u2-muted);background:var(--u2-track);
  border-radius:999px;padding:2px 7px;font-variant-numeric:tabular-nums;
}
.ui2 .mvGroupChevron{color:var(--u2-muted);}
.ui2 .mvSubTitle{font-size:var(--u2-fs-sm);font-weight:600;color:var(--u2-ink-2);}

/* one shape for every small action button in the module */
.ui2 .mvGroupsBtn,
.ui2 .mvCopyImgBtn,
.ui2 .mvRrgOpen,
.ui2 .mvEarnNav{
  box-sizing:border-box;height:30px;padding:0 11px;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink-2);
  border-radius:var(--u2-radius);font:600 var(--u2-fs-sm)/1 inherit;cursor:pointer;
}
.ui2 .mvGroupsBtn:hover,
.ui2 .mvCopyImgBtn:hover,
.ui2 .mvRrgOpen:hover,
.ui2 .mvEarnNav:hover{border-color:var(--u2-muted);color:var(--u2-ink);background:var(--u2-panel);}
.ui2 .mvRrgGroupSel,
.ui2 .mvEarnWeek,
.ui2 .mvEarnUniSearch{
  box-sizing:border-box;height:30px;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink);
  border-radius:var(--u2-radius);font:400 var(--u2-fs-sm)/1 inherit;padding:0 10px;
}

/* timeframe / range toggles */
.ui2 .mvTfToggle,
.ui2 .mvRangeBtns{display:inline-flex;gap:3px;align-items:center;}
.ui2 .mvRangeBtns button{
  box-sizing:border-box;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink-2);
  border-radius:4px;font:600 11px/1 inherit;padding:5px 9px;cursor:pointer;
}
.ui2 .mvRangeBtns button.active{background:var(--u2-accent);border-color:var(--u2-accent);color:#fff;}
.ui2 .mvTfSep{background:var(--u2-line);}

/* language toggle -> segmented control */
.ui2 .mvLangSeg{
  display:inline-flex;align-items:stretch;background:var(--u2-track);
  border-radius:var(--u2-radius);padding:2px;gap:2px;border:0;
}
.ui2 .mvLangSeg button{
  appearance:none;box-sizing:border-box;border:1px solid transparent;background:transparent;
  font:500 var(--u2-fs-sm)/1 inherit;color:var(--u2-ink-2);
  padding:6px 12px;border-radius:4px;cursor:pointer;
}
.ui2 .mvLangSeg button.active{
  background:var(--u2-panel);color:var(--u2-ink);font-weight:600;border-color:var(--u2-line);
}

/* badges */
.ui2 .mvNewBadge,
.ui2 .mvIdxBadge,
.ui2 .mvRegBadge,
.ui2 .mvCnChip,
.ui2 .mvFutChip,
.ui2 .mvNowChip{font-size:10px;font-weight:700;letter-spacing:.03em;border-radius:4px;padding:2px 6px;}

/* every big number: tabular, so values line up down a column of cards */
.ui2 .mvAiBig, .ui2 .mvIdxBig, .ui2 .mvInflBig, .ui2 .mvFgScore,
.ui2 .mvMomVal, .ui2 .mvMomNum, .ui2 .mvGdpVal, .ui2 .mvSiaVal,
.ui2 .mvNowScore, .ui2 .mvIdxStat, .ui2 .mvHiborLv,
.ui2 .mvAnatNums{font-variant-numeric:tabular-nums;}

/* the module HTML tables, arranged like the grids */
.ui2 .mvAiTbl, .ui2 .mvSeasTbl, .ui2 .mvCmeTbl, .ui2 .mvXlsrTbl{
  font-size:var(--u2-fs-sm);border-collapse:collapse;width:100%;
}
.ui2 .mvAiTbl th, .ui2 .mvSeasTbl th, .ui2 .mvCmeTbl th, .ui2 .mvXlsrTbl th{
  font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;
  color:var(--u2-muted);border-bottom:1px solid var(--u2-line);padding:6px 8px;background:transparent;
}
.ui2 .mvAiTbl td, .ui2 .mvSeasTbl td, .ui2 .mvCmeTbl td, .ui2 .mvXlsrTbl td{
  border-bottom:1px solid var(--u2-line-soft);padding:5px 8px;font-variant-numeric:tabular-nums;
}
/* numeric columns right-aligned, the way a terminal arranges a table */
.ui2 .mvAiTbl td.num,  .ui2 .mvAiTbl th.num,
.ui2 .mvXlsrTbl td.num,.ui2 .mvXlsrTbl th.num,
.ui2 .mvTable td.num,  .ui2 .mvTable th.num{text-align:right;}
.ui2 .mvAiTbl tbody tr:hover,
.ui2 .mvXlsrTbl tbody tr:hover{background:var(--u2-line-soft);}

/* ============================ stat strip: long values ============================
   The Options strip uses .metricBox (not .statCard) and its values are long strings
   such as "2026-08-20T16:20:35 latest / 2026-06-02T16:20:03 oldest". The single-line
   ellipsis that suits short values truncated them, so these wrap to two lines. */
.ui2 .strip .metricBox{
  flex:1 1 0;min-width:0;
  border:0;border-radius:0;box-shadow:none;background:transparent;
  padding:9px var(--u2-s4);
  border-left:1px solid var(--u2-line-soft);
}
.ui2 .strip .metricBox:first-child{border-left:0;}
.ui2 .strip .metricBox::before{display:none;}
.ui2 .strip .metricBox strong{
  display:block;font-size:var(--u2-fs-sm);font-weight:600;line-height:1.35;
  white-space:normal;overflow:visible;text-overflow:clip;font-variant-numeric:tabular-nums;
}
html.mobileLayout .ui2 .strip .metricBox{border-left:0;border-top:1px solid var(--u2-line-soft);}
html.mobileLayout .ui2 .strip .metricBox:first-child{border-top:0;}

/* ============================ panel-header toolbars ============================
   A panelHeader carrying controls (Top Tickers: title + Show All + order + search)
   was a row of mismatched heights and widths. Title left, one aligned cluster right. */
.ui2 .panelHeader > h2:first-child{margin-right:auto;}
.ui2 .panelHeader button{
  box-sizing:border-box;height:30px;padding:0 12px;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink-2);
  border-radius:var(--u2-radius);font:600 var(--u2-fs-sm)/1 inherit;cursor:pointer;white-space:nowrap;
}
.ui2 .panelHeader button:hover{border-color:var(--u2-muted);color:var(--u2-ink);}
.ui2 .panelHeader input[type="text"],
.ui2 .panelHeader input[type="search"]{
  box-sizing:border-box;height:30px;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink);
  border-radius:var(--u2-radius);padding:0 10px;font:400 var(--u2-fs-sm)/1 inherit;width:190px;
}
.ui2 .panelHeader input::placeholder{color:var(--u2-muted);}
html.mobileLayout .ui2 .panelHeader button,
html.mobileLayout .ui2 .panelHeader input{height:var(--u2-ctl);font-size:16px;}
html.mobileLayout .ui2 .panelHeader input[type="text"],
html.mobileLayout .ui2 .panelHeader input[type="search"]{width:100%;}

/* ============================ feed modules (zsxq / src / news / kol) ============================ */
.ui2 .zsxqCardBtns button,
.ui2 .srcTreeLabel,
.ui2 .zsxqLink{font-size:var(--u2-fs-sm);}
.ui2 .zsxqReadDot{color:var(--u2-accent);}
.ui2 .srcAvatar{border-radius:var(--u2-radius);}
.ui2 .srcAiResolHead,
.ui2 .soHead{
  font-size:var(--u2-fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--u2-muted);
}
.ui2 .soModelTag,
.ui2 .srcAiDate{font-size:10px;color:var(--u2-muted);}

/* ============================ basket (bk*) ============================ */
.ui2 .bkCard{
  background:var(--u2-panel);border:1px solid var(--u2-line);
  border-radius:var(--u2-radius);box-shadow:none;
}
.ui2 .bkCardHead{border-bottom:1px solid var(--u2-line-soft);padding:9px var(--u2-s3);}
.ui2 .bkTable{font-size:var(--u2-fs-sm);}
.ui2 .bkTable td{font-variant-numeric:tabular-nums;}
.ui2 .bkTable th{
  font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--u2-muted);
}

/* ============================ MV toolbar — corrections ============================
   .mvSearchWrap is the BORDERED CONTROL and .mvSearch inside it is deliberately
   borderless/transparent. My first pass gave the inner input its own border and
   height, which produced a box inside a box. The wrapper is the control; the input
   just sits in it. Every item on this toolbar is now the same 32px. */
.ui2 .mvSearchWrap{
  box-sizing:border-box;
  height:var(--u2-ctl);
  display:inline-flex;align-items:center;gap:6px;
  border:1px solid var(--u2-line);
  background:var(--u2-panel);
  border-radius:var(--u2-radius);
  padding:0 10px;
  min-width:300px;
  box-shadow:none;
}
.ui2 .mvSearchWrap:focus-within{
  border-color:var(--u2-accent);
  box-shadow:0 0 0 3px var(--u2-accent-soft);
}
.ui2 .mvSearch{
  flex:1 1 auto;min-width:0;
  height:auto;padding:0;
  border:0 !important;background:transparent !important;
  border-radius:0;box-shadow:none;outline:none;
  font:400 var(--u2-fs-sm)/1 inherit;color:var(--u2-ink);
}
.ui2 .mvSearch::placeholder{color:var(--u2-muted);}
.ui2 .mvSearchIco{
  font-size:12px;line-height:1;color:var(--u2-muted);
  position:static;flex:0 0 auto;opacity:.75;
}
.ui2 .mvSearchClear{
  flex:0 0 auto;border:0;background:transparent;cursor:pointer;
  color:var(--u2-muted);font-size:12px;line-height:1;padding:0 2px;
}
.ui2 .mvSearchClear:hover{color:var(--u2-ink);}

/* toolbar buttons: same height as the search, quiet until hovered */
.ui2 .mvToolbar{gap:var(--u2-s2);margin:0 0 var(--u2-s4);align-items:center;}
.ui2 .mvGroupsBtn{
  box-sizing:border-box;
  height:var(--u2-ctl);
  padding:0 12px;
  border:1px solid var(--u2-line);
  background:var(--u2-panel);
  color:var(--u2-ink-2);
  border-radius:var(--u2-radius);
  font:500 var(--u2-fs-sm)/1 inherit;
  cursor:pointer;white-space:nowrap;
  display:inline-flex;align-items:center;gap:6px;
}
.ui2 .mvGroupsBtn:hover{
  background:var(--u2-line-soft);
  color:var(--u2-ink);
  border-color:var(--u2-line);
}
.ui2 .mvSearchCount{margin-left:2px;margin-right:auto;}

/* ============================ MV group header ============================
   The group title is a clickable h3. Make it a real header ROW: chevron, label,
   count, and a hairline underneath, instead of a floating uppercase string. */
.ui2 .mvGroupTitle{
  display:flex;align-items:center;gap:8px;
  margin:0 0 var(--u2-s3);
  padding:0 0 7px;
  border-bottom:1px solid var(--u2-line);
  border-radius:0;
  font-size:var(--u2-fs-xs);
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:.07em;
  color:var(--u2-muted);
  cursor:pointer;
}
.ui2 .mvGroupTitle:hover{background:transparent;color:var(--u2-ink-2);}
.ui2 .mvGroupTitle .mvGroupCount,
.ui2 .mvGroupCount{margin-left:auto;}
.ui2 .mvGroupChevron{font-size:10px;opacity:.7;}
.ui2 .mvGroup{margin-bottom:var(--u2-s5);}

/* card titles: readable, not shouty */
.ui2 .mvCardTitle{
  font-size:var(--u2-fs-md);font-weight:600;color:var(--u2-ink);letter-spacing:0;
}
.ui2 .mvCardHead{background:transparent;padding:9px var(--u2-s3);}
.ui2 .mvCardMeta{font-size:10.5px;color:var(--u2-muted);}

html.mobileLayout .ui2 .mvSearchWrap{min-width:0;width:100%;height:var(--u2-ctl);}
html.mobileLayout .ui2 .mvGroupsBtn{height:var(--u2-ctl);font-size:var(--u2-fs-md);}

/* ============================ MV groups are SECTIONS, not panels ============================
   styles.css wraps every group in a grey rounded panel (1px border, 14px radius,
   grey fill, shadow) that then contains the cards - a card inside a card. Collapsed,
   that wrapper is an empty grey slab with a title floating in it, which is what
   looked wrong. A section needs a label and its content, nothing more: the group
   loses its panel entirely and the header hairline carries the structure. */
.ui2 .mvGroup{
  margin:0 0 var(--u2-s5);
  border:0;
  border-radius:0;
  background:transparent;
  box-shadow:none;
  overflow:visible;
}
.ui2 .mvGroup > .mvGrid,
.ui2 .mvGroup .mvGrid{padding:0;}
/* collapsed: keep the rule under the label so the section still reads as a divider */
.ui2 .mvGroup.mvCollapsed > .mvGroupTitle{border-bottom-color:var(--u2-line);}
.ui2 .mvGroup.mvCollapsed{margin-bottom:var(--u2-s4);}
/* sub-sections inside a group get the same quiet treatment */
.ui2 .mvSubTitle{
  display:flex;align-items:center;gap:8px;
  margin:var(--u2-s4) 0 var(--u2-s2);
  padding:0 0 6px;
  border-bottom:1px solid var(--u2-line-soft);
  background:transparent;
  font-size:var(--u2-fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--u2-muted);
}
.ui2 .mvSubTitle .mvSubCount{margin-left:auto;}

/* ============================ Relative Rotation (rrg.html) ============================
   NOTE ON REACH: in the app, rrgView is only an <iframe> pointing at /rrg.html, and a
   parent .ui2 class cannot cross an iframe boundary. RRG is therefore styled because
   rrg.html itself loads these sheets and carries ui2 on <body> (workstream 3) - not
   because the module was adopted. The same is true of Supply Chain. */

/* panes and layout: the chart panes are surfaces, not floating boxes */
.ui2 .chartBox,
.ui2 .chartBox2,
.ui2 .tailPane,
.ui2 .tailPaneD,
.ui2 .tailPaneW,
.ui2 .perfWrap,
.ui2 .corrHeatWrap,
.ui2 .corrRollWrap{
  background:var(--u2-panel);
  border:1px solid var(--u2-line);
  border-radius:var(--u2-radius);
  box-shadow:none;
}
.ui2 .chartSplit{gap:var(--u2-s3);}
.ui2 .splitter{background:var(--u2-line);}
.ui2 .paneTag,
.ui2 .paneTagD,
.ui2 .pqTitle,
.ui2 .corrTitle{
  font-size:var(--u2-fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--u2-muted);
}
.ui2 .chartHint,
.ui2 .corrNote,
.ui2 .corrMeta,
.ui2 .corrRollHint{font-size:var(--u2-fs-xs);color:var(--u2-muted);}

/* group tabs -> the same underline tabs used everywhere else */
.ui2 .gtabs,
.ui2 .gsubtabs,
.ui2 .gsubtabs2{
  display:flex;gap:22px;
  background:transparent;border:0;border-bottom:1px solid var(--u2-line);
  border-radius:0;padding:0;margin:0 0 var(--u2-s3);
}
.ui2 .gtab,
.ui2 .gsub{
  background:transparent;border:0;border-bottom:2px solid transparent;border-radius:0;
  margin-bottom:-1px;padding:7px 0 9px;min-height:0;
  font-size:var(--u2-fs-md);font-weight:500;color:var(--u2-ink-2);cursor:pointer;
}
.ui2 .gtab:hover,
.ui2 .gsub:hover{background:transparent;color:var(--u2-ink);border-bottom-color:var(--u2-line);}
.ui2 .gtab.on,   .ui2 .gtab.active,
.ui2 .gsub.on,   .ui2 .gsub.active{
  background:transparent;color:var(--u2-accent);font-weight:600;
  border-bottom:2px solid var(--u2-accent);
}

/* summary cards: sumCard already lands on the generic card primitive; these are its
   internals - a compact quote row, tabular figures, quadrant colour kept meaningful */
.ui2 .sumGrid{gap:var(--u2-s3);}
.ui2 .sumHead{
  border-bottom:1px solid var(--u2-line-soft);padding:8px var(--u2-s3);
  font-size:var(--u2-fs-md);font-weight:600;color:var(--u2-ink);background:transparent;
}
.ui2 .sumRowH{
  font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;
  color:var(--u2-muted);border-bottom:1px solid var(--u2-line);
}
.ui2 .sumRow{
  border-bottom:1px solid var(--u2-line-soft);
  font-size:var(--u2-fs-sm);
  font-variant-numeric:tabular-nums;
}
.ui2 .sumRow:hover{background:var(--u2-line-soft);}
.ui2 .sumRow:last-child{border-bottom:0;}
.ui2 .sumCode{font-weight:600;color:var(--u2-ink);}
.ui2 .sumName{color:var(--u2-muted);font-size:var(--u2-fs-xs);}
.ui2 .sumTurn,
.ui2 .sumCount{font-variant-numeric:tabular-nums;color:var(--u2-ink-2);}
.ui2 .sumBadge,
.ui2 .sumQuad,
.ui2 .benchBadge,
.ui2 .qdot{
  font-size:10px;font-weight:700;letter-spacing:.03em;border-radius:4px;padding:2px 6px;
}
.ui2 .sumGrp{
  font-size:var(--u2-fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--u2-muted);
}
.ui2 .sumMore,
.ui2 .sumEmpty{font-size:var(--u2-fs-xs);color:var(--u2-muted);}

/* tables: the cheat sheet and the correlation heat map */
.ui2 .cheatTbl{font-size:var(--u2-fs-sm);border-collapse:collapse;width:100%;}
.ui2 .cheatTbl th{
  font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;
  color:var(--u2-muted);border-bottom:1px solid var(--u2-line);padding:6px 8px;
}
.ui2 .cheatTbl td{
  border-bottom:1px solid var(--u2-line-soft);padding:5px 8px;font-variant-numeric:tabular-nums;
}
.ui2 .corrHeat{font-size:var(--u2-fs-xs);font-variant-numeric:tabular-nums;}
.ui2 .corrHeat td,
.ui2 .corrHeat th{border-color:var(--u2-line-soft);}

/* controls: timeframe, zoom, tail, filters, help */
.ui2 .tfToggle,
.ui2 .zoomBar,
.ui2 .tailCtl,
.ui2 .corrRollSeg,
.ui2 .corrWinSeg{display:inline-flex;gap:3px;align-items:center;}
.ui2 .tfBtn{
  box-sizing:border-box;min-height:0;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink-2);
  border-radius:4px;font:600 11px/1 inherit;padding:6px 10px;cursor:pointer;
}
.ui2 .tfBtn:hover{background:var(--u2-line-soft);color:var(--u2-ink);}
.ui2 .tfBtn.on,
.ui2 .tfBtn.active{background:var(--u2-accent);border-color:var(--u2-accent);color:#fff;}
.ui2 .gfilter{
  box-sizing:border-box;min-height:var(--u2-ctl);
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink);
  border-radius:var(--u2-radius);padding:0 10px;font:400 var(--u2-fs-sm)/1 inherit;
}
.ui2 .helpBtn{
  box-sizing:border-box;width:26px;height:26px;min-height:0;padding:0;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-muted);
  border-radius:999px;font:700 12px/1 inherit;
}
.ui2 .helpBtn:hover{border-color:var(--u2-accent);color:var(--u2-accent);background:var(--u2-panel);}
.ui2 .perfChk{font-size:var(--u2-fs-sm);color:var(--u2-ink-2);}

/* help modal -> the shared overlay panel language */
.ui2 .helpModal{background:rgba(12,17,24,.55);}
.ui2 .helpPanel{
  background:var(--u2-panel);border:1px solid var(--u2-line);
  border-radius:var(--u2-radius);box-shadow:0 18px 48px rgba(10,16,26,.28);
}
.ui2 .helpClose{
  box-sizing:border-box;width:30px;height:30px;min-height:0;padding:0;
  border:1px solid var(--u2-line);background:var(--u2-panel);
  border-radius:var(--u2-radius);color:var(--u2-muted);
}

/* ============================ RRG header + controls ============================ */
.ui2 body > header,
.ui2 header:first-of-type{
  display:flex;align-items:center;gap:var(--u2-s3);flex-wrap:wrap;
  padding:10px var(--u2-s4);
  background:var(--u2-panel);
  border-bottom:1px solid var(--u2-line);
}
.ui2 header h1{
  font-size:var(--u2-fs-lg);font-weight:700;color:var(--u2-ink);
  margin:0 var(--u2-s2) 0 0;letter-spacing:.01em;
}
/* the round icon buttons (中 / ? / perf / corr) become one quiet square set */
.ui2 .helpBtn{
  box-sizing:border-box;width:28px;height:28px;min-height:0;padding:0;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink-2);
  border-radius:var(--u2-radius);font:600 12px/1 inherit;
  display:inline-flex;align-items:center;justify-content:center;
}
.ui2 .helpBtn:hover{background:var(--u2-line-soft);color:var(--u2-ink);border-color:var(--u2-line);}
.ui2 .helpBtn.on,
.ui2 .helpBtn.active{background:var(--u2-accent);border-color:var(--u2-accent);color:#fff;}

/* Weekly | Daily | Compare -> the grey-track segmented control, like Futu */
.ui2 .tfToggle{
  display:inline-flex;align-items:stretch;
  box-sizing:border-box;height:var(--u2-ctl);
  background:var(--u2-track);
  border:1px solid var(--u2-line);
  border-radius:var(--u2-radius);
  padding:2px;gap:2px;
  overflow:visible;
}
.ui2 .tfToggle .tfBtn{
  border:1px solid transparent;background:transparent;color:var(--u2-ink-2);
  border-radius:3px;padding:0 13px;height:100%;min-height:0;
  font:500 var(--u2-fs-sm)/1 inherit;
}
.ui2 .tfToggle .tfBtn:hover{background:transparent;color:var(--u2-ink);}
.ui2 .tfToggle .tfBtn.active,
.ui2 .tfToggle .tfBtn.on{
  background:var(--u2-panel);color:var(--u2-ink);font-weight:600;
  border-color:var(--u2-line);box-shadow:0 1px 2px rgba(16,24,40,.06);
}

/* tail-length control: a labelled slider, not a loose range input */
.ui2 .tailCtl{
  display:inline-flex;align-items:center;gap:7px;
  box-sizing:border-box;height:var(--u2-ctl);
  padding:0 10px;
  border:1px solid var(--u2-line);background:var(--u2-panel);
  border-radius:var(--u2-radius);
  font-size:var(--u2-fs-sm);color:var(--u2-ink-2);
}
.ui2 .tailCtl input[type="range"]{
  min-height:0;height:4px;padding:0;border:0;background:var(--u2-track);
  border-radius:999px;accent-color:var(--u2-accent);width:96px;box-shadow:none;
}
.ui2 .tailCtl input[type="range"]:focus{box-shadow:none;outline:none;}
.ui2 .tailVal{
  font-variant-numeric:tabular-nums;font-weight:600;color:var(--u2-ink);
  min-width:18px;text-align:right;
}
.ui2 .tailUnit{font-size:var(--u2-fs-xs);color:var(--u2-muted);}
/* the little pane dots that key a slider to its chart */
.ui2 .tailPane{width:8px;height:8px;border-radius:2px;flex:0 0 auto;}

/* filter box in the group bar */
.ui2 .gfilter{min-width:170px;}
/* correlation toolbar sits on one line with the rest */
.ui2 .corrBar{gap:var(--u2-s3);margin-bottom:var(--u2-s3);}
.ui2 .corrClose{
  box-sizing:border-box;width:28px;height:28px;min-height:0;padding:0;
  border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-muted);
  border-radius:var(--u2-radius);
}
.ui2 .empty{color:var(--u2-muted);font-size:var(--u2-fs-sm);}

/* ============================ RRG controls, fine-tuned ============================
   Working against rrg.html's own inline styles, which are specific about these:
     .tfBtn.active      -> hard-coded #2563eb fill
     .gtab.summaryTab   -> purple gradient chip with a lift on hover
     .helpBtn           -> 30px, 9px radius, translateY + glow on hover
   Each is overridden explicitly rather than hoped to lose the cascade. */

/* icon buttons: one quiet square set, no lift, no glow */
.ui2 .helpBtn{
  width:28px !important;height:28px !important;
  border-radius:var(--u2-radius) !important;
  border:1px solid var(--u2-line) !important;
  background:var(--u2-panel) !important;
  color:var(--u2-ink-2) !important;
  font:600 11.5px/1 inherit !important;
  box-shadow:none !important;
  transform:none !important;
  transition:background .12s,border-color .12s,color .12s;
}
.ui2 .helpBtn:hover{
  background:var(--u2-line-soft) !important;color:var(--u2-ink) !important;
  border-color:var(--u2-line) !important;box-shadow:none !important;transform:none !important;
}
.ui2 .helpBtn:active{transform:none !important;box-shadow:none !important;}
.ui2 .helpBtn.on,
.ui2 .helpBtn.active{
  background:var(--u2-accent) !important;border-color:var(--u2-accent) !important;color:#fff !important;
}

/* Weekly | Daily | Compare: a real grey track with a raised white pill.
   rrg.html joins the buttons with a divider and fills the active one blue. */
.ui2 .tfToggle{
  border:1px solid var(--u2-line) !important;
  background:var(--u2-track) !important;
  border-radius:var(--u2-radius) !important;
  padding:2px !important;gap:2px;overflow:visible !important;
  height:var(--u2-ctl);box-sizing:border-box;
}
.ui2 .tfToggle .tfBtn{
  border:1px solid transparent !important;
  background:transparent !important;
  color:var(--u2-ink-2) !important;
  border-radius:3px !important;
  font:500 var(--u2-fs-sm)/1 inherit !important;
  padding:0 13px !important;height:100%;min-height:0;
  box-shadow:none !important;
}
.ui2 .tfToggle .tfBtn + .tfBtn{border-left:1px solid transparent !important;}
.ui2 .tfToggle .tfBtn:hover{color:var(--u2-ink) !important;background:transparent !important;}
.ui2 .tfToggle .tfBtn.active{
  background:var(--u2-panel) !important;
  color:var(--u2-ink) !important;
  font-weight:600 !important;
  border-color:var(--u2-line) !important;
  box-shadow:0 1px 2px rgba(16,24,40,.06) !important;
}

/* group tabs: quieter, roomier, one underline language */
.ui2 .gtabs{gap:18px;border-bottom:1px solid var(--u2-line);align-items:stretch;}
.ui2 .gtab{
  font:500 var(--u2-fs-sm)/1 inherit !important;
  letter-spacing:.04em;
  padding:9px 0 10px !important;
  color:var(--u2-ink-2) !important;
  border-bottom:2px solid transparent !important;
  margin-bottom:-1px;border-radius:0 !important;background:none !important;
}
.ui2 .gtab:hover{color:var(--u2-ink) !important;background:none !important;}
.ui2 .gtab.active{
  color:var(--u2-accent) !important;font-weight:600 !important;
  border-bottom-color:var(--u2-accent) !important;
}
/* SUMMARY was a purple gradient chip - the loudest thing on the page and the only
   element in the app using that palette. It becomes a normal tab; the star keeps a
   touch of colour so it still reads as the special one. */
.ui2 .gtab.summaryTab{
  background:none !important;
  background-image:none !important;
  color:var(--u2-ink-2) !important;
  box-shadow:none !important;
  transform:none !important;
  border-radius:0 !important;
  border-bottom:2px solid transparent !important;
  padding:9px 0 10px !important;
}
.ui2 .gtab.summaryTab:hover{
  color:var(--u2-ink) !important;filter:none !important;transform:none !important;box-shadow:none !important;
}
.ui2 .gtab.summaryTab.active{
  color:var(--u2-accent) !important;
  border-bottom:2px solid var(--u2-accent) !important;
  background:none !important;box-shadow:none !important;
}
.ui2 .gtab.summaryTab .sumStar{color:#e0a500 !important;margin-right:4px;}
/* the little separator dots after SUMMARY / HOLDING */
.ui2 .gtab.summaryTab::after,
.ui2 .gtab.holdTab::after{background:var(--u2-line) !important;}

/* sub-tabs: quiet chips, selected reads as selected without shouting */
.ui2 .gsub{
  font:500 var(--u2-fs-sm)/1 inherit !important;
  padding:6px 11px !important;
  border-radius:var(--u2-radius) !important;
  border:1px solid var(--u2-line) !important;
  background:var(--u2-panel) !important;
  color:var(--u2-ink-2) !important;
  min-height:0;
}
.ui2 .gsub:hover{background:var(--u2-line-soft) !important;color:var(--u2-ink) !important;border-color:var(--u2-line) !important;}
.ui2 .gsub.active{
  background:var(--u2-accent-soft) !important;
  border-color:var(--u2-accent) !important;
  color:var(--u2-accent) !important;
  font-weight:600 !important;
}

/* ============================ RRG / standalone pages: adopt the app palette ============================
   rrg.html (and the other standalone pages) declare their own variables at :root -
   --bg:#fff, --text, --muted, --line, --subtle, --row - and every rule in those files
   is written against them. The result was a WHITE page while every module in the app
   sits on light grey with white cards, so RRG read as a different product.

   Rather than chase each rule, redefine those SAME variable names on .ui2. Because
   .ui2 is on <body>, an element-level custom property beats the :root value for every
   descendant, so the page adopts the app palette with no other change. This is the
   cheapest possible alignment and it also fixes the standalone pages wholesale. */
.ui2{
  --bg:var(--u2-bg);
  --text:var(--u2-ink);
  --muted:var(--u2-muted);
  --line:var(--u2-line);
  --subtle:var(--u2-track);
  --row:var(--u2-line-soft);
  /* names used by the app stylesheet, kept in step for the same reason */
  --panel:var(--u2-panel);
  --ink:var(--u2-ink);
}
[data-theme="dark"] .ui2,
[data-bs-theme="dark"] .ui2{
  --bg:var(--u2-bg);
  --text:var(--u2-ink);
  --muted:var(--u2-muted);
  --line:var(--u2-line);
  --subtle:var(--u2-track);
  --row:var(--u2-line-soft);
  --panel:var(--u2-panel);
  --ink:var(--u2-ink);
}
/* the page itself takes the app background; the panes are the white cards on top */
.ui2 body,
body.ui2{background:var(--u2-bg);color:var(--u2-ink);}
/* RRG header sits on the panel colour, like the app topbar */
.ui2 > header,
body.ui2 > header{background:var(--u2-panel);border-bottom:1px solid var(--u2-line);}
/* group tab strip and the content wrap sit on the page, not on white */
body.ui2 .groups{background:var(--u2-panel);border-bottom:1px solid var(--u2-line);padding:6px var(--u2-s4) 0;}
body.ui2 .wrap{background:transparent;padding:var(--u2-s4);}
body.ui2 #grid,
body.ui2 .chartBox,
body.ui2 .chartBox2{background:var(--u2-panel);}

/* ============================ card action row ============================
   The row under every feed card meta line (AI / Open / Copy / Image / Save /
   Unread). styles.css uppercased it, which is what made it read as small caps,
   and the glyphs were three emoji plus four typographic characters, so no two
   buttons shared a weight or a baseline. Icons now come from window.ICO
   (js/01-core.js) - inline SVG on currentColor - and the labels are sentence case.
   Same object as every other control, one size down because it sits inside a card. */
.ui2 .zsxqMeta > .zsxqCardBtns,
.ui2 .zsxqCardBtns{display:inline-flex;align-items:center;gap:4px;flex-wrap:wrap;margin-left:0;justify-content:flex-start;}
.ui2 .zsxqCardBtns .zsxqIconBtn,
.ui2 .zsxqCardBtns .zsxqReadDot{
  text-transform:none !important;
  letter-spacing:0 !important;
  display:inline-flex;align-items:center;gap:5px;
  box-sizing:border-box;height:24px;min-height:0;padding:0 8px;
  font:500 11.5px/1 "Noto Sans",system-ui,sans-serif;
  border:1px solid var(--u2-line);border-radius:var(--u2-radius);
  background:var(--u2-panel);color:var(--u2-ink-2);
  white-space:nowrap;
}
.ui2 .zsxqCardBtns .zsxqIconBtn:hover{
  background:var(--u2-line-soft);color:var(--u2-ink);border-color:var(--u2-line);
}
/* selected: the same accent fill the rest of the app uses for "on" */
.ui2 .zsxqCardBtns .zsxqIconBtn.on{
  background:var(--u2-accent);border-color:var(--u2-accent);color:#fff;font-weight:600;
}
/* read/unread is a STATUS, not a button - no border, no fill, just the state */
.ui2 .zsxqCardBtns .zsxqReadDot{
  border-color:transparent;background:transparent;color:var(--u2-muted);padding:0 4px;
}
.ui2 .zsxqCardBtns .zsxqReadDot.on{color:var(--u2-up);}
.ui2 .zsxqCardBtns .uiIco{flex:0 0 auto;display:block;}
.ui2 .zsxqCardBtns .zsxqLink{
  font:500 11.5px/1 "Noto Sans",system-ui,sans-serif;color:var(--u2-accent);
  text-decoration:none;padding:0 4px;
}
.ui2 .zsxqCardBtns .zsxqLink:hover{text-decoration:underline;}
html.mobileLayout .ui2 .zsxqCardBtns .zsxqIconBtn,
html.mobileLayout .ui2 .zsxqCardBtns .zsxqReadDot{
  height:32px;min-height:32px;padding:0 10px;font-size:12px;
}

/* the monogram stand-in for a source with no icon: identical footprint to the <img>,
   so the label pills line up down the feed whether or not an icon exists */
.ui2 .srcAvatarMono{
  width:22px;height:22px;flex:0 0 auto;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--u2-line);border-radius:var(--u2-radius);
  background:var(--u2-track);color:var(--u2-muted);
  font:700 10px/1 "Noto Sans",system-ui,sans-serif;
  letter-spacing:0;text-transform:uppercase;
}

/* ============================ Watch → Saved articles ============================
   One mixed feed across KOL / Research / ZSXQ / Sources / News. The cards ARE the
   feeds' own .zsxqCard markup, so everything above already styles them; the only
   new object is the module badge, which says which feed a card came from. */
.ui2 .savedMod{
  display:inline-flex;align-items:center;height:20px;padding:0 7px;
  border:1px solid var(--u2-line);border-radius:var(--u2-radius);
  background:var(--u2-track);color:var(--u2-ink-2);
  font:700 10px/1 "Noto Sans",system-ui,sans-serif;
  text-transform:uppercase;letter-spacing:.05em;white-space:nowrap;
}
.ui2 #savedFeed .zsxqTitleCn{
  font-size:var(--u2-fs-sm);color:var(--u2-ink);margin-top:2px;
}
.ui2 #savedFeed .savedTickers{margin-top:6px;display:flex;flex-wrap:wrap;gap:4px;}
.ui2 .savedEmpty{
  padding:28px 16px;text-align:center;color:var(--u2-muted);
  font-size:var(--u2-fs-sm);border:1px dashed var(--u2-line);border-radius:var(--u2-radius);
}
/* an un-saved card stays put, dimmed, until the next load - one click to undo */
.ui2 #savedFeed .savedOff{opacity:.55;}
.ui2 #savedFeed .savedOff .zsxqTitle,
.ui2 #savedFeed .savedOff .zsxqText{text-decoration:line-through;text-decoration-color:var(--u2-line);}

/* ============================ translated text reads as text ============================
   Machine-translated text was set in the muted grey the app uses for METADATA - the
   translated tweet blocks in the KOL reader, and the Chinese headline / item titles /
   second-brief facts on the daily digests (one renderer shared by KOL, Other key
   sources, ZSXQ and News). It is content, not chrome: a Chinese-only view was a page
   of grey. It now takes the body ink, which flips with the theme. A translation stays
   identifiable by what marks it - the 译 tag and dashed rule on KOL tweet blocks, the
   中文（机器翻译） label in Sources - not by being harder to read. */
.ui2 .kolTweetTr,
.ui2 .newsReaderTitleCn,
.ui2 .newsDigestItemTitleCn,
.ui2 .dailyCardHeadCn,
.ui2 .dailyCardBrief + .dailyCardBrief .newsBriefFacts{color:var(--u2-ink);}
/* ...and the ORIGINAL tweet text with it. .kolTweetText was hard-coded #0f172a with no dark
   override, so in dark mode the originals rendered near-black on a dark reader - and once
   the translations above flip to light ink they would have been the only unreadable text
   on the page. Original and translation are one ink in both themes. */
.ui2 .kolTweetText{color:var(--u2-ink);}
/* the second language of a Saved card: separated by a dashed rule, tagged 译 when it
   is the machine translation - never greyed (it is content, same ink as the original) */
.ui2 #savedFeed .savedTr{margin-top:6px;padding-top:6px;border-top:1px dashed var(--u2-line);}
.ui2 #savedFeed .kolTrTag{margin-right:6px;}

/* ==== Quant > Book Tracker (qb*) - Zephyr L/S book, js/24b-quant-book.js =================
   Futu/ui2 surfaces: white cards on the grey ground, 4px radius, up/down tokens, condensed
   tabular tables (same language as the RRG / Basket grids). The panel is display:flex only
   when NOT [hidden] - a bare display rule would override the hidden attribute. */
.ui2 #quantTabBook:not([hidden]){display:flex;flex-direction:column;gap:var(--u2-s3);}
.ui2 .qbHead{display:flex;align-items:center;gap:var(--u2-s4);flex-wrap:wrap;background:var(--u2-panel);
  border:1px solid var(--u2-line);border-radius:var(--u2-radius);padding:var(--u2-s2) var(--u2-s3);}
.ui2 .qbNav{display:flex;align-items:center;gap:4px;}
.ui2 .qbNavBtn{height:26px;min-width:26px;border:1px solid var(--u2-line);background:var(--u2-panel);
  color:var(--u2-ink-2);border-radius:var(--u2-radius);font-size:11px;line-height:1;cursor:pointer;}
.ui2 .qbNavBtn:disabled{opacity:.35;cursor:default;}
.ui2 .qbDateSel{height:26px;border:1px solid var(--u2-line);background:var(--u2-panel);color:var(--u2-ink);
  border-radius:var(--u2-radius);font-size:12px;font-variant-numeric:tabular-nums;padding:0 6px;}
.ui2 .qbKpis{display:flex;flex-wrap:wrap;gap:var(--u2-s4);}
.ui2 .qbKpi{display:flex;flex-direction:column;gap:1px;}
.ui2 .qbKpiL{font-size:10.5px;color:var(--u2-muted);text-transform:uppercase;letter-spacing:.03em;}
.ui2 .qbKpiV{font-size:14px;font-weight:600;color:var(--u2-ink);font-variant-numeric:tabular-nums;}
.ui2 .qbRow{display:flex;gap:var(--u2-s3);flex-wrap:wrap;align-items:stretch;}
.ui2 .qbCard{flex:1 1 420px;min-width:0;margin:0;}
.ui2 .qbPosCard{flex:3 1 640px;}
.ui2 .qbNavCard{flex:2 1 420px;}
.ui2 .qbChgCard{flex:3 1 560px;}
.ui2 .qbPendCard{flex:2 1 360px;}
.ui2 .qbFitCard{flex:1 1 100%;}
.ui2 .qbBody{padding:var(--u2-s2);}
.ui2 .qbGrid.ag-theme-quartz{width:100%;height:460px;
  font-family:"Roboto Condensed","Noto Sans",system-ui,sans-serif;
  --ag-font-family:"Roboto Condensed","Noto Sans",system-ui,sans-serif;
  --ag-font-size:11.5px;--ag-grid-size:3px;--ag-cell-horizontal-padding:6px;}
.ui2 .qbGridSm.ag-theme-quartz{height:260px;}
.ui2 .qbChart{width:100%;height:460px;position:relative;}
.ui2 .qbChartMd{height:340px;}
.ui2 .qbChartSm{height:240px;}
.ui2 .qbFitGrid{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,2fr);gap:var(--u2-s3);}
.ui2 .qbSeg{display:inline-flex;border:1px solid var(--u2-line);border-radius:var(--u2-radius);overflow:hidden;margin-left:auto;}
.ui2 .qbSeg button{border:0;background:var(--u2-panel);color:var(--u2-ink-2);font-size:11px;padding:3px 9px;cursor:pointer;}
.ui2 .qbSeg button+button{border-left:1px solid var(--u2-line);}
.ui2 .qbSeg button.on{background:var(--u2-accent-soft);color:var(--u2-accent);font-weight:600;}
.ui2 .qbSearch{height:24px;width:140px;border:1px solid var(--u2-line);border-radius:var(--u2-radius);
  background:var(--u2-panel);color:var(--u2-ink);font-size:11.5px;padding:0 6px;margin-left:var(--u2-s2);}
.ui2 .qbUp{color:var(--u2-up);}
.ui2 .qbDown{color:var(--u2-down);}
.ui2 .qbMuted{color:var(--u2-muted);font-size:11.5px;}
.ui2 #quantTabBook .ag-cell.qbUp{color:var(--u2-up);}
.ui2 #quantTabBook .ag-cell.qbDown{color:var(--u2-down);}
.ui2 #quantTabBook .ag-cell.qbSideL{color:var(--u2-up);font-weight:600;}
.ui2 #quantTabBook .ag-cell.qbSideS{color:var(--u2-down);font-weight:600;}
.ui2 #quantTabBook .ag-cell.qbStOpen{color:var(--u2-accent);font-weight:600;}
.ui2 #quantTabBook .ag-cell.qbStClose{color:#b58f2e;font-weight:600;}
.ui2 .qbPend{display:flex;flex-direction:column;gap:var(--u2-s3);}
.ui2 .qbPendRow{display:flex;flex-wrap:wrap;gap:5px;align-items:center;}
.ui2 .qbPendL{font-size:11px;font-weight:600;min-width:64px;}
.ui2 .qbChip{font-size:11.5px;font-family:"Roboto Condensed","Noto Sans",sans-serif;border:1px solid var(--u2-line);
  border-radius:var(--u2-radius);padding:1px 6px;background:var(--u2-panel);color:var(--u2-ink);}
.ui2 .qbChip small{color:var(--u2-muted);}
.ui2 .qbChipOpen{border-color:var(--u2-up);}
.ui2 .qbChipClose{border-color:var(--u2-down);}
.ui2 .qbRho{max-height:340px;overflow:auto;}
.ui2 .qbRhoTbl,.ui2 .qbIcTbl{width:100%;border-collapse:collapse;font-family:"Roboto Condensed","Noto Sans",sans-serif;
  font-size:11.5px;font-variant-numeric:tabular-nums;}
.ui2 .qbRhoTbl td{padding:3px 4px;border-bottom:1px dashed var(--u2-line-soft);color:var(--u2-ink);white-space:nowrap;}
.ui2 .qbRhoTbl td:last-child{text-align:right;width:52px;}
.ui2 .qbRhoBarCell{width:45%;}
.ui2 .qbRhoBar{display:block;height:6px;border-radius:2px;}
.ui2 .qbBgUp{background:var(--u2-up);}
.ui2 .qbBgDown{background:var(--u2-down);}
.ui2 .qbIcTbl{margin-bottom:var(--u2-s2);}
.ui2 .qbIcTbl th{font-size:10.5px;font-weight:500;text-transform:uppercase;color:var(--u2-muted);text-align:right;
  padding:3px 6px;border-bottom:1px solid var(--u2-line);}
.ui2 .qbIcTbl td{text-align:right;padding:3px 6px;border-bottom:1px dashed var(--u2-line-soft);color:var(--u2-ink);}
.ui2 .qbIcTbl th:first-child,.ui2 .qbIcTbl td:first-child{text-align:left;}
.ui2 .qbAttrToday{font-size:11.5px;color:var(--u2-ink-2);padding:var(--u2-s2) 2px 0;line-height:1.5;}
html.mobileLayout .ui2 .qbFitGrid{grid-template-columns:1fr;}
/* Book Tracker card surfaces + head: own classes, NOT .mvCard - Market View's card head
   re-orders its children and .mvCard carries the enlarge affordance; neither wanted here. */
.ui2 .qbCard{background:var(--u2-panel);border:1px solid var(--u2-line);border-radius:var(--u2-radius);
  display:flex;flex-direction:column;}
.ui2 .qbCardHead{display:flex;align-items:center;gap:var(--u2-s2);flex-wrap:wrap;min-height:38px;
  padding:var(--u2-s2) var(--u2-s3);border-bottom:1px solid var(--u2-line-soft);}
.ui2 .qbCardTitle{font-size:var(--u2-fs-md);font-weight:600;color:var(--u2-ink);margin-right:auto;}
.ui2 .qbCardMeta{font-size:11px;color:var(--u2-muted);}
.ui2 .qbSeg{margin-left:0;}
.ui2 .qbEmpty{padding:28px 8px;text-align:center;color:var(--u2-muted);font-size:12px;}
.ui2 #quantTabBook [hidden]{display:none !important;}
/* Book Tracker live overlay (zephyr.live -> mv_panel quant_book_live, US session only). */
.ui2 .qbKpiLive .qbKpiL{color:var(--u2-up);font-weight:600;}
.ui2 .qbLiveDot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--u2-up);
  margin-right:4px;vertical-align:1px;}
.ui2 .qbKpiV small{font-size:11px;font-weight:500;color:var(--u2-muted);}
