:root {
  /* Soft, low-contrast light palette — warm off-white ground, white cards,
     muted accents. Avoids pure #fff/#000 to keep long viewing sessions easy. */
  --bg: #f7f8fa;
  --surface: #ffffff;
  --surface-sunken: #f2f4f7;
  --border: #e4e8ed;
  --border-strong: #d3dae2;
  --text: #2c3742;
  --text-muted: #6b7885;
  --accent: #2563eb;
  --accent-soft: #eff4ff;

  /* Chart series — saturated and high-contrast against the light ground, reused
     across both charts so a colour means the same thing everywhere. Mirrored in
     CHART_COLORS in app.js. */
  --chart-1: #2563eb;
  --chart-2: #9333ea;
  --chart-3: #10b981;
  --chart-4: #dc2626;
  --tone-caution: #ea8c00;

  --shadow-sm: 0 1px 2px rgba(44, 55, 66, 0.04), 0 1px 3px rgba(44, 55, 66, 0.03);
  --shadow-md: 0 4px 16px rgba(44, 55, 66, 0.08);
  --radius: 12px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  font-size: 15px;
  line-height: 1.6;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 2rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.topbar h1 {
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}

.global-controls {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

/* Right side of the topbar: when the data was last refreshed. */
.topbar-meta {
  display: flex;
  align-items: center;
}

.data-as-of {
  font-size: 0.8rem;
  color: var(--text-muted);
  letter-spacing: 0.01em;
}

.data-as-of-key {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  margin-right: 0.35rem;
}

/* Kept: in-card selects (publish-status and window pickers) still use .control. */
.control {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.control select {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  padding: 0.4rem 0.6rem;
  font-family: inherit;
  font-size: 0.85rem;
  text-transform: none;
  letter-spacing: normal;
}

.tabs {
  display: flex;
  gap: 0.5rem;
  padding: 0 2rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}

.tab {
  background: none;
  border: none;
  color: var(--text-muted);
  padding: 0.85rem 0.5rem;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}

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

.tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

main {
  padding: 2rem;
  max-width: 1180px;
  margin: 0 auto;
}

.panel {
  display: none;
}

.panel.active {
  display: block;
}

.section-description {
  color: var(--text-muted);
  font-size: 0.9rem;
  max-width: 65ch;
  margin: 0 0 1.75rem;
}

.section-description strong {
  color: var(--text);
  font-weight: 600;
}

.kpi-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  margin-bottom: 1.75rem;
}

.kpi-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  box-shadow: var(--shadow-sm);
}

.kpi-value {
  font-size: 1.9rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.kpi-label {
  color: var(--text-muted);
  font-size: 0.8rem;
}

.kpi-sublabel {
  color: var(--text-muted);
  font-size: 0.72rem;
  line-height: 1.45;
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
}

.chart-row,
.table-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1rem;
  margin-bottom: 1.75rem;
}

.placeholder-block {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  /* Cards stack full width, so each one carries the gap to the next itself. */
  margin-bottom: 1.75rem;
  min-height: 140px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  box-shadow: var(--shadow-sm);
}

/* Not-yet-wired sections keep a dashed hint; real content uses a solid card. */
.placeholder-block .placeholder-body {
  color: var(--text-muted);
  font-size: 0.8rem;
  align-self: flex-end;
  font-style: italic;
}

.placeholder-block:has(.placeholder-body) {
  border-style: dashed;
  border-color: var(--border-strong);
  box-shadow: none;
  background: var(--surface-sunken);
}

.placeholder-title {
  font-size: 0.9rem;
  font-weight: 500;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

.data-table th,
.data-table td {
  text-align: right;
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--border);
}

.data-table th {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

.data-table tbody tr:hover {
  background: var(--surface-sunken);
}

/* Rows excluded from the charted trend (e.g. pre-launch cohorts) are de-emphasised
   but still shown, so the exclusion is visible rather than silent. */
.data-table tbody tr.row-muted td {
  color: var(--text-muted);
  font-style: italic;
}

.table-footnote em {
  font-style: normal;
  color: var(--text);
}

.data-table th:first-child,
.data-table td:first-child {
  text-align: left;
  white-space: nowrap;
}

.table-footnote {
  color: var(--text-muted);
  font-size: 0.75rem;
  margin: 0.85rem 0 0;
}

/* An insight panel stacked under a full-width table rather than beside it. Bullets go
   two-up so the text does not run to an uncomfortable line length. */
.insight-below {
  margin: 1rem 0 1.75rem;
}

.insight-below .insight-points {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 0.7rem 2rem;
}

/* Wide tables scroll inside their own container so the page body never scrolls sideways. */
.table-scroll {
  overflow-x: auto;
}

/* At day grain the creation-source table is 60 rows, which would push everything below it off
   the page. Give it its own viewport and keep the column names pinned while it scrolls. Only
   the second header row is sticky: the group band above it carries its tint on the cells
   themselves, so letting it scroll away loses nothing, and pinning both rows would need a
   hard-coded offset for the first row's height. */
.table-scroll-tall {
  max-height: 30rem;
  overflow-y: auto;
}

.table-scroll-tall thead tr:last-child th {
  position: sticky;
  top: 0;
  z-index: 2;
}

.table-scroll-tall thead tr:last-child .src-corner {
  background: var(--surface-sunken);
}

/* The Total row is the one summary a reader wants while scanning 60 daily rows, so pin it to
   the bottom of the viewport instead of burying it at the end of the scroll. The group tints
   already sit on these cells; only the row label needs a background of its own. */
.table-scroll-tall tbody .total-row td,
.table-scroll-tall tbody .total-row th {
  position: sticky;
  bottom: 0;
  z-index: 1;
}

.table-scroll-tall tbody .total-row .src-row-label {
  background: var(--surface-sunken);
}

/* Creation-source table: grouped column bands, tinted like the source spreadsheet so the
   three groups stay visually separable across 13 columns. Padding and font are tightened
   so all three groups fit without horizontal scrolling at desktop width. */
.src-table {
  min-width: 860px;
  font-size: 0.8rem;
}

.src-table th,
.src-table td {
  padding: 0.5rem 0.45rem;
}

.src-table thead th {
  font-size: 0.65rem;
  line-height: 1.3;
}

.src-group {
  text-align: center !important;
  font-size: 0.68rem !important;
  border-bottom: 2px solid var(--surface);
}

.src-corner {
  text-align: left !important;
  white-space: normal !important;
}

.src-row-label {
  text-align: left !important;
  font-size: 0.82rem !important;
  font-weight: 500;
  color: var(--text) !important;
  text-transform: none !important;
  letter-spacing: normal !important;
  white-space: nowrap;
}

.src-table .grp-a {
  background: #fdf8e7;
}

.src-table .grp-b {
  background: #eef5ec;
}

.src-table .grp-c {
  background: #eceffb;
}

/* Bold, separated grand-total row. */
.src-table tbody tr.total-row th,
.src-table tbody tr.total-row td {
  font-weight: 700;
  color: var(--text);
  border-top: 2px solid var(--border-strong);
}

.src-table tbody tr.total-row:hover {
  background: none;
}

.placeholder-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  /* Kept small because the canvas legend below carries its own row padding; a full
     1rem here stacked with that and left a visible gap under the heading. */
  margin-bottom: 0.5rem;
}

/* Chart.js needs a fixed-height parent once maintainAspectRatio is off. */
.chart-canvas-wrap {
  position: relative;
  flex: 1;
  min-height: 300px;
}

/* The card is a column flexbox with space-between, so a short host div would sink the
   chart to the bottom. Make the host grow and let the canvas take the slack instead. */
#trend-view {
  flex: 1;
  display: flex;
  flex-direction: column;
}

