/* ==========================================================================
   Towbook Job Acceptance Intelligence -- dashboard stylesheet
   ==========================================================================

   Audience: a business owner glancing at numbers, not a developer reading a
   debug tool. So: large primary figures, one accent colour per meaning, dense
   but airy tables, and rate colouring that is never the only signal.

   Colour roles come from a validated palette (light + dark are separately
   chosen steps, not an automatic inversion). Dark is the default because this
   screen gets looked at at 6am and at 11pm; a light theme is available via the
   OS setting or the header toggle, and the toggle wins both ways.

   Accessibility notes that are load-bearing, not decoration:
     * every rate cell carries a shape glyph (● ◆ ▼) as well as a colour, so
       good/warn/bad survives colourblindness and greyscale printing;
     * `—` is the universal "no data" mark and is never a zero;
     * focus rings are visible and never removed.
   ========================================================================== */

:root {
  color-scheme: dark;

  /* surfaces & ink */
  --plane:            #0d0d0d;
  --surface:          #1a1a19;
  --surface-2:        #212120;
  --surface-3:        #2a2a28;
  --text:             #ffffff;
  --text-2:           #c3c2b7;
  --muted:            #898781;
  --grid:             #2c2c2a;
  --baseline:         #383835;
  --border:           rgba(255, 255, 255, 0.10);
  --border-strong:    rgba(255, 255, 255, 0.18);

  /* categorical series (fixed order, never cycled) */
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #008300;
  --series-7: #9085e9;
  --series-8: #e66767;

  /* status (reserved -- never reused as a series colour) */
  --good:     #0ca30c;
  --warning:  #fab219;
  --serious:  #ec835a;
  --critical: #d03b3b;

  /* sequential blue ramp, 7 steps, for the heatmap */
  --seq-0: #cde2fb;
  --seq-1: #9ec5f4;
  --seq-2: #6da7ec;
  --seq-3: #3987e5;
  --seq-4: #256abf;
  --seq-5: #184f95;
  --seq-6: #0d366b;

  /* Map marker colours. Defined once: markers sit on basemap tiles, not on the
     themed app surface, so they read the same in dark and light. */
  --map-no-response:   #d03b3b;   /* nobody answered -- the big one */
  --map-declined:      #e07b1a;   /* we said no */
  --map-withdrew:      #7c8792;   /* client pulled it */
  --map-accept-failed: #9085e9;   /* we tried to accept and it failed */
  --map-light-ring:    #f2c94c;   /* gold ring == light service */

  --radius:    10px;
  --radius-sm: 6px;
  --shadow:    0 1px 2px rgba(0, 0, 0, 0.35);
  --mono: ui-monospace, "Cascadia Mono", "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --plane:         #f9f9f7;
    --surface:       #fcfcfb;
    --surface-2:     #f2f1ed;
    --surface-3:     #e8e7e2;
    --text:          #0b0b0b;
    --text-2:        #52514e;
    --muted:         #6f6d68;
    --grid:          #e1e0d9;
    --baseline:      #c3c2b7;
    --border:        rgba(11, 11, 11, 0.12);
    --border-strong: rgba(11, 11, 11, 0.22);

    --series-1: #2a78d6;
    --series-2: #eb6834;
    --series-3: #1baf7a;
    --series-4: #eda100;
    --series-5: #e87ba4;
    --series-6: #008300;
    --series-7: #4a3aa7;
    --series-8: #e34948;

    --good:     #006300;
    --warning:  #b07a00;
    --serious:  #c05a2a;
    --critical: #c02c2c;

    --shadow: 0 1px 2px rgba(11, 11, 11, 0.08);
  }
}

:root[data-theme="light"] {
  color-scheme: light;
  --plane:         #f9f9f7;
  --surface:       #fcfcfb;
  --surface-2:     #f2f1ed;
  --surface-3:     #e8e7e2;
  --text:          #0b0b0b;
  --text-2:        #52514e;
  --muted:         #6f6d68;
  --grid:          #e1e0d9;
  --baseline:      #c3c2b7;
  --border:        rgba(11, 11, 11, 0.12);
  --border-strong: rgba(11, 11, 11, 0.22);

  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --series-4: #eda100;
  --series-5: #e87ba4;
  --series-6: #008300;
  --series-7: #4a3aa7;
  --series-8: #e34948;

  --good:     #006300;
  --warning:  #b07a00;
  --serious:  #c05a2a;
  --critical: #c02c2c;

  --shadow: 0 1px 2px rgba(11, 11, 11, 0.08);
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--plane);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--series-1); text-decoration: none; }
a:hover { text-decoration: underline; }

:focus-visible {
  outline: 2px solid var(--series-1);
  outline-offset: 2px;
  border-radius: 3px;
}

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.01em; }
h1 { font-size: 22px; }
h2 { font-size: 17px; }
h3 { font-size: 14px; color: var(--text-2); }

code, pre, .mono { font-family: var(--mono); }

.wrap {
  max-width: 1440px;
  margin: 0 auto;
  padding: 20px 22px 64px;
}

