/* ============================================================
   SimpleCov HTML Report — Main Stylesheet
   ============================================================ */

/* --- Design tokens ----------------------------------------- */

:root {
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;

  /* Spacing scale (4px base) */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;

  /* The index reserves this slot so its toolbar stays pixel-aligned with the
     source toolbar when the close button appears. */
  --source-close-size: 34px;
  --source-close-gap: var(--sp-4);
  --source-close-slot: calc(var(--source-close-size) + var(--source-close-gap));

  /* Light theme */
  --bg: #f0f1f3;
  --surface: #fff;
  --surface-alt: #f0f1f3;
  --text: #111;
  --text-secondary: #333;
  --text-tertiary: #444;
  --zebra: #f4f5f7;
  --border: #c0c5cc;
  --border-strong: #999;

  --accent: #0550ae;
  --accent-hover: #033d8b;
  --accent-subtle: #ddf4ff;

  --green: #116329;
  --red: #a40e26;
  --yellow: #7a5200;
  --orange: #953800;

  /* Source code lines */
  --covered-bg: #ccf5d0;
  --covered-line-num-bg: #9ae6a4;
  --missed-bg: #ffd8d5;
  --missed-line-num-bg: #ffb8b3;
  --never-bg: #fff;
  --never-line-num-bg: #f0f1f3;
  --skipped-bg: #fff0a0;
  --skipped-line-num-bg: #eed860;
  --missed-branch-bg: #ffd0a0;
  --missed-branch-line-num-bg: #ffb060;
  --missed-branch-text: #b45309;
  --missed-method-bg: #e8d0ff;
  --missed-method-line-num-bg: #d4b0ff;
  --missed-method-text: #7b2d8e;

  --source-bg: #fff;
  --source-border: #c0c5cc;
  --source-line-number: #444;
  --source-line-num-bg: #f0f1f3;

  --hits-bg: #e0e3e8;
  --hits-color: #333;

  /* Dialog */
  --overlay-bg: rgba(0, 0, 0, 0.5);

  /* Coverage bar */
  --bar-bg: #d0d7de;
  --bar-height: 6px;
}

/* --- Dark theme -------------------------------------------- */

@media (prefers-color-scheme: dark) {
  :root:not(.light-mode) {
    --bg: #010409;
    --surface: #0d1117;
    --surface-alt: #161b22;
    --text: #f0f3f6;
    --text-secondary: #b0b8c4;
    --text-tertiary: #9aa5b1;
    --zebra: #161b22;
    --border: #3d444d;
    --border-strong: #555e68;

    --accent: #6cb6ff;
    --accent-hover: #96ccff;
    --accent-subtle: #121d2f;

    --green: #56d364;
    --red: #ff6b61;
    --yellow: #e3b341;
    --orange: #f0883e;

    --covered-bg: #122d1e;
    --covered-line-num-bg: #1e4430;
    --missed-bg: #351418;
    --missed-line-num-bg: #4e1d20;
    --never-bg: #0d1117;
    --never-line-num-bg: #161b22;
    --skipped-bg: #302818;
    --skipped-line-num-bg: #443920;
    --missed-branch-bg: #322218;
    --missed-branch-line-num-bg: #483020;
    --missed-branch-text: #ffb86c;
    --missed-method-bg: #1e1830;
    --missed-method-line-num-bg: #2a2044;
    --missed-method-text: #dcb8ff;

    --source-bg: #0d1117;
    --source-border: #3d444d;
    --source-line-number: #9aa5b1;
    --source-line-num-bg: #161b22;

    --hits-bg: #262c34;
    --hits-color: #b0b8c4;

    --overlay-bg: rgba(1, 4, 9, 0.8);

    --bar-bg: #3d444d;
  }
}