/* A .control living inside a card's title row rather than the topbar: horizontal, so it
   does not push the card heading taller than the row it shares. */
.inline-control {
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
}

.inline-control select {
  padding: 0.3rem 0.5rem;
  font-size: 0.8rem;
}

/* Chart on the left, its insight panel on the right. Collapses to stacked on
   narrow screens so the chart keeps usable width. */
.chart-with-insight .placeholder-block {
  margin-bottom: 0;
}

.chart-with-insight {
  display: grid;
  grid-template-columns: minmax(0, 1.85fr) minmax(250px, 1fr);
  gap: 1rem;
  margin-bottom: 1.75rem;
  align-items: stretch;
}

@media (max-width: 940px) {
  .chart-with-insight {
    grid-template-columns: 1fr;
  }
}

.insight-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--chart-1);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 1.25rem;
}

.insight-panel.tone-caution {
  border-left-color: var(--tone-caution);
}

.insight-panel.tone-positive {
  border-left-color: var(--chart-3);
}

.insight-eyebrow {
  display: block;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}

.insight-headline {
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -0.01em;
  margin: 0 0 0.85rem;
}

.insight-points {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}

.insight-points li {
  position: relative;
  padding-left: 0.9rem;
  font-size: 0.83rem;
  line-height: 1.55;
  color: var(--text-muted);
}

.insight-points li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--border-strong);
}

.insight-points strong {
  color: var(--text);
  font-weight: 600;
}

/* Caveat under a table whose columns do not sum the way a reader expects. */
.table-note {
  margin: 0.85rem 0 0;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-muted);
}

