/* ============================================================
   Blue Tees Usage — dashboard-only styles
   Loaded by index.html and game.html only. The shared chrome these sit
   inside is in assets/chrome.css.

   Card, KPI, panel and table styling still lives in each dashboard's own
   <style> block. Those are now on the design tokens — the legacy names are
   gone — but they have not been reworked into the shared components yet.
   ============================================================ */

/* ---------- Range controls ---------- */

.range-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.preset-group,
.gran-group {
  padding: 3px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  display: flex;
  gap: 2px;
}

.preset,
.gran-btn {
  min-width: 46px;
  height: 32px;
  padding: 0 12px;
  color: var(--text-secondary);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  font-family: inherit;
  font-size: 12px;
  font-weight: var(--weight-semibold);
  transition: var(--transition-color);
}

.preset:hover,
.gran-btn:hover {
  color: var(--text-primary);
}

.date-field {
  height: 34px;
  padding: 0 10px;
  color: var(--text-primary);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  font-size: 12.5px;
  font-weight: var(--weight-semibold);
  font-variant-numeric: var(--numeric);
  transition: var(--transition-color);
}

.date-field:hover {
  border-color: var(--border-strong);
}

.date-separator,
.period-label {
  color: var(--text-muted);
  font-size: 11.5px;
}

.period-label {
  white-space: nowrap;
}

/* Shown when the selected range contains no data. */
.empty-note {
  display: none;
  margin: 16px 0 0;
  padding: 14px 16px;
  border: 1px dashed var(--border-dashed);
  border-radius: var(--radius-lg);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: 13px;
}

body.no-data .empty-note { display: block; }

/* ---------- Delta pill ----------
   A period-over-period comparison has four outcomes, not two, and the two the
   old markup left as bare text were the ones that mattered most.

     .up        rose        positive tint, up arrow
     .down      fell        negative tint, down arrow
     .flat      no change   neutral tint, no arrow — NOT the positive tint,
                            which is what "+0.0%" used to get
     .withheld  refused     dashed outline, em dash. There is no comparable
                            prior period, so the product declines to compare
                            rather than printing a number that looks like one.
                            Dashed and muted, never empty: see CLAUDE.md on
                            comparing only equal MEASURED windows.

   The arrow is an inline SVG rather than a glyph so it inherits currentColor
   and cannot be dropped by a font fallback. It is aria-hidden — the sign is
   already in the number, and the tint is not the only cue. */
.delta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 3px var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-size: 11.5px;
  font-weight: var(--weight-bold);
  line-height: 1.35;
  font-variant-numeric: var(--numeric);
  white-space: nowrap;
}

.delta svg {
  width: 12px;
  height: 12px;
  flex: 0 0 12px;
}

.delta.up {
  background: var(--positive-soft);
  color: var(--positive);
}

.delta.down {
  background: var(--negative-soft);
  color: var(--negative);
}

.delta.flat {
  background: var(--surface-sunken);
  color: var(--text-secondary);
}

.delta.withheld {
  background: var(--withheld-soft);
  color: var(--withheld);
  border-color: var(--withheld-border);
  border-style: dashed;
}

.delta.withheld .dash {
  font-weight: var(--weight-black);
  letter-spacing: .06em;
}

.icon-button svg {
  width: 16px;
  height: 16px;
}

/* ---------- Coverage pill ----------
   How much data stands behind the page, beside the page title. Shared by both
   dashboards, so it lives here rather than being duplicated in each.

   It is NOT the selected range (.period-label carries that) and NOT the rail
   note, which states the internal-user exclusion and the day boundary.

   It has to survive the 980px collapse: below that width the rail is gone and
   .title-wrap's heading is hidden, so this is the only thing left saying how
   much data there is. That is also why it wraps rather than truncating — an
   ellipsis here would cut a date in half and make the statement useless. The
   dates themselves are NBSP-joined in JS so a break can only land between the
   count and the span, never inside a date. */
.coverage-pill {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  row-gap: 2px;
  max-width: 100%;
  min-width: 0;
  padding: 4px var(--space-5);
  border-radius: var(--radius-pill);
  background: var(--positive-soft);
  color: var(--positive);
  font-size: 11px;
  font-weight: var(--weight-bold);
  font-variant-numeric: var(--numeric);
}

.coverage-pill .status-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 6px;
}

/* Title and pill share a line and wrap together when the topbar is tight. */
.title-row {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  flex-wrap: wrap;
  min-width: 0;
}