.dark-mode {
  --bg: #010409;
  --surface: #0d1117;
  --surface-alt: #161b22;
  --text: #f0f3f6;
  --text-secondary: #b0b8c4;
  --text-tertiary: #9aa5b1;
  --zebra: #161b22;
  --border: #3d444d;
  --border-strong: #555e68;

  --accent: #6cb6ff;
  --accent-hover: #96ccff;
  --accent-subtle: #121d2f;

  --green: #56d364;
  --red: #ff6b61;
  --yellow: #e3b341;
  --orange: #f0883e;

  --covered-bg: #122d1e;
  --covered-line-num-bg: #1e4430;
  --missed-bg: #351418;
  --missed-line-num-bg: #4e1d20;
  --never-bg: #0d1117;
  --never-line-num-bg: #161b22;
  --skipped-bg: #302818;
  --skipped-line-num-bg: #443920;
  --missed-branch-bg: #322218;
  --missed-branch-line-num-bg: #483020;
  --missed-branch-text: #ffb86c;
  --missed-method-bg: #1e1830;
  --missed-method-line-num-bg: #2a2044;
  --missed-method-text: #dcb8ff;

  --source-bg: #0d1117;
  --source-border: #3d444d;
  --source-line-number: #9aa5b1;
  --source-line-num-bg: #161b22;

  --hits-bg: #262c34;
  --hits-color: #b0b8c4;

  --overlay-bg: rgba(1, 4, 9, 0.8);

  --bar-bg: #3d444d;
}

/* --- Colorblind palette ------------------------------------ */

/* Red/green is the coverage report's core signal (covered vs missed) and the
   pairing most colorblind viewers cannot separate (see issue #534). This mode
   swaps it for blue (covered) vs orange/vermillion (missed) — the classic
   colorblind-safe pairing — while leaving skipped (yellow), missed-branch
   (orange-brown) and missed-method (purple) as-is, since those already read as
   distinct hues.
   Only the covered/missed and the green/red band tokens change, so the rest of
   the theme is untouched. The blocks are ordered after the light/dark token
   definitions so they win on equal specificity; the dark variants raise
   specificity so they win over the light colorblind values under dark.

   The light values apply on screen and in print (the @media print reset below
   re-asserts them so a printout keeps the colorblind palette). The dark values
   are scoped to `@media screen` so they never reach paper: their higher
   specificity would otherwise beat the print reset and print dark backgrounds. */
.colorblind-mode {
  --green: #0060a8;
  --red: #c2410c;
  --covered-bg: #d3eaf7;
  --covered-line-num-bg: #a5d2ee;
  --missed-bg: #ffe0cc;
  --missed-line-num-bg: #ffc39a;
}

@media screen and (prefers-color-scheme: dark) {
  .colorblind-mode:not(.light-mode) {
    --green: #6cb6ff;
    --red: #f0883e;
    --covered-bg: #0e2a45;
    --covered-line-num-bg: #12385c;
    --missed-bg: #3a2410;
    --missed-line-num-bg: #52331a;
  }
}

@media screen {
  .colorblind-mode.dark-mode {
    --green: #6cb6ff;
    --red: #f0883e;
    --covered-bg: #0e2a45;
    --covered-line-num-bg: #12385c;
    --missed-bg: #3a2410;
    --missed-line-num-bg: #52331a;
  }
}

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

/* Opening the source dialog sets overflow:hidden on this element to stop the
   page behind it from scrolling. Where scrollbars take up layout space (the
   Windows and Linux default rather than macOS overlay scrollbars), that would
   widen the viewport by the scrollbar's width mid-interaction and shift the
   toolbar the --source-close-slot alignment exists to hold still. Reserving
   the gutter for good keeps the width constant whether or not the scrollbar
   is showing. */
html {
  scrollbar-gutter: stable;
}

body {
  font-family: var(--font-sans);
  font-size: 18px;
  color: var(--text);
  background: var(--bg);
  padding: var(--sp-6);
}

a {
  color: var(--accent);
  text-decoration: none;
  transition: color 0.15s;
}
a:hover {
  color: var(--accent-hover);
}

strong, b { font-weight: 600; }

/* --- Loading screen ---------------------------------------- */

#loading {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  z-index: 9999;
}

