/* ==========================================================================
   FinView — unification layer
   v1.0 · fv-unify-1.0.0
   ==========================================================================

   Loaded LAST on every page, after tokens.css and components.css.

   This file exists because the platform has seven stylesheets that each grew
   their own answer to the same four questions — how tall is a control, how much
   padding does a panel have, what does a row look like on hover, and what
   colour is "interactive". Whichever answer won depended on link order, which
   is why two boards side by side never matched.

   It is deliberately a thin corrective layer, not a new design system: it sets
   ONE answer per question at a specificity the legacy files cannot beat, using
   the tokens already defined in tokens.css. Nothing here invents a value.

   Sections
     1. Missing tokens          — --fv-on-accent, density, palette shims
     2. Density                 — one scale, three steps, every board
     3. Tables                  — the single hover rule, sticky cells, headers
     4. KPI cards               — equal heights, one internal structure
     5. Controls                — one height, one radius, one focus ring
     6. Panels & spacing        — the token scale applied to legacy classes
     7. Segmented / tabs        — overflow, active state
     8. Card grids              — no orphaned last card
     9. Chrome                  — sidebar, topbar, icons, brand
    10. Command palette         — ⌘K
    11. States                  — loading, empty, error
    12. Accessibility           — skip link, focus, reduced motion, print
   ========================================================================== */

/* ==========================================================================
   1. MISSING TOKENS
   ========================================================================== */
:root {
  /* Text that sits ON the accent. One token was doing two jobs: white on the
     light accent (fine, 5.1:1) and white on the dark theme's bright cyan
     (1.81:1, unreadable). Split so each theme names its own. */
  --fv-on-accent: #FFFFFF;

  /* Density — every table cell, control height and panel pad multiplies these.
     Set by [data-density] on <html>; the default is the comfortable step. */
  --fv-density-cell-y: var(--fv-space-3);
  --fv-density-cell-x: var(--fv-space-4);
  --fv-density-control: var(--fv-control-md);
  --fv-density-panel: var(--fv-space-5);
  --fv-density-text: var(--fv-text-base);
  --fv-density-row: 40px;
}
html[data-theme="dark"] { --fv-on-accent: #04121A; }

/* Legacy names some rules still read, pointed at the real tokens so a stray
   var() cannot resolve to nothing and collapse a background to transparent. */
:root, html[data-theme="dark"] {
  --amber: var(--fv-warn);
  --surface-soft: var(--fv-surface-2);
  --on-accent: var(--fv-on-accent);
  --module-accent: var(--fv-accent);
}

/* ==========================================================================
   2. DENSITY
   Three steps, persisted by pro.js, shared by every board. Comfortable is for
   reading, compact for scanning a screener, tight for a full option chain on a
   laptop. Nothing below 11px: a tighter row is useless if the figure in it
   cannot be read.
   ========================================================================== */
html[data-density="compact"] {
  --fv-density-cell-y: var(--fv-space-2);
  --fv-density-cell-x: var(--fv-space-3);
  --fv-density-control: var(--fv-control-sm);
  --fv-density-panel: var(--fv-space-4);
  --fv-density-text: var(--fv-text-sm);
  --fv-density-row: 32px;
}
html[data-density="tight"] {
  --fv-density-cell-y: 3px;
  --fv-density-cell-x: var(--fv-space-2);
  --fv-density-control: var(--fv-control-sm);
  --fv-density-panel: var(--fv-space-3);
  --fv-density-text: var(--fv-text-xs);
  --fv-density-row: 26px;
}

:is(.data-table, .special-table, .fv-table, .chain-table, .strategy-legs-table) :is(th, td) {
  padding-block: var(--fv-density-cell-y);
  padding-inline: var(--fv-density-cell-x);
}
:is(.data-table, .special-table, .fv-table) tbody td { font-size: var(--fv-density-text); }
html[data-density="tight"] :is(.data-table, .special-table, .fv-table) :is(th, td) { line-height: 1.3; }

/* ==========================================================================
   3. TABLES — one hover rule for the whole platform
   ==========================================================================

   Before: five competing `tr:hover` declarations (app.css twice with different
   colours, site.css, ui-clean.css, specialized.css, components.css). Two
   consequences the user sees:

     · Pinned columns did not highlight. .symbol-sticky / .symbol-cell /
       .watch-column carry their own opaque background so the row broke in half
       under the pointer.
     · ui-clean.css set `pointer-events: none` on the table while scrolling, so
       hover died for a moment after every wheel tick and felt broken.

   One rule, applied to the row, with every sticky cell forced to the same
   opaque hover colour. Sticky cells must be opaque — a translucent tint lets
   the scrolling columns render straight through the pinned one.
   ========================================================================== */
:is(.data-table, .special-table, .fv-table, .watchlist-table, .comparison-table,
    .v2-market-table, .chain-table, .option-unusual-table, .nearest-expiry-table,
    .depth-table) tbody tr {
  transition: background var(--fv-duration-fast) var(--fv-ease);
}
:is(.data-table, .special-table, .fv-table, .watchlist-table, .comparison-table,
    .v2-market-table, .chain-table, .option-unusual-table, .nearest-expiry-table,
    .depth-table) tbody tr:hover > td,
:is(.data-table, .special-table, .fv-table, .watchlist-table, .comparison-table,
    .v2-market-table, .chain-table, .option-unusual-table, .nearest-expiry-table,
    .depth-table) tbody tr:focus-within > td {
  background: var(--fv-surface-2);
}
/* Pinned cells: same colour as the rest of the row, opaque in both states. */
:is(.data-table, .special-table, .fv-table, .v2-market-table, .chain-table) tbody td:is(
  .symbol-sticky, .symbol-cell, .watch-column, .select-cell,
  .strategy-chain-symbol-col, .strategy-chain-buy-col, .strategy-chain-sell-col
) { background: var(--fv-surface); }
:is(.data-table, .special-table, .fv-table, .v2-market-table, .chain-table) tbody tr:hover > td:is(
  .symbol-sticky, .symbol-cell, .watch-column, .select-cell,
  .strategy-chain-symbol-col, .strategy-chain-buy-col, .strategy-chain-sell-col
) { background: var(--fv-surface-2); }

/* Selected beats hover, and keeps its tint while hovered. */
:is(.data-table, .special-table, .fv-table, .v2-market-table) tbody tr:is(.is-selected, [aria-selected="true"]) > td,
:is(.data-table, .special-table, .fv-table, .v2-market-table) tbody tr:is(.is-selected, [aria-selected="true"]):hover > td {
  background: var(--fv-accent-soft);
}

/* The scroll-lock that killed hover. Momentum scrolling is not a reason to
   disable the pointer. */
.v2-market-page .table-scroll.is-scrolling .v2-market-table { pointer-events: auto; }
.v2-market-page .table-scroll.is-scrolling .v2-market-table tbody tr:hover td { background: var(--fv-surface-2); }

/* Headers: one treatment. Muted label on surface-2, accent only when the
   column is the active sort — an accent-coloured header row on every table made
   the header compete with the data. */
:is(.data-table, .special-table, .fv-table, .v2-market-table, .chain-table) thead th {
  position: sticky;
  top: 0;
  z-index: var(--fv-z-sticky);
  background: var(--fv-surface-2);
  color: var(--fv-muted);
  font-size: var(--fv-text-xs);
  font-weight: var(--fv-weight-semibold);
  border-bottom: 1px solid var(--fv-line);
  white-space: nowrap;
}
:is(.data-table, .special-table, .fv-table, .v2-market-table) thead th:is(.asc, .desc, [aria-sort]:not([aria-sort="none"])) {
  color: var(--fv-accent);
  box-shadow: inset 0 -2px 0 0 var(--fv-accent);
}

/* Every figure LTR-isolated. This is what stops a negative number rendering
   as "4.55−" on an RTL page, and it applies to any cell marked numeric. */
:is(.data-table, .special-table, .fv-table, .v2-market-table) :is(td, th):is(.num, .numeric),
.fv-num, .special-bar-value, .kpi-value strong, .special-kpi .value {
  direction: ltr;
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
}

/* Zebra is opt-in per board, off by default: with a hover this clear, stripes
   are a second signal for the same thing. */
html[data-zebra="on"] :is(.data-table, .special-table, .fv-table) tbody tr:nth-child(even) > td {
  background: color-mix(in srgb, var(--fv-surface-2) 55%, var(--fv-surface));
}

/* ==========================================================================
   4. KPI CARDS
   ==========================================================================
   Two internal structures existed for one card — `.kpi-card > .kpi-icon +
   div > span + .kpi-value` on the hub home, and `.kpi-card > .kpi-icon + div >
   span + strong + small` on the market boards. Both are supported here, and
   both now produce cards of equal height: the note is pushed to the bottom and
   clamped to two lines, so a card with a three-line hint no longer stretches
   its whole row.
   ========================================================================== */
:is(.kpi-grid, .module-kpi-grid, .v2-kpi-grid, .special-kpis, .fv-kpi-grid, .market-overview-kpis) {
  display: grid;
  /* A definite inline size is load-bearing: without it this grid is sized
     against an indefinite width, auto-fit lays one 190px track per card
     instead of dropping columns, and the row overflows the page (measured
     1220px inside a 990px column at 1280px viewport). min() keeps a single
     card from forcing that same overflow on narrow screens. */
  width: 100%;
  max-width: 100%;
  min-width: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
  gap: var(--fv-space-4);
  align-items: stretch;
}
/* Cards must be allowed to shrink inside their track; a grid item defaults to
   min-width:auto, which is min-content and can push the track wider. */
:is(.kpi-grid, .module-kpi-grid, .v2-kpi-grid, .special-kpis, .fv-kpi-grid, .market-overview-kpis) > * {
  min-width: 0;
}
.kpi-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--fv-space-4);
  padding: var(--fv-space-5);
  min-width: 0;
  background: var(--fv-surface);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-lg);
  box-shadow: var(--fv-shadow-sm);
}
.kpi-card > div:last-child {
  display: flex;
  flex-direction: column;
  gap: var(--fv-space-1);
  min-width: 0;
  height: 100%;
}
.kpi-icon {
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  flex: 0 0 auto;
  border-radius: var(--fv-radius-md);
  background: var(--fv-accent-soft);
  color: var(--fv-accent);
  font-size: var(--fv-text-base);
  font-weight: var(--fv-weight-semibold);
  line-height: 1;
}
.kpi-card > div > span {
  font-size: var(--fv-text-sm);
  font-weight: var(--fv-weight-medium);
  color: var(--fv-muted);
  line-height: var(--fv-leading-snug);
  text-wrap: pretty;
}
.kpi-card :is(.kpi-value, > div > strong) {
  display: flex;
  align-items: baseline;
  gap: var(--fv-space-2);
  color: var(--fv-text);
  font-size: var(--fv-text-2xl);
  font-weight: var(--fv-weight-bold);
  line-height: var(--fv-leading-tight);
  letter-spacing: -0.01em;
  direction: ltr;
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
}
.kpi-card .kpi-value strong { font: inherit; }
.kpi-card :is(.kpi-value small, > div > small) {
  margin-block-start: auto;
  color: var(--fv-faint);
  font-size: var(--fv-text-sm);
  font-weight: var(--fv-weight-normal);
  line-height: var(--fv-leading-snug);
  text-wrap: pretty;
  /* Two lines, always the same two lines' worth of space, so a row of six
     cards has one baseline for its notes. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.kpi-card .kpi-value small { margin-block-start: 0; }
.kpi-card.primary { border-color: var(--fv-accent-line); }
.kpi-card :is(.up, .positive) { color: var(--fv-up); }
.kpi-card :is(.down, .negative) { color: var(--fv-down); }

/* The market-overview strip uses the same card without an icon. */
.market-kpi, .market-decision-card {
  display: flex;
  flex-direction: column;
  gap: var(--fv-space-1);
  padding: var(--fv-space-5);
  min-width: 0;
  background: var(--fv-surface);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-lg);
  box-shadow: var(--fv-shadow-sm);
}
:is(.market-kpi, .market-decision-card) > span {
  font-size: var(--fv-text-sm); font-weight: var(--fv-weight-medium); color: var(--fv-muted);
}
:is(.market-kpi, .market-decision-card) > strong {
  font-size: var(--fv-text-2xl); font-weight: var(--fv-weight-bold);
  line-height: var(--fv-leading-tight); letter-spacing: -0.01em;
  direction: ltr; unicode-bidi: isolate; font-variant-numeric: tabular-nums;
}
:is(.market-kpi, .market-decision-card) > small {
  margin-block-start: auto; color: var(--fv-faint); font-size: var(--fv-text-sm);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ==========================================================================
   5. CONTROLS — one height, one radius, one focus ring
   ==========================================================================
   Before: 28/32/34/36/38/40px controls appeared in the same filter row
   depending on which file styled them. Everything now resolves to the density
   control height, which is what makes a toolbar read as a single object.
   ========================================================================== */
:is(.primary-button, .mini-button, .icon-button, .text-button, .filter-toggle,
    .column-trigger, .special-tab, .segment-button, .fv-button, .small-select,
    .inline-search, select, input:not([type="checkbox"]):not([type="radio"]):not([type="range"])) {
  font-family: inherit;
}
:is(.primary-button, .secondary-button, .mini-button, .icon-button, .column-trigger, .filter-toggle) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--fv-space-2);
  height: var(--fv-density-control);
  min-height: var(--fv-density-control);
  padding-inline: var(--fv-space-4);
  border-radius: var(--fv-radius-md);
  font-size: var(--fv-text-base);
  font-weight: var(--fv-weight-medium);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--fv-duration-fast) var(--fv-ease),
              border-color var(--fv-duration-fast) var(--fv-ease),
              color var(--fv-duration-fast) var(--fv-ease);
}
.icon-button {
  width: var(--fv-density-control);
  padding-inline: 0;
  border: 1px solid var(--fv-line);
  background: var(--fv-surface);
  color: var(--fv-text-2);
}
.icon-button:hover { background: var(--fv-surface-2); border-color: var(--fv-line-strong); color: var(--fv-text); }
.icon-button .ui-icon, .icon-button svg {
  width: 18px; height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.primary-button {
  border: 1px solid var(--fv-accent);
  background: var(--fv-accent);
  color: var(--fv-on-accent);
  font-weight: var(--fv-weight-semibold);
}
.primary-button:hover { background: var(--fv-accent-hover); border-color: var(--fv-accent-hover); }
.primary-button:disabled, .mini-button:disabled { opacity: 0.45; cursor: not-allowed; }
.mini-button {
  border: 1px solid var(--fv-line);
  background: var(--fv-surface);
  color: var(--fv-text-2);
}
.mini-button:hover { background: var(--fv-surface-2); border-color: var(--fv-line-strong); }
.mini-button.danger { color: var(--fv-down); border-color: color-mix(in srgb, var(--fv-down) 32%, var(--fv-line)); }
.mini-button.danger:hover { background: var(--fv-down-soft); }
.mini-button[aria-pressed="true"], .icon-button[aria-pressed="true"] {
  border-color: var(--fv-accent);
  background: var(--fv-accent-soft);
  color: var(--fv-accent);
}

:is(select, .small-select, .inline-search,
    input[type="text"], input[type="search"], input[type="number"],
    input[type="email"], input[type="tel"], input[type="password"]) {
  height: var(--fv-density-control);
  padding-inline: var(--fv-space-4);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-md);
  background: var(--fv-surface);
  color: var(--fv-text);
  font-size: var(--fv-text-base);
}
:is(select, input):hover:not(:disabled) { border-color: var(--fv-line-strong); }
:is(select, input):focus-visible {
  outline: 0;
  border-color: var(--fv-accent);
  box-shadow: var(--fv-ring);
}
input::placeholder { color: var(--fv-faint); }

