/* The gopher sites' listings table: every table rule the sites share, in one sheet (the design language's rules 1 and
   6, docs/gopher-network/design-language/README.md). gopher/layout.html loads it on every listings page
   (gopher_listings_page), after shell.css and before the site's own sheet, so a site's sheet may override it; the
   shared listings page's panel and page-head sheet (listings.css) follows the site's.

   It holds LabGopher's table look (app/static/js/lg/table.js), which the shared table (js/table/table.js) now takes
   too. Selectors key on DataTables' table.dataTable, which both tables carry. A numeric column is .lg-num on
   LabGopher and .text-end on the shared table, until DL-08 puts LabGopher on the shared table.

   Plain and data-dense: no pills, chips, accent bars, gradients, glow, stripes or tiny uppercase labels. Color carries
   meaning only (links, the grade fill, the sorted column's header tint): nothing is shaded by where its data came
   from. The one solid 2px focus outline (--lg-focus-color, shell.css). Built on Bootstrap's variables, so both color
   modes work. No !important. */

/* ---- Tokens -------------------------------------------------------------------------------------------------- */

:root {
  /* Grade cell fills: the original site's colors. The word always names the grade; the dark text on every fill has at
     least 5:1 contrast. */
  --lg-great-bg: #63d863;
  --lg-good-bg: #a0e7a0;
  --lg-fair-bg: #fcf4a3;
  --lg-bad-bg: #ff6961;
  --lg-grade-fg: #1a1d1a;

  --lg-visited-bg: rgba(111, 66, 193, .07);  /* rows whose eBay link was opened (js/common/visited.js) */
  --lg-visited-link: #6f42c1;
  --lg-sorted-bg: rgba(13, 110, 253, .08);   /* header of the column the rows are sorted by */
}

[data-bs-theme="dark"] {
  /* Slightly deeper fills so they don't glare on the dark page; text stays dark. */
  --lg-great-bg: #3fae5a;
  --lg-good-bg: #7cc98a;
  --lg-fair-bg: #d9cc6a;
  --lg-bad-bg: #e0605a;
  --lg-grade-fg: #0b0f0c;
  --lg-visited-bg: rgba(194, 159, 250, .08);
  --lg-visited-link: #c29ffa;
  --lg-sorted-bg: rgba(110, 168, 254, .14);
}

/* ---- Focus --------------------------------------------------------------------------------------------------- */

.lg-expand:focus-visible { outline: 2px solid var(--lg-focus-color); outline-offset: 2px; }

/* ---- "No listings match these filters: …" with a Reset button, inside the empty table ------------------------ */

.lg-no-match { max-width: 60ch; margin: 0 auto .5rem; white-space: normal; }

/* ---- DataTables' controls: page length, "Filter rows", the count line and the pager -------------------------- */

div.dt-container { font-size: .875rem; }
div.dt-container div.dt-search input { width: 14rem; max-width: 60vw; }
div.dt-container div.dt-info { color: var(--bs-secondary-color); }
/* Below 768px DataTables centers its controls (page length, "Filter rows", the count and the pager); the rest of the
   page is left-aligned, so these are too. The pager list is centered with !important, so it shrinks to its buttons
   instead and the line aligns it. */
@media (max-width: 767.98px) {
  div.dt-container div.dt-length,
  div.dt-container div.dt-search,
  div.dt-container div.dt-info,
  div.dt-container div.dt-paging { text-align: left; }
  div.dt-container div.dt-paging ul.pagination { display: inline-flex; }
}
div.dt-container .pagination {
  --bs-pagination-padding-x: .625rem;
  --bs-pagination-padding-y: .25rem;
  --bs-pagination-font-size: .875rem;
}
/* Pager buttons: the focus outline above the neighboring buttons. */
.page-link:focus-visible { z-index: 3; }

/* ---- The table ------------------------------------------------------------------------------------------------ */

table.dataTable { font-size: .875rem; font-variant-numeric: tabular-nums; }
/* table-sm's .25rem side padding leaves a right-aligned number touching the left-aligned text of the next column
   ("10,348 2.5″"): widen just those gaps. */
table.dataTable.table-sm > :not(caption) > tr > :is(.lg-num, .text-end) + :not(.lg-num, .text-end):not(.lg-grade-col) { padding-left: .875rem; }
/* Likewise after the solid grade fill ("Great" then "2U"). The fill's edge already separates it from the column
   before; from 576px the word gets room inside the fill too (phones keep .25rem so the grade fits beside the
   prices). */
