/* Dashboard — Redesign Phase 3, task T16 (FRONTEND_ARCHITECTURE_PLAN.md §4).
 *
 * Only rules styles.css does not already paint: the four-card answer row, the
 * two-column chart/leaders row, the Movers head, and the symbol cell that
 * styles.css's td-scoped `td.sym` can never reach. Colour, type, spacing,
 * radius and motion come only from tokens.css custom properties — no hex,
 * rgb()/hsl() or named colour literal lives here (transparent, currentColor
 * and inherit are allowed), and no raw length equals a token value.
 *
 * Loaded by views/dashboard.js, which appends one <link> to <head> on mount.
 */

/* ---- stale / error slot ------------------------------------------------- */

.dashboard-stale:not(:empty) {
  margin-bottom: var(--space-2);
}

/* ---- four answer cards --------------------------------------------------- */

.dashboard-cards {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* ---- chart + last completed hour ------------------------------------------ */

.dashboard-row {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); grid-template-areas: "chart leaders" "movers movers";
  gap: var(--space-2); row-gap: var(--space-4);
  align-items: start; container-type: inline-size;
}

.dashboard-chart,
.dashboard-leaders,
.dashboard-movers {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

/* ChartPanel owns the host; this view only adds the sibling foot link. */
.dashboard-chart-foot {
  display: flex;
  justify-content: flex-end;
}

.dashboard-chart-link {
  color: var(--muted);
  font-size: var(--fs-label);
  text-decoration: none;
}

.dashboard-chart-link:hover {
  color: var(--ink);
  text-decoration: underline;
}

/* Leaders stack in this column instead of the shared horizontal strip. */
.dashboard-leaders .leaders {
  flex-direction: column;
  overflow-x: visible;
}

.dashboard-leaders .leader {
  width: 100%;
  min-width: 0;
}

.dashboard-leader-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.dashboard-pace {
  margin: 0;
  color: var(--muted);
  font-size: var(--fs-label);
}

/* ---- movers head ---------------------------------------------------------- */

.dashboard-movers-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.dashboard-movers-head .panel-title {
  margin: 0;
  margin-right: auto;
}

/* ---- symbol cell ---------------------------------------------------------- */

.sym-cell {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.sym-cell-row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

a.sym {
  font-weight: var(--fw-semibold);
  color: var(--ink);
  text-decoration: none;
}

a.sym:hover {
  text-decoration: underline;
}

/* ---- responsive ------------------------------------------------------------ */

@media (max-width: 1100px) {
  .dashboard-row { grid-template-columns: minmax(0, 1fr); grid-template-areas: "chart" "leaders" "movers"; row-gap: var(--space-2); container-type: normal; }
  .dashboard-row .dashboard-movers { margin-top: calc(var(--space-4) - var(--space-2)); width: auto; }
}


@media (max-width: 920px) {
  .dashboard-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 479.98px) {
  .dashboard-cards {
    grid-template-columns: minmax(0, 1fr);
  }

  .dashboard-movers-head {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ---- empty watchlist state (§10 W1) ---------------------------------------
   The Movers table's note when the LIST itself is empty: "Your watchlist is
   empty" and a link to #/watchlist. The table's own `.empty-note` wrapper
   (styles.css) already paints the muted centred note; this stacks the
   sentence over the link. */

.dashboard-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

.dashboard-empty-title {
  margin: 0;
}

/* ---- named grid areas (MOBILE_PLAN.md §3.1) --------------------------------
   One grid, three named panels. The area strings live on `.dashboard-row`
   itself (above, at every width) so the cascade order never has to fight the
   1100px rule; this block only assigns each panel to its area. */

.dashboard-chart {
  grid-area: chart;
}

.dashboard-leaders {
  grid-area: leaders;
}

.dashboard-movers {
  grid-area: movers;
  /* A spanning grid item is sized as the sum of its tracks plus the column
     gap, and Chrome rounds each `fr` track to a 1/64 LayoutUnit first — at
     546 of the 820 widths from 1101 to 1920 the span lands 1/64 px off the
     row, which shifts the table's auto columns and every glyph's
     antialiasing. The pre-restructure Movers was a full-width flex item, so
     pin the span to the row's own content width: `100cqw` against the row
     (`container-type: inline-size`, set on `.dashboard-row` at the top of
     this file) is exact at all 820 widths (a fixed `+ 1px/64` was not). The
     ≤1100px block resets both — `width: auto` at higher specificity and
     `container-type: normal` — so tablets and phones keep the single exact
     track and no containment. No new media query: the architecture test
     pins the allowed values. */
  width: 100cqw;
}

/* ---- movers quick sort (phones only) --------------------------------------
   Winners | Losers | RVOL is a 3-button control, not data: the strip is
   display:none at 768 and wider, which also keeps it out of the desktop
   structural snapshot (vis() drops zero-size nodes). The preset <select>
   stays the only <select> on the page at every width. */

.dashboard-movers-seg {
  display: none;
  flex: 1 0 100%;
  min-width: 0;
}

/* ---- mobile Movers row ----------------------------------------------------
   Built by views/dashboard.js's mobileMoverRow inside `a.dt-item-main`
   (list mode only), so it never exists at 768 and wider. Classes are
   dashboard-scoped to avoid colliding with the table-cell kinds. */

.dash-mover-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.dash-mover-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  /* The two meta groups are one logical line (§3.1). When they do not both
     fit — 320 and 375 always, 430 with a long Vol — wrap the WHOLE group to
     the next line instead of squeezing it. flex-wrap decides on flex-basis
     (max-content), so a group never shrinks once it has a line to itself. */
  flex-wrap: wrap;
  min-width: 0;
}

.dash-mover-sym {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
}

.dash-mover-ticker {
  font-weight: var(--fw-semibold);
  font-size: var(--fs-small);
  color: var(--ink);
}

.dash-mover-group {
  /* Normal inline flow, not a flex container. As `inline-flex` each label and
     value span was its own shrinkable flex item, so a squeezed group wrapped
     every child independently and shredded "2.33x" into one glyph per line.
     The label strings already carry their spaces, so plain flow keeps the
     §3.1 spacing and wraps only at those spaces. */
  min-width: 0;
}

.dash-mover-lbl,
.dash-mover-sep {
  color: var(--muted);
  font-size: var(--fs-label);
}

.dash-mover-warn-glyph {
  color: var(--warn);
}

/* styles.css paints .row-warnings at 11px, below the phone 12px floor for
   non-allowlisted text. This node only exists in list mode, so raising it to
   --fs-meta (12px on a phone) cannot touch a desktop pixel. */
.dash-mover-warn {
  font-size: var(--fs-meta);
  overflow-wrap: anywhere;
}

/* ---- phone (MOBILE_PLAN.md §3.1) -------------------------------------------
   Area order leaders → Movers → chart (dashboard.js also moves the chart node
   last on a phone so Tab order matches). StatCards stay
   two columns at every phone width (stat-card.css's `.cards.cards` auto-fit
   would grow past two above 480, so `.dashboard-cards` wins with equal
   specificity and later load order). The divergence card spans both columns
   when JS finds its detail wrapping past two lines. */

@media (max-width: 767.98px) {
  .dashboard-row {
    grid-template-areas: "leaders" "movers" "chart";
    row-gap: var(--space-3);
  }

  .dashboard-row .dashboard-movers {
    margin-top: 0;
  }

  .dashboard-cards.dashboard-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .dashboard-cards .card-wide {
    grid-column: 1 / -1;
  }

  /* A full-width divergence card would leave Lagging alone in its row next
     to an empty cell. Keep the grid balanced and the §3.1 order: Unusual
     volume takes the full first row, Leading | Lagging pair up, and the
     divergence card spans the last row. */
  .dashboard-cards:has(> .card-wide) > :first-child {
    grid-column: 1 / -1;
  }

  /* "Manage watchlist": the phone .btn is 44px tall (styles.css Pattern 2);
     centre its label in that box instead of leaving it top-aligned. */
  .dashboard-header .view-head-actions > a.btn {
    display: inline-flex;
    align-items: center;
  }

  /* Leader meta ("hour -0.83%", "day +1.2%", "slot 12:00–12:30 · 30 min"):
     each item stays on one line and the row wraps between items, so a long
     30m slot label drops to its own line instead of squeezing all three
     into cramped wrapped columns. */
  .dashboard-leaders .leader-sub {
    flex-wrap: wrap;
    column-gap: var(--space-3);
    row-gap: 1px;
  }

  .dashboard-leaders .leader-sub > span {
    white-space: nowrap;
  }

  .dashboard-movers-seg {
    display: block;
  }

  /* §3.1: leaders are a compact list, rows 44px or taller. */
  .dashboard-leaders .leader {
    min-height: var(--hit-min);
  }
}

/* ---- Pattern 1 hit extensions (MOBILE_PLAN.md §2.9) ------------------------
   The small symbol/foot/card links keep their 18px visual and grow only their
   hit area to --hit-min. Invisible, so a fine-pointer desktop never sees it. */

@media (pointer: coarse), (max-width: 767.98px) {
  .leader-symbol,
  .dashboard-chart-link,
  .dashboard-cards .card-link {
    position: relative;
    pointer-events: auto;
  }

  .leader-symbol::after,
  .dashboard-chart-link::after,
  .dashboard-cards .card-link::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: max(100%, var(--hit-min));
    height: max(100%, var(--hit-min));
    transform: translate(-50%, -50%);
    pointer-events: auto;
  }
}