#loading-inner {
  width: 280px;
  text-align: center;
}

#loading-bar-track {
  width: 100%;
  height: 6px;
  background: var(--bar-bg);
  border-radius: 6px;
  overflow: hidden;
}

#loading-bar-fill {
  width: 0%;
  height: 100%;
  background: var(--accent);
  border-radius: 6px;
  transition: width 0.15s ease-out;
}

#loading-text {
  margin-top: var(--sp-3);
  font-size: 18px;
  color: var(--text-tertiary);
}

/* --- Re-sort overlay --------------------------------------- */

/* Dims the report (keeping it visible) and swallows clicks while a large
   file list re-sorts. Shown only above the row threshold in sort.ts. */
#sort-overlay {
  position: fixed;
  inset: 0;
  z-index: 9998;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--overlay-bg);
}

#sort-overlay-label {
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  font-size: 16px;
  color: var(--text-tertiary);
}

/* --- Layout ------------------------------------------------ */

#wrapper {
  margin: 0 auto;
}

/* Navigation on the left, display controls on the right. Both start at the
   same top edge, which is what keeps the controls from jumping when the
   source dialog opens over them, so the two groups are told apart by the
   gutter between them rather than by sitting at different heights. */
.tab-bar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: -1px;
  position: relative;
  z-index: 1;
}

abbr.timeago {
  text-decoration: none;
  border: none;
}

/* --- Tabs -------------------------------------------------- */

/* Too many groups to fit and the strip scrolls, which otherwise guillotines
   whichever tab straddles the right edge and leaves a hard vertical cut
   against the controls. Fade the last stretch instead, so a tab that runs
   past the edge dissolves into the gutter. The matching trailing padding
   keeps the final tab clear of the fade when everything already fits, so
   nothing is dimmed that isn't actually overflowing. */
.group_tabs {
  display: flex;
  align-self: flex-end;
  gap: var(--sp-1);
  overflow-x: auto;
  padding-right: var(--sp-6);
  mask-image: linear-gradient(to right, #000 calc(100% - var(--sp-6)), transparent);
}

/* The leading edge cannot use the same trailing-padding trick: padding there
   would push the first tab off the panel's flush left corner. So it fades
   only once the strip has actually scrolled, which tab_scroll.ts reports,
   and then says the same thing the trailing fade does, that tabs continue
   past the edge. */
.group_tabs.is-scrolled {
  mask-image: linear-gradient(
    to right,
    transparent,
    #000 var(--sp-6),
    #000 calc(100% - var(--sp-6)),
    transparent
  );
}

/* Every tab carries an outline, so an unselected group reads as a tab rather
   than as loose text floating above the panel. The selected one sets itself
   apart by filling with the panel's own colour and dropping its bottom
   border, merging into the panel across the 1px the tab bar overlaps it. */
.group_tabs li a {
  display: block;
  padding: var(--sp-2) var(--sp-4);
  font-size: 18px;
  font-weight: 500;
  color: var(--text-secondary);
  background: transparent;
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  white-space: nowrap;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}

.group_tabs li a:hover {
  color: var(--text);
  background: var(--surface-alt);
  border-color: var(--border-strong);
  text-decoration: none;
}

.group_tabs li.active a {
  color: var(--accent);
  background: var(--surface);
  border-color: var(--border);
  font-weight: 600;
}

/* --- Content panel ----------------------------------------- */

#content {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0 var(--radius-lg) var(--radius-lg) var(--radius-lg);
  padding: var(--sp-6);
}

/* --- File list header -------------------------------------- */


.file_list_container h2 {
  font-size: 24px;
  font-weight: 600;
  color: var(--text);
  margin: 0;
}

.file_list_container h2 .covered_percent {
  font-weight: 600;
}

.summary-stats {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  font-size: 18px;
  color: var(--text-secondary);
}


.summary-stats b {
  color: var(--text);
}

.summary-stats .missed-branch-text b,
.summary-stats .missed-method-text-color b,
.summary-stats .green b,
.summary-stats .red b {
  color: inherit;
}