/* A search field's own placeholder names what it searches; a label above it
   repeating "جست‌وجوی صندوق" is the same statement twice, and it pushed the
   input out of the header's baseline. The label stays in the accessibility
   tree via aria-label. */
.special-table-tools .special-field > span,
.field-search-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* Checkboxes and radios use the accent, at a real hit size. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--fv-accent); width: 16px; height: 16px; }
.check-label, .column-option > label { min-height: 24px; }

/* ==========================================================================
   6. PANELS & SPACING
   ==========================================================================
   One panel object. Padding, radius and header treatment come from the token
   scale rather than from whichever of five files loaded last.
   ========================================================================== */
:is(.panel, .fv-panel, .special-card, .filter-panel) {
  background: var(--fv-surface);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-lg);
  box-shadow: var(--fv-shadow-sm);
  min-width: 0;
}
:is(.panel, .fv-panel) > :is(.panel-header, .fv-panel__head) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--fv-space-4);
  flex-wrap: wrap;
  padding: var(--fv-space-4) var(--fv-space-5);
  border-bottom: 1px solid var(--fv-line);
  background: var(--fv-surface-2);
}
.panel-header > div { min-width: 0; }
.panel-header h2 {
  margin: 0;
  font-size: var(--fv-text-md);
  font-weight: var(--fv-weight-semibold);
  line-height: var(--fv-leading-tight);
  color: var(--fv-text);
}
.panel-header p {
  margin: var(--fv-space-1) 0 0;
  font-size: var(--fv-text-sm);
  line-height: var(--fv-leading-snug);
  color: var(--fv-muted);
  text-wrap: pretty;
}
.panel-actions, .special-insight-actions, .history-controls, .filter-head-actions {
  display: flex;
  align-items: center;
  gap: var(--fv-space-2);
  flex-wrap: wrap;
  margin-inline-start: auto;
}
.panel-footer, .page-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--fv-space-4);
  flex-wrap: wrap;
  padding: var(--fv-space-4) var(--fv-space-5);
  border-top: 1px solid var(--fv-line);
  color: var(--fv-faint);
  font-size: var(--fv-text-sm);
}
.page-footer { border-top: 0; padding-inline: 0; }