/* --------------------------------------------------------------------------
   Header & navigation
   -------------------------------------------------------------------------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}

.topbar-inner {
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 22px;
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: 56px;
  flex-wrap: wrap;
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 9px;
  font-weight: 650;
  font-size: 15px;
  color: var(--text);
  white-space: nowrap;
}
.brand:hover { text-decoration: none; }
.brand .brand-sub {
  font-weight: 400;
  font-size: 12px;
  color: var(--muted);
}

nav.main {
  display: flex;
  gap: 2px;
  flex: 1 1 auto;
  flex-wrap: wrap;
}

nav.main a {
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}
nav.main a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
nav.main a[aria-current="page"] {
  background: var(--surface-3);
  color: var(--text);
  font-weight: 600;
}

.topbar-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}

.icon-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-2);
  border-radius: var(--radius-sm);
  padding: 5px 9px;
  cursor: pointer;
  font-size: 13px;
  font-family: inherit;
  line-height: 1.4;
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }

/* --------------------------------------------------------------------------
   Cards & layout
   -------------------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 18px;
  margin-bottom: 18px;
  overflow: hidden;
}

.card > header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}

.card > header .hint { font-size: 12px; color: var(--muted); font-weight: 400; }

.grid { display: grid; gap: 18px; }
.grid.two   { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
.grid.three { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid.side  { grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr); }
/* Columns of very different natural height: let the shorter one end where its
   content ends instead of stretching a card full of empty surface. */
.grid.top > * { align-self: start; }

@media (max-width: 900px) {
  .grid.side { grid-template-columns: 1fr; }
}

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.page-head .sub { color: var(--muted); font-size: 13px; margin-top: 3px; }

/* --------------------------------------------------------------------------
   Stat tiles -- the primary numbers
   -------------------------------------------------------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 18px;
}

.stat {
  background: var(--surface);
  padding: 15px 17px 16px;
  min-width: 0;
}

.stat .label {
  font-size: 11px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  margin-bottom: 5px;
}

.stat .value {
  font-size: 34px;
  line-height: 1.06;
  font-weight: 600;
  letter-spacing: -0.02em;
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.stat .value.hero { font-size: 44px; }
.stat .value .unit { font-size: 15px; font-weight: 500; color: var(--muted); letter-spacing: 0; }
.stat .sub { font-size: 12px; color: var(--text-2); margin-top: 6px; }
.stat .sub .dim { color: var(--muted); }

/* --------------------------------------------------------------------------
   Rate bands -- colour AND shape, never colour alone
   -------------------------------------------------------------------------- */

.band { font-variant-numeric: tabular-nums; white-space: nowrap; }
.band::before {
  content: "";
  display: inline-block;
  width: 1.05em;
  margin-right: 0.12em;
  font-size: 0.78em;
  text-align: center;
  vertical-align: 0.06em;
}
.band-good     { color: var(--good); }
.band-good::before     { content: "\25CF"; }  /* ● */
.band-warn     { color: var(--warning); }
.band-warn::before     { content: "\25C6"; }  /* ◆ */
.band-bad      { color: var(--critical); }
.band-bad::before      { content: "\25BC"; }  /* ▼ */
.band-none     { color: var(--muted); }
.band-none::before     { content: "\2013"; }  /* – */

.delta { font-variant-numeric: tabular-nums; white-space: nowrap; font-size: 13px; }
.delta-up   { color: var(--good); }
.delta-down { color: var(--critical); }
.delta-flat { color: var(--muted); }

.legend-bands {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 12px;
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   Tables
   -------------------------------------------------------------------------- */

.table-scroll { overflow-x: auto; margin: 0 -18px; padding: 0 18px; }

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}

table.data th,
table.data td {
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--grid);
  vertical-align: middle;
  white-space: nowrap;
}

table.data thead th {
  position: sticky;
  top: 0;
  background: var(--surface);
  z-index: 2;
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  border-bottom: 1px solid var(--baseline);
  padding-top: 6px;
  padding-bottom: 6px;
}

table.data tbody tr:hover { background: var(--surface-2); }
table.data tbody tr:last-child td { border-bottom: none; }

table.data td.num,
table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }

table.data td.wrap-text { white-space: normal; min-width: 220px; }
table.data td.dim { color: var(--muted); }

table.data tfoot td {
  border-top: 1px solid var(--baseline);
  border-bottom: none;
  font-weight: 600;
  color: var(--text-2);
  padding-top: 9px;
}

/* sortable headers (HTMX-driven) */
th.sortable {
  cursor: pointer;
  user-select: none;
}
th.sortable:hover { color: var(--text); }
th.sortable .caret { opacity: 0; margin-left: 3px; font-size: 10px; }
th.sortable:hover .caret { opacity: 0.45; }
th.sortable[aria-sort] { color: var(--text); }
th.sortable[aria-sort] .caret { opacity: 1; color: var(--series-1); }

/* --------------------------------------------------------------------------
   Pills, badges, chips
   -------------------------------------------------------------------------- */

.pill {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1px solid var(--border-strong);
  color: var(--text-2);
  background: var(--surface-2);
  white-space: nowrap;
}

.pill-accepted { color: var(--good);     border-color: color-mix(in srgb, var(--good) 45%, transparent); }
.pill-denied   { color: var(--critical); border-color: color-mix(in srgb, var(--critical) 45%, transparent); }
.pill-expired  { color: var(--serious);  border-color: color-mix(in srgb, var(--serious) 45%, transparent); }
.pill-canceled { color: var(--muted); }
.pill-pending  { color: var(--warning);  border-color: color-mix(in srgb, var(--warning) 45%, transparent); }

.pill-high     { color: var(--critical); border-color: color-mix(in srgb, var(--critical) 45%, transparent); }
.pill-medium   { color: var(--warning);  border-color: color-mix(in srgb, var(--warning) 45%, transparent); }
.pill-low      { color: var(--text-2); }

.pill-succeeded { color: var(--good);     border-color: color-mix(in srgb, var(--good) 45%, transparent); }
.pill-failed    { color: var(--critical); border-color: color-mix(in srgb, var(--critical) 45%, transparent); }
.pill-partial   { color: var(--warning);  border-color: color-mix(in srgb, var(--warning) 45%, transparent); }
.pill-started   { color: var(--series-1); border-color: color-mix(in srgb, var(--series-1) 45%, transparent); }