.summary-stats .green { color: var(--green); }
.summary-stats .red { color: var(--red); }

.coverage-disabled {
  color: var(--text-tertiary);
  font-style: italic;
}

/* --- DataTables overrides ---------------------------------- */


/* --- Column filters ---------------------------------------- */

.th-with-filter {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

table.file_list th.cell--coverage .th-with-filter {
  white-space: nowrap;
  justify-content: flex-end;
}

.th-with-filter .th-label {
  white-space: nowrap;
}

.col-filter--name {
  width: 100%;
  min-width: 200px;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: var(--sp-1) var(--sp-4);
  font-size: 14px;
  background: var(--surface);
  color: var(--text);
  outline: none;
}

.col-filter--name:focus {
  border-color: var(--accent);
}

.col-filter__coverage {
  display: flex;
  gap: var(--sp-1);
}

.col-filter__op {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-1) var(--sp-1);
  font-size: 14px;
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
}

.col-filter__value {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-1) var(--sp-2);
  font-size: 14px;
  background: var(--surface);
  color: var(--text);
  width: 60px;
  outline: none;
}

.col-filter__value:focus {
  border-color: var(--accent);
}


/* --- File list table --------------------------------------- */

.file_list--responsive {
  overflow-x: auto;
}

table.file_list {
  width: 100%;
  font-size: 18px;
}

table.file_list {
  border-collapse: separate;
  border-spacing: 0;
}


table.file_list thead th {
  font-size: 14px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  background: var(--surface);
  padding: var(--sp-2) var(--sp-2);
  border-bottom: 2px solid var(--border-strong);
  white-space: nowrap;
}

table.file_list tbody tr {
  background: var(--surface);
  cursor: pointer;
}

table.file_list tbody tr:nth-child(even) {
  background: var(--zebra);
}

table.file_list tbody tr:hover {
  background: var(--accent-subtle);
}