/* Section rhythm: one gap between stacked sections everywhere. */
:is(.section-stack, .v2-main, .main-content > .section-stack) { display: flex; flex-direction: column; gap: var(--fv-space-6); }
:is(.upper-grid, .home-analysis-grid, .home-visual-grid, .personal-home-grid,
    .v2-insight-grid, .market-overview-lower, .home-section) { gap: var(--fv-space-5); }
.main-content { padding: var(--fv-space-6) var(--fv-space-7) var(--fv-space-9); min-width: 0; }
@media (max-width: 720px) { .main-content { padding: var(--fv-space-4) var(--fv-space-4) var(--fv-space-11); } }

/* ==========================================================================
   7. SEGMENTED / TABS
   ==========================================================================
   The inactive label overflowed its pill because the option had a fixed height
   and a padding that assumed a two-word Persian label. Options size to their
   content, clip nothing, and the group scrolls rather than wrapping mid-pill.
   ========================================================================== */
:is(.segmented, .special-tabs, .watchlist-mode-group, .market-radar-filters, .history-metric-switch) {
  display: inline-flex;
  align-items: center;
  gap: var(--fv-space-1);
  max-width: 100%;
  padding: var(--fv-space-1);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-md);
  background: var(--fv-surface-2);
  overflow-x: auto;
  scrollbar-width: none;
}
:is(.segmented, .special-tabs, .watchlist-mode-group, .market-radar-filters, .history-metric-switch)::-webkit-scrollbar { display: none; }
:is(.segmented, .watchlist-mode-group, .market-radar-filters, .history-metric-switch) > button,
.segment-button {
  display: inline-flex;
  align-items: center;
  gap: var(--fv-space-2);
  height: calc(var(--fv-density-control) - var(--fv-space-3));
  padding-inline: var(--fv-space-4);
  border: 0;
  border-radius: var(--fv-radius-sm);
  background: transparent;
  color: var(--fv-muted);
  font: inherit;
  font-size: var(--fv-text-base);
  font-weight: var(--fv-weight-medium);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--fv-duration-fast) var(--fv-ease), color var(--fv-duration-fast) var(--fv-ease);
}
:is(.segmented, .watchlist-mode-group, .market-radar-filters, .history-metric-switch) > button:hover,
.segment-button:hover { color: var(--fv-text); background: var(--fv-surface-3); }
:is(.segmented, .watchlist-mode-group, .market-radar-filters, .history-metric-switch) > button.active,
:is(.segmented, .watchlist-mode-group, .market-radar-filters, .history-metric-switch) > button[aria-pressed="true"],
.segment-button.active {
  background: var(--fv-surface);
  color: var(--fv-text);
  font-weight: var(--fv-weight-semibold);
  box-shadow: var(--fv-shadow-sm);
}

/* ==========================================================================
   8. CARD GRIDS — no orphaned last card
   ==========================================================================
   The strategy template picker put 16 cards into a fixed 5-column grid, so the
   16th sat alone on its own row. auto-fit with a real minimum lets the browser
   pick a column count that divides the set, and the cards keep a usable width
   at every breakpoint.
   ========================================================================== */
:is(.strategy-template-grid, .strategy-templates, .template-grid,
    .section-grid, .market-radar-grid, .watchlist-preview, .workspace-quick-grid,
    .special-chart-grid) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: var(--fv-space-4);
}
:is(.strategy-template-grid, .strategy-templates, .template-grid) > * {
  display: flex;
  flex-direction: column;
  gap: var(--fv-space-1);
  align-items: flex-start;
  padding: var(--fv-space-4) var(--fv-space-5);
  min-height: 72px;
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-md);
  background: var(--fv-surface);
  cursor: pointer;
  transition: border-color var(--fv-duration-fast) var(--fv-ease),
              background var(--fv-duration-fast) var(--fv-ease);
}
:is(.strategy-template-grid, .strategy-templates, .template-grid) > *:hover {
  border-color: var(--fv-accent-line);
  background: var(--fv-surface-2);
}
:is(.strategy-template-grid, .strategy-templates, .template-grid) > *[aria-pressed="true"],
:is(.strategy-template-grid, .strategy-templates, .template-grid) > *.active {
  border-color: var(--fv-accent);
  background: var(--fv-accent-soft);
}

/* ==========================================================================
   9. CHROME — sidebar, topbar, icons, brand
   ========================================================================== */
.sidebar {
  background: var(--fv-chrome);
  border-inline-end: 1px solid var(--fv-chrome-line);
  padding: var(--fv-space-5) var(--fv-space-3);
  gap: var(--fv-space-5);
}
.side-nav { display: flex; flex-direction: column; gap: var(--fv-space-1); }
/* A group heading is the control for its own section now: sixteen boards is
   a lot to carry on every page, and most people work in two or three areas.
   Collapsing is remembered per browser. */