.pill-accept  { color: var(--good); border-color: color-mix(in srgb, var(--good) 45%, transparent); }
.pill-decline { color: var(--serious); border-color: color-mix(in srgb, var(--serious) 45%, transparent); }

.chips { display: flex; flex-wrap: wrap; gap: 5px; }
.chip {
  display: inline-block;
  padding: 1px 7px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--text-2);
  font-family: var(--mono);
}

.reason-mix { display: flex; flex-wrap: wrap; gap: 4px; font-size: 11.5px; }
.reason-mix .reason {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0 6px;
  color: var(--text-2);
  max-width: 210px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.reason-mix .reason b { color: var(--text); font-weight: 600; }

/* --------------------------------------------------------------------------
   Charts
   -------------------------------------------------------------------------- */

.chart-wrap { position: relative; width: 100%; }

/* BOTH dimensions are forced, and the height is why.
   A <canvas> is a replaced element with intrinsic dimensions taken from its
   width/height ATTRIBUTES. With only `width: 100%` set, `height: auto` resolves
   through that intrinsic ratio -- so the canvas grows to half the card's width
   (679px in a 1360px card) and paints straight over whatever follows it, while
   the .chart-h-* class below silently does nothing. Pinning height to 100%
   makes the wrapper's height the one that counts, which is what those classes
   were always meant to express. */
.chart-wrap canvas { display: block; width: 100% !important; height: 100% !important; }
.chart-h-200 { height: 200px; }
.chart-h-240 { height: 240px; }
.chart-h-280 { height: 280px; }

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  font-size: 12px;
  color: var(--text-2);
  margin-top: 10px;
}
.chart-legend .key { display: inline-flex; align-items: center; gap: 6px; }
.chart-legend .swatch {
  width: 11px; height: 11px; border-radius: 3px; display: inline-block;
  border: 1px solid var(--border);
}
.chart-legend .swatch.line { height: 0; border: 0; border-top: 2px solid currentColor; width: 16px; border-radius: 0; }
.chart-legend .swatch.dashed { border-top-style: dashed; }

/* tooltip drawn by the vendored Chart.js */
.tbk-tooltip {
  position: absolute;
  pointer-events: none;
  z-index: 30;
  background: var(--surface-3);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 7px 10px;
  font-size: 12px;
  line-height: 1.45;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
  white-space: nowrap;
  transform: translate(-50%, -100%);
  opacity: 0;
  transition: opacity 90ms linear;
}
.tbk-tooltip.on { opacity: 1; }
.tbk-tooltip .t-title { font-weight: 600; margin-bottom: 3px; }
.tbk-tooltip .t-row { display: flex; align-items: center; gap: 6px; }
.tbk-tooltip .t-swatch { width: 9px; height: 9px; border-radius: 2px; }
.tbk-tooltip .t-value { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 600; }

/* --------------------------------------------------------------------------
   Sparklines
   -------------------------------------------------------------------------- */

.spark { display: block; overflow: visible; }
.spark polyline { fill: none; stroke: var(--series-1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.spark .spark-base { stroke: var(--baseline); stroke-width: 1; }
.spark-cell { display: flex; align-items: center; gap: 9px; }
.spark-peak { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   Heatmap (hour of week) -- server rendered, no canvas
   -------------------------------------------------------------------------- */

.heatmap { display: grid; grid-template-columns: 42px repeat(24, minmax(0, 1fr)); gap: 2px; min-width: 760px; }
.heatmap .hm-corner { }
.heatmap .hm-hour {
  font-size: 10px;
  color: var(--muted);
  text-align: center;
  font-variant-numeric: tabular-nums;
  padding-bottom: 3px;
}
.heatmap .hm-day {
  font-size: 11px;
  color: var(--text-2);
  display: flex;
  align-items: center;
  padding-right: 6px;
  font-weight: 500;
}
.heatmap .hm-cell {
  aspect-ratio: 1 / 1;
  min-height: 18px;
  border-radius: 3px;
  background: var(--surface-2);
  border: 1px solid transparent;
  position: relative;
  cursor: default;
}
.heatmap .hm-cell.s0 { background: var(--seq-0); }
.heatmap .hm-cell.s1 { background: var(--seq-1); }
.heatmap .hm-cell.s2 { background: var(--seq-2); }
.heatmap .hm-cell.s3 { background: var(--seq-3); }
.heatmap .hm-cell.s4 { background: var(--seq-4); }
.heatmap .hm-cell.s5 { background: var(--seq-5); }
.heatmap .hm-cell.s6 { background: var(--seq-6); }
.heatmap .hm-cell.empty {
  background: transparent;
  border: 1px dashed var(--grid);
}
/* low sample: hatched, so a 1-of-1 cell never reads as a confident 100% */
.heatmap .hm-cell.low::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 2px;
  background-image: repeating-linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.55) 0 1.5px,
    transparent 1.5px 4px
  );
}
.heatmap .hm-cell:hover { outline: 2px solid var(--text); outline-offset: 1px; }

.heat-legend { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); flex-wrap: wrap; }
.heat-legend .ramp { display: flex; gap: 2px; }
.heat-legend .ramp i { width: 18px; height: 12px; border-radius: 2px; display: block; }

/* A legend swatch that carries its own paint. The .hm-cell rules are scoped to
   a .heatmap ancestor, so a swatch outside the grid cannot borrow them. */
.swatch-key {
  display: inline-block;
  width: 13px;
  height: 13px;
  border-radius: 3px;
  vertical-align: -2px;
  margin-right: 4px;
}

/* --------------------------------------------------------------------------
   Bars used inside tables (service class split, denial mix)
   -------------------------------------------------------------------------- */