/* Two segmented controls side by side in one title row — the stacked chart carries
   Absolute/%Mix next to Day/Week/Month, and the source table Projects/Locations/Agencies next
   to it. Wraps rather than squeezing the card's heading on narrow screens. */
.toggle-cluster {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* A caveat under a chart whose reading changes with the selected grain. Same voice as
   .table-note, but it sits inside a flex card so it must not absorb the leftover space. */
.chart-note {
  flex: 0 0 auto;
  margin: 0.75rem 0 0;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-muted);
}

.chart-toggle {
  display: inline-flex;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 2px;
  gap: 2px;
}

.chart-toggle-btn {
  background: none;
  color: var(--text-muted);
  border: none;
  border-radius: 6px;
  padding: 0.3rem 0.75rem;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.chart-toggle-btn:hover:not(.active) {
  color: var(--text);
}

.chart-toggle-btn.active {
  background: var(--surface);
  color: var(--accent);
  box-shadow: var(--shadow-sm);
}

.table-details {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  margin-bottom: 1.75rem;
  overflow: hidden;
}

.table-details summary {
  cursor: pointer;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 500;
  padding: 0.9rem 1.25rem;
  list-style: none;
}

.table-details summary::-webkit-details-marker {
  display: none;
}

.table-details summary::before {
  content: '▸';
  display: inline-block;
  margin-right: 0.5rem;
  transition: transform 0.15s ease;
}

.table-details[open] summary::before {
  transform: rotate(90deg);
}

.table-details summary:hover {
  color: var(--text);
}

.table-details[open] summary {
  color: var(--text);
  border-bottom: 1px solid var(--border);
}

/* The table sits inside the <details> card, so it drops its own card chrome. */
.table-details .placeholder-block {
  border: none;
  border-radius: 0;
  box-shadow: none;
  background: none;
}

/* Inline variant of the topbar control, used for the in-card band picker. */
.control-inline {
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
}

  font-weight: 600;
}

.alt-controls {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
  margin-bottom: 0.85rem;
}

.alt-hint {
  font-size: 0.75rem;
  color: var(--text-muted);
}

.alt-hint strong {
  color: var(--text);
}

/* Floating explainer for chart legend items. Legends are canvas-drawn, so this is a
   single shared DOM element repositioned at the cursor by showLegendTip(). It must never
   capture the pointer, or hovering would flicker as the cursor enters the box. */
.legend-tip {
  position: fixed;
  z-index: 200;
  max-width: 320px;
  padding: 0.7rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 9px;
  box-shadow: var(--shadow-md);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.12s ease;
}

.legend-tip.open {
  opacity: 1;
  visibility: visible;
}

.legend-tip strong {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  margin-bottom: 0.25rem;
}

.legend-tip span {
  display: block;
  font-size: 0.76rem;
  line-height: 1.5;
  color: var(--text-muted);
}

.info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
  background: var(--surface);
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 0.7rem;
  font-style: italic;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.info-icon:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-soft);
}

/* Unit suffix on a numeric KPI — smaller and muted so the number still reads first. */
.kpi-unit {
  font-size: 0.5em;
  font-weight: 500;
  color: var(--text-muted);
  margin-left: 0.12em;
}

.kpi-label-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.3rem;
}

.summary-with-icon {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.info-modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(44, 55, 66, 0.32);
  backdrop-filter: blur(2px);
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  z-index: 100;
}

.info-modal-overlay.open {
  display: flex;
}

.info-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: 1.5rem;
  max-width: 760px;
  width: 100%;
  max-height: 82vh;
  overflow-y: auto;
}

.info-modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.6rem;
}

.info-modal-header h2 {
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}

.info-modal-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 1.4rem;
  cursor: pointer;
  line-height: 1;
  padding: 0;
}

.info-modal-close:hover {
  color: var(--text);
}

#info-modal-logic {
  color: var(--text-muted);
  font-size: 0.88rem;
  margin: 0 0 1.25rem;
}

.info-modal-sql-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.45rem;
}

.copy-sql-btn {
  background: var(--accent);
  color: #ffffff;
  border: none;
  border-radius: 7px;
  padding: 0.3rem 0.7rem;
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  cursor: pointer;
  transition: background 0.15s ease;
}

.copy-sql-btn:hover {
  background: #1d4fd0;
}

.copy-sql-btn.copied {
  background: var(--chart-3);
}

.info-modal-sql {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1rem;
  overflow-x: auto;
  font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
  font-size: 0.72rem;
  line-height: 1.6;
  color: var(--text);
  margin: 0;
  white-space: pre;
}