.nav-group { display: flex; flex-direction: column; }
.nav-group-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--fv-space-2);
  width: 100%;
  margin: var(--fv-space-4) 0 var(--fv-space-1);
  padding: var(--fv-space-2) var(--fv-space-3);
  border: 0;
  background: transparent;
  color: var(--fv-chrome-muted);
  font: inherit;
  cursor: pointer;
}
.nav-group-toggle:hover { color: #fff; }
.side-nav .nav-group-label {
  font-size: var(--fv-text-2xs);
  font-weight: var(--fv-weight-semibold);
  letter-spacing: var(--fv-tracking-caps);
  text-transform: uppercase;
}
.nav-chevron {
  width: 14px; height: 14px;
  flex: 0 0 auto;
  transition: transform var(--fv-duration-fast) var(--fv-ease);
}
.nav-group.is-closed .nav-chevron { transform: rotate(-90deg); }
.nav-group-items { display: flex; flex-direction: column; gap: 2px; }
.nav-group-items[hidden] { display: none; }

/* The tile, not the text, is what the eye lands on -- it is what makes a
   long list scannable and it keeps its meaning when the rail is collapsed. */
.nav-tile {
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  flex: 0 0 30px;
  border-radius: var(--fv-radius-md);
  background: var(--fv-chrome-2);
  color: var(--fv-chrome-text);
  transition: background var(--fv-duration-fast) var(--fv-ease),
              color var(--fv-duration-fast) var(--fv-ease);
}
.nav-tile svg {
  width: 17px; height: 17px;
  fill: none; stroke: currentColor;
  stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
}
.nav-item:hover .nav-tile { background: var(--fv-chrome-3, var(--fv-chrome-2)); color: #fff; }
.nav-item.active .nav-tile,
.nav-item[aria-current="page"] .nav-tile {
  background: color-mix(in srgb, var(--fv-accent-bright) 22%, transparent);
  color: var(--fv-accent-bright);
}
.nav-item {
  display: flex;
  align-items: center;
  gap: var(--fv-space-3);
  min-height: var(--fv-control-md);
  padding: 0 var(--fv-space-3);
  border-radius: var(--fv-radius-md);
  color: var(--fv-chrome-text);
  font-size: var(--fv-text-base);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--fv-duration-fast) var(--fv-ease), color var(--fv-duration-fast) var(--fv-ease);
}
.nav-item:hover { background: var(--fv-chrome-2); color: #fff; }
.nav-item.active, .nav-item[aria-current="page"] {
  background: var(--fv-chrome-2);
  color: #fff;
  font-weight: var(--fv-weight-semibold);
  box-shadow: inset -2px 0 0 0 var(--fv-accent-bright);
}
.nav-icon {
  display: grid; place-items: center;
  width: 18px; height: 18px; flex: 0 0 auto;
  opacity: 0.7;
}
.nav-item:hover .nav-icon, .nav-item.active .nav-icon { opacity: 1; }
.nav-icon svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }

/* Icon-only sidebar (app.css collapses labels between 761px and 1100px, and
   whenever the user collapses it). A group heading with no labels under it is
   just vertical noise, so the heading becomes a divider rule instead. */
@media (max-width: 1100px) and (min-width: 761px) {
  .side-nav .nav-group-label { height: 1px; margin: var(--fv-space-3) var(--fv-space-3); padding: 0; overflow: hidden; text-indent: -999px; background: var(--fv-chrome-line); }
  .side-nav .nav-group-label:first-child { display: none; }
}
/* Collapsed, the rail keeps a short label under each tile rather than going
   icon-only: an unlabelled rail makes you hover every item to find anything,
   and the labels here are one or two words. */
html.sidebar-collapsed .nav-group-toggle { display: none; }
html.sidebar-collapsed .nav-group + .nav-group {
  border-top: 1px solid var(--fv-chrome-line);
  margin-top: var(--fv-space-3);
  padding-top: var(--fv-space-3);
}
html.sidebar-collapsed .nav-group-items[hidden] { display: flex; }
html.sidebar-collapsed .nav-item {
  flex-direction: column;
  gap: 3px;
  min-height: 0;
  padding: var(--fv-space-2) 0;
  text-align: center;
}
html.sidebar-collapsed .nav-item .nav-label {
  font-size: 9px;
  line-height: 1.3;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
html.sidebar-collapsed .nav-item-anchor { display: none; }
@media (max-width: 760px) {
  /* Bottom bar: groups do not apply to a single scrolling row. */
  .side-nav .nav-group-label, .side-nav .nav-item-anchor { display: none; }
}

.topbar {
  display: flex;
  align-items: center;
  gap: var(--fv-space-5);
  flex-wrap: wrap;
  min-height: var(--fv-topbar);
  margin-bottom: var(--fv-space-6);
  padding-bottom: var(--fv-space-5);
  border-bottom: 1px solid var(--fv-line);
}
.topbar h1 {
  margin: 0;
  font-size: var(--fv-text-xl);
  font-weight: var(--fv-weight-semibold);
  line-height: var(--fv-leading-tight);
  letter-spacing: -0.015em;
}
.topbar p {
  margin: var(--fv-space-1) 0 0;
  max-width: 76ch;
  font-size: var(--fv-text-sm);
  color: var(--fv-muted);
  text-wrap: pretty;
}
.title-wrap { display: flex; align-items: center; gap: var(--fv-space-4); min-width: 0; flex: 1 1 340px; }
.topbar-actions {
  display: flex;
  align-items: center;
  gap: var(--fv-space-2);
  flex-wrap: wrap;
  margin-inline-start: auto;
}
.clock-box {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
  padding-inline: var(--fv-space-3);
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}
.clock-box strong { font-size: var(--fv-text-sm); font-weight: var(--fv-weight-semibold); }
.clock-box span { font-size: var(--fv-text-xs); color: var(--fv-muted); }

/* The connection badge and the freshness badge said the same thing in two
   visual languages. One badge object for both. */
:is(.connection-badge, .fv-badge, .market-session-chip) {
  display: inline-flex; align-items: center; gap: var(--fv-space-2);
  height: 24px; padding-inline: var(--fv-space-3);
  border: 1px solid var(--fv-line); border-radius: var(--fv-radius-full);
  background: var(--fv-surface-2); color: var(--fv-muted);
  font-size: var(--fv-text-sm); font-weight: var(--fv-weight-medium); white-space: nowrap;
}
:is(.connection-badge, .market-session-chip) > i {
  width: 6px; height: 6px; border-radius: var(--fv-radius-full);
  background: currentColor; flex: 0 0 auto;
}
.connection-badge.connecting { color: var(--fv-warn); background: var(--fv-warn-soft); border-color: color-mix(in srgb, var(--fv-warn) 26%, var(--fv-line)); }
.connection-badge.live, .connection-badge.connected { color: var(--fv-up); background: var(--fv-up-soft); border-color: color-mix(in srgb, var(--fv-up) 26%, var(--fv-line)); }
.connection-badge.offline, .connection-badge.error { color: var(--fv-down); background: var(--fv-down-soft); border-color: color-mix(in srgb, var(--fv-down) 26%, var(--fv-line)); }

/* Any icon anywhere: one stroke weight, one size, currentColor. Glyph icons
   (⌂ ★ ▤ ↻) are replaced with real SVGs by pro.js; this keeps whichever
   survive from rendering at a random font size. */
.ui-icon, .theme-icon, .account-chevron { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.fv-brand__mark { width: 28px; height: 28px; }

/* --------------------------------------------------------- admin rail ------ */
/* Sticky index for the admin view's nine panels. */
.admin-rail {
  position: sticky;
  top: 0;
  z-index: var(--fv-z-sticky);
  display: flex;
  gap: var(--fv-space-1);
  overflow-x: auto;
  scrollbar-width: none;
  margin: calc(-1 * var(--fv-space-2)) 0 var(--fv-space-1);
  padding: var(--fv-space-2);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-md);
  background: color-mix(in srgb, var(--fv-surface) 88%, transparent);
  backdrop-filter: blur(6px);
}
.admin-rail::-webkit-scrollbar { display: none; }
.admin-rail a {
  display: inline-flex;
  align-items: center;
  height: calc(var(--fv-control-md) - var(--fv-space-3));
  padding-inline: var(--fv-space-4);
  border-radius: var(--fv-radius-sm);
  color: var(--fv-muted);
  font-size: var(--fv-text-sm);
  font-weight: var(--fv-weight-medium);
  text-decoration: none;
  white-space: nowrap;
}
.admin-rail a:hover { background: var(--fv-surface-2); color: var(--fv-text); }
.admin-rail a:target, .admin-rail a.active { background: var(--fv-accent-soft); color: var(--fv-accent); }
.admin-workspace-panel { scroll-margin-top: var(--fv-space-11); }
.admin-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--fv-space-4);
  padding: var(--fv-space-5);
}
.admin-form-grid .field { display: flex; flex-direction: column; gap: var(--fv-space-2); min-width: 0; }
.admin-form-grid .field > span { font-size: var(--fv-text-sm); font-weight: var(--fv-weight-medium); color: var(--fv-muted); }
.admin-form-grid .input-with-unit { position: relative; display: flex; align-items: center; }
.admin-form-grid .input-with-unit input { width: 100%; padding-inline-end: var(--fv-space-11); }
.admin-form-grid .input-with-unit small {
  position: absolute; inset-inline-end: var(--fv-space-3);
  color: var(--fv-faint); font-size: var(--fv-text-xs); pointer-events: none;
}

/* ==========================================================================
   10. COMMAND PALETTE (⌘K) — injected by pro.js
   ========================================================================== */
.fvp-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--fv-z-modal);
  display: grid;
  place-items: start center;
  padding-top: 12vh;
  background: var(--fv-overlay);
  backdrop-filter: blur(2px);
}
.fvp-scrim[hidden] { display: none; }
.fvp {
  width: min(620px, calc(100vw - 32px));
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-lg);
  background: var(--fv-surface);
  box-shadow: var(--fv-shadow-lg);
}
.fvp__field {
  display: flex; align-items: center; gap: var(--fv-space-3);
  padding: var(--fv-space-4) var(--fv-space-5);
  border-bottom: 1px solid var(--fv-line);
}
.fvp__field svg { width: 18px; height: 18px; flex: 0 0 auto; fill: none; stroke: var(--fv-faint); stroke-width: 1.75; }
.fvp__input {
  flex: 1 1 auto; min-width: 0; height: auto;
  border: 0; background: none; padding: 0;
  color: var(--fv-text); font: inherit; font-size: var(--fv-text-lg);
}
.fvp__input:focus-visible { outline: 0; box-shadow: none; }
.fvp__hint {
  font-size: var(--fv-text-xs); color: var(--fv-faint);
  border: 1px solid var(--fv-line); border-radius: var(--fv-radius-sm);
  padding: 1px var(--fv-space-2); white-space: nowrap;
}
.fvp__list { overflow-y: auto; padding: var(--fv-space-2); }
.fvp__group {
  padding: var(--fv-space-3) var(--fv-space-3) var(--fv-space-1);
  font-size: var(--fv-text-2xs); font-weight: var(--fv-weight-semibold);
  letter-spacing: var(--fv-tracking-caps); text-transform: uppercase;
  color: var(--fv-faint);
}
.fvp__item {
  display: flex; align-items: center; gap: var(--fv-space-3);
  width: 100%;
  padding: var(--fv-space-3);
  border: 0; border-radius: var(--fv-radius-md);
  background: none; color: var(--fv-text);
  font: inherit; font-size: var(--fv-text-base);
  text-align: start; text-decoration: none; cursor: pointer;
}
.fvp__item:hover, .fvp__item[aria-selected="true"] { background: var(--fv-surface-2); }
.fvp__item[aria-selected="true"] { box-shadow: inset -2px 0 0 0 var(--fv-accent); }
.fvp__item b { font-weight: var(--fv-weight-semibold); }
.fvp__item small { margin-inline-start: auto; color: var(--fv-faint); font-size: var(--fv-text-sm); }
.fvp__icon {
  display: grid; place-items: center;
  width: 24px; height: 24px; flex: 0 0 auto;
  border-radius: var(--fv-radius-sm);
  background: var(--fv-surface-3); color: var(--fv-muted);
}
.fvp__icon svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.75; }
.fvp__empty { padding: var(--fv-space-8); text-align: center; color: var(--fv-muted); font-size: var(--fv-text-base); }
.fvp__foot {
  display: flex; gap: var(--fv-space-4); flex-wrap: wrap;
  padding: var(--fv-space-3) var(--fv-space-5);
  border-top: 1px solid var(--fv-line);
  background: var(--fv-surface-2);
  color: var(--fv-faint); font-size: var(--fv-text-xs);
}
.fvp__foot kbd {
  font: inherit; font-family: var(--fv-font);
  border: 1px solid var(--fv-line); border-radius: var(--fv-radius-sm);
  padding: 0 var(--fv-space-2); background: var(--fv-surface); color: var(--fv-muted);
}

/* Keyboard row cursor, driven by pro.js j/k navigation. */
tr.fvp-cursor > td { box-shadow: inset 0 0 0 1px var(--fv-accent-line); }
tr.fvp-cursor > td:first-child { box-shadow: inset 0 0 0 1px var(--fv-accent-line), inset -2px 0 0 0 var(--fv-accent); }