.meter {
  display: block;
  height: 6px;
  border-radius: 999px;
  background: var(--surface-3);
  overflow: hidden;
  min-width: 70px;
}
.meter > span { display: block; height: 100%; border-radius: 999px; background: var(--series-1); }
.meter.good > span { background: var(--good); }
.meter.warn > span { background: var(--warning); }
.meter.bad  > span { background: var(--critical); }

/* --------------------------------------------------------------------------
   Empty state
   -------------------------------------------------------------------------- */

.empty {
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 34px 26px;
  text-align: center;
  color: var(--text-2);
}
.empty h2 { color: var(--text); margin-bottom: 8px; }
.empty p { margin: 0 auto 14px; max-width: 54ch; font-size: 14px; }
.empty pre {
  display: inline-block;
  margin: 0;
  padding: 10px 16px;
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 13.5px;
  text-align: left;
  user-select: all;
}
.empty .note { font-size: 12px; color: var(--muted); margin-top: 14px; }

.empty-inline {
  padding: 22px 14px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  border: 1px dashed var(--grid);
  border-radius: var(--radius-sm);
}

/* --------------------------------------------------------------------------
   Notices & banners
   -------------------------------------------------------------------------- */

.notice {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 11px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  font-size: 13.5px;
  margin-bottom: 16px;
  color: var(--text-2);
}
.notice .ico { font-size: 14px; line-height: 1.4; flex: 0 0 auto; }
.notice strong { color: var(--text); }
.notice-ok    { border-color: color-mix(in srgb, var(--good) 50%, transparent); }
.notice-ok .ico    { color: var(--good); }
.notice-warn  { border-color: color-mix(in srgb, var(--warning) 55%, transparent); }
.notice-warn .ico  { color: var(--warning); }
.notice-error { border-color: color-mix(in srgb, var(--critical) 55%, transparent); }
.notice-error .ico { color: var(--critical); }
.notice-info .ico  { color: var(--series-1); }
.notice a.dismiss { margin-left: auto; font-size: 12px; color: var(--muted); }

/* --------------------------------------------------------------------------
   Forms & controls
   -------------------------------------------------------------------------- */

.controls {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 13px;
}
.controls label { color: var(--muted); font-size: 12px; }

input[type="date"],
input[type="text"],
select {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 6px 9px;
  font: inherit;
  font-size: 13px;
}

.btn {
  display: inline-block;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 6px 12px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
}
.btn:hover { background: var(--surface-3); text-decoration: none; }
.btn-accept {
  border-color: color-mix(in srgb, var(--good) 60%, transparent);
  color: var(--good);
}
.btn-accept:hover { background: color-mix(in srgb, var(--good) 14%, var(--surface-2)); }
.btn-reject {
  border-color: color-mix(in srgb, var(--critical) 55%, transparent);
  color: var(--critical);
}
.btn-reject:hover { background: color-mix(in srgb, var(--critical) 12%, var(--surface-2)); }
.btn-sm { padding: 3px 9px; font-size: 12px; }

.seg { display: inline-flex; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); overflow: hidden; }
.seg a {
  padding: 5px 11px;
  font-size: 12.5px;
  color: var(--text-2);
  border-right: 1px solid var(--border);
}
.seg a:last-child { border-right: none; }
.seg a:hover { background: var(--surface-2); text-decoration: none; }
.seg a[aria-current="true"] { background: var(--surface-3); color: var(--text); font-weight: 600; }

/* --------------------------------------------------------------------------
   YAML / code display
   -------------------------------------------------------------------------- */

pre.yaml {
  margin: 0;
  padding: 14px 16px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow-x: auto;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-2);
  max-height: 620px;
  tab-size: 2;
}
pre.yaml.short { max-height: 260px; }
pre.yaml .c { color: var(--muted); }
pre.yaml .k { color: var(--series-1); }
pre.yaml .v { color: var(--text); }

/* --------------------------------------------------------------------------
   Proposals
   -------------------------------------------------------------------------- */