table.dataTable.table-sm > :not(caption) > tr > .lg-grade-col + * { padding-left: .75rem; }
@media (min-width: 576px) {
  table.dataTable.table-sm > :not(caption) > tr > .lg-grade-col { padding-inline: .5rem; }
  /* An ungraded dash right after "Time left" (also a dash for Buy It Now) read as one "— —" cell. */
  table.dataTable.table-sm > tbody > tr > .lg-num + td.lg-grade-col:has(> .lg-muted) { padding-left: .875rem; }
}
/* Rule 1, one listing, one line: no cell wraps. What doesn't fit goes into the row's details (the child row, which
   wraps), where Responsive puts the columns with the lowest priority; the listing title is the last of them. */
table.dataTable > tbody > tr > td { white-space: nowrap; }
table.dataTable > tbody > tr > td.child { white-space: normal; }
/* A <wbr> still breaks a nowrap line in Chrome: in a cell it isn't rendered (the child row keeps it). */
table.dataTable > tbody > tr > td:not(.child) wbr { display: none; }
/* Phones: header titles ("Price w/ shipping") wrap rather than push the price columns out of the row. */
@media (max-width: 575.98px) {
  table.dataTable > thead > tr > th .dt-column-title { white-space: normal; }
  table.dataTable.table-sm > * > tr > .lg-control { width: 1.5rem; padding-inline: 0; }   /* the page gutter is beside it */
  /* The "Sort by" select above the table is the phone's sort control, so a column the rows aren't sorted by shows no
     arrows; its header stays a sort button (the whole cell is the target and gets the focus ring), and the sorted
     column keeps its arrow. */
  table.dataTable > thead > tr > th { position: relative; }
  table.dataTable.table-sm > thead > tr > th.dt-orderable-asc:not(.dt-ordering-asc):not(.dt-ordering-desc) .dt-column-order {
    position: absolute;
    inset: 0;
    width: auto; height: auto;
    margin: 0; padding: 0;
  }
  table.dataTable.table-sm > thead > tr > th.dt-orderable-asc:not(.dt-ordering-asc):not(.dt-ordering-desc) .dt-column-order::before,
  table.dataTable.table-sm > thead > tr > th.dt-orderable-asc:not(.dt-ordering-asc):not(.dt-ordering-desc) .dt-column-order::after { display: none; }
}

/* ---- The header ----------------------------------------------------------------------------------------------- */

/* Small bold titles (rule 6). */
table.dataTable > thead > tr > th { font-size: .75rem; font-weight: 600; line-height: 1.25; vertical-align: bottom; }
/* A title on two lines ("Ships from", "Drive bays" on laptops) keeps its sort arrows beside its last line, the line
   every header's title ends on, rather than halfway up. */
table.dataTable > thead { --dt-header-align-items: flex-end; }
table.dataTable > thead > tr > th:focus-visible { outline: 2px solid var(--lg-focus-color); outline-offset: -2px; }
/* The sort button (the arrows) gets a 24px box, the minimum target size, without moving the header text: padding
   grows it, negative margins give the space back. Its content box is one line of the title tall, so the arrows are
   centered on the title's last line (--dt-header-align-items). */
table.dataTable.table-sm > thead > tr > th .dt-column-order { box-sizing: content-box; height: .9375rem; padding: 4.5px 6px; margin: -4.5px -6px; }
/* The title row is tall enough for a 24px button inside its bottom rule: on phones a header without arrows is a sort
   button the size of its cell. */
table.dataTable > thead > tr:last-child > th { height: calc(1.5rem + var(--bs-border-width)); }
table.dataTable.table-sm > thead > tr > th .dt-column-order::before,
table.dataTable.table-sm > thead > tr > th .dt-column-order::after { left: 6px; }
table.dataTable > thead > tr > th .dt-column-order:focus-visible { outline: 2px solid var(--lg-focus-color); outline-offset: 0; border-radius: 2px; }
/* The column the rows are sorted by: a faint blue tint behind its header (Bootstrap's state layer, over the header's
   background) and its arrow at full strength, so the order shows at a glance; DataTables' own arrow alone is
   faint. */
table.dataTable > thead > tr > th:is(.dt-ordering-asc, .dt-ordering-desc) { --bs-table-bg-state: var(--lg-sorted-bg); }
table.dataTable > thead > tr > th.dt-ordering-asc .dt-column-order::before,
table.dataTable > thead > tr > th.dt-ordering-desc .dt-column-order::after { opacity: 1; }
/* A wrapped left-aligned title fills the column's width and its arrows would sit at the column's edge: LabGopher's
   table.js (alignSortArrows) gives the gap to the end of its last line as --lg-order-shift, so they sit beside the
   text as on one-line titles (DataTables' own right: .25rem included). */
table.dataTable.table-sm > thead > tr > th.lg-order-shifted .dt-column-order { left: calc(var(--lg-order-shift, 0px) - .25rem); }
/* Sort icons sit right after their title (numeric headers right-aligned), not at the far edge of the cell, where they
   read as belonging to the neighboring column. */