/* Density switch in the topbar. */
/* Sits directly under .visual-manager-head now (نمایش بخش‌ها), styled after
   column management's .column-presets: a bordered-bottom pill row between
   the panel head and the list it sits above. When it falls back to the
   topbar (a page with no section manager) the border/margin read as noise
   next to unrelated buttons, so they only apply inside the menu. */
.fvp-density {
  display: inline-flex;
  gap: 6px;
  flex-wrap: wrap;
}
.visual-manager-menu .fvp-density {
  width: 100%;
  margin: 10px 0 8px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.visual-manager-menu .fvp-density [data-density-option] {
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--muted);
  font-size: 11.5px;
}
.visual-manager-menu .fvp-density [data-density-option]:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.visual-manager-menu .fvp-density [data-density-option].active {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--panel-2));
  color: var(--accent);
  font-weight: 700;
}

/* ==========================================================================
   11. STATES
   ==========================================================================
   "در حال بارگذاری…" as plain grey text is indistinguishable from an empty
   result, which is the most common support question on a data board. Loading
   now shimmers, empty states carry a title and a reason, and an error is red.
   ========================================================================== */
.empty-state, .empty-cell, .loading-cell {
  padding: var(--fv-space-8) var(--fv-space-5);
  color: var(--fv-muted);
  font-size: var(--fv-text-base);
  text-align: center;
}
.loading-cell, .history-status, .market-radar-meta, .module-status-banner span {
  position: relative;
}
:is(.loading-cell, .empty-state):not(:empty)::after { content: none; }
/* One shimmering placeholder bar for any container that says it is loading. */
.fvp-skeleton {
  display: block;
  height: 12px;
  border-radius: var(--fv-radius-sm);
  background: linear-gradient(90deg, var(--fv-surface-2) 25%, var(--fv-surface-3) 37%, var(--fv-surface-2) 63%);
  background-size: 400% 100%;
  animation: fvp-shimmer 1.4s var(--fv-ease) infinite;
}
@keyframes fvp-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

.module-status-banner {
  display: flex; align-items: center; gap: var(--fv-space-3); flex-wrap: wrap;
  padding: var(--fv-space-3) var(--fv-space-5);
  border: 1px solid var(--fv-line); border-radius: var(--fv-radius-md);
  background: var(--fv-surface-2); color: var(--fv-muted); font-size: var(--fv-text-sm);
}
.module-status-banner strong { color: var(--fv-text); font-weight: var(--fv-weight-semibold); }
.module-status-banner.is-error { border-color: color-mix(in srgb, var(--fv-down) 30%, var(--fv-line)); background: var(--fv-down-soft); color: var(--fv-down); }
.module-status-banner.is-stale { border-color: color-mix(in srgb, var(--fv-warn) 30%, var(--fv-line)); background: var(--fv-warn-soft); color: var(--fv-warn); }

.toast {
  position: fixed;
  inset-inline: auto var(--fv-space-6);
  bottom: var(--fv-space-6);
  z-index: var(--fv-z-toast);
  max-width: min(420px, calc(100vw - 32px));
  padding: var(--fv-space-4) var(--fv-space-5);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-md);
  background: var(--fv-surface);
  color: var(--fv-text);
  font-size: var(--fv-text-base);
  box-shadow: var(--fv-shadow-lg);
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity var(--fv-duration) var(--fv-ease), transform var(--fv-duration) var(--fv-ease);
}
.toast.show, .toast.visible { opacity: 1; transform: none; }

/* ==========================================================================
   12. ACCESSIBILITY
   ========================================================================== */
.fvp-skip {
  position: fixed;
  inset-inline-start: var(--fv-space-4);
  top: calc(-1 * var(--fv-space-11));
  z-index: var(--fv-z-toast);
  padding: var(--fv-space-3) var(--fv-space-5);
  border-radius: var(--fv-radius-md);
  background: var(--fv-accent);
  color: var(--fv-on-accent);
  font-weight: var(--fv-weight-semibold);
  text-decoration: none;
  transition: top var(--fv-duration) var(--fv-ease);
}
.fvp-skip:focus-visible { top: var(--fv-space-4); color: var(--fv-on-accent); }

.visually-hidden, .sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Every board's primary action reads on its own background in both themes.
   .special-tab.active is deliberately NOT here: specialized.css gives it a
   surface background (amber is a series colour now, not the accent), so
   --fv-on-accent would paint dark text on a dark panel -- 1.09:1. Its own
   rule sets var(--fv-text), which is right against a surface. */
:is(.primary-button, .fv-button--primary, .pagination button.active,
    .ticker-pill, .badge-count) { color: var(--fv-on-accent); }
:is(.primary-button, .fv-button--primary) svg { stroke: currentColor; }

@media print {
  .sidebar, .topbar-actions, .mobile-bottom-nav, .hub-mobile-nav,
  .market-ticker, .fvp-scrim, .toast, .fvp-skip { display: none !important; }
  .app-shell { display: block !important; }
  :is(.panel, .special-card, .kpi-card) { break-inside: avoid; box-shadow: none; }
}

/* app.css:675 hides `.nav-item > span:not(.nav-icon)` with !important when the
   sidebar is collapsed -- written when the icon carried the class .nav-icon.
   The icon is now .nav-tile, so that rule matches the tile AND the label and
   would empty the rail completely. Re-assert both: the rail shows a tile with
   a short label under it. !important is required only to beat that !important. */
/*  is load-bearing here: app.css's selector is
    = (0,4,2), and a class-only selector is
   (0,4,1), so it lost on specificity even though this file loads later and
   also uses !important. Matching the element selector levels it, and source
   order then decides. */
html.sidebar-collapsed .sidebar .nav-item > span.nav-label {
  display: block !important;
}
html.sidebar-collapsed .sidebar .nav-item > span.nav-tile {
  display: grid !important;
}
html.sidebar-collapsed .sidebar .nav-item { justify-content: center; }

/* Collapse works at every width the button is visible at.
   app.css pins `html.sidebar-collapsed { --sidebar: 232px }` under 1100px and
   hides the toggle there -- but this file's .icon-button rule un-hides it, so
   the control was visible and inert: it set the class and nothing moved.
   Since the rail is genuinely useful at 1100px and below, honour the collapse
   instead of hiding the button. Above 760px only: below that the sidebar is a
   bottom bar and has no collapsed form. */
@media (min-width: 761px) and (max-width: 1100px) {
  html.sidebar-collapsed { --sidebar: 76px; }
}

/* ---- collapsed rail: brand mark only ---- */
/* app.css hides `.brand-mark + .brand-copy`, a class this markup does not
   use -- the brand here is .fv-brand__text (name + tagline), so the wordmark
   stayed at full width in a 76px rail. */
html.sidebar-collapsed .sidebar .fv-brand__text { display: none !important; }
html.sidebar-collapsed .sidebar .fv-brand,
html.sidebar-collapsed .sidebar .brand-mark { justify-content: center; }

/* ---- pinned boards + hotkey hints ---- */
/* The row wraps the link so a pin control can sit beside it without becoming
   part of the link's hit area. */
.nav-row { position: relative; display: flex; align-items: center; }
.nav-row > .nav-item { flex: 1 1 auto; min-width: 0; }

.nav-pin {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  margin-inline-end: 2px;
  border: 0;
  border-radius: var(--fv-radius-sm);
  background: transparent;
  color: var(--fv-chrome-muted);
  cursor: pointer;
  /* Hidden until the row is touched: a pin on every row is visual noise for
     a control most people set once. */
  opacity: 0;
  transition: opacity var(--fv-duration-fast) var(--fv-ease), color var(--fv-duration-fast) var(--fv-ease);
}
.nav-pin svg { width: 14px; height: 14px; fill: none; stroke: currentColor; }
.nav-row:hover .nav-pin,
.nav-pin:focus-visible { opacity: 1; }
.nav-pin:hover { color: #fff; }
.nav-row.is-pinned .nav-pin {
  opacity: 1;
  color: var(--fv-accent-bright);
}

/* The shortcut already exists (g then the letter); showing it is what makes
   it learnable. Muted, so it never competes with the board name. */
.nav-hot {
  margin-inline-start: auto;
  padding: 1px 5px;
  border: 1px solid var(--fv-chrome-line);
  border-radius: var(--fv-radius-sm);
  background: transparent;
  color: var(--fv-chrome-muted);
  font-family: inherit;
  font-size: 9px;
  line-height: 1.6;
  opacity: 0;
  transition: opacity var(--fv-duration-fast) var(--fv-ease);
}
.nav-item:hover .nav-hot,
.nav-item.active .nav-hot { opacity: 1; }

/* Neither belongs in a 76px rail. */
html.sidebar-collapsed .nav-pin,
html.sidebar-collapsed .nav-hot { display: none; }

/* ---- sidebar scrolls when the board list outgrows the window ---- */
/* Measured at a 700px-tall window: the nav is 842px, so the last boards sat
   below the fold with overflow:visible and no way to reach them. Only the
   nav scrolls -- the brand stays put, so the rail keeps an anchor and the
   scroll region is the part that actually has overflow.
   `min-height: 0` is load-bearing: a flex child defaults to min-height:auto,
   which refuses to shrink below its content and would leave the overflow
   unreachable even with overflow-y set. */
/* NOT overflow:hidden -- the collapse toggle is deliberately positioned
   , i.e. hanging outside the sidebar, and clipping
   the box swallowed it. Only the nav needs to clip, and it does that itself
   below. */
.sidebar { overflow: visible; }
.side-nav {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--fv-chrome-line) transparent;
}
.side-nav::-webkit-scrollbar { width: 6px; }
.side-nav::-webkit-scrollbar-track { background: transparent; }
.side-nav::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: transparent;
}
/* The bar appears once there is something to scroll and the pointer is in
   the rail, so a full-height sidebar shows no chrome at all. */
