/*
  Dashboard furniture: stat tiles, chart cards, tab strips and data tables.

  Hand-authored for the same reason as status.css -- workspace.css is a Tailwind
  build output and most of this markup is created at runtime by JavaScript, so a
  utility-class version would be purged.

  Two rules from the data-viz method are enforced here rather than left to each
  page: the chart surface is a token (the validator's contrast results are only
  meaningful against the surface the chart actually renders on), and every chart
  card has room for the table view that the light-mode contrast WARN obliges.
*/

:root {
  --viz-surface: #ffffff;
  --viz-plane: #f8fafc;
  --viz-ink: #0f172a;
  --viz-ink-strong: #020617;
  --viz-muted: #64748b;
  --viz-line: #e2e8f0;
  --viz-hairline: #eef1f5;
  --viz-good: #0ca30c;
  --viz-critical: #d03b3b;
}

[data-theme="midnight"] {
  --viz-surface: #141d33;
  --viz-plane: #10182b;
  --viz-ink: #e8edf7;
  --viz-ink-strong: #ffffff;
  --viz-muted: #94a3b8;
  --viz-line: rgba(148, 163, 184, 0.16);
  --viz-hairline: rgba(148, 163, 184, 0.1);
}

/* ------------------------------------------------------------- stat tiles */

/*
  The `hidden` attribute is only a USER-AGENT stylesheet rule, so any author
  `display` in this file outranks it without a specificity contest -- author
  beats UA. `.viz-empty { display: flex; min-height: 8rem }` did exactly that:
  every chart card carried an invisible 142px box below its chart, on the
  overview, billing and report pages alike, because the element was never
  actually hidden.

  Declared once, up front and with !important, so adding a new `display` rule
  further down this file can never quietly resurrect it.
*/
[class^="viz-"][hidden],
[class*=" viz-"][hidden] {
  display: none !important;
}

.viz-kpis {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

.viz-kpi {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  padding: 0.875rem 1rem;
  border: 1px solid var(--viz-line);
  border-radius: 0.625rem;
  background: var(--viz-surface);
}

.viz-kpi__label {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--viz-muted);
}

/*
  The icon chip. Tinted by tone so a row of tiles can be scanned by colour, but
  the label always says the same thing -- colour is never the only carrier.
*/
.viz-kpi__icon {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 0.375rem;
  background: #f1f5f9;
  color: #475569;
}

.viz-kpi__icon svg {
  width: 0.9375rem;
  height: 0.9375rem;
}

.viz-kpi__icon--blue {
  background: #eff6ff;
  color: #1d4ed8;
}

.viz-kpi__icon--green {
  background: #ecfdf5;
  color: #047857;
}

.viz-kpi__icon--amber {
  background: #fffbeb;
  color: #b45309;
}

.viz-kpi__icon--rose {
  background: #fff1f2;
  color: #be123c;
}

.viz-kpi__icon--violet {
  background: #f5f3ff;
  color: #6d28d9;
}

/* Proportional figures for the standalone number; tabular is for columns. */
.viz-kpi__value {
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--viz-ink-strong);
}

.viz-kpi__value--sm {
  font-size: 1.125rem;
}

.viz-kpi__sub {
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--viz-muted);
}

.viz-kpi__delta {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
}

/* A delta never rests on colour: the caller ships the arrow glyph too. */
.viz-kpi__delta--up {
  color: var(--viz-good);
}

.viz-kpi__delta--down {
  color: var(--viz-critical);
}

.viz-kpi__delta--flat {
  color: var(--viz-muted);
}

/* ------------------------------------------------------------ chart cards */

.viz-grid {
  display: grid;
  gap: 0.75rem;
}

.viz-grid--2 {
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}

.viz-grid--3 {
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.viz-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--viz-line);
  border-radius: 0.625rem;
  background: var(--viz-surface);
  overflow: hidden;
}

.viz-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.875rem 1rem 0.5rem;
}

.viz-card__title {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--viz-ink-strong);
}

.viz-card__note {
  margin: 0.1875rem 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--viz-muted);
}

.viz-card__body {
  position: relative;
  padding: 0.25rem 0.75rem 0.875rem;
}

/* Chart.js needs a sized parent; the canvas fills it. */
.viz-canvas-wrap {
  position: relative;
  height: 15rem;
}

.viz-canvas-wrap--tall {
  height: 19rem;
}

.viz-canvas-wrap--short {
  height: 11rem;
}

.viz-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 8rem;
  padding: 1rem;
  font-size: 0.8125rem;
  text-align: center;
  color: var(--viz-muted);
}

/* ------------------------------------------------------------ skeletons */

/*
  Loading placeholders shaped like the thing that will replace them: a KPI tile
  keeps its icon chip and number, a bar chart shows bars, a line chart shows a
  line. The point is that the page does not jump when the data lands -- the
  boxes are already the right size, so only their contents change.

  The sweep lives on the CONTAINER, not on each block. One animation per card
  instead of one per bar keeps a six-card page to six animated layers, and makes
  the highlight travel across the whole card as a single pass rather than each
  bar glinting independently.
*/
.viz-skel-shimmer {
  position: relative;
  overflow: hidden;
}

.viz-skel-shimmer::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.75), transparent);
  animation: viz-skel-sweep 1.5s ease-in-out infinite;
  pointer-events: none;
}

@keyframes viz-skel-sweep {
  100% {
    transform: translateX(100%);
  }
}