.proposal {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  padding: 14px 16px;
  margin-bottom: 14px;
}
.proposal.done { opacity: 0.66; }
.proposal > header {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.proposal .pid { font-family: var(--mono); font-size: 13px; font-weight: 600; }
.proposal .rationale { font-size: 13.5px; color: var(--text-2); margin: 0 0 10px; max-width: 80ch; }
.proposal .actions { display: flex; gap: 8px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.proposal .actions form { display: inline; }
.proposal .evidence { font-size: 12.5px; color: var(--muted); margin-bottom: 10px; }

/* --------------------------------------------------------------------------
   Misc
   -------------------------------------------------------------------------- */

.kv { display: grid; grid-template-columns: auto 1fr; gap: 5px 16px; font-size: 13px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; color: var(--text); font-variant-numeric: tabular-nums; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.muted { color: var(--muted); }
.small { font-size: 12px; }
.mono-sm { font-family: var(--mono); font-size: 12px; }
.right { text-align: right; }
.nowrap { white-space: nowrap; }
.stack > * + * { margin-top: 12px; }

.htmx-request { opacity: 0.55; transition: opacity 120ms linear; }

/* --------------------------------------------------------------------------
   Missed work
   --------------------------------------------------------------------------

   The primary view leads with one number -- work that was ours to lose -- and
   four supporting ones. Everything below exists to make that hierarchy legible
   at a glance and to keep "this crossed a threshold" from being carried by
   colour alone.

   No rule here introduces a new colour ramp. Magnitude on the blind-spot grid
   reuses the sequential --seq-* steps already validated for this app; crossing
   a threshold is a STATE, so it borrows the reserved status colour and is
   always paired with a ring, a glyph or a word.
   -------------------------------------------------------------------------- */

/* The lead tile is wider and heavier than the rest of the row: the recoverable
   count is the answer to the owner's question and the others are its parts. */
.stats-headline { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.stats-headline .stat-lead { grid-column: span 2; background: var(--surface-2); }

@media (max-width: 700px) {
  .stats-headline .stat-lead { grid-column: span 1; }
}

/* A tile whose number is the one to act on. A left rule, not a fill: the value
   inside still has to be readable, and a tinted panel fights the figure. */
.stat-flag { box-shadow: inset 3px 0 0 var(--critical); }

/* The mandatory ranking disclaimer. Quiet, but never collapsible and never
   further from the table than one line -- it is the difference between a
   column of jobs and a column somebody reads as dollars. */
.rank-note {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin: 0 0 10px;
  font-size: 12px;
  color: var(--muted);
}
.rank-note .ico { color: var(--series-1); }

/* Cause / remedy chips on the inventory. Deliberately one neutral treatment
   rather than a colour per cause: there are six causes, colour here would be
   categorical encoding on a column that is already labelled in words, and it
   would compete with the status colours that do mean something. */
.pill[class*="pill-cause-"],
.pill-remedy {
  background: var(--surface-3);
  color: var(--text-2);
  border-color: var(--border-strong);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
}

/* A row that crossed a threshold. The tint is a hint; the row always also
   carries a word ("uncovered") or a tag, so this survives greyscale. */
table.data tbody tr.row-flag {
  background: color-mix(in srgb, var(--critical) 8%, transparent);
}
table.data tbody tr.row-flag:hover {
  background: color-mix(in srgb, var(--critical) 14%, transparent);
}

.tag {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  vertical-align: 1px;
}
.tag-bad  { color: var(--critical); border-color: color-mix(in srgb, var(--critical) 50%, transparent); }
.tag-good { color: var(--good);     border-color: color-mix(in srgb, var(--good) 50%, transparent); }

/* Blind-spot grid. Same geometry and same sequential ramp as the acceptance
   heatmap on /trends -- only the quantity being ramped changes, so a reader who
   has learned one has learned the other. `.flag` is the threshold state: a
   status-coloured ring plus a centre dot, so it is legible in greyscale, in
   forced-colours mode, and to a reader who cannot separate the ramp steps. */
.heatmap-miss .hm-cell.flag {
  outline: 2px solid var(--critical);
  outline-offset: -2px;
  border-radius: 3px;
}
.heatmap-miss .hm-cell.flag::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 4px;
  height: 4px;
  margin: -2px 0 0 -2px;
  border-radius: 50%;
  background: var(--plane);
  box-shadow: 0 0 0 1px var(--critical);
}
.heatmap-miss .hm-cell.flag:hover { outline-color: var(--text); }

/* --------------------------------------------------------------------------
   Copy-to-clipboard block (the close-off note)
   -------------------------------------------------------------------------- */

.copyblock {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  overflow: hidden;
  min-width: 0;
}
.copyblock-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.copyblock pre {
  margin: 0;
  padding: 12px 14px;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-2);
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 460px;
  overflow: auto;
  /* One click selects the whole note, so the copy button is an accelerator
     and never the only way to get the text out. */
  user-select: all;
}
.copyblock.copied .copyblock-head { border-bottom-color: var(--good); }

.closeoff-client > header h2 { font-size: 18px; }

/* --------------------------------------------------------------------------
   The four tabs, and the detail row beneath them

   Top-level navigation is HOURLY / WEEKLY / MONTHLY / TRENDS. They are visually
   heavier than the detail links below them because they are the board; the
   detail views are where you go when a tab raises a question.
   -------------------------------------------------------------------------- */

nav.main.tabs a {
  padding: 9px 16px;
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
nav.main.tabs a[aria-current="page"] {
  background: var(--surface-3);
  box-shadow: inset 0 -2px 0 var(--series-1);
}

.subbar {
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--plane) 55%, transparent);
}
.subbar nav.detail {
  max-width: 1440px;
  margin: 0 auto;
  padding: 5px 22px;
  display: flex;
  align-items: center;
  gap: 2px;
  flex-wrap: wrap;
}
.subbar-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-right: 8px;
}
.subbar nav.detail a {
  padding: 4px 9px;
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-size: 13px;
  white-space: nowrap;
}
.subbar nav.detail a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.subbar nav.detail a[aria-current="page"] { color: var(--text); background: var(--surface-2); font-weight: 600; }

/* An hour that has not happened yet. Dimmed, never zeroed. */
table.data tbody tr.dim-row td { opacity: 0.45; }

/* --------------------------------------------------------------------------
   Recommendations (the weekly / monthly "what to do about it" list)
   -------------------------------------------------------------------------- */

.reco-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }

.reco {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  padding: 11px 13px;
  box-shadow: inset 3px 0 0 var(--baseline);
}
.reco-high   { box-shadow: inset 3px 0 0 var(--critical); }
.reco-medium { box-shadow: inset 3px 0 0 var(--warning); }
.reco-low    { box-shadow: inset 3px 0 0 var(--muted); }

.reco-head { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.reco-head strong { font-size: 15px; }
.reco-detail { color: var(--text-2); margin: 5px 0 4px; }

/* --------------------------------------------------------------------------
   Login

   Its own page, not the dashboard shell: there is no navigation to show
   somebody who is not signed in, and rendering the tab bar behind a login form
   invites them to click it.
   -------------------------------------------------------------------------- */

.btn-primary {
  border-color: color-mix(in srgb, var(--series-1) 55%, transparent);
  color: var(--text);
  background: color-mix(in srgb, var(--series-1) 22%, var(--surface-2));
  font-weight: 600;
}
.btn-primary:hover { background: color-mix(in srgb, var(--series-1) 34%, var(--surface-2)); }

.login-wrap {
  max-width: 560px;
  margin: 0 auto;
  padding: 8vh 20px 40px;
}

.login-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  padding: 22px;
}