.sidebar:hover .side-nav::-webkit-scrollbar-thumb,
.side-nav:focus-within::-webkit-scrollbar-thumb {
  background: var(--fv-chrome-line);
}

/* The toggle sits with the brand at the top of the rail rather than 78px
   down, where it floated against the first nav row. Matching hub.css's
   !important is required only to beat its !important. */
.sidebar-collapse-toggle {
  top: 20px !important;
}

/* ── Insight grid sizes to the panels it actually has ─────────────────────
   hub.css lays this out as three fixed columns (1.2fr .8fr 1fr), which is
   right for a board showing composition + breadth + special. A board that
   shows only two -- IME, which has no meaningful positive/negative split --
   left the third column empty and pushed both panels to one side. The count
   is published by applyPanelVisibility() in market.js.

   Declared here because unify.css loads last: the base rules live inside
   max-width media queries and would otherwise win on source order. */
.v2-insight-grid[data-panels='2'] { grid-template-columns: 1fr 1fr; }
.v2-insight-grid[data-panels='1'] { grid-template-columns: 1fr; }
.v2-insight-grid[data-panels='2'] > .panel:first-child,
.v2-insight-grid[data-panels='1'] > .panel:first-child { grid-column: auto; }

/* pro.css spans the special panel across every column, which is right when it
   sits under a composition + breadth pair and wrong when it IS one of the two:
   the span dropped it onto a row of its own. */
.v2-insight-grid[data-panels='2'] > #specialInsightPanel,
.v2-insight-grid[data-panels='1'] > #specialInsightPanel { grid-column: auto; }

/* .main-content is a flex column whose children carry margin-inline:auto, so
   an item without an explicit width is centred at its content width -- the two
   IME panels sat across two thirds of the page with the rest blank. The
   existing max-width and centring still apply. */
.v2-insight-grid[data-panels='2'],
.v2-insight-grid[data-panels='1'] { width: 100%; }

/* Below the phone breakpoint everything stacks, as it already did. */
@media (max-width: 900px) {
  .v2-insight-grid[data-panels] { grid-template-columns: 1fr; }
}

/* ── Card header tools stay on one row ────────────────────────────────────
   specialized.css already states the intent -- search and column picker
   'belong on one baseline at the end of the header, never stacked' -- but the
   tools block is a plain flex item, so space-between let the title shrink it
   to 274px. The search field alone asks for 280px, so it wrapped under the
   picker and the header grew to two rows.

   The title takes the slack and truncates; the tools size to their content. */
.special-card > header > div:first-child { flex: 1 1 260px; min-width: 0; }
.special-table-tools { flex: 0 0 auto; flex-wrap: nowrap; }

/* On a phone the header itself wraps, and 280px + picker no longer fits on
   one line -- let the tools stack again rather than overflow. */
@media (max-width: 640px) {
  .special-table-tools { flex-wrap: wrap; }
}

/* The search field's own min-width was min(280px, 100%) -- and 100% resolves
   against the tools box it is supposed to be widening, so it could never push
   the container out. It collapsed to the shrunk width and overflowed the card.
   A fixed floor has no such circularity. */
.special-table-tools .special-field { min-width: 240px; }
@media (max-width: 640px) {
  .special-table-tools .special-field { min-width: 0; }
}

/* ── Industry rank rows: space freed by moving the unit to the header ─────
   Each figure used to read «۴۷٬۴۳۸٫۰۳ میلیارد ریال», so the value column was
   sized for the unit and the industry names were truncated to «بانکها و
   موسسات اعت…». The unit is now stated once in the panel header, so the value
   column only has to fit a number and the name column takes what it gives up. */
.market-rank-row {
  grid-template-columns: minmax(118px, 1.45fr) minmax(64px, 1fr) auto;
  gap: 8px;
}
.market-rank-row > span:first-child { font-size: 11.5px; }
.market-rank-row > strong { min-width: 54px; font-size: 11px; }

@media (max-width: 1280px) {
  .market-rank-row { grid-template-columns: minmax(96px, 1.3fr) minmax(56px, 1fr) auto; }
  .market-rank-row > span:first-child { font-size: 11px; }
}

/* ── Admin member filters: give auto-fit a width to resolve against ───────
   .admin-form-grid uses repeat(auto-fit, minmax(190px, 1fr)), which needs a
   definite inline size. Inside .panel-header it is a flex item sized by its
   content, so auto-fit resolved to a single track and the six controls stacked
   into a narrow column while three quarters of the panel sat empty.
   Taking a full row of the header gives it that definite width. */
.panel-header > .admin-form-grid.member-filter-grid {
  flex: 1 1 100%;
  width: 100%;
  padding: 0;
  align-items: end;
}
.panel-header > .admin-form-grid.member-filter-grid > button { min-height: 38px; }

/* ── Scenario-parameter row: columns to match the content ────────────────
   pro.css fixes .strategy-settings-pro at repeat(4, minmax(130px,1fr)) while
   the row holds three controls, so a full 277px column sat empty on the far
   side. auto-fit sizes to what is actually there. */
.strategy-settings-pro {
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  align-items: end;
}

/* ── Strategy: stop tall boxes stranding the controls beside them ─────────
   Both of these rows pair a four-row stacked box with single-row controls, so
   the row took the tall box's height and left ~140px of dead air above the
   selects. Neither box needs to be a single column -- laid out in two, they
   come down to roughly the height of the controls they sit beside, which is
   what closes the gap without narrowing anything. */

/* زنجیره زنده readout: coverage / spot / live toggles on one line, note under */
.strategy-pro-page .strategy-source-inline {
  grid-template-columns: auto 1fr;
  column-gap: var(--fv-space-5);
  align-content: center;
}
.strategy-pro-page .strategy-source-inline > div:first-of-type { grid-column: 1; grid-row: 1; }
.strategy-pro-page .strategy-source-inline > .strategy-live-row {
  grid-column: 2; grid-row: 1; justify-self: end;
}
.strategy-pro-page .strategy-source-inline > small { grid-column: 1 / -1; grid-row: 2; }

/* Scenario toggles: 2x2 rather than a four-high column */
.strategy-settings-pro .strategy-toggle-stack {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--fv-space-5);
}

/* With both boxes shortened the row no longer needs bottom-alignment to hide
   the mismatch; top-aligning keeps the labels on one line. */
.strategy-settings-pro { align-items: start; }

/* .main-content is a flex column whose children carry margin-inline:auto, so
   a child with no explicit width is centred at its content width. The strategy
   workbench was sitting at 905px inside 1358px of page, which is why
   پارامترهای سناریو and the panels under it never reached full width. Same fix
   as the home insight grid; the existing max-width still caps it. */
.strategy-workbench-grid { width: 100%; }

/* ── تنظیمات پیشرفته reads as a button ────────────────────────────────────
   It only carried justify-self and a margin, so it inherited a flat bordered
   box that looked like another read-only field next to the ones it sits
   beside. It is a disclosure control, so give it the affordances: accent
   colour, a pointer, a hover/focus state, and a chevron that turns when the
   panel opens (aria-expanded is already maintained). */
.strategy-advanced-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--fv-space-2);
  cursor: pointer;
  padding: var(--fv-space-2) var(--fv-space-4);
  border: 1px solid color-mix(in srgb, var(--fv-accent) 45%, var(--fv-line));
  border-radius: var(--fv-radius-md);
  background: color-mix(in srgb, var(--fv-accent) 8%, transparent);
  color: var(--fv-accent);
  font-weight: var(--fv-weight-medium);
  transition: background var(--fv-duration-fast) var(--fv-ease),
              border-color var(--fv-duration-fast) var(--fv-ease);
}
.strategy-advanced-toggle::after {
  content: '';
  width: 8px; height: 8px;
  border-inline-end: 2px solid currentColor;
  border-block-end: 2px solid currentColor;
  transform: rotate(45deg);
  margin-block-start: -3px;
  transition: transform var(--fv-duration-fast) var(--fv-ease);
}
.strategy-advanced-toggle[aria-expanded='true']::after {
  transform: rotate(-135deg);
  margin-block-start: 3px;
}
.strategy-advanced-toggle:hover {
  background: color-mix(in srgb, var(--fv-accent) 15%, transparent);
  border-color: var(--fv-accent);
}
.strategy-advanced-toggle:focus-visible {
  outline: 2px solid var(--fv-accent);
  outline-offset: 2px;
}