table.file_list tbody tr.keyboard-focus {
  background: var(--accent-subtle);
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

table.file_list tbody td {
  padding: var(--sp-2) var(--sp-2);
  border-bottom: 1px solid var(--border);
  color: var(--text);
}

table.file_list td.cell--number {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

table.file_list th.cell--left,
table.file_list th.cell--coverage {
  text-align: left;
}

table.file_list th.cell--number {
  text-align: right;
}

table.file_list th.cell--numerator {
  text-align: right;
  padding-right: 0;
}

table.file_list th.cell--denominator {
  text-align: left;
  padding-left: 0;
}

table.file_list td.strong {
  font-weight: 600;
  color: var(--text);
}

table.file_list td.t-file__name {
  white-space: nowrap;
}

a.src_link {
  color: var(--accent);
  font-weight: 500;
  word-break: break-all;
}

/* --- Coverage columns -------------------------------------- */

table.file_list td.cell--coverage {
  white-space: nowrap;
}

.coverage-cell {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}

.coverage-cell .coverage-pct {
  flex: 0 0 4.5em;
  font-variant-numeric: tabular-nums;
}

/* Rows beyond the window in a large file list (see row_window.ts). */
tr.t-window-hidden {
  display: none;
}

tr.t-show-all td {
  padding: var(--sp-3);
  text-align: center;
  color: var(--text-tertiary);
  cursor: pointer;
}

/* The width is uniform per table, so bar_width.ts equalizes it through one
   custom property on the table instead of inline styles on every sizer. */
.coverage-cell .bar-sizer {
  flex: 0 0 auto;
  width: var(--bar-sizer-width, 240px);
  min-width: 160px;
  max-width: 240px;
}

table.file_list td.cell--numerator {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  padding-left: var(--sp-1);
  padding-right: 0;
}

table.file_list td.cell--denominator {
  text-align: left;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  padding-left: 0;
  padding-right: var(--sp-1);
}

table.file_list .totals-row td.cell--numerator {
  color: var(--text);
  padding-right: 0;
}

table.file_list .totals-row td.cell--denominator {
  color: var(--text);
  padding-left: 0;
}

.coverage-cell__fraction {
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
  font-size: 14px;
  white-space: nowrap;
}

.coverage-bar {
  width: 100%;
  height: var(--bar-height);
  background: var(--bar-bg);
  border-radius: 6px;
  overflow: hidden;
}

.coverage-bar__fill {
  height: 100%;
  border-radius: 6px;
}

.coverage-bar__fill--green { background: var(--green); }
.coverage-bar__fill--yellow { background: var(--yellow); }
.coverage-bar__fill--red { background: var(--red); }


/* --- Color utility classes --------------------------------- */

.green, table.file_list td.green { color: var(--green); }
.red, table.file_list td.red { color: var(--red); }
.yellow, table.file_list td.yellow { color: var(--yellow); }
.missed-branch-text { color: var(--missed-branch-text); }
.missed-method-text-color { color: var(--missed-method-text); }

/* --- Source file dialog ------------------------------------ */

dialog.source-dialog {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  border: none;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  overflow: hidden;
}

dialog.source-dialog::backdrop {
  background: var(--overlay-bg);
}

dialog.source-dialog[open] {
  display: flex;
  flex-direction: column;
}

.source-dialog__header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: flex-start;
  padding: var(--sp-6);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.source-dialog__title {
  display: contents;
  min-width: 0;
}

.source-dialog__title h2 {
  grid-column: 1;
  grid-row: 1;
  font-size: 22px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: var(--sp-2);
  word-break: break-all;
}

.source-dialog__title .summary-stats {
  display: contents;
}

.source-dialog__title .t-line-summary {
  grid-column: 1;
  grid-row: 2;
}

.source-dialog__title .t-branch-summary {
  grid-column: 1;
  grid-row: 3;
}

.source-dialog__title .t-method-summary {
  grid-column: 1;
  grid-row: 4;
}

.source-dialog__title > .t-missed-method-list {
  grid-column: 1 / -1;
  grid-row: 5;
}

/* --- Source legend ------------------------------------------ */

.source-legend {
  display: contents;
}

.source-legend__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  align-items: center;
  align-self: center;
  justify-content: flex-end;
  grid-column: 2 / 4;
}

.source-legend__row--line {
  grid-row: 2;
}

.source-legend__row--branch {
  grid-row: 3;
}

.source-legend__row--method {
  grid-row: 4;
}

.source-legend__item {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: 13px;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* A chip of the exact background and line-number colours the source view
   paints each status with, so the legend is a sample of the thing itself. */
.source-legend__swatch {
  display: inline-block;
  width: 16px;
  height: 16px;
  border-radius: 3px;
  border: 1px solid var(--border);
}

.source-legend__swatch--covered       { background: var(--covered-bg); border-color: var(--covered-line-num-bg); color: var(--green); }
.source-legend__swatch--missed        { background: var(--missed-bg); border-color: var(--missed-line-num-bg); color: var(--red); }
.source-legend__swatch--skipped       { background: var(--skipped-bg); border-color: var(--skipped-line-num-bg); color: var(--text-secondary); }
.source-legend__swatch--missed-branch { background: var(--missed-branch-bg); border-color: var(--missed-branch-line-num-bg); color: var(--missed-branch-text); }
.source-legend__swatch--missed-method { background: var(--missed-method-bg); border-color: var(--missed-method-line-num-bg); color: var(--missed-method-text); }

/* The colorblind and dark toggles, repeated in the dialog header so the mode
   can be changed while a source file is open (the modal covers the report's
   own toolbar). The index toolbar reserves the close button's exact width and
   gap, so both copies have identical viewport coordinates. */
.source-dialog__toggles {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-shrink: 0;
  margin-left: var(--sp-4);
  align-self: flex-start;
}

.source-dialog__close {
  appearance: none;
  background: none;
  border: 1px solid var(--border);
  border-radius: 50%;
  width: var(--source-close-size);
  height: var(--source-close-size);
  font-size: 0;
  color: var(--text-secondary);
  cursor: pointer;
  position: relative;
  flex-shrink: 0;
  margin-left: var(--source-close-gap);
  transition: color 0.15s, border-color 0.15s;
}

.source-dialog__close::before,
.source-dialog__close::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
}

.source-dialog__close::before {
  transform: translate(-50%, -50%) rotate(45deg);
}

.source-dialog__close::after {
  transform: translate(-50%, -50%) rotate(-45deg);
}

.source-dialog__close:hover {
  color: var(--text);
  border-color: var(--border-strong);
}

.source-dialog__body {
  flex: 1;
  overflow: auto;
}

/* --- Source code viewer ------------------------------------- */

.source_table .header {
  padding: var(--sp-4) var(--sp-6);
  background: var(--surface);
}

.source_table .header h2 {
  font-size: 22px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: var(--sp-2);
}

table.file_list .totals-row td {
  padding: var(--sp-2) var(--sp-2);
  font-weight: 600;
  border-bottom: 2px solid var(--border-strong);
  background: var(--surface-alt);
}

.totals-row .t-file-count {
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
}

.t-missed-method-toggle {
  color: var(--missed-method-text);
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}

.t-missed-method-toggle:hover {
  text-decoration: underline;
  color: var(--missed-method-text);
}

.t-missed-method-list ul {
  padding-left: 2em;
  margin-top: var(--sp-1);
  max-height: 200px;
  overflow-y: auto;
}

.t-missed-method-list li {
  list-style: none;
}

.source_table pre {
  margin: 0;
  padding: 0;
  white-space: normal;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 16px;
  line-height: 24px;
  background: var(--source-bg);
  border: 1px solid var(--source-border);
  border-top: none;
}

.source_table code {
  color: inherit;
  font-family: var(--font-mono);
}

.source_table pre ol {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: linenumber;
}

.source_table pre li {
  display: flex;
  counter-increment: linenumber;
  background: var(--never-bg);
}

.source_table pre li::before {
  content: counter(linenumber);
  flex-shrink: 0;
  width: 50px;
  padding: 0 8px;
  text-align: right;
  color: var(--source-line-number);
  background: var(--source-line-num-bg);
  border-right: 1px solid var(--source-border);
  -webkit-user-select: none;
  user-select: none;
  cursor: pointer;
}

.source_table pre li:hover::before {
  color: var(--text);
}

.source_table pre li:hover {
  cursor: pointer;
}

.source_table pre li code {
  order: 1;
  flex: 1;
  min-width: 0;
  padding: 0 12px;
  white-space: pre-wrap;
}

/* Hit count badges */
.source_table pre .hits {
  order: 2;
  flex-shrink: 0;
  padding: 0 var(--sp-2);
  background: var(--hits-bg);
  color: var(--hits-color);
  font-family: var(--font-mono);
  font-size: 14px;
  text-align: center;
  line-height: 24px;
  border-left: 1px solid var(--source-border);
  -webkit-user-select: none;
  user-select: none;
}

.source_table pre .hits::after {
  content: attr(data-content);
}

/* Coverage line status */
.source_table .covered       { background-color: var(--covered-bg); }
.source_table .missed        { background-color: var(--missed-bg); }
.source_table .never         { background-color: var(--never-bg); }
.source_table .skipped       { background-color: var(--skipped-bg); }
.source_table .missed-branch { background-color: var(--missed-branch-bg); }
.source_table .missed-method { background-color: var(--missed-method-bg); }

.source_table .covered::before       { background-color: var(--covered-line-num-bg); }
.source_table .missed::before        { background-color: var(--missed-line-num-bg); }
.source_table .never::before         { background-color: var(--never-line-num-bg); }
.source_table .skipped::before       { background-color: var(--skipped-line-num-bg); }
.source_table .missed-branch::before { background-color: var(--missed-branch-line-num-bg); }
.source_table .missed-method::before { background-color: var(--missed-method-line-num-bg); }

/* --- Toolbar toggles (colorblind + dark) ------------------- */

.toolbar {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  flex-shrink: 0;
  margin-right: var(--source-close-slot);
}

/* The pill shape marks these as controls, the same as the filter input. This
   padding puts them at exactly --source-close-size tall, so they match the
   dialog's close button and sit level with it there and with the tab tops
   here. They stay unfilled, taking the same outline-on-page-background the
   unselected tabs use rather than the panel white, so the bar reads as one
   family of chips and the filled shapes stay meaningful: the selected tab,
   and a toggle that is switched on. */
.toolbar-toggle {
  appearance: none;
  background: transparent;
  color: var(--text-secondary);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: var(--sp-1) var(--sp-4);
  font-size: 16px;
  font-family: var(--font-sans);
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}

.toolbar-toggle:hover {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border-strong);
}