.login-brand {
  display: flex;
  align-items: baseline;
  gap: 9px;
  font-weight: 650;
  font-size: 17px;
  margin-bottom: 16px;
}

.login-form {
  display: grid;
  gap: 8px;
  margin: 0 0 16px;
}
.login-form label { font-size: 13px; color: var(--text-2); }
.login-form input[type="password"] {
  font: inherit;
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text);
}
.login-form button { justify-self: start; padding: 8px 20px; }

/* The banner is the point of the page when the password is still the default,
   so it is allowed to be long and it is allowed to be loud. */
.login-warning { align-items: flex-start; }
.login-note { margin: 10px 0 0; }

.login-foot {
  text-align: center;
  color: var(--muted);
  font-size: 12px;
  margin-top: 18px;
}

footer.foot {
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 22px 30px;
  color: var(--muted);
  font-size: 12px;
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

/* ==========================================================================
   MAPS  (/maps -- the offered heat map and the declined-jobs map)
   ==========================================================================

   The map container gets its own stacking context (`isolation: isolate`) so
   Leaflet's internal high z-indexes -- panes, popups, zoom control -- stay
   inside the card and never rise over the sticky top bar. A neutral background
   means a window with no tiles (or before they load) is a plain surface, not a
   black hole. */

.jobmap {
  height: 460px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-2);
  position: relative;
  z-index: 0;
  isolation: isolate;
}

@media (max-width: 640px) {
  .jobmap { height: 340px; }
}

/* Leaflet draws its own text; keep it in the board's font. Popups stay on
   Leaflet's light bubble (readable over any basemap in either theme), so their
   text is a fixed dark, not a themed variable. */
.leaflet-container { font-family: var(--sans); }

.map-popup { color: #1a1a19; min-width: 180px; }
.map-popup .pop-head {
  font-weight: 600;
  margin-bottom: 6px;
  padding-bottom: 5px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
.map-popup .pop-row {
  display: flex;
  gap: 8px;
  font-size: 12.5px;
  line-height: 1.55;
}
.map-popup .pop-k { color: #6f6d68; flex: 0 0 74px; }
.map-popup .pop-v { color: #1a1a19; flex: 1 1 auto; word-break: break-word; }

/* The bucket legend above the declined map. */
.map-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  align-items: center;
  margin-bottom: 12px;
  font-size: 12.5px;
  color: var(--text-2);
}
.map-legend .key { display: inline-flex; align-items: center; gap: 6px; }
.map-legend .dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
  border: 1px solid rgba(0, 0, 0, 0.25);
}
.map-legend .ring {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
  background: transparent;
  border: 2.5px solid var(--map-light-ring);
}

/* Prev/next window arrows next to the scope selector. */
.seg.mapnav a, .seg.mapnav .disabled { padding: 4px 10px; }
.seg.mapnav .disabled { color: var(--muted); opacity: 0.5; cursor: not-allowed; }

/* A tighter stat row for the tally card, and its total row. */
.stats.tight { margin: 0 0 4px; }
table.data tr.total-row td { border-top: 2px solid var(--border-strong); }

/* ==========================================================================
   PRINT
   ==========================================================================

   The Print button in the topbar calls window.print(); "Save as PDF" in the
   browser's own dialog is the PDF export. There is deliberately no
   server-side renderer: WeasyPrint, wkhtmltopdf and headless Chromium each
   cost a large dependency and a second layout engine whose output would have
   to be checked separately from the one every user already looks at. The
   browser is right there and already renders this page correctly.

   The letterhead in base.html is display:none on screen and restored here, so
   it exists only in the printed document.

   `.no-print` is the general escape hatch; add it to anything interactive
   that a later tab introduces.
   ========================================================================== */

/* ==========================================================================
   Lost-revenue view.

   The hour bars are a horizontal bar chart built out of two spans, because a
   bar chart of 24 values does not need a charting library and this app ships
   none. Length encodes dollars against the WORST hour, so the shape of the day
   stays readable at any volume.

   Length is the only quantitative channel here -- colour is used solely to
   separate staffed from unstaffed hours, which is categorical. That keeps the
   chart readable in greyscale, and the "unstaffed" tag repeats the same fact
   in text so the distinction never rests on colour alone.
   ========================================================================== */
.hourbars { list-style: none; margin: 12px 0 0; padding: 0; }

.hourbar {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr) 78px 44px 78px;
  align-items: center;
  gap: 10px;
  padding: 3px 0;
  font-variant-numeric: tabular-nums;
}

.hourbar-label { font-size: 12px; color: var(--muted); }

.hourbar-track {
  display: block;
  height: 14px;
  min-width: 40px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  overflow: hidden;
}

.hourbar-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--series-1);
  /* A non-zero hour must never render as an invisible sliver. */
  min-width: 2px;
}

/* Unstaffed hours are the actionable ones, so they carry the reserved status
   colour -- and the tag beside them says so in words. */
.hourbar-uncovered .hourbar-fill { background: var(--warning); }

.hourbar-value { font-size: 12.5px; font-weight: 600; text-align: right; }
.hourbar-jobs  { font-size: 11.5px; text-align: right; }
.hourbar-flag  { text-align: right; }

.tag-warn { color: var(--warning); border-color: color-mix(in srgb, var(--warning) 50%, transparent); }

/* The period still being accumulated. A left rule rather than a fill, so it
   reads as "this one is live" without competing with the numbers. */
