/* ============================================================================
   BRAINWEBER THEME — APPLICATION LAYER.

   Styles for markup THIS application owns and a buyer of the theme would not have:
   the dashboard Razor views under Modules/Common/Dashboard — KPI row, module
   launcher, quick actions, attention queue, installation panel and the chart region.

   ⚠ Loads AFTER theme-core.css and depends on its tokens (--bw-*). It declares no
   tokens of its own, which is what lets the core be swapped without touching this.

   ⚠ The split boundary is a rule, not a judgement call: if the markup ships with the
   theme package, its styles belong in the core; if the host application renders it,
   they belong here.
   ============================================================================ */

/* ============================================================================
   8. DASHBOARD — the designed landing screen (Modules/Common/Dashboard).
   ============================================================================ */
:root[data-theme-version] .m-dash { display: flex; flex-direction: column; gap: var(--bw-pad); }
:root[data-theme-version] .m-dash-head {
  align-items: flex-end;
  display: flex;
  flex-wrap: wrap;
  gap: var(--bw-pad);
  justify-content: space-between;
}
:root[data-theme-version] .m-dash-greeting { display: flex; flex-direction: column; gap: 5px; }
:root[data-theme-version] .m-dash-greeting h1 {
  font-size: var(--bw-h1-size);
  font-weight: 600;
  letter-spacing: -.02em;
  margin: 0;
}
:root[data-theme-version] .m-dash-sub { color: var(--bw-muted); font-size: var(--bw-text-base); margin: 0; }
:root[data-theme-version] .m-dash-actions { display: flex; gap: 8px; }