/* ==========================================================================
   DISPLAY MODE  —  ساده | پیشرفته  and  فشرده
   ==========================================================================
   Two independent choices, set as data-mode and data-density on <html> by
   pro.js and remembered in cookies. Mode decides WHAT is on the page, compact
   decides HOW TIGHT it sits. They were one three-step control before, so
   wanting tighter rows meant also losing half the board.
   ========================================================================== */

/* Sections opt IN to being advanced, so anything unclassified stays visible in
   both modes: a board nobody has gone through yet degrades to "shows
   everything", never to "shows nothing". */
html[data-mode="simple"] [data-mode-only="pro"],
html[data-mode="pro"] [data-mode-only="simple"] { display: none !important; }

/* The active segment used to go from medium to semibold, which widens the
   label: every click resized the button and shoved its neighbours sideways.
   A hairline stroke gives the same optical weight with no metrics change. */
:is(.segmented, .watchlist-mode-group, .market-radar-filters, .history-metric-switch) > button.active,
:is(.segmented, .watchlist-mode-group, .market-radar-filters, .history-metric-switch) > button[aria-pressed="true"],
.segment-button.active {
  font-weight: var(--fv-weight-medium);
  -webkit-text-stroke: 0.25px currentColor;
}

.fvp-display {
  display: flex;
  align-items: center;
  gap: var(--fv-space-3);
  flex-wrap: wrap;
  padding: var(--fv-space-3) var(--fv-space-4);
  border-block-end: 1px solid var(--fv-line);
}
/* Size the pair to its labels. Letting it grow put a dead gap the width of the
   panel between ساده and پیشرفته, which read as a third, empty segment. */
.fvp-display .fvp-mode { flex: 0 0 auto; }
.fvp-display .fvp-mode > button {
  min-width: 5.5rem;
  justify-content: center;
}

/* فشرده is a different kind of control from the ساده/پیشرفته pair -- a toggle,
   not one of two choices -- so it is a rounded chip rather than a third
   segment that would look mutually exclusive with them. Its icon is two rules
   that close up when it is on, which says "tighter" without a label change. */
.fvp-compact {
  flex: 0 0 auto;
  gap: var(--fv-space-2);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-full);
  background: var(--fv-surface-2);
  color: var(--fv-muted);
}
.fvp-compact::before {
  content: "";
  inline-size: 14px;
  block-size: 11px;
  border-block: 2px solid currentColor;
  transition: block-size var(--fv-duration-fast) var(--fv-ease);
}
.fvp-compact:hover { color: var(--fv-text); border-color: var(--fv-line-strong); }
.fvp-compact.active {
  background: var(--fv-accent-soft);
  border-color: var(--fv-accent);
  color: var(--fv-accent);
}
.fvp-compact.active::before { block-size: 5px; }

/* The --fv-density-* tokens were defined for three steps but read by almost
   nothing outside this file, so the control was inert on every board. Rather
   than re-pad every surface unconditionally -- which would change the default
   look for everyone -- compact is written as an override: comfortable stays
   exactly what the boards already are, and فشرده tightens what carries the
   page. */
html[data-density="compact"] :is(.panel, .card, .kpi, .kpi-card, .special-kpi,
  .home-section, .market-overview-section, .visual-manager-menu) {
  padding: var(--fv-density-panel);
}
html[data-density="compact"] :is(.section-stack, .specialized-board, .home-grid, .main-content) {
  gap: var(--fv-density-panel);
}
html[data-density="compact"] :is(.data-table, .special-table) tbody tr {
  height: var(--fv-density-row);
}


/* .bubble-market is not a card grid -- it holds exactly two children, the
   four-box summary strip and the card grid itself. Sweeping it into the
   auto-fit rule above put those two side by side, so the summary boxes were
   stretched to the full height of the card grid beside them and stood almost
   empty. It stacks, as hub.css always intended. */
.bubble-market {
  grid-template-columns: 1fr;
  gap: var(--fv-space-4);
}
/* "+۲٫۰۳" and its "٪" are one figure and must not break across lines. */
.bubble-main-value { white-space: nowrap; }

/* ---------------------------------------------------- applied filter chips --
   One chip per applied value, so a multi-select can lose a single choice
   instead of all of them at once. That means several chips now share a field
   label, so the label is set quiet and divided off by a hairline: the values
   are what the eye should land on, not four repetitions of "صنعت". */
.filter-chips { gap: var(--fv-space-2); }
.filter-chip {
  gap: var(--fv-space-2);
  padding-block: 4px;
  padding-inline: var(--fv-space-3) 4px;
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-full);
  background: var(--fv-surface-2);
  color: var(--fv-text);
  font-size: var(--fv-text-xs);
  cursor: pointer;
  transition: background var(--fv-duration-fast) var(--fv-ease),
              border-color var(--fv-duration-fast) var(--fv-ease);
}
.filter-chip .chip-label {
  color: var(--fv-faint);
  padding-inline-end: var(--fv-space-2);
  border-inline-end: 1px solid var(--fv-line);
}
.filter-chip .chip-value { font-weight: var(--fv-weight-semibold); }
/* The × is what is being aimed at, so give it a real target: an 18px circle
   that fills in, rather than a bare glyph the pointer has to hunt for. */
.filter-chip .chip-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 18px;
  block-size: 18px;
  border-radius: 50%;
  font-size: 13px;
  line-height: 1;
  color: var(--fv-muted);
  transition: background var(--fv-duration-fast) var(--fv-ease),
              color var(--fv-duration-fast) var(--fv-ease);
}
.filter-chip:hover {
  background: var(--fv-surface);
  border-color: color-mix(in srgb, var(--fv-down) 45%, var(--fv-line));
}
.filter-chip:hover .chip-x { background: var(--fv-down); color: #fff; }
.filter-chip:focus-visible { outline: 2px solid var(--fv-accent); outline-offset: 2px; }

/* ------------------------------------------------- market context strip --
   The index under a module's history chart, on its own axis. شاخص کل sits
   around 6,500,000 while trade value runs to trillions; one shared scale would
   flatten whichever is smaller, so this is a separate, quieter chart rather
   than a second series. */
.index-context {
  margin-block-start: var(--fv-space-4);
  padding-block-start: var(--fv-space-3);
  border-block-start: 1px dashed var(--fv-line);
}
.index-context[hidden] { display: none !important; }
.index-context-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--fv-space-3);
  margin-block-end: var(--fv-space-2);
  font-size: var(--fv-text-sm);
}
.index-context-head #indexContextTitle {
  font-weight: var(--fv-weight-semibold);
  color: var(--fv-text-2);
}
.index-context-head .muted { color: var(--fv-faint); font-size: var(--fv-text-xs); }

/* ------------------------------------------------------ fund history panel --
   Per-fund NAV, assets and unit flow on the symbol page. FIPIRAN's coverage
   differs per series, so "not published" is a first-class state here and gets
   its own muted treatment rather than reading as a zero. */
.fund-history-panel[hidden] { display: none !important; }
.fund-history-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
  gap: var(--fv-space-3);
  margin-block-end: var(--fv-space-4);
}
.fund-history-stats .fund-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--fv-space-3);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-md);
  background: var(--fv-surface-2);
  min-width: 0;
}
.fund-history-stats .fund-stat span {
  font-size: var(--fv-text-xs);
  color: var(--fv-faint);
}
.fund-history-stats .fund-stat strong {
  font-size: var(--fv-text-base);
  font-weight: var(--fv-weight-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--fv-text);
}
.fund-history-stats .fund-stat strong.positive { color: var(--fv-up); }
.fund-history-stats .fund-stat strong.negative { color: var(--fv-down); }
.fund-history-stats .fund-stat strong.muted {
  color: var(--fv-faint);
  font-weight: var(--fv-weight-medium);
  font-size: var(--fv-text-sm);
}
#fundFlowChart { margin-block-start: var(--fv-space-4); }
#fundFlowChart[hidden] { display: none !important; }
.fund-history-note {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-block-start: var(--fv-space-3);
  font-size: var(--fv-text-xs);
  color: var(--fv-faint);
}

/* روند صندوق carries a stat row and two charts, so it needs the whole row --
   it sits in .symbol-secondary-grid beside the narrow depth and client-type
   panels, which squeezed both charts into a column meant for a small table. */
#fundHistoryPanel { grid-column: 1 / -1; }

/* دارایی‌های ماه holds three ranked lists side by side. Every other fund panel
   in .symbol-market-row claims the whole row; this one had no rule, so it fell
   into one column of a two-column grid and the three lists were squeezed into
   roughly a third of the width they need. */
#fundTopPanel { grid-column: 1 / -1; }

/* ------------------------------------------------- commodity certificates --
   Open interest is the headline here, not price: it is what these instruments
   add that the board never had. It gets the large figure; price and volume are
   supporting facts underneath. */
