/* ============================================================================
   dashboard-common.css — the ONE set of tokens and parts shared by every
   dashboard and report screen (2026-09-03 visual audit).

   Before this file each screen carried its own :root block (three copies of
   the indigo tokens), six KPI-tile designs, five card-header designs, seven
   timestamp formats and ~300 hex literals. Everything here is additive and
   namespaced `dq-` so it cannot collide with Bootstrap or the legacy shell.

   Tokens: legacy default is the brand navy/blue the city-hall dashboard and
   the daily report already used (the two best-designed pages). Under
   body.theme-v2 the same names re-point to the --eq-* palette, so the theme
   toggle flips every dashboard at once. Charts read these tokens at runtime
   through dq-charts.js — never hardcode a chart colour in a template.
   ========================================================================== */

:root {
  --dq-ink:#0f2740;         /* headings, primary numerals */
  --dq-text:#2f3f52;        /* body copy */
  --dq-muted:#5b6b7d;       /* secondary text — 5.6:1 on white; never lighter than this for words */
  --dq-faint:#94a3b8;       /* decorative only: dots, dividers, placeholders */
  --dq-surface:#ffffff;
  --dq-ground:#f4f6f9;
  --dq-line:#e4eaf1;
  --dq-accent:#1d4ed8;      /* one accent. Meaning comes from the semantic set below, not from hue. */
  --dq-accent-2:#3b82f6;    /* lighter accent for fills / second series */
  --dq-accent-soft:#e8effc;
  --dq-good:#067647;  --dq-good-soft:#e6f4ec;
  --dq-warn:#b54708;  --dq-warn-soft:#fef1e2;
  --dq-bad:#b42318;   --dq-bad-soft:#fdecea;
  --dq-radius:12px;
  --dq-shadow:0 1px 3px rgba(15,39,64,.06);
  --dq-shadow-hover:0 4px 14px rgba(15,39,64,.10);
  /* Categorical palette for nominal series (roles, towns, buildings). Ten
     hues that stay distinct for common colour-vision deficiencies; grey is
     reserved for "Other". Sequential/ordinal data (grades) uses --dq-seq-*. */
  --dq-cat-1:#1d4ed8; --dq-cat-2:#0e9f6e; --dq-cat-3:#d97706; --dq-cat-4:#7c3aed;
  --dq-cat-5:#db2777; --dq-cat-6:#0891b2; --dq-cat-7:#65a30d; --dq-cat-8:#9f1239;
  --dq-cat-9:#4b5563; --dq-cat-10:#b45309;
  --dq-seq-1:#dbeafe; --dq-seq-2:#93c5fd; --dq-seq-3:#3b82f6; --dq-seq-4:#1d4ed8; --dq-seq-5:#1e3a8a;
}
body.theme-v2 {
  --dq-ink:var(--eq-ink); --dq-text:var(--eq-text); --dq-muted:var(--eq-muted);
  --dq-surface:var(--eq-surface); --dq-line:var(--eq-line);
  --dq-accent:var(--eq-blue-dp); --dq-accent-2:var(--eq-blue);
  --dq-good:var(--eq-emerald);
  --dq-radius:var(--eq-radius); --dq-shadow:var(--eq-shadow); --dq-shadow-hover:var(--eq-shadow-hover);
}

/* ---- Page frame ---------------------------------------------------------- */
.dq-page { max-width:1440px; margin:0 auto; }
.dq-head { display:flex; align-items:flex-end; justify-content:space-between; flex-wrap:wrap; gap:.75rem 1rem; margin:0 0 1.25rem; }
.dq-title { font-size:1.5rem; font-weight:700; color:var(--dq-ink); margin:0; line-height:1.2; }
.dq-sub { font-size:.85rem; color:var(--dq-muted); margin:.15rem 0 0; }
.dq-section { font-size:1.1rem; font-weight:700; color:var(--dq-ink); margin:1.75rem 0 .75rem; }
.dq-actions { display:flex; gap:.5rem; flex-wrap:wrap; align-items:center; }

/* ---- KPI tile: label / value / note, one optional accent rule ------------- */
.dq-tiles { display:grid; grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); gap:1rem; margin:0 0 1.25rem; }
.dq-tile { background:var(--dq-surface); border:1px solid var(--dq-line); border-radius:var(--dq-radius);
  padding:1rem 1.15rem; box-shadow:var(--dq-shadow); min-width:0; text-decoration:none; color:inherit; display:block; }
