/* /sales layout. No gradient literals here -- those live in gradients.css.
 *
 * Deliberately small. Everything that is page CHROME comes from shared
 * building blocks: the masthead (pm-*), the filter bar (cc-toolbar), the
 * condition/publisher/price chips (cc-chip), the CARDS and the grid itself
 * (the /omnis tile, comic_tile.css), the empty and error states (cc-empty),
 * the loading state (skel-*), and the paging button (cc-btn). What is left
 * below is toolbar spacing, paging furniture, and the two sale-specific bits
 * of the tile footer -- so /sales adds no local card, panel, or toolbar
 * primitive to the repo's inventory (scripts/audit_css_building_blocks.py).
 */

/* Filter bar. cc-toolbar supplies the surface, border, padding and gap; this
   only spaces the groups within it. */
.sales-controls { margin: 1rem 0 1.25rem; row-gap: 0.75rem; }

/* Sits above the toolbar and selects the row population. Layout only -- the
   look is the shared cc-tabs/cc-segment primitive. */
.sales-mode-switch { margin: 1.25rem 0 0; }

.storefront-context,
.storefront-discovery {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem 1rem;
  margin: 1rem 0 0;
  padding: 0.8rem 1rem;
  border-block: 1px solid var(--border);
  color: var(--text-muted);
}
.storefront-context p { margin: 0; }
.storefront-condition {
  color: var(--text);
  font-weight: 600;
}
.storefront-condition i { margin-right: 0.35rem; color: var(--accent-upcoming); }
.storefront-discovery > span {
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.storefront-context a,
.storefront-discovery a { font-weight: 600; }

@media (max-width: 640px) {
  .storefront-context,
  .storefront-discovery { align-items: flex-start; flex-direction: column; }
}

/* The facet groups themselves are the shared cc-filters panel (theme.css);
   nothing about them is page-local any more. The one thing that is: the
   trigger sits at the far end of the toolbar, past the selects. Computes to 0
   while the search box grows, but is the whole right-align mechanism if it
   ever does not. */
.sales-filter-trigger { margin-left: auto; }

.sales-select { width: auto; min-width: 10rem; }
/* Square, so the arrow reads as a control on the select beside it rather
   than as a stray chip. */
.sales-reverse { min-width: 2.25rem; justify-content: center; padding-inline: 0.5rem; }
/* The search box takes the slack so the two selects and the trigger keep
   their natural widths instead of stretching across the bar. */
#sales-q { flex: 1 1 12rem; min-width: 10rem; }

/* Presentation switch. It sits outside the filter surface in a dedicated row
   immediately before the results it changes. The shared segment owns its
   border, surface and active state. */
.sales-results-controls {
  display: flex;
  justify-content: flex-end;
  margin: -0.75rem 0 1.25rem;
}
/* The negative margin above closes the gap to the toolbar when the filter
   panel is collapsed (its usual state). With the panel OPEN and in flow, the
   same -12px pulls this row 12px INSIDE the panel's bottom edge -- measured,
   not guessed. Scoped to the desktop query because below 640px the panel is a
   fixed-position sheet and never occupies flow here. */
@media (min-width: 640.1px) {
  .cc-filters.is-open + .sales-results-controls { margin-top: 0.75rem; }
}
.sales-view-toggle { flex: 0 0 auto; }
.sales-view-toggle .cc-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

/* Table view. Bootstrap owns table color/surface behavior; these rules own
   scan-friendly geometry and preserve every column through horizontal scroll. */
.sales-table-wrap { margin-bottom: 0.25rem; }
.sales-table {
  min-width: 64rem;
  margin-bottom: 0;
}
.sales-table th {
  color: var(--text-muted);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.sales-table td { vertical-align: middle; }
.sales-table-book { min-width: 18rem; }
.sales-table-book-link {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  align-items: center;
  gap: 0.75rem;
  color: inherit;
  text-decoration: none;
}
.sales-table-book-link:hover .sales-table-title { color: var(--accent); }
.sales-table-cover {
  display: block;
  width: 2.5rem;
  aspect-ratio: 2 / 3;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  background: var(--omni-surface);
}
.sales-table-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.sales-table-book-copy {
  display: grid;
  gap: 0.15rem;
  min-width: 0;
}
.sales-table-publisher {
  color: var(--text-muted);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.sales-table-title {
  font-weight: 650;
  line-height: 1.25;
}
/* The flex row lives on an inner wrapper, NOT on the <td>: a table cell set to
   display:flex stops being a table-cell box, so the row wraps it in an
   anonymous cell. It then no longer stretches to the row height, ignores the
   table's vertical-align: middle, and paints its own border-bottom part-way up
   the row -- the retailer column sat ~19px above every other one. */
.sales-table-retailer {
  min-width: 9rem;
  white-space: nowrap;
}
.sales-table-retailer-inner {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.sales-table-retailer .store-logo {
  --store-logo-size: 1.35rem;
  flex: 0 0 auto;
  border-radius: 0.25rem;
}
.sales-table-number,
.sales-table-added {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sales-table-number { text-align: right; }
.sales-comparable {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  margin-top: 0.25rem;
  font-size: 0.8rem;
  line-height: 1.3;
}
.sales-comparable-gap { font-weight: 600; }
.sales-comparable-offer { color: var(--text-muted); }

.sales-shipping-note {
  color: var(--text-muted);
  font-size: 0.75rem;
  line-height: 1.4;
  white-space: normal;
}
.sales-table-number .sales-shipping-note { max-width: 14rem; }
.sales-table-mobile-label { display: none; }
.sales-table-skeleton .placeholder { min-height: 0.8rem; }

/* Phone table reflow. */
@media (max-width: 640px) {
  /* Every value fits in the viewport, so Bootstrap's horizontal-scroll
     affordance is unnecessary and no column is parked off-screen. */
  .sales-table-wrap { overflow-x: visible; }
  .sales-table {
    width: 100%;
    min-width: 0;
  }
  /* Keep the native headings in the accessibility tree while each visible
     value repeats its heading through data-label below. */
  .sales-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
  .sales-table tbody {
    display: block;
    width: 100%;
  }
  .sales-table tbody tr {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.7rem 1rem;
    padding: 0.85rem 0.15rem;
    border-bottom: 1px solid var(--border);
  }
  .sales-table tbody td {
    display: grid;
    align-content: start;
    gap: 0.15rem;
    min-width: 0;
    padding: 0;
    border: 0;
    white-space: normal;
    text-align: left;
  }
  .sales-table-mobile-label {
    display: block;
    color: var(--text-muted);
    font-size: 0.65rem;
    font-weight: 650;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }
  .sales-table tbody .sales-table-book {
    grid-column: 1 / -1;
    min-width: 0;
    order: 0;
  }
  .sales-table-title { overflow-wrap: anywhere; }
  .sales-table tbody td[data-label="Sale price"] { order: 1; }
  .sales-table tbody td[data-label="Discount"] { order: 2; }
  .sales-table tbody .sales-table-retailer {
    grid-column: 1 / -1;
    order: 3;
  }
  .sales-table-retailer-inner { flex-wrap: wrap; }
  .sales-table-buy-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .sales-table tbody td[data-label="Format"] { order: 4; }
  .sales-table tbody td[data-label="Condition"] {
    order: 5;
    /* Override Bootstrap's .text-nowrap utility, which is !important. */
    white-space: normal !important;
    overflow-wrap: anywhere;
  }
  .sales-table tbody td[data-label="MSRP"] { order: 6; }
  .sales-table tbody .sales-table-added { order: 7; }
  /* The thumbs come last and take the full row: two 44px targets do not
     share a half-width cell with a date. */
  .sales-table tbody .sales-table-vote {
    grid-column: 1 / -1;
    order: 8;
  }
  .sales-table-number .sales-shipping-note { max-width: none; }
}

/* Paging. The sentinel is a 1px in-flow probe sitting just above the manual
   fallback button; the observer's rootMargin is what gives it lead time, so it
   needs no offset of its own. Deliberately NOT positioned or hidden -- a
   sentinel with no layout box measures as all-zeros, which reads as "at the
   top of the viewport" and would page forever. */
.sales-sentinel {
  height: 1px;
  width: 100%;
  pointer-events: none;
}
.sales-more {
  display: flex;
  justify-content: center;
  margin: 1.5rem 0 0;
}

.sales-error { margin: 1rem 0 0; }

/* The two sale-specific bits of the shared tile footer. */
.sales-msrp {
  color: var(--omni-text-muted);
  font-size: 0.85em;
  text-decoration: line-through;
}
/* Flex so the storefront logo chip sits on one line with the retailer name
   rather than stacking above it. The chip's shared 1.75rem box is shrunk here
   to suit the tile footer's 0.7rem type instead of dominating the card. */
.sales-retailer {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--omni-text-muted);
  font-size: 0.7rem;
  margin-top: 0.15rem;
}
.sales-retailer .store-logo {
  --store-logo-size: 1.1rem;
  border-radius: 0.25rem;
}
.sales-buy-link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  margin: 0.5rem 0 0;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: 0.375rem;
  color: var(--text);
  font-weight: 650;
  text-align: center;
  text-decoration: none;
}
.sales-buy-link:hover,
.sales-table-buy-link:hover { color: var(--accent); }
.sales-buy-link:focus-visible,
.sales-table-buy-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.sales-table-buy-link { font-weight: 650; white-space: nowrap; }

/* Every sales tile stacks its content: storefront buy links and general-sale
   assessments both belong below the full-width book, including when no
   assessment is rendered. The shared shell otherwise defaults to a row. */
#sales-app .omni-card-shell {
  flex-direction: column;
}
/* Share the book, vote and assessment row heights across each grid row. Longer
   titles, shipping notes and explanations cannot move a neighbor's footer. */
@supports (grid-template-rows: subgrid) {
  #sales-app .omni-grid > .omni-card-shell {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 3;
    row-gap: 0;
  }
  #sales-app .omni-grid > .omni-card-shell > .deal-vote-hidden { align-self: start; }
  #sales-app .omni-grid > .omni-card-shell > .omni-card { grid-row: 1; }
  #sales-app .omni-grid > .omni-card-shell > .deal-vote { grid-row: 2; }
  #sales-app .omni-grid > .omni-card-shell > .sale-assessment,
  #sales-app .omni-grid > .omni-card-shell > .sales-buy-link { grid-row: 3; }
}

/* Server-authored sale assessment. The native disclosure keeps longer
   replacement evidence out of the default card height. */
.sale-assessment {
  padding: 0 0.75rem 0.75rem;
  color: var(--omni-text-muted);
  font-size: 0.78rem;
}
.sale-assessment-status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.sale-assessment-verdict {
  font-size: 0.72rem;
}
.sale-assessment-confidence { text-transform: capitalize; }
.sale-assessment-explanation { margin: 0.45rem 0; }
.sale-assessment-alternatives > summary {
  cursor: pointer;
  color: var(--text-muted);
}
.sale-assessment-alternatives > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.sale-assessment-list {
  display: grid;
  gap: 0.35rem;
  margin: 0.5rem 0 0;
  padding-left: 1.1rem;
}
.sale-assessment-alternative-title {
  display: block;
  color: var(--omni-text);
  font-weight: 600;
}
.sale-assessment-alternative-meta { overflow-wrap: anywhere; }
.sale-assessment-more { margin: 0.45rem 0 0; }

/* Thumbs up / thumbs down (sales-deal-votes.md). The pair sits below the
   tile, outside its full-card link, so each thumb is its own 44px control.
   The active thumb is the reader's own vote; the counts are everyone's. */
.deal-vote {
  display: flex;
  gap: 0.4rem;
  margin: 0.5rem 0 0;
}
.deal-vote--compact {
  display: inline-flex;
  margin: 0;
}
.deal-vote-thumb {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  min-height: 44px;
  min-width: 44px;
  flex: 1 1 0;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 0.375rem;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 650;
  line-height: 1;
  cursor: pointer;
}
.deal-vote--compact .deal-vote-thumb {
  min-height: 36px;
  min-width: 36px;
  flex: 0 0 auto;
  padding: 0.25rem 0.45rem;
  font-size: 0.78rem;
}
.deal-vote-thumb:hover { color: var(--text); }
.deal-vote-thumb:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.deal-vote-thumb:disabled { cursor: default; opacity: 0.6; }
.deal-vote-thumb.is-active {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--on-brand);
}
.deal-vote-thumb .bi { font-size: 1rem; }
.deal-vote-count { font-variant-numeric: tabular-nums; }

/* A thumbs-down this visit folds the tile to one strip. The strip is the
   ONLY child left visible, so the reader can still take the vote back. */
.deal-vote-hidden {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.5rem 0.75rem;
  border: 1px dashed var(--border-strong);
  border-radius: var(--omni-radius, 0.5rem);
  color: var(--text-muted);
  font-size: 0.8rem;
}
.deal-vote-hidden-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.deal-vote-hidden-note { flex: 0 0 auto; }
.deal-vote-undo {
  flex: 0 0 auto;
  min-height: 32px;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 0.375rem;
  background: transparent;
  color: var(--text);
  font-weight: 650;
  cursor: pointer;
}
.deal-vote-undo:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
#sales-app .omni-card-shell.is-dismissed > :not(.deal-vote-hidden) { display: none; }
.sales-table-vote { white-space: nowrap; }