.certificate-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
  gap: var(--fv-space-3);
  padding: var(--fv-space-4);
}
.certificate-card {
  display: grid;
  gap: var(--fv-space-2);
  padding: var(--fv-space-4);
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-md);
  background: var(--fv-surface-2);
  min-width: 0;
}
.certificate-card > header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--fv-space-2);
}
.certificate-card > header strong { font-size: var(--fv-text-base); color: var(--fv-text); }
.certificate-card > header small { font-size: var(--fv-text-xs); color: var(--fv-faint); }
.certificate-oi { display: grid; gap: 2px; }
.certificate-oi span { font-size: var(--fv-text-xs); color: var(--fv-faint); }
.certificate-oi b {
  font-size: var(--fv-text-lg);
  font-weight: var(--fv-weight-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--fv-text);
  line-height: 1.15;
}
.certificate-oi i {
  font-style: normal;
  font-size: var(--fv-text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--fv-faint);
}
.certificate-oi i.positive { color: var(--fv-up); }
.certificate-oi i.negative { color: var(--fv-down); }
.certificate-facts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--fv-space-2);
  margin: 0;
  padding-block-start: var(--fv-space-2);
  border-block-start: 1px solid var(--fv-line);
}
.certificate-facts div { display: grid; gap: 1px; min-width: 0; }
.certificate-facts dt { font-size: var(--fv-text-xs); color: var(--fv-faint); }
.certificate-facts dd {
  margin: 0;
  font-size: var(--fv-text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--fv-text-2);
}

/* ------------------------------------------------- fund history row --------
   Returns table plus three charts across one row on a wide screen, wrapping to
   two and then one as it narrows. auto-fit with a real minimum rather than a
   fixed four-column grid: a 15rem chart is the point at which these stop being
   readable, so that is where they wrap. */
/* Four cells, four different shapes of data -- so not four equal columns.
   auto-fit gave each about a quarter of the panel, which put a 346-point daily
   series in roughly 300px and turned all three charts into smears.

   بازدهی is a five-row table: it needs a narrow column and no more, and it
   spans both rows because it is short enough to sit beside them.
   خالص ارزش دارایی هر واحد is the series the page is about, so it takes the
   full width of the two chart columns.
   سهم هر طبقه and صدور و ابطال are read against each other, so they share the
   row beneath at equal width. */
.fund-history-row {
  display: grid;
  grid-template-columns: minmax(9rem, 0.7fr) minmax(0, 2fr) minmax(0, 2fr);
  grid-template-areas:
    "returns nav   nav"
    "returns alloc flow";
  gap: var(--fv-space-4);
  align-items: start;
}
/* .panel-header > div sets min-width:0 for the title block; the range chips
   are a sibling div and must keep their intrinsic width instead of collapsing. */
#fundRangeToggle { flex: 0 0 auto; }

/* The monthly ledger is the longest thing on the fund page -- 30 rows pushed
   everything below it off the screen. It keeps all its rows and scrolls in
   place instead, so the panel stays a readable height. */
.fund-holdings-scroll { max-height: 24rem; overflow-y: auto; }
/* The industry bars sit directly above it; cap their block too so the two
   sections together no longer dominate the page. */
.fund-clean-industry .fund-symbol-allocation { max-height: 20rem; overflow-y: auto; }
.fund-returns-cell { grid-area: returns; }
.fund-nav-cell { grid-area: nav; }
.fund-alloc-cell { grid-area: alloc; }
.fund-flow-cell { grid-area: flow; }

/* Below this the two secondary charts stop being readable side by side, so
   they stack full width rather than shrink further. */
@media (max-width: 80rem) {
  .fund-history-row {
    grid-template-columns: minmax(9rem, 0.8fr) minmax(0, 3fr);
    grid-template-areas:
      "returns nav"
      "alloc   alloc"
      "flow    flow";
  }
}
@media (max-width: 52rem) {
  .fund-history-row {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "returns" "nav" "alloc" "flow";
  }
}
.fund-cell { min-width: 0; display: grid; gap: var(--fv-space-2); }
.fund-cell h3 {
  margin: 0;
  font-size: var(--fv-text-sm);
  font-weight: var(--fv-weight-semibold);
  color: var(--fv-text-2);
}
.fund-cell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--fv-space-2);
  flex-wrap: wrap;
}
.fund-metric-toggle > button { font-size: var(--fv-text-xs); padding-inline: var(--fv-space-3); }

.fund-returns-table { width: 100%; border-collapse: collapse; }
.fund-returns-table th,
.fund-returns-table td {
  padding: var(--fv-space-2) 0;
  border-block-end: 1px solid var(--fv-line);
  font-size: var(--fv-text-sm);
}
.fund-returns-table tr:last-child th,
.fund-returns-table tr:last-child td { border-block-end: 0; }
.fund-returns-table th {
  text-align: start;
  font-weight: var(--fv-weight-medium);
  color: var(--fv-faint);
}
.fund-returns-table td {
  text-align: end;
  font-variant-numeric: tabular-nums;
  font-weight: var(--fv-weight-semibold);
  color: var(--fv-text);
}
.fund-returns-table td.positive { color: var(--fv-up); }
.fund-returns-table td.negative { color: var(--fv-down); }
.fund-returns-table td.muted { color: var(--fv-faint); font-weight: var(--fv-weight-regular); text-align: start; }

/* ---------------------------------------------- fund: category chips -------
   One category at a time, chosen by the reader. Only categories the fund
   actually reports get a chip -- an empty axis for commodity on an equity
   fund is noise, not information. */
.chip-row { display: flex; flex-wrap: wrap; gap: var(--fv-space-1); }
.chip-toggle {
  border: 1px solid var(--fv-line);
  border-radius: var(--fv-radius-full);
  background: var(--fv-surface-2);
  color: var(--fv-muted);
  font: inherit;
  font-size: var(--fv-text-xs);
  padding: 2px var(--fv-space-3);
  cursor: pointer;
  transition: background var(--fv-duration-fast) var(--fv-ease),
              color var(--fv-duration-fast) var(--fv-ease),
              border-color var(--fv-duration-fast) var(--fv-ease);
}
.chip-toggle:hover { color: var(--fv-text); border-color: var(--fv-line-strong); }
.chip-toggle.active {
  background: var(--fv-accent-soft);
  border-color: var(--fv-accent);
  color: var(--fv-accent);
  font-weight: var(--fv-weight-semibold);
}

/* ---------------------------------------------- fund: month holdings -------
   Ranked by end-of-period value. The figure leads and the share follows it,
   because how much is the question and what fraction is the qualifier. */
.fund-top-panel[hidden] { display: none !important; }
/* The three lists -- positions, buys, sells -- are one comparison and belong
   on one line. auto-fit with a 17rem minimum needed ~54rem of PANEL width
   before it would place three columns, which this panel does not get once the
   sidebar is open, so it silently reflowed to two columns and then one. The
   count is fixed here and only relaxed when the viewport genuinely cannot
   hold it. */
.fund-top-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--fv-space-5);
  align-items: start;
}
@media (max-width: 60rem) {
  .fund-top-row { grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr)); }
}
.fund-top-list { margin: 0; padding: 0; list-style: none; counter-reset: rank; display: grid; gap: var(--fv-space-2); }
/* Name and figure on separate lines, not separate columns.
   The old row was `1.4rem minmax(0,1fr) auto`, and the auto column holds a
   string like «۱۴٫۱۸ هزار میلیارد ریال» which cannot shrink. In a cell about a
   third of the panel wide it consumed the row, the name column collapsed to
   almost nothing, and the text wrapped one character per line. Three of these
   sit side by side, so the width is never generous: giving the name the full
   line and letting the figures share the one below is stable at any width. */
.fund-top-list li {
  counter-increment: rank;
  display: grid;
  grid-template-columns: 1.4rem minmax(0, 1fr);
  align-items: baseline;
  gap: 2px var(--fv-space-2);
  padding-block-end: var(--fv-space-2);
  border-block-end: 1px solid var(--fv-line);
}
.fund-top-list li:last-child { border-block-end: 0; padding-block-end: 0; }
.fund-top-list li::before {
  content: counter(rank);
  font-variant-numeric: tabular-nums;
  font-size: var(--fv-text-xs);
  color: var(--fv-faint);
}
.fund-top-name { min-width: 0; display: grid; gap: 1px; }
.fund-top-name strong {
  font-size: var(--fv-text-sm);
  font-weight: var(--fv-weight-semibold);
  color: var(--fv-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The subtitle carries the full company name and industry, which is longer
   than the column: clip it on one line like the symbol above it. Both carry a
   title attribute, so the full text is still reachable on hover. */
.fund-top-name small {
  font-size: var(--fv-text-xs);
  color: var(--fv-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fund-top-name { grid-column: 2; }
.fund-top-figures {
  grid-column: 2;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--fv-space-2);
}
.fund-top-figures b { white-space: nowrap; }
.fund-top-figures b {
  font-size: var(--fv-text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--fv-text);
}
.fund-top-figures i {
  font-style: normal;
  font-size: var(--fv-text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--fv-faint);
}