a.dq-tile:hover, a.dq-tile:focus-visible { box-shadow:var(--dq-shadow-hover); color:inherit; text-decoration:none; }
.dq-tile .k { font-size:.72rem; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--dq-muted); }
.dq-tile .v { font-size:2rem; font-weight:700; color:var(--dq-ink); line-height:1.15; margin-top:.3rem;
  font-variant-numeric:tabular-nums; }
.dq-tile .n { font-size:.78rem; color:var(--dq-muted); margin-top:.2rem; }
.dq-tile.accent { border-left:4px solid var(--dq-accent); }
.dq-tile.good { border-left:4px solid var(--dq-good); }  .dq-tile.good .v { color:var(--dq-good); }
.dq-tile.warn { border-left:4px solid var(--dq-warn); }  .dq-tile.warn .v { color:var(--dq-warn); }
.dq-tile.bad  { border-left:4px solid var(--dq-bad); }   .dq-tile.bad .v  { color:var(--dq-bad); }
.dq-tile .delta { font-size:.78rem; font-weight:600; }
.dq-tile .delta.up { color:var(--dq-good); } .dq-tile .delta.down { color:var(--dq-bad); }

/* ---- Card with a white header ------------------------------------------- */
.dq-card { background:var(--dq-surface); border:1px solid var(--dq-line); border-radius:var(--dq-radius);
  box-shadow:var(--dq-shadow); display:flex; flex-direction:column; min-width:0; }
.dq-card-head { display:flex; align-items:center; justify-content:space-between; gap:.75rem;
  padding:.9rem 1.15rem; border-bottom:1px solid var(--dq-line); }
.dq-card-head h3, .dq-card-title { font-size:.95rem; font-weight:700; color:var(--dq-ink); margin:0; }
.dq-card-hint { font-size:.78rem; color:var(--dq-muted); margin:.1rem 0 0; }
.dq-card-body { padding:1rem 1.15rem; flex:1; min-height:0; }
.dq-card-foot { display:flex; justify-content:space-between; gap:.75rem; padding:.6rem 1.15rem;
  border-top:1px solid var(--dq-line); font-size:.75rem; color:var(--dq-muted); }
.dq-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(min(420px, 100%), 1fr)); gap:1.25rem; }
.dq-grid > .wide { grid-column:1 / -1; }
.dq-chart { position:relative; height:260px; }            /* the ONLY place a chart height is set */
.dq-chart.tall { height:340px; }
.dq-chart.short { height:180px; }
.dq-chart canvas { display:block; }  /* main.css:267 hides every canvas until Chart.js runs; class specificity undoes that here */

/* Icon-only buttons in card headers: always visible, real focus ring. */
.dq-iconbtn { width:2rem; height:2rem; display:inline-flex; align-items:center; justify-content:center;
  border:1px solid var(--dq-line); border-radius:8px; background:var(--dq-surface); color:var(--dq-muted); cursor:pointer; }
.dq-iconbtn:hover, .dq-iconbtn:focus-visible { color:var(--dq-accent); border-color:var(--dq-accent); outline:none; }

/* ---- Status pill: text + colour, never colour alone ----------------------- */
.dq-pill { display:inline-flex; align-items:center; gap:.35rem; font-size:.72rem; font-weight:600;
  padding:.15rem .55rem; border-radius:999px; white-space:nowrap; line-height:1.4;
  background:var(--dq-accent-soft); color:var(--dq-accent); }