.viz-skel-block {
  display: block;
  border-radius: 0.25rem;
  background: #e7edf4;
}

/* The chart placeholder fills the same sized wrap the canvas would. */
.viz-skel-chart {
  display: flex;
  width: 100%;
  height: 100%;
  padding: 0.75rem 0.5rem;
}

/* Vertical bars sit on a shared baseline. */
.viz-skel-chart--bars {
  align-items: flex-end;
  gap: 0.5rem;
}

.viz-skel-chart--bars .viz-skel-block {
  flex: 1 1 0;
  border-radius: 0.25rem 0.25rem 0 0;
}

/* Horizontal bars: a short label stub, then the bar, like the real chart. */
.viz-skel-chart--hbars {
  flex-direction: column;
  justify-content: center;
  gap: 0.75rem;
}

.viz-skel-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}

.viz-skel-chart--stack {
  align-items: center;
}

.viz-skel-chart--stack .viz-skel-stack {
  display: flex;
  width: 100%;
  gap: 2px;
}

.viz-skel-chart--donut {
  align-items: center;
  justify-content: center;
}

/* A ring, not a disc: a doughnut placeholder that fills in solid reads as a
   pie and then visibly changes shape when the real chart arrives. */
.viz-skel-donut {
  width: 7rem;
  height: 7rem;
  border-radius: 9999px;
  border: 1.125rem solid #e7edf4;
  background: transparent;
}

.viz-skel-chart--line {
  align-items: stretch;
}

.viz-skel-chart--line svg {
  width: 100%;
  height: 100%;
  color: #e7edf4;
}

/* A list row: two stacked text lines with a right-aligned meta stub. */
/* Padding and row gap match the real list row (px-3 py-2.5, two text lines), so
   the list does not grow when the rows fill in. */
.viz-skel-listrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-height: 3.375rem;
  padding: 0.625rem 0.75rem;
  border: 1px solid var(--viz-line);
  border-radius: 0.375rem;
}

.viz-skel-listrow > div {
  display: grid;
  gap: 0.5rem;
}

@media (prefers-reduced-motion: reduce) {
  /* Remove the sweep entirely rather than slowing it: the grey blocks already
     say "loading", and a crawling highlight is worse than none. */
  .viz-skel-shimmer::after {
    display: none;
  }
}

/* -------------------------------------------------- the obligatory table */

/*
  The light-mode contrast check WARNs on palette slots 3-5, and that warning is
  not dismissable: a reader who cannot distinguish two marks must still be able
  to get the numbers. Every chart card therefore ships this, collapsed.
*/
.viz-table-toggle {
  align-self: flex-start;
  margin: 0 1rem 0.75rem;
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--viz-line);
  border-radius: 0.375rem;
  background: transparent;
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--viz-muted);
  cursor: pointer;
}

.viz-table-toggle:hover {
  color: var(--viz-ink);
}

.viz-table-wrap {
  margin: 0 1rem 0.875rem;
  max-height: 14rem;
  overflow: auto;
  border: 1px solid var(--viz-line);
  border-radius: 0.375rem;
}

.viz-table-wrap[hidden] {
  display: none;
}

.viz-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.75rem;
  /* Columns of figures have to line up. */
  font-variant-numeric: tabular-nums;
}

.viz-table th,
.viz-table td {
  padding: 0.375rem 0.625rem;
  text-align: left;
  border-bottom: 1px solid var(--viz-hairline);
}

.viz-table th {
  position: sticky;
  top: 0;
  background: var(--viz-plane);
  font-weight: 600;
  color: var(--viz-muted);
}

.viz-table td:last-child,
.viz-table th:last-child {
  text-align: right;
}

.viz-table__swatch {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  margin-right: 0.4375rem;
  border-radius: 9999px;
  vertical-align: baseline;
}

/* ------------------------------------------------------------------ tabs */

.viz-tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--viz-line);
  padding: 0 0.25rem;
  overflow-x: auto;
}

.viz-tab {
  position: relative;
  padding: 0.625rem 0.875rem;
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  font-size: 0.8125rem;
  font-weight: 600;
  white-space: nowrap;
  color: var(--viz-muted);
  cursor: pointer;
}

.viz-tab:hover {
  color: var(--viz-ink);
}

.viz-tab[aria-selected="true"] {
  border-bottom-color: #2563eb;
  color: var(--viz-ink-strong);
}

.viz-tab__count {
  margin-left: 0.375rem;
  padding: 0.0625rem 0.375rem;
  border-radius: 9999px;
  background: var(--viz-plane);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  color: var(--viz-muted);
}

.viz-tabpanel[hidden] {
  display: none;
}

/* --------------------------------------------------------------- insights */

.viz-insights {
  display: grid;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.viz-insight {
  display: flex;
  gap: 0.625rem;
  padding: 0.625rem 0.75rem;
  border: 1px solid var(--viz-line);
  border-left-width: 3px;
  border-radius: 0.375rem;
  background: var(--viz-surface);
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--viz-ink);
}

.viz-insight--good {
  border-left-color: var(--viz-good);
}

.viz-insight--watch {
  border-left-color: #fab219;
}

.viz-insight--risk {
  border-left-color: var(--viz-critical);
}

.viz-insight--info {
  border-left-color: #2a78d6;
}

.viz-insight__icon {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  margin-top: 0.125rem;
}

.viz-insight strong {
  color: var(--viz-ink-strong);
}