/* Pressed state for the colorblind toggle: it is a mode switch, not a
   this-or-that swap like the dark toggle, so reflect "on" with a filled
   accent chip (aria-pressed carries it to assistive tech). */
.toolbar-toggle[aria-pressed="true"] {
  background: var(--accent-subtle);
  color: var(--accent);
  border-color: var(--accent);
}

/* --- Keyboard focus ---------------------------------------- */

/* A visible focus ring on every keyboard-focused control. :focus-visible keeps
   it off mouse clicks, so it aids keyboard users without adding chrome for
   everyone else. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
[tabindex]:focus-visible,
.source_table pre li:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* --- Footer ------------------------------------------------ */

#footer,
.source-dialog__footer {
  color: var(--text-tertiary);
  font-size: 16px;
  text-align: center;
}

#footer {
  margin-top: var(--sp-5);
}

.source-dialog__footer {
  flex-shrink: 0;
  padding: var(--sp-3) var(--sp-6);
  background: var(--bg);
  border-top: 1px solid var(--border);
}

#footer a,
.source-dialog__footer a {
  color: var(--text-secondary);
  text-decoration: underline;
}

#footer a:hover,
.source-dialog__footer a:hover {
  color: var(--text);
}

/* --- Sorting indicators (DataTables) ----------------------- */