table.dataTable thead > tr > th div.dt-column-header { justify-content: flex-start; }
table.dataTable thead > tr > th div.dt-column-header .dt-column-title { flex-grow: 0; }
table.dataTable thead > tr > th.dt-type-numeric div.dt-column-header,
table.dataTable thead > tr > th:is(.lg-num, .text-end) div.dt-column-header { flex-direction: row; justify-content: flex-end; }

/* Topic group labels: a first header row (not sortable: data-dt-order="disable") with a small label over each group of
   more than one column ("CPU", "Storage"); the empty cells beside them draw no rule. No arrows, no shading. */
table.dataTable > thead .lg-group {
  padding-bottom: .125rem;
  font-size: .75rem;
  text-align: center;
  color: var(--bs-secondary-color);
  border-bottom: 2px solid var(--bs-border-color);
}
table.dataTable > thead .lg-group div.dt-column-header { justify-content: center; }
table.dataTable > thead > tr:has(> .lg-group) > :not(.lg-group) { border-bottom-color: transparent; }

/* ---- Child rows ----------------------------------------------------------------------------------------------- */

/* Responsive's child rows (collapsed columns): the hidden values in the row's column order, as compact label/value
   pairs in one grid that flows into as many columns as fit; no shading and no rule between groups. :nth-child(n)
   matches the specificity of Responsive's :first-child and :last-child padding rules so every item gets the same
   padding. */
table.dataTable > tbody > tr.child ul.dtr-details {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  column-gap: 1.5rem;
  width: 100%;
}
table.dataTable > tbody > tr.child ul.dtr-details > li:nth-child(n) { display: flex; gap: .75rem; padding-block: .25rem; }
table.dataTable > tbody > tr.child span.dtr-title { min-width: 8rem; font-weight: 600; color: var(--bs-secondary-color); }
.lg-no-details { margin: 0; color: var(--bs-secondary-color); }

/* The expand column (Responsive's control column, shown only while columns are collapsed): one chevron button per
   row, turned down while the row's details are open. Tapping elsewhere on a row that isn't a link or a button
   toggles it too (both tables' table.js), on a table with a control column (details type 'lg' on LabGopher, 'gopher'
   on the shared table). */
table.dataTable > * > tr > .lg-control { width: 1.75rem; padding-inline: .25rem 0; text-align: center; }
table.dataTable.collapsed:is(.dtr-lg, .dtr-gopher) > tbody > tr:not(.child) { cursor: pointer; }
.lg-expand {
  --bs-btn-color: var(--bs-secondary-color);
  --bs-btn-hover-color: var(--bs-link-hover-color);
  --bs-btn-active-color: var(--bs-link-hover-color);
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; min-height: 1.5rem;              /* 24px target */
  line-height: 1;
  vertical-align: middle;
}
tr.dtr-expanded .lg-expand { --bs-btn-color: var(--bs-emphasis-color); }
tr.dtr-expanded .lg-expand .lg-icon { transform: rotate(90deg); }
@media (prefers-reduced-motion: no-preference) {
  .lg-expand .lg-icon { transition: transform .15s ease-out; }
}

/* ---- Cells ---------------------------------------------------------------------------------------------------- */

.lg-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lg-muted { color: var(--bs-secondary-color); }

/* Bootstrap's link blue is exactly 4.5:1 on white and 3.8:1 on a hovered row: use its darker hover blue for links in
   the table (5.4:1 on a hovered row). */
[data-bs-theme="light"] table.dataTable { --bs-link-color-rgb: 10, 88, 202; --bs-link-hover-color-rgb: 8, 66, 152; }
/* A row whose eBay link was opened in this browser session (js/common/visited.js): a faint tint, and the listing
   link in the visited color (4.8:1 or more in both modes, hovered or not). */
table.dataTable > tbody > tr.lg-visited > * { --bs-table-bg-type: var(--lg-visited-bg); }
tr.lg-visited a[data-itemid] { color: var(--lg-visited-link); }

/* An unknown value: a muted dash (the shared table's columns.js dash(); LabGopher's is a muted .lg-tip). */
.lg-dash { color: var(--bs-secondary-color); }

/* Explained values (.lg-tip): the auction gavel, the ≈ markers, the grade, "est." and an unknown value's dash. Each
   shows its explanation on hover, tap or focus; padding gives a muted one at least a 24px target and matching
   negative margins keep the text where it was. */
.lg-tip { display: inline-block; cursor: help; border-radius: 2px; }
/* A tooltip fading out (focus or the pointer has moved on) no longer catches the pointer: placed beside a value at the
   window's edge, it would cover the next value for its 150ms fade. */