/* ---- KPI tiles ---- */
:root[data-theme-version] .m-kpis {
  display: grid;
  gap: var(--bw-gap);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
:root[data-theme-version] .m-kpi {
  background-color: var(--bw-surface);
  border: 1px solid var(--bw-border);
  border-radius: var(--bw-radius-xl);
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 15px var(--bw-pad);
}
/* v1's tiles carry a coloured left edge, which is the one job its orange accent
   has on this screen; v2's do not, because its green already carries emphasis. */
:root[data-theme-version="v1"] .m-kpi { border-left: 3px solid var(--bw-primary); }
:root[data-theme-version="v1"] .m-kpi.m-kpi-accent { border-left-color: var(--bw-accent); }
:root[data-theme-version] .m-kpi-label {
  color: var(--bw-eyebrow-color);
  font-size: var(--bw-text-xs);
  font-weight: 600;
  letter-spacing: var(--bw-colhead-spacing);
  text-transform: var(--bw-eyebrow-transform);
}
:root[data-theme-version="v2"] .m-kpi-label {
  color: var(--bw-muted);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0;
}
:root[data-theme-version] .m-kpi-figure { align-items: baseline; display: flex; gap: 8px; }
:root[data-theme-version] .m-kpi-value {
  color: var(--bw-text-strong);
  font-family: var(--bw-font-mono);
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -.025em;
  font-variant-numeric: tabular-nums;
}
:root[data-theme-version] .m-kpi-unit { color: var(--bw-faint); font-size: var(--bw-text-sm); }
:root[data-theme-version] .m-kpi-bar { background-color: var(--bw-rule); border-radius: var(--bw-pill); height: 5px; overflow: hidden; }
:root[data-theme-version] .m-kpi-bar > span { background-color: var(--bw-primary); display: block; height: 100%; border-radius: var(--bw-pill); }
:root[data-theme-version] .m-kpi-note { color: var(--bw-faint); font-size: var(--bw-text-xs); }

/* ---- two-column body ---- */
:root[data-theme-version] .m-dash-body {
  align-items: start;
  display: grid;
  gap: var(--bw-gap);
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
}
@media (max-width: 1099.98px) {
  :root[data-theme-version] .m-dash-body { grid-template-columns: minmax(0, 1fr); }
}
:root[data-theme-version] .m-card {
  background-color: var(--bw-surface);
  border: 1px solid var(--bw-border);
  border-radius: var(--bw-radius-xl);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* ⚠ Stacked cards need this; cards in a GRID must not have it. Inside .m-charts it offset every
   panel but the first by 12px AND, because the grid stretches items, took the same 12px off their
   height — so a row of four chart cards sat 12px lower than the first one and 12px shorter. The
   row read as misaligned with no rule looking wrong. Scoped out wherever the parent already does
   the spacing with `gap`. */
:root[data-theme-version] .m-card + .m-card { margin-top: var(--bw-gap); }
:root[data-theme-version] .m-charts > .m-card + .m-card { margin-top: 0; }
:root[data-theme-version] .m-card-head {
  align-items: center;
  border-bottom: 1px solid var(--bw-rule);
  display: flex;
  gap: 10px;
  padding: 13px var(--bw-pad);
}
:root[data-theme-version] .m-card-title { color: var(--bw-text-strong); font-size: var(--bw-h2-size); font-weight: 600; margin: 0; }
:root[data-theme-version] .m-card-note { color: var(--bw-faint); font-size: var(--bw-text-sm); }
:root[data-theme-version] .m-card-link { margin-left: auto; font-size: var(--bw-text-sm); font-weight: 500; }

/* ---- module launcher ---- */
/* ---- the dashboard's chart region ----
   Bars are HTML, not SVG and certainly not a chart library: the Chart.js/jVectorMap/knob set was
   deleted from this app deliberately, and a bar chart is a div with a width. Plain elements also
   keep the values as real text, so the panel needs no table view to be readable and prints from
   section 9 like everything else.

   ⚠ One hue for every bar, from --bw-chart-mark. These are counts by class and bar length already
   carries magnitude — a darker-where-bigger ramp would re-encode length as colour, and a per-class
   palette would claim the classes are series that must be told apart. No legend either: one series
   means the title already names what is plotted.

   ⚠ --bw-chart-mark, not --bw-primary. A bar has nothing on top of it, so it has to stand off the
   surface like ink; v1 dark's primary is 2.08:1 there, below the 3:1 a data mark needs. */
:root[data-theme-version] .m-charts {
  display: grid;
  gap: var(--bw-gap);
  /* ⚠ 280px, not 320px. v2's sidebar is 248px against v1's 56px rail, so at the same viewport it
     has ~180px less content width — enough that a 320px minimum fitted four panels in v1 and only
     three in v2, dropping the fourth onto a row of its own. 280 fits four in both. */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  /* ⚠ Equal rows, so a panel that DOES wrap at a narrower viewport still matches the row above
     instead of shrinking to its own content height — which is what made the wrapped v2 panel
     135px against its neighbours' 222px and read as a broken layout. */
  grid-auto-rows: 1fr;
}
:root[data-theme-version] .m-chart {
  /* The grid stretches the cards to a common height; making each one a column with the plot
     allowed to grow is what stops the taller card's content floating and the shorter card's
     content stranding a gap at the bottom. */
  display: flex;
  flex-direction: column;
  /* A container query, because the thing that decides the donut's layout is how wide THIS PANEL is,
     not how wide the viewport is — and the two disagree by ~180px between the generations, since
     v2 spends that on its sidebar. A viewport media query would have to encode the sidebar width
     twice and would still be wrong at any other window size. */
  container-type: inline-size;
}
/* ⚠ Below ~330px the ring and the legend cannot share a row without truncating the labels — and
   these labels are not optional decoration: they are the relief channel that discharges the
   palette's light-mode contrast WARN, so "Unit Fr…" is a real defect, not a cosmetic one. Stacking
   gives the label the panel's full width. v1's panels are ~349px and stay side by side; v2's are
   ~298px and stack. */
@container (max-width: 330px) {
  :root[data-theme-version] .m-chart-donut-wrap {
    align-items: center;
    flex-direction: column;
  }
  :root[data-theme-version] .m-chart-donut-wrap .m-chart-legend { width: 100%; }
}
/* ⚠ A fixed two-line description block, so every panel's PLOT starts on the same line. Without it
   a one-line description and a two-line one push their plots 18px apart, and a row of charts whose
   baselines disagree reads as sloppy even when the cards themselves align. */
:root[data-theme-version] .m-chart-sub {
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  display: -webkit-box;
  min-height: 2.9em;
  overflow: hidden;

  color: var(--bw-faint);
  font-size: var(--bw-text-sm);
  line-height: 1.45;
  margin: 0;
  padding: 0 var(--bw-pad) 2px;
}
:root[data-theme-version] .m-chart-link { color: inherit; text-decoration: none; }
:root[data-theme-version] .m-chart-link:hover { color: var(--bw-link); }

/* A <dl> laid out as label / bar+value rows. */
:root[data-theme-version] .m-chart-bars {
  display: grid;
  grid-template-columns: minmax(84px, 34%) 1fr;
  align-items: center;
  column-gap: 10px;
  row-gap: 8px;
  margin: 0;
  padding: 4px var(--bw-pad) var(--bw-pad);
}
:root[data-theme-version] .m-chart-label {
  color: var(--bw-muted);
  font-size: var(--bw-text-sm);
  font-weight: 500;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
:root[data-theme-version] .m-chart-value {
  align-items: center;
  display: flex;
  gap: 8px;
  margin: 0;
}
/* The track is the unfilled remainder, one step off the surface — recessive, like a gridline. */
:root[data-theme-version] .m-chart-track {
  background-color: var(--bw-chart-track);
  border-radius: 0 var(--bw-radius-sm) var(--bw-radius-sm) 0;
  flex: 1 1 auto;
  height: 14px;
  overflow: hidden;
}
/* ⚠ Rounded at the DATA end only, square at the baseline — a bar rounded at both ends reads as a
   floating pill and loses the shared zero the comparison depends on. Capped well under the 24px
   ceiling: these are small multiples in a card, not hero bars. */
:root[data-theme-version] .m-chart-bar {
  background-color: var(--bw-chart-mark);
  border-radius: 0 var(--bw-radius-sm) var(--bw-radius-sm) 0;
  display: block;
  height: 100%;
  min-width: 3px;
}
/* ⚠ Values wear a TEXT token, never the mark colour: in dark mode --bw-chart-mark is a light
   tint that is fine as a fill and illegible as small text. The bar beside it carries the colour. */
:root[data-theme-version] .m-chart-num {
  color: var(--bw-text);
  flex: 0 0 auto;
  font-family: var(--bw-font-mono);
  font-size: var(--bw-text-sm);
  font-variant-numeric: tabular-nums;
  min-width: 2.5ch;
  text-align: right;
}
/* ---- COLUMN: the same single-hue magnitude comparison, stood up ----
   ⚠ Rounded at the data end only, which for a column is the TOP — square at the baseline, same
   reason as the bar: rounding both ends floats the mark off the shared zero. */
:root[data-theme-version] .m-chart-cols {
  align-items: end;
  display: flex;
  gap: 10px;
  height: 132px;
  padding: 8px var(--bw-pad) 0;
}
:root[data-theme-version] .m-chart-col {
  align-items: center;
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  gap: 4px;
  height: 100%;
  justify-content: flex-end;
  min-width: 0;
}
:root[data-theme-version] .m-chart-col-num {
  color: var(--bw-text);
  font-family: var(--bw-font-mono);
  font-size: var(--bw-text-sm);
  font-variant-numeric: tabular-nums;
}
:root[data-theme-version] .m-chart-col-bar {
  background-color: var(--bw-chart-mark);
  border-radius: var(--bw-radius-sm) var(--bw-radius-sm) 0 0;
  min-height: 3px;
  width: 100%;
  max-width: 24px;   /* the mark cap — never fill the slot, let the band's leftover be air */
}
:root[data-theme-version] .m-chart-col-label {
  color: var(--bw-muted);
  font-size: var(--bw-text-sm);
  max-width: 100%;
  overflow: hidden;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- DONUT: part-to-whole at a glance ----
   ⚠ A conic-gradient on a div, not SVG and not a library. The 2px separators are drawn as hard
   stops in the SURFACE colour — the guidance's "white doing the separating" — rather than a stroke
   around each segment, which would add ink that is not data. The hole is a centred surface-coloured
   disc, so it inherits the card and needs no per-theme rule. */
:root[data-theme-version] .m-chart-donut-wrap {
  align-items: center;
  display: flex;
  gap: 18px;
  padding: 4px var(--bw-pad) var(--bw-pad);
}
:root[data-theme-version] .m-chart-donut {
  border-radius: 50%;
  flex: 0 0 auto;
  height: 118px;
  position: relative;
  width: 118px;
}
:root[data-theme-version] .m-chart-donut::after {
  background-color: var(--bw-surface);
  border-radius: 50%;
  content: "";
  inset: 26px;
  position: absolute;
}

/* ---- STACKED BAR: part-to-whole in one row ---- */
:root[data-theme-version] .m-chart-stack {
  border-radius: var(--bw-radius-sm);
  display: flex;
  gap: 2px;                /* the surface gap, same 2px as the donut's separators */
  height: 18px;
  margin: 6px var(--bw-pad) 0;
  overflow: hidden;
}
:root[data-theme-version] .m-chart-stack-seg { min-width: 3px; }

/* ---- the legend the categorical forms MUST carry ----
   ⚠ Not decoration and not optional. Three of the six light slots sit below 3:1 on white, and the
   validator's contrast WARN is discharged by visible labels — so this is the relief channel, which
   also means identity is never colour-alone. Values live here too, so nothing is gated behind a
   hover. A swatch beside text, never coloured text: a light categorical hue is illegible as type. */
:root[data-theme-version] .m-chart-legend {
  /* ⚠ align-content: start, or the rows DISTRIBUTE. The cards are stretched to a common height and
     this grid grows with them, so without it a three-row legend in a tall card spread its rows to
     the corners with a void between them — which reads as a rendering fault, not as spacing. The
     spare height pools at the bottom of every panel instead, which is what makes the row look
     deliberate. Same reason .m-chart-bars sets it. */
  align-content: start;
  display: grid;
  flex: 1 1 auto;
  gap: 5px;
  grid-template-columns: 1fr;
  margin: 0;
  min-width: 0;
  padding: 0;
}
:root[data-theme-version] .m-chart-stack + .m-chart-legend { padding: 10px var(--bw-pad) var(--bw-pad); }
:root[data-theme-version] .m-chart-legend-item {
  align-items: baseline;
  display: flex;
  gap: 7px;
  list-style: none;
  min-width: 0;
}
:root[data-theme-version] .m-chart-swatch {
  border-radius: 2px;
  flex: 0 0 auto;
  height: 9px;
  position: relative;
  top: 1px;
  width: 9px;
}
:root[data-theme-version] .m-chart-legend-label {
  color: var(--bw-muted);
  flex: 1 1 auto;
  font-size: var(--bw-text-sm);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
:root[data-theme-version] .m-chart-legend-num {
  color: var(--bw-text);
  flex: 0 0 auto;
  font-family: var(--bw-font-mono);
  font-size: var(--bw-text-sm);
  font-variant-numeric: tabular-nums;
}
:root[data-theme-version] .m-chart-legend-share {
  color: var(--bw-faint);
  flex: 0 0 auto;
  font-family: var(--bw-font-mono);
  font-size: var(--bw-text-sm);
  font-variant-numeric: tabular-nums;
  min-width: 4ch;
  text-align: right;
}

/* Every plot area grows into the card's spare height, so a stretched card does not leave its
   content clinging to the top. */
:root[data-theme-version] .m-chart-bars,
:root[data-theme-version] .m-chart-cols,
:root[data-theme-version] .m-chart-donut-wrap { flex: 1 1 auto; }
:root[data-theme-version] .m-chart-bars { align-content: start; }

/* One class is a figure, not a chart — a single full-width bar would imply a comparison that is
   not there. */
:root[data-theme-version] .m-chart-single {
  align-items: center;
  display: flex;
  /* Centred in the leftover height rather than pinned under the description — a single figure in a
     card stretched to match three charts beside it otherwise reads as a panel that failed to load. */
  flex: 1 1 auto;
  gap: 8px;
  padding: 2px var(--bw-pad) var(--bw-pad);
}
:root[data-theme-version] .m-chart-single-value {
  color: var(--bw-text-strong);
  font-family: var(--bw-font-mono);
  font-size: 30px;
  font-weight: 600;
  line-height: 1.1;
}
:root[data-theme-version] .m-chart-single-label {
  color: var(--bw-muted);
  font-size: var(--bw-text-sm);
}

/* ---- drag-to-reorder affordance for the dashboard tiles ----
   ⚠ Applied via .m-reorderable, which the script adds only after the server said this viewer may
   save — so a read-only viewer gets no grab cursor and no promise it cannot keep. */
:root[data-theme-version] .m-reorderable > * { cursor: grab; }
:root[data-theme-version] .m-reorderable > *:active { cursor: grabbing; }
/* The tile being carried recedes rather than disappearing, so the gap it will leave stays legible. */
:root[data-theme-version] .m-drag-src { opacity: .4; }
/* The drop target is marked with an INSET ring, not a border: a border would change the tile's box
   and shove its neighbours mid-drag, which reads as the layout breaking under the cursor. */
:root[data-theme-version] .m-drag-over {
  box-shadow: inset 0 0 0 2px var(--bw-link);
  background-color: var(--bw-primary-soft);
}

:root[data-theme-version] .m-modules {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}
:root[data-theme-version] .m-module {
  border-bottom: 1px solid var(--bw-rule);
  border-right: 1px solid var(--bw-rule);
  color: var(--bw-text);
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px var(--bw-gap);
}
:root[data-theme-version] .m-module:hover { background-color: var(--bw-hover-bg); color: var(--bw-text); }
:root[data-theme-version] .m-module-name {
  align-items: center;
  color: var(--bw-text-strong);
  display: flex;
  font-size: var(--bw-text-base);
  font-weight: 600;
  gap: 8px;
  letter-spacing: -.01em;
}
:root[data-theme-version] .m-module-name .fa { color: var(--bw-link); font-size: 14px; width: 16px; }
:root[data-theme-version] .m-module-sub { color: var(--bw-faint); font-size: var(--bw-text-xs); line-height: 1.4; }

/* ---- work queue ---- */
:root[data-theme-version] .m-queue { display: flex; flex-direction: column; }
:root[data-theme-version] .m-queue-item {
  align-items: center;
  border-bottom: 1px solid var(--bw-row-line);
  color: var(--bw-text);
  display: flex;
  gap: 11px;
  padding: 11px var(--bw-pad);
}
:root[data-theme-version] .m-queue-item:hover { background-color: var(--bw-hover-bg); color: var(--bw-text); }
:root[data-theme-version] .m-queue-tone { align-self: stretch; border-radius: 2px; flex: 0 0 3px; }
:root[data-theme-version] .m-queue-tone-warn   { background-color: var(--bw-accent); }
:root[data-theme-version] .m-queue-tone-danger { background-color: var(--bw-danger); }
:root[data-theme-version] .m-queue-tone-info   { background-color: var(--bw-primary); }
:root[data-theme-version] .m-queue-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 auto; }
:root[data-theme-version] .m-queue-title { color: var(--bw-text-strong); font-size: var(--bw-text-base); font-weight: 600; line-height: 1.3; }
:root[data-theme-version] .m-queue-meta { color: var(--bw-faint); font-size: var(--bw-text-xs); }
:root[data-theme-version] .m-queue-value {
  color: var(--bw-text);
  font-family: var(--bw-font-mono);
  font-size: var(--bw-text-sm);
  font-weight: 600;
  white-space: nowrap;
}
:root[data-theme-version] .m-queue-empty { color: var(--bw-faint); font-size: var(--bw-text-base); padding: 24px var(--bw-pad); }

/* ---- v2's queue row: a TAG and an ACTION, not a colour bar and a count ----
   v1 ends each row with the number that made it interesting; v2's doc labels the row
   with a tag pill and ends it with what you can do about it. Only v2 renders this
   markup (see DashboardIndex), so the classes need no version scoping. */
:root[data-theme-version] .m-queue-tag {
  border-radius: var(--bw-pill);
  flex: none;
  font-size: var(--bw-text-xs);
  font-weight: 600;
  letter-spacing: .02em;
  padding: 3px 9px;
  text-transform: capitalize;
}
:root[data-theme-version] .m-queue-tag.m-queue-tone-warn {
  background-color: var(--bw-warning-bg);
  color: var(--bw-warning);
}
:root[data-theme-version] .m-queue-tag.m-queue-tone-danger {
  background-color: var(--bw-danger-bg);
  color: var(--bw-danger-ink);
}
:root[data-theme-version] .m-queue-tag.m-queue-tone-info {
  background-color: var(--bw-primary-soft);
  color: var(--bw-link);
}
:root[data-theme-version] .m-queue-action {
  color: var(--bw-link);
  flex: none;
  font-size: var(--bw-text-sm);
  font-weight: 600;
  white-space: nowrap;
}
:root[data-theme-version] .m-queue-item:hover .m-queue-action { text-decoration: underline; }

/* ---- v2's Quick actions panel ---- */
/* ⚠ A GRID, not a single column. The handoff draws Quick actions with four entries, and a column
   was right for four — but the list is the dashboard's card set now, which is a dozen. In one
   column that made this panel 517px tall beside a "Needs attention" card of 108px: a 5:1 mismatch
   that read as a broken layout even though both cards were correct in themselves. Two columns at
   this panel's width halves the height and the row balances.
   auto-fit with a floor rather than a fixed 2, so the panel still collapses to one column when the
   layout narrows instead of squeezing two unreadable ones. */
:root[data-theme-version] .m-quick {
  display: grid;
  gap: 2px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  padding: 6px;
}
:root[data-theme-version] .m-quick-item {
  align-items: center;
  border-radius: var(--bw-radius-sm);
  color: var(--bw-text);
  display: flex;
  font-size: var(--bw-text-base);
  gap: 11px;
  padding: 9px 10px;
  text-decoration: none;
}
:root[data-theme-version] .m-quick-item i { color: var(--bw-faint); width: 16px; }
:root[data-theme-version] .m-quick-item:hover {
  background-color: var(--bw-hover-bg);
  color: var(--bw-link);
  text-decoration: none;
}
:root[data-theme-version] .m-quick-item:hover i { color: var(--bw-link); }

/* ---- fact list (environment panel) ---- */
:root[data-theme-version] .m-facts { display: flex; flex-direction: column; }
:root[data-theme-version] .m-fact {
  align-items: baseline;
  border-bottom: 1px solid var(--bw-row-line);
  display: flex;
  gap: var(--bw-gap);
  justify-content: space-between;
  padding: 10px var(--bw-pad);
}
:root[data-theme-version] .m-fact:last-child { border-bottom: 0; }
:root[data-theme-version] .m-fact-key { color: var(--bw-muted); font-size: var(--bw-text-sm); }
:root[data-theme-version] .m-fact-val {
  color: var(--bw-text-strong);
  font-family: var(--bw-font-mono);
  font-size: var(--bw-text-sm);
  font-weight: 500;
  text-align: right;
}