table.file_list thead th.sorting,
table.file_list thead th.sorting_asc,
table.file_list thead th.sorting_desc {
  cursor: pointer;
  position: relative;
  padding-right: 12px;
}

table.file_list thead th.sorting::after,
table.file_list thead th.sorting_asc::after,
table.file_list thead th.sorting_desc::after {
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 14px;
  color: var(--text-tertiary);
}

table.file_list thead th.sorting::after        { content: "\2195"; }
table.file_list thead th.sorting_asc::after     { content: "\2191"; }
table.file_list thead th.sorting_desc::after    { content: "\2193"; }

/* --- Print ------------------------------------------------- */

@media print {
  /* Force light palette */
  :root, .dark-mode {
    --bg: #fff;
    --surface: #fff;
    --surface-alt: #f4f5f7;
    --text: #111;
    --text-secondary: #333;
    --text-tertiary: #444;
    --zebra: #f4f5f7;
    --border: #c0c5cc;
    --border-strong: #999;
    --accent: #0550ae;
    --green: #116329;
    --red: #a40e26;
    --yellow: #7a5200;
    --orange: #953800;
    --bar-bg: #d0d7de;
    --covered-bg: #ccf5d0;
    --covered-line-num-bg: #9ae6a4;
    --missed-bg: #ffd8d5;
    --missed-line-num-bg: #ffb8b3;
    --never-bg: #fff;
    --never-line-num-bg: #f0f1f3;
    --skipped-bg: #fff0a0;
    --skipped-line-num-bg: #eed860;
    --missed-branch-bg: #ffd0a0;
    --missed-branch-line-num-bg: #ffb060;
    --missed-branch-text: #b45309;
    --missed-method-bg: #e8d0ff;
    --missed-method-line-num-bg: #d4b0ff;
    --missed-method-text: #7b2d8e;
    --source-bg: #fff;
    --source-border: #c0c5cc;
    --source-line-number: #444;
    --source-line-num-bg: #f0f1f3;
    --hits-bg: #e0e3e8;
    --hits-color: #333;
  }

  /* Keep the colorblind palette on paper. The reset above forces the standard
     light green/red for every context; re-assert the light colorblind values
     (same specificity, later in source) so a colorblind report prints blue and
     orange rather than the green and red its reader configured away. */
  .colorblind-mode {
    --green: #0060a8;
    --red: #c2410c;
    --covered-bg: #d3eaf7;
    --covered-line-num-bg: #a5d2ee;
    --missed-bg: #ffe0cc;
    --missed-line-num-bg: #ffc39a;
  }

  body {
    padding: 0;
    font-size: 12pt;
  }

  /* Hide interactive/non-printable elements */
  #loading,
  #sort-overlay,
  .toolbar,
  .source-dialog__toggles,
  .tab-bar,
  .source_files,
  .col-filter--name,
  .col-filter__coverage,
  tr.t-show-all,
  table.file_list thead th.sorting::after,
  table.file_list thead th.sorting_asc::after,
  table.file_list thead th.sorting_desc::after {
    display: none !important;
  }

  /* --- File list view (dialog closed) --- */

  /* Show all tab groups */
  #wrapper, .file_list_container {
    display: block !important;
  }

  /* Hide file list when source dialog is open */
  body:has(.source-dialog[open]) #wrapper {
    display: none !important;
  }

  /* Remove panel border/radius since there are no tabs */
  #content {
    border: none;
    border-radius: 0;
    padding: 0;
  }

  /* Group headings — re-show the hidden group name */
  .file_list_container .group_name {
    display: inline !important;
    font-size: 16pt;
    font-weight: 700;
  }

  .file_list_container .covered_percent {
    display: inline !important;
    font-weight: 600;
  }

  /* Add space between groups */
  .file_list_container + .file_list_container {
    margin-top: 24pt;
  }

  /* --- Source file view (dialog open) --- */

  dialog.source-dialog {
    display: none;
  }

  dialog.source-dialog[open] {
    display: block !important;
    position: static;
    width: 100%;
    height: auto;
    max-height: none;
    overflow: visible;
    background: #fff;
  }

  .source-dialog__close {
    display: none !important;
  }

  /* On screen the header is a grid that seats each legend row beside its
     coverage summary, in the columns the toggles and close button occupy.
     Those controls don't print, so on paper that layout only squeezes the
     summaries against a legend column. Fall back to document flow, which
     prints each legend row full width beneath the summary it describes. */
  .source-dialog__header {
    display: block;
    border-bottom: none;
    padding: 0 0 8pt 0;
  }

  .source-dialog__title h2 {
    word-break: normal;
    overflow-wrap: break-word;
  }

  .source-legend__row {
    justify-content: flex-start;
  }

  .source-dialog__body {
    overflow: visible;
  }

  .source_table pre {
    font-size: 8pt;
    line-height: 1.4;
  }

  .source_table pre li {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  .source_table pre li::before {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  .source_table pre .hits {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* Coverage bar: add border so it's visible without color printing */
  .coverage-bar {
    border: 1px solid var(--border);
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  .coverage-bar__fill {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* Preserve background colors for coverage status */
  table.file_list tbody tr:nth-child(even) {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* Table typography for print */
  table.file_list {
    font-size: 10pt;
  }

  table.file_list thead th {
    font-size: 9pt;
  }

  /* Page break handling */
  table.file_list {
    page-break-inside: auto;
  }

  table.file_list tr {
    page-break-inside: avoid;
  }

  table.file_list thead {
    display: table-header-group;
  }

  #footer,
  .source-dialog__footer {
    font-size: 10pt;
    margin-top: 12pt;
  }

  /* Links: show URL after link text */
  #footer a::after,
  .source-dialog__footer a::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    color: var(--text-tertiary);
  }
}