.tooltip:not(.show) { pointer-events: none; }
.lg-tip:focus-visible { outline: 2px solid var(--lg-focus-color); outline-offset: 0; }
.lg-muted.lg-tip,
.lg-dash.lg-tip { padding: 3px 5px; margin: -3px -5px; }
/* Our estimate: the number, then a muted "est." ("19,679 est."). The shared vocabulary's .lg-est follows a literal
   space, so its margin only cancels its own padding; LabGopher's .lg-pm-est has no space before it. When some values
   in a column are estimates, the others get an invisible "est." (.lg-pm-est-space), so the column's digits line up. */
.lg-est {
  padding: 3px 4px;
  margin: -3px -4px;
  font-size: .75rem;
  color: var(--bs-secondary-color);
}
.lg-pm-est {
  padding: 3px 4px;
  margin: -3px -4px -3px calc(.25rem - 4px);
  font-size: .75rem;
  color: var(--bs-secondary-color);
}
.lg-pm-est-space { visibility: hidden; }
/* An auction: the gavel sits before the price, so auction prices line up with the others. Muted by its own class
   (no marker carries .lg-muted, whose .lg-muted.lg-tip padding would override this). */
.lg-auction {
  padding: 5px;
  margin: -5px calc(.25rem - 5px) -5px -5px;
  line-height: 1;
  vertical-align: -.125em;
  color: var(--bs-secondary-color);
}
.lg-auction .lg-icon { display: block; }
/* The same gavel before Price w/ shipping (.lg-auction-ship) shows only while the Price column, which has its own, is
   collapsed: the shared table sets .lg-price-hidden then (table.js; LabGopher's table.js, with labgopher.css's copy of
   these two rules, until DL-08). */
.lg-auction.lg-auction-ship { display: none; }
table.dataTable.lg-price-hidden .lg-auction.lg-auction-ship { display: inline-block; }
/* Approximate or inferred: "≈" before the value, muted and dotted ("≈$116.98", "≈E5530", or "≈ one of 3" for several
   candidates), explained in its tooltip. .lg-approx is the shared vocabulary's (approx()); LabGopher's ≈ shipping and
   inferred CPU move onto it in DL-07. */
.lg-approx,
.lg-ship-approx,
.lg-cpu-inf {
  padding: .25rem .5rem;
  margin: -.25rem calc(.125rem - .5rem) -.25rem -.5rem;
  color: var(--bs-secondary-color);
  text-decoration: underline dotted;
  text-underline-offset: .2em;
}
.lg-cpu-inf-several { margin-right: -.5rem; white-space: nowrap; }

/* The grade (the verdict): the whole cell is filled with the grade's color, as on the original site. Setting
   Bootstrap's table color variables on the cell keeps the fill solid under row hover and visited-row tints. In child
   rows the word gets the fill. */
.lg-grade { font-weight: 600; }
.lg-grade-great { --lg-grade-bg: var(--lg-great-bg); }
.lg-grade-good { --lg-grade-bg: var(--lg-good-bg); }
.lg-grade-fair { --lg-grade-bg: var(--lg-fair-bg); }
.lg-grade-bad { --lg-grade-bg: var(--lg-bad-bg); }
table.dataTable > tbody > tr > td:has(> .lg-grade-great) { --lg-cell-bg: var(--lg-great-bg); }
table.dataTable > tbody > tr > td:has(> .lg-grade-good) { --lg-cell-bg: var(--lg-good-bg); }
table.dataTable > tbody > tr > td:has(> .lg-grade-fair) { --lg-cell-bg: var(--lg-fair-bg); }
table.dataTable > tbody > tr > td:has(> .lg-grade-bad) { --lg-cell-bg: var(--lg-bad-bg); }
table.dataTable > tbody > tr > td:has(> .lg-grade) {
  --bs-table-bg: var(--lg-cell-bg);
  --bs-table-bg-type: var(--lg-cell-bg);
  --bs-table-bg-state: var(--lg-cell-bg);
  --bs-table-color: var(--lg-grade-fg);
  --bs-table-color-type: var(--lg-grade-fg);
  --bs-table-color-state: var(--lg-grade-fg);
}
/* DataTables tints a hovered row with its own inset shadow (7.5% black, white in dark mode), which replaces
   Bootstrap's fill: the grade cell keeps its own color instead. */
table.table.dataTable.table-hover > tbody > tr:hover > td:has(> .lg-grade) { box-shadow: inset 0 0 0 9999px var(--lg-cell-bg); }
table.dataTable > tbody > tr.child .dtr-data > .lg-grade {
  padding: 0 .375rem;
  color: var(--lg-grade-fg);
  background: var(--lg-grade-bg);
}
/* The grade word is focusable (its meaning is a tooltip). On the fills the focus blue is under 3:1 (2.5:1 on Great's
   green), so its outline takes the grade text's color, 6:1 or more on every fill. */
.lg-grade.lg-tip:focus-visible { outline-color: var(--lg-grade-fg); }