.dq-pill.good { background:var(--dq-good-soft); color:var(--dq-good); }
.dq-pill.warn { background:var(--dq-warn-soft); color:var(--dq-warn); }
.dq-pill.bad  { background:var(--dq-bad-soft);  color:var(--dq-bad); }
.dq-pill.muted { background:#eef1f5; color:var(--dq-muted); }
.dq-pill.live::before { content:""; width:.45rem; height:.45rem; border-radius:50%; background:currentColor; }

/* ---- Empty / loading states (use the empty_state macro) ------------------- */
.dq-empty { display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
  gap:.35rem; padding:2rem 1rem; color:var(--dq-muted); min-height:160px; margin:auto; }
.dq-empty i { font-size:1.6rem; color:var(--dq-faint); margin-bottom:.25rem; }
.dq-empty .t { font-size:.95rem; font-weight:600; color:var(--dq-text); }
.dq-empty .d { font-size:.82rem; max-width:34ch; }
.dq-empty a.btn { margin-top:.5rem; }
.dq-skeleton { display:block; height:1em; border-radius:6px; background:linear-gradient(90deg, #eef1f5 25%, #f6f8fa 50%, #eef1f5 75%);
  background-size:200% 100%; animation:dq-shimmer 1.4s infinite; }
@keyframes dq-shimmer { from { background-position:200% 0; } to { background-position:-200% 0; } }

/* ---- Tables -------------------------------------------------------------- */
.dq-table { width:100%; border-collapse:separate; border-spacing:0; font-size:.875rem; }
.dq-table th { position:sticky; top:0; z-index:1; background:var(--dq-surface);
  font-size:.7rem; letter-spacing:.06em; text-transform:uppercase; color:var(--dq-muted); font-weight:600;
  text-align:left; padding:.6rem .75rem; border-bottom:1px solid var(--dq-line); }
.dq-table td { padding:.65rem .75rem; border-bottom:1px solid var(--dq-line); vertical-align:middle; color:var(--dq-text); }
.dq-table tr:last-child td { border-bottom:0; }
.dq-table .num, .dq-table th.num { text-align:right; font-variant-numeric:tabular-nums; }
.dq-table .strong { font-weight:600; color:var(--dq-ink); }
.dq-table .muted { color:var(--dq-muted); font-size:.8rem; }
.dq-table .truncate { max-width:22ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dq-table .avatar { width:36px; height:36px; border-radius:50%; object-fit:cover; background:#eef1f5; }
.dq-table .avatar.initial { display:inline-flex; align-items:center; justify-content:center; font-weight:700; color:var(--dq-muted); }
.dq-scroll { overflow-x:auto; -webkit-overflow-scrolling:touch; }
/* DataTables draws sort glyphs on every th, sortable or not. */
.dq-table th.sorting_disabled::before, .dq-table th.sorting_disabled::after { display:none; }
.dq-table th.sorting { cursor:pointer; }
/* DataTables toolbar without the negative-gutter .row hack */
.dq-dt-top { display:flex; flex-wrap:wrap; align-items:center; gap:.5rem .75rem; margin-bottom:.75rem; }
.dq-dt-top .dataTables_filter { margin-left:auto; }
.dq-dt-bottom { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:.5rem; margin-top:.75rem; }

/* ---- Report result summary strip ------------------------------------------ */
.dq-summary { display:flex; flex-wrap:wrap; align-items:center; gap:.4rem .9rem; font-size:.85rem; color:var(--dq-text);
  padding:.65rem .9rem; margin:0 0 .9rem; background:var(--dq-ground); border:1px solid var(--dq-line); border-radius:8px; }
.dq-summary b { color:var(--dq-ink); font-variant-numeric:tabular-nums; }
.dq-summary .sep { color:var(--dq-faint); }

/* ---- Motion --------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .dq-skeleton { animation:none; }
  .dq-pill.live::before { animation:none; }
}

/* ---- Print: every report page, once --------------------------------------
   Before this block Ctrl+P printed the 220px sidebar over page 1 of every
   report. Hide chrome and controls, keep table headers on every page, never
   split a row. Pages with their own @page rules (the WeasyPrint PDFs) don't
   go through this stylesheet. */
@media print {
  .sidebar, .sidebar-nav, .scroll-to-top, .navbar, .breadcrumb, .dt-buttons, .dataTables_filter,
  .dataTables_length, .dataTables_paginate, .dataTables_info, .dq-actions, .dq-noprint, form.dq-filters,
  .building-selector-btn, #sidebarToggle { display:none !important; }
  .main-content { margin-left:0 !important; }
  .main-content .container-fluid, body:not(.theme-v2) .container-fluid { padding:0 !important; margin:0 !important; box-shadow:none !important; }
  body, body.fixed-nav, body.sticky-footer { background:#fff !important; }
  .dq-card, .dq-tile, .card { box-shadow:none !important; border-color:#cbd5e1 !important; break-inside:avoid; }
  .dq-table th { position:static; }
  thead { display:table-header-group; }
  tr { break-inside:avoid; page-break-inside:avoid; }
  a[href]::after { content:"" !important; }
}