table.data tbody tr.is-current > :first-child { box-shadow: inset 3px 0 0 var(--series-1); }
table.data tbody tr.is-current { background: var(--surface-2); }

@media (max-width: 640px) {
  /* Drop the job count and the tag before the bar itself gets squeezed. */
  .hourbar { grid-template-columns: 68px minmax(0, 1fr) 70px; }
  .hourbar-jobs, .hourbar-flag { display: none; }
}

.letterhead { display: none; }

@page {
  size: letter portrait;
  /* Room for the letterhead at the top of page 1 and for the browser's own
     footer at the bottom of every page. */
  margin: 14mm 12mm 16mm;
}

@media print {
  /* FORCE THE LIGHT PALETTE. The variables are redefined rather than
     overridden per rule, so every card, border and muted label follows
     without a print-specific version of each. dash.js separately repaints the
     chart canvases, which CSS cannot reach. */
  :root, :root[data-theme="dark"], :root[data-theme="light"] {
    color-scheme: light;
    /* The light theme's own values, with the tinted surfaces flattened to
       white -- #f9f9f7 is a warm paper tone on a screen and a faint grey wash
       on paper. Series and status colours are inherited from the light block
       unchanged, so a chart printed here matches a chart on screen. */
    --plane:         #ffffff;
    --surface:       #ffffff;
    --surface-2:     #ffffff;
    --surface-3:     #f4f4f2;
    --text:          #0b0b0b;
    --text-2:        #3a3a38;
    --muted:         #55534f;
    --grid:          #dcdbd5;
    --baseline:      #b4b3ab;
    --border:        rgba(11, 11, 11, 0.30);
    --border-strong: rgba(11, 11, 11, 0.45);
    --shadow:        none;

    --series-1: #2a78d6;
    --series-2: #eb6834;
    --series-3: #1baf7a;
    --series-4: #eda100;
    --series-5: #e87ba4;
    --series-6: #008300;
    --series-7: #4a3aa7;
    --series-8: #e34948;

    --good:     #006300;
    --warning:  #b07a00;
    --serious:  #c05a2a;
    --critical: #c02c2c;
  }

  html, body {
    background: #fff !important;
    color: #000 !important;
    font-size: 10.5pt;
  }

  /* Screen chrome and every control. None of it means anything on paper, and
     a printed button is a printed lie. */
  .topbar, .subbar, footer.foot,
  .controls, .btn, .icon-btn, .company-switch,
  .tabs, .detail, #theme-toggle, #print-btn,
  .tip, .tooltip, .copy-btn, .no-print { display: none !important; }

  /* ---------------------------------------------------------------- identity
     A printed report needs one accent colour and the confidence to use it.
     Bleaching the screen design to white produces something technically
     correct and completely forgettable; this is the same information with a
     masthead, a rule, and a hierarchy you can read from across a desk. */
  :root, :root[data-theme="dark"], :root[data-theme="light"] {
    --print-accent: #123a63;   /* deep navy: reads black on a mono printer */
    --print-rule:   #123a63;
  }

  /* The letterhead, restored. min-width:0 on both columns is what lets them
     shrink instead of forcing the row wider than the page. */
  .letterhead {
    display: flex !important;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    padding: 0 0 9px;
    margin: 0 0 15px;
    border-bottom: 3px solid var(--print-rule);
    max-width: 100%;
  }
  .letterhead-id { min-width: 0; flex: 1 1 auto; }
  .letterhead-logo { max-height: 52px; max-width: 300px; }
  .letterhead-name {
    font-size: 16pt;
    font-weight: 800;
    letter-spacing: -0.3px;
    line-height: 1.1;
    color: var(--print-accent);
  }
  .letterhead-contact {
    margin-top: 4px;
    font-size: 8pt;
    color: #444;
    display: flex;
    flex-direction: column;
    line-height: 1.35;
  }
  .letterhead-doc {
    text-align: right;
    min-width: 0;
    flex: 0 1 auto;
  }
  /* The document's own name, set as a label rather than a heading: it is what
     kind of report this is, and the period below it is the headline. */
  .letterhead-title {
    font-size: 8.5pt;
    font-weight: 700;
    text-transform: uppercase;
    /* Tracking adds a trailing space after the last letter, which on a
       right-aligned line pushes it into the margin and clips the final glyph.
       The negative margin takes that trailing space back. */
    letter-spacing: 0.12em;
    margin-right: -0.12em;
    color: var(--print-accent);
    line-height: 1.2;
  }
  .letterhead-period { font-size: 11pt; font-weight: 700; margin-top: 2px; line-height: 1.15; }
  .letterhead-meta { font-size: 7.5pt; color: #555; margin-top: 3px; }

  .wrap { max-width: none; padding: 0; margin: 0; overflow: visible; }

  /* The page heading duplicates the letterhead's document title, and at screen
     size it eats a third of the first page before a number appears. */
  .page-head h1 { font-size: 12.5pt; margin: 0 0 2px; letter-spacing: -0.2px; }
  .page-head .sub { font-size: 8.5pt; color: #444; }

  /* Section labels: small, uppercase, tracked, in the accent. Reads as a
     report's table of contents rather than a stack of widget titles. */
  .card > header h2 {
    font-size: 8.5pt;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--print-accent);
    margin: 0;
  }
  .card > header .hint { font-size: 7.5pt; color: #555; display: block; margin-top: 1px; }

  /* Cards become ruled SECTIONS, not boxes. A page of outlined rectangles is a
     screenshot of an interface; a report is set with rules and whitespace. */
  .card {
    background: #fff !important;
    border: none;
    border-top: 1.5px solid var(--print-rule);
    border-radius: 0;
    box-shadow: none !important;
    padding: 7px 0 0;
    break-inside: avoid;
    page-break-inside: avoid;
    margin: 0 0 13px;
  }
  .card > header {
    padding: 0;
    background: none !important;
    border: none;
    margin-bottom: 5px;
  }

  h1, h2, h3, .card-title {
    break-after: avoid;
    page-break-after: avoid;
  }

  /* NOTHING SCROLLS ON PAPER, so a horizontal scroller is a guillotine.
     `.table-scroll` is overflow-x:auto on screen, which is right there and
     wrong here: the hour-by-hour table is eleven columns, so in print it
     stretched the document past the page and Chrome trimmed the right edge off
     EVERY element -- the last table column and the letterhead timestamp with
     it. Nothing looked broken; it looked like a page with a narrow margin. */
  .table-scroll,
  .scroller,
  [class*="overflow"] {
    overflow: visible !important;
    max-width: 100% !important;
  }

  /* Tables: repeat the header on every page, and never split a row. A row cut
     across a page break is the classic way a printed report becomes unreadable
     exactly where it matters. */
  table {
    width: 100%;
    max-width: 100%;
    border-collapse: collapse;
    font-size: 7.5pt;      /* eleven columns have to fit 8.5in minus margins */
  }

  /* TABLE-LAYOUT: FIXED IS THE ONLY THING THAT ACTUALLY GUARANTEES A FIT.
     `overflow: visible` stops the scroller clipping, but an auto-layout table
     still takes its minimum content width and simply spills off the sheet --
     which is why "Day offered" printed as "Day offe" and, because the spill
     widened the whole document, the masthead lost its right edge too. Fixed
     layout makes the columns share the page width and wrap instead. */
  .table-scroll > table,
  table.data {
    table-layout: fixed;
    width: 100%;
  }
  /* The label column carries "00:00-00:59" and a "now" pill; the rest are
     short numbers and can share what is left. */
  .table-scroll > table th:first-child,
  .table-scroll > table td:first-child,
  table.data th:first-child,
  table.data td:first-child {
    width: 15%;
  }
  thead { display: table-header-group; }
  tfoot { display: table-footer-group; }
  tr, td, th { break-inside: avoid; page-break-inside: avoid; }
  /* Same specificity problem as the header band: the screen `.data td` rules
     set the cell type, so the print sizes have to insist. */
  th, td {
    border-bottom: 1px solid #e3e3e3;
    padding: 3px 4px !important;
    font-size: 7pt !important;
    white-space: normal !important;
    overflow-wrap: normal;
  }
  /* A reversed header band is the single change that makes a table look
     typeset instead of dumped. print-color-adjust:exact above is what keeps
     the browser from helpfully removing it to save ink. */
  /* EVERY DECLARATION HERE IS !important, AND THAT IS NOT LAZINESS.
     The screen rules are written as `.data th`, a class selector, which
     outranks any plain element selector this block can use. Without the
     overrides the header keeps its screen font size, and at that size an
     eleven-column table under table-layout:fixed cannot fit a word like
     "Unanswered" -- so it broke mid-word into "UNAN SWERE D". Sized properly,
     each label sits on one line. */
  thead th {
    background: var(--print-accent) !important;
    color: #ffffff !important;
    border-bottom: none !important;
    font-size: 5.9pt !important;
    font-weight: 700 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.01em !important;
    padding: 4px 3px !important;
    white-space: normal !important;
    overflow-wrap: normal !important;   /* wrap between words, never inside one */
    vertical-align: bottom !important;
    line-height: 1.15 !important;
  }
  /* Banding light enough to guide the eye across eleven columns and not so
     heavy it greys the page. */
  tbody tr:nth-child(even) { background: #f2f5f8 !important; }
  td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
  tbody tr:last-child td { border-bottom: 1px solid #bbb; }

  /* Charts. Sized down so a tall canvas does not push a whole section onto a
     page of its own, and told to keep their colours -- browsers otherwise
     drop background fills to save ink, which erases a bar chart. */
  canvas {
    max-height: 62mm !important;
    break-inside: avoid;
    page-break-inside: avoid;
  }
  * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* Keep the status colours -- a red acceptance rate is the point of the
     report -- but drop the tinted pill backgrounds, which print as grey mud. */
  .pill, .badge, .chip {
    background: transparent !important;
    border: 1px solid #999;
  }

  /* Banners are worth printing -- "the data may be stale" is exactly the kind
     of caveat that should travel with a document that outlives the session it
     came from. But two of them at full screen size claimed the top third of
     page one before a single number, so they print as a compact rule instead
     of a filled panel. */
  .notice {
    background: #fff !important;
    border: none;
    border-left: 2.5px solid #999;
    border-radius: 0;
    padding: 3px 0 3px 8px;
    margin: 0 0 6px;
    font-size: 8pt;
    line-height: 1.35;
    break-inside: avoid;
  }
  .notice .ico { display: none; }
  .notice a { text-decoration: underline; }

  /* Stat tiles: the headline numbers, and the reason anyone opens the report.
     Big, in the accent, over a small tracked label -- the one place on the page
     that should be loud. */
  .stat .value, .tile .value, .kpi .value {
    font-size: 19pt !important;
    font-weight: 800 !important;
    color: var(--print-accent) !important;
    line-height: 1.05 !important;
  }
  .stat .label, .tile .label, .kpi .label,
  .stat .k, .tile .k, .kpi .k {
    font-size: 6.6pt !important;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: #55534f !important;
  }
  .stat, .tile, .kpi {
    break-inside: avoid;
    background: #fff !important;
    border-color: #d5d5d5 !important;
  }

  /* Expose link targets nobody can click on paper -- but only real ones. */
  a { color: #000 !important; text-decoration: none; }
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 8pt;
    color: #555;
  }
}