/* ---------- Sortable table headers ----------
   .sortable and the arrow are added by wireSortableHeaders() in format.js, not
   written into the markup, so a page whose JS failed shows a plain readable
   table rather than controls that do nothing. */
.sortable {
  cursor: pointer;
  user-select: none;
  transition: var(--transition-color);
}

.sortable:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}

.sortable.sorted {
  color: var(--text-primary);
}

.sort-arrow {
  display: inline-block;
  width: 9px;
  margin-left: var(--space-2);
  font-weight: var(--weight-black);
}

/* The arrow occupies its 9px whether or not a column is the sorted one, so the
   header row does not reflow as sorting moves between columns. */
.sortable:not(.sorted) .sort-arrow {
  opacity: 0;
}

.sortable:hover:not(.sorted) .sort-arrow {
  opacity: .45;
}

.sortable:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: calc(var(--focus-ring-offset-width) * -1);
}

/* ---------- Proportion bar ----------
   A two-or-three way split of one whole, as a single bar rather than a
   doughnut. Used for outdoor/indoor sessions on LAUNCH and for interaction
   source and mobile platform on GAME.

   Why not a doughnut: comparing two arc lengths is guesswork, and a doughnut
   spends a whole panel of height saying what one 30px bar says exactly. The
   legend carries the numbers, so the reader never has to estimate.

   The bar itself is aria-hidden and the legend is real text — the legend is
   the accessible representation, not a caption for a picture.

   It is plain CSS, so unlike the canvas it replaced it re-themes on its own
   and needs no repaint on btg:themechange. */
/* Sits where a .chart-box did, so the panel keeps its internal rhythm. */
.proportion-box {
  padding: var(--space-8) var(--space-9) var(--space-9);
}

.proportion-bar {
  display: flex;
  gap: 2px;
  height: 30px;
  margin: var(--space-5) 0 var(--space-6);
  border-radius: 9px;
  overflow: hidden;
  background: var(--surface-sunken);
}

/* Width is the true share, so bar length matches the printed percentage.
   min-width keeps a sub-1% segment visible rather than collapsing it to
   nothing — these splits never contain a genuine zero. */
.proportion-bar > span {
  min-width: 3px;
  border-radius: 3px;
  transition: flex-basis var(--duration-base) var(--ease-out);
}

.proportion-bar > span:first-child {
  border-radius: 9px 3px 3px 9px;
}

.proportion-bar > span:last-child {
  border-radius: 3px 9px 9px 3px;
}

.proportion-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-9);
}

.proportion-legend > span {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-3);
  font-size: 12px;
}

.proportion-legend .swatch {
  width: 9px;
  height: 9px;
  flex: 0 0 9px;
  border-radius: 3px;
  align-self: center;
}

.proportion-legend .label {
  color: var(--text-secondary);
  font-weight: var(--weight-semibold);
}

.proportion-legend .value {
  color: var(--text-primary);
  font-weight: var(--weight-bold);
  font-variant-numeric: var(--numeric);
}

/* ---------- Chart canvases ----------
   A <canvas> with no width/height attributes is 300x150 CSS px, and that is
   what every remaining chart is until Chart.js first renders it. At 320px the
   .chart-box content box is only ~270px wide, so each canvas overhung it by
   ~30px and pushed the document past the viewport — LAUNCH scrolled sideways
   by 5px, GAME by 1px (its boxes are a little wider at that width). That is
   worst on the signed-out gate, which is a fixed overlay with the whole
   un-rendered dashboard still laying out behind it, so the sideways scroll was
   on the one screen nobody has signed in to fix yet. The same gap opens again
   between load and the first render on a slow Firestore read.

   The .proportion-bar above is immune to all of this — it is plain CSS with no
   intrinsic size — so replacing a doughnut with one also removes it from this
   rule's reach. This still has to exist for the canvases that remain.

   Chart.js runs `responsive: true` on every chart here, so once it renders it
   sets the canvas style width from the container and this cap stops binding —
   measured identical with and without it at 320/375/720/980/1440 on both
   dashboards. It only ever bites pre-render. It lives here rather than in
   chrome.css because guide.html and methodology.html have no charts.

   `.chart-box canvas`, not a bare `canvas`, so an unrelated canvas added
   later is not silently resized by a rule about chart boxes. */
.chart-box canvas {
  max-width: 100%;
}
