/**
 * PPC Sherpa - shared data table (.dt-*)
 *
 * The styles for assets/js/data-table.js (window.PPCSDataTable), enqueued
 * together from $data_table_templates in functions.php, ahead of the page's
 * own stylesheet so a page's column budget is layered on top of this and never
 * the other way round.
 *
 * ***** ONE SET OF RULES, NOT A FIFTH PREFIXED COPY. ***** negkw-, qs-,
 * metamon- and adcopy- each carried their own table, filter, pager and
 * selection CSS and drifted from the standard in different ways. A page that
 * adopts the component deletes its own copies of these rules rather than
 * overriding them.
 *
 * .sherpa-table, .sherpa-table-wrap, .status-badge, .bulk-action-bar,
 * .has-popover and .popover-content are style.css's and are used as-is, never
 * re-declared. Every value below that a token covers is the token: the visual
 * reference is the Data Tables (App) section of page-styleguide.php, and the
 * pass/fail list is docs/51-ui-patterns-tables-popovers-loader.md.
 */


/* ============================================
   CONTROLS BAR
   ============================================
   ***** ON THE PAGE BACKGROUND: NO FILL, NO BORDER, NO RADIUS, NO PADDING,
   NO CONTAINER. ***** Inside a white or bordered box it reads as a second card
   stacked on the results card. */

.dt-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

.dt-filter {
  position: relative;
}

/* ***** CONTROLS THAT SIT BESIDE EACH OTHER SHARE ONE DECLARATION. ***** The
   Advanced filters toggle and Expand selected are both .dt-control. Two rules
   carrying matching values drift the first time either is touched; anything
   that genuinely differs is a modifier below, never a second copy. */
.dt-control {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 8px 14px;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  white-space: nowrap;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.dt-control:hover,
.dt-filter-toggle[aria-expanded="true"],
.dt-filter-toggle--active {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* The control acting on a live selection reads in the page's own text color,
   so it is the more prominent of the pair. */
.dt-control--emphasis {
  color: var(--color-text);
}

/* [hidden] re-declared: display above is an author rule and beats the UA's
   [hidden] { display: none } regardless of specificity. */
.dt-control[hidden] {
  display: none;
}

.dt-filter-toggle__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  background: var(--color-primary);
  color: var(--color-surface);
  border-radius: var(--radius-full);
  font-size: 11px;
  font-weight: var(--weight-bold);
}

/* Without this the badge renders as an empty blue dot with no filters. */
.dt-filter-toggle__count[hidden] {
  display: none;
}

.dt-chevron {
  flex-shrink: 0;
}

/* How many rows the live conditions left, with its own Clear. */
.dt-filter-scope {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.dt-filter-scope[hidden] {
  display: none;
}

.dt-filter-scope strong {
  color: var(--color-text);
}

.dt-filter-scope__clear {
  margin-left: var(--space-1);
  font-size: var(--text-sm);
}


/* ============================================
   ADVANCED FILTERS PANEL
   ============================================
   Include/Exclude + Field + Operator + Value, combining with AND. z-index 30
   clears the sticky header at 10 (style.css), so an open panel is never
   scrolled under the navy header row. */

.dt-filter-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 30;
  width: min(680px, 92vw);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-4);
}

.dt-filter-panel[hidden] {
  display: none;
}

.dt-filter-rows {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: var(--space-3);
}

.dt-filter-row {
  display: grid;
  grid-template-columns: 100px 1fr 1fr 1fr 28px;
  gap: var(--space-2);
  align-items: center;
}

/* The selects and the value input are one declaration; the selects add only
   their own arrow below. */
.dt-filter-select,
.dt-filter-input {
  min-width: 0;
  padding: 7px 10px;
  font-family: var(--font-body);
  font-size: var(--text-control);
  color: var(--color-text);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
}

.dt-filter-select {
  padding-right: 26px;
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%235A5A72' d='M1.41 0L6 4.58 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
}

.dt-filter-select:focus,
.dt-filter-input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(26, 107, 255, 0.12);
}

.dt-filter-row__remove {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--radius-control);
  color: var(--color-text-muted);
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

.dt-filter-row__remove:hover {
  color: var(--color-danger);
  background: #FEE2E2;
}

.dt-filter-panel__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.dt-filter-panel__end {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.dt-filter-panel__add,
.dt-filter-panel__clear {
  padding: 0;
  background: transparent;
  border: none;
  font-family: var(--font-body);
  font-size: var(--text-control);
  font-weight: var(--weight-semibold);
  text-decoration: underline;
  cursor: pointer;
}

.dt-filter-panel__add {
  color: var(--color-primary);
}

.dt-filter-panel__clear {
  color: var(--color-text-muted);
}

.dt-filter-panel__apply {
  padding: 7px 16px;
  background: var(--color-primary);
  color: var(--color-surface);
  border: none;
  border-radius: var(--radius-control);
  font-family: var(--font-body);
  font-size: var(--text-control);
  font-weight: var(--weight-semibold);
  cursor: pointer;
}

.dt-filter-panel__apply:hover {
  background: var(--color-primary-hover);
}

@media (max-width: 640px) {
  /* ***** THE PANEL IS MEASURED FROM THE CONTROLS BAR, NOT ITS TOGGLE. *****
     The toggle's wrapper is only as wide as the button, so a phone-width panel
     positioned from it either overflows the page or collapses to the button's
     width. The bar spans the content column, so the panel does too. */
  .dt-controls {
    position: relative;
  }

  .dt-filter {
    position: static;
  }

  .dt-filter-panel {
    width: auto;
    left: 0;
    right: 0;
  }

  /* Five columns cannot fit a phone: each control on its own line, with the
     remove button pinned to the first. */
  .dt-filter-row {
    grid-template-columns: 1fr 28px;
    grid-template-areas:
      "include remove"
      "field   field"
      "op      op"
      "value   value";
  }

  .dt-filter-select--include   { grid-area: include; }
  .dt-filter-row__remove       { grid-area: remove; }
  .dt-filter-select--field     { grid-area: field; }
  .dt-filter-select--operator  { grid-area: op; }
  .dt-filter-value             { grid-area: value; }
}


/* ============================================
   STATUS PILLS AND SUMMARY CHIPS
   ============================================
   Page markup, shared look. Each pill's count is filled by
   PPCSDataTable.statusPills() from the same pipeline the tables render, so it
   equals the rows clicking it produces. */

.dt-status-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.dt-status-filter {
  padding: 6px 14px;
  font-family: var(--font-body);
  font-size: var(--text-control);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  background: transparent;
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-full);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.dt-status-filter:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.dt-status-filter--active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-surface);
}

/* (0,2,0) so it beats :hover (0,1,1): otherwise hovering the filled pill paints
   its label the same blue as its own ground. */
.dt-status-filter.dt-status-filter--active:hover {
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
  color: var(--color-surface);
}

.dt-status-filter__count {
  margin-left: 6px;
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}

/* Empty until counted, so no stray gap renders before a count exists. */
.dt-status-filter__count:empty {
  display: none;
}

/* ***** THE SHARED PILL SHAPE FOR SUMMARY CHIPS. ***** A count here equals the
   rows shown; anything account-wide says so in its own label. */
.dt-summary-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.dt-summary-bar[hidden] {
  display: none;
}

.dt-stat-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 10px 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-sm);
  color: var(--color-text-muted);
  font-size: var(--text-control);
  font-weight: var(--weight-semibold);
  white-space: nowrap;
}

.dt-stat-pill svg {
  flex-shrink: 0;
  color: var(--color-primary);
}


/* ============================================
   SELECTION NOTICE, AND BUTTON-LINKS
   ============================================ */

.dt-selectall-banner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  padding: 10px 16px;
  background: var(--color-primary-light);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-md);
  font-size: var(--text-control);
  color: var(--color-dark);
}

.dt-selectall-banner[hidden] {
  display: none;
}

/* ***** ROWS THE SERVER HELD BACK. ***** Shown only when an endpoint with a
   ceiling sent fewer rows than match (serverCount in data-table.js). The
   warning tint because it is a limit on what the user is looking at, not a
   routine note: the pager, the filters and the counts below it cover only
   the rows that arrived. */
.dt-truncation {
  margin: 0 0 var(--space-3);
  padding: 10px 16px;
  background: var(--color-warning-light);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius-md);
  font-size: var(--text-control);
  line-height: 1.5;
  color: var(--color-dark);
}

.dt-truncation[hidden] {
  display: none;
}

/* A <button> that reads as a link, so it is keyboard-operable without a
   fake href. */
.dt-link {
  padding: 0;
  background: none;
  border: none;
  font-family: var(--font-body);
  font-size: inherit;
  font-weight: var(--weight-semibold);
  color: var(--color-primary);
  text-decoration: underline;
  white-space: nowrap;
  cursor: pointer;
}

.dt-link:hover {
  color: var(--color-primary-hover);
}


/* ============================================
   RESULTS CARD, TABLE AND CARDS
   ============================================ */

/* ***** NO overflow HERE. ***** Any non-visible overflow makes this element,
   not the viewport, the sticky header's positioning container: the header
   renders perfectly and never pins. The header rounds its own corners and the
   pager carries the bottom edge, so nothing needs clipping. */
.dt-results-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

/* ***** BELOW 768px THE TABLE IS REPLACED BY STACKED CARDS. ***** On /app/
   pages .sherpa-table-wrap is overflow-x: visible so the header can pin, so
   nothing would contain a wide table at phone width and it would push the
   whole document sideways. Both layouts are always in the DOM; CSS alone
   picks one. */
.dt-table-wrap {
  display: none;
}

.dt-cards {
  display: block;
}

@media (min-width: 768px) {
  .dt-table-wrap {
    display: block;
  }

  .dt-cards {
    display: none;
  }
}

/* ***** A HEADING MAY WRAP, AND THE VALUES BENEATH STAY ALIGNED. *****
   .sherpa-table th is nowrap globally; a data table relaxes that for its own
   headings, and vertical-align: bottom puts a one-line heading on the same
   baseline as the last line of a two-line one. */
.dt-table th {
  white-space: normal;
  vertical-align: bottom;
}

.dt-th-sortable {
  cursor: pointer;
  user-select: none;
}

/* Qualified with .sherpa-table so the hover and active ground beat
   .sherpa-table th's own background-color. */
.sherpa-table th.dt-th-sortable:hover,
.sherpa-table th.dt-th-sorted {
  background-color: #142c5c;
}

.dt-sort-arrow {
  margin-left: var(--space-1);
  font-size: 0.85em;
}

.dt-sort-arrow:empty {
  display: none;
}

/* A heading that is also a popover trigger keeps the sort pointer. */
.dt-th-sortable.has-popover {
  cursor: pointer;
}

.dt-th-check,
.dt-td-check {
  width: 40px;
}

.dt-check {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  cursor: pointer;
}

.dt-check[hidden] {
  display: none;
}

.dt-check__input {
  width: 16px;
  height: 16px;
  margin: 0;
  flex-shrink: 0;
  cursor: pointer;
  accent-color: var(--color-primary);
}

/* ***** NUMERIC CELLS ARE LEFT ALIGNED, WITH TABULAR NUMERALS. ***** Never
   text-align: right, which pulls a figure away from the heading naming it. */
.dt-num {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ***** AN UNKNOWN VALUE IS A DASH, NOT A ZERO. ***** */
.dt-unknown {
  color: var(--color-text-muted);
}

/* ***** THE ACTIONS CELL IS ITSELF THE FLEX CONTAINER, AND THE COLUMN
   DIRECTION IS STATED. ***** An inner div rides to the top of a tall row, and
   a stack that relies on the column being narrow un-stacks the moment it has
   room. */
.dt-td-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-1);
}

/* ***** APPROVE GATING: THE SERVER'S REASON STANDS WHERE APPROVE WOULD. *****
   It wraps, because the sentence is the server's and its length is not ours to
   choose. */
.dt-approve-reason {
  max-width: 100%;
  white-space: normal;
  overflow-wrap: break-word;
  font-size: var(--text-control);
  font-style: italic;
  line-height: 1.4;
  color: var(--color-text-muted);
}

/* ---- Striping by class, not by position ----
   .sherpa-table stripes with :nth-child(even), which counts every <tr> -- a
   hidden detail row, or a row-error line (see ROW ACTION ERRORS below) --
   so an interleaved row shifts or erases the stripes. Every shared table
   therefore stripes by an explicit class the script sets on alternate DATA
   rows. Hover and the open row are restated after it so the stripe cannot
   cover them. */
.dt-table tbody tr:nth-child(even) {
  background: transparent;
}

.dt-table tbody tr.dt-row--alt {
  background: var(--color-bg);
}

.dt-table tbody tr.dt-row:hover {
  background: var(--color-primary-light);
}

/* The last data row's own border would double up against the pager's while
   its detail row is closed. */
.dt-table tbody tr.dt-row--last:not(.dt-row--expanded) {
  border-bottom: none;
}

.dt-row--clickable,
.dt-card--clickable {
  cursor: pointer;
}

.dt-table tbody tr.dt-row--expanded,
.dt-table tbody tr.dt-row--expanded:hover {
  background: var(--color-primary-light);
}


/* A column hidden for the current view (actions.visible). [hidden] restated
   because nothing guarantees a later author display rule never lands on th. */
.dt-table th[hidden] {
  display: none;
}


/* ============================================
   ROW ACTION ERRORS
   ============================================
   ***** A FAILED ROW ACTION IS SHOWN ON THE ROW ITSELF. ***** A full-width
   line directly beneath the row in the table, and inside the card below
   768px, so it is on screen wherever the user clicked. The row's own state
   is untouched: the line says the action did not happen, and the row still
   shows the state it is really in. Danger tint from the shared .alert--danger
   pair, so it reads as the same kind of message as the page's other errors. */

.sherpa-table td.dt-row-error-cell {
  padding: 0 14px 10px;
}

.dt-table tbody tr.dt-row-error-row,
.dt-table tbody tr.dt-row-error-row:hover {
  background: var(--color-surface);
}

/* The data row and its error line read as one unit: no rule between them. */
.dt-table tbody tr.dt-row--error {
  border-bottom: none;
}

.dt-row-error {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-control);
  background: #FEE2E2;
  color: #991B1B;
  font-size: var(--text-control);
  line-height: 1.5;
  white-space: normal;
  overflow-wrap: break-word;
}

.dt-card .dt-row-error {
  margin: 0 0 var(--space-4);
}

.dt-card--error {
  border-color: var(--color-danger);
}


/* ============================================
   DETAIL ROWS (optional capability)
   ============================================ */

.dt-detail-toggle {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: var(--space-1);
  margin-top: var(--space-1);
  padding: 0;
  background: none;
  border: none;
  font-family: inherit;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-primary);
  cursor: pointer;
}

.dt-detail-toggle:hover {
  color: var(--color-primary-hover);
  text-decoration: underline;
}

.dt-detail-toggle__chevron {
  transition: transform var(--transition-fast);
}

/* Driven by the button's own aria-expanded, so the glyph and the announced
   state cannot disagree. */
.dt-detail-toggle[aria-expanded="true"] .dt-detail-toggle__chevron {
  transform: rotate(180deg);
}

/* `hidden` on a <tr> is honored inconsistently once a display value is in
   play, so the closed state is asserted here too. */
.dt-detail-row[hidden],
.dt-detail-panel[hidden] {
  display: none;
}

.sherpa-table td.dt-detail-cell {
  padding: 0;
  background-color: var(--color-bg);
}

.dt-detail {
  padding: var(--space-4);
  cursor: auto;
}

.dt-detail-panel {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
  cursor: auto;
}


/* ============================================
   STACKED CARDS (below 768px)
   ============================================ */

.dt-card {
  margin: var(--space-3);
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.dt-card--expanded {
  border-color: var(--color-primary);
}

.dt-card__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

/* The card stacks its actions exactly as the table cell does. The gap below
   separates the last action from the Details toggle, which is close enough on
   a phone to mis-tap otherwise. */
.dt-card__actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  margin-top: var(--space-3);
  margin-bottom: var(--space-4);
}


/* ============================================
   FILTERED-TO-ZERO EMPTY STATE
   ============================================
   ***** A REAL ROW IN THE REAL TABLE. ***** The header, the filter button and
   the pager all stay on screen, and the message names the filter that caused
   it, so an empty table is never read as an account with nothing in it. */

.sherpa-table td.dt-empty-row__cell {
  padding: 0;
}

.dt-table tbody tr.dt-empty-row,
.dt-table tbody tr.dt-empty-row:hover {
  background: var(--color-surface);
}

.dt-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 200px;
  padding: var(--space-6);
  text-align: center;
}

.dt-empty__title {
  font-weight: var(--weight-semibold);
  color: var(--color-text);
}

.dt-empty__body {
  max-width: 60ch;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.dt-empty .dt-link {
  font-size: var(--text-sm);
}

.dt-card--empty .dt-empty {
  min-height: 0;
  padding: var(--space-4);
}


/* ============================================
   PAGER
   ============================================
   24 per page by default, 12 / 24 / 36 / 48. The negative keywords page's
   hover and focus treatment, built entirely from tokens. */

.dt-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border);
  color: var(--color-text);
  border-bottom-left-radius: var(--radius-lg);
  border-bottom-right-radius: var(--radius-lg);
}

.dt-pagination__left {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.dt-pagination__pagesize {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-control);
  color: var(--color-text-muted);
  white-space: nowrap;
}

.dt-pagesize-select {
  padding: 5px 26px 5px 10px;
  font-family: var(--font-body);
  font-size: var(--text-control);
  color: var(--color-text);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%235A5A72' d='M1.41 0L6 4.58 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
}

.dt-pagesize-select:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(26, 107, 255, 0.12);
}

.dt-pagination__range,
.dt-pagination__page {
  font-size: var(--text-control);
  color: var(--color-text-muted);
  white-space: nowrap;
}

.dt-pagination__controls {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* Reads as plain text at rest, gains a border on hover, and the full focus
   treatment once clicked into. Enter commits; blur always reverts. */
.dt-pagination__page-input {
  padding: 1px 3px;
  font: inherit;
  font-size: var(--text-control);
  color: var(--color-text-muted);
  text-align: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  transition: border-color var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast);
}

/* Plain :hover, the same specificity as :focus below, so focus wins while the
   pointer is still resting on the field. A :not(:disabled) here outranked
   :focus and showed the hover border on a field being typed into. */
.dt-pagination__page-input:hover {
  border-color: var(--color-border);
}

.dt-pagination__page-input:focus {
  outline: none;
  border-color: var(--color-primary);
  background: var(--color-surface);
  color: var(--color-text);
}

.dt-pagination__btn {
  padding: 5px 12px;
  font-family: var(--font-body);
  font-size: var(--text-control);
  font-weight: var(--weight-semibold);
  color: var(--color-text);
  background: transparent;
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-control);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

.dt-pagination__btn:hover:not(:disabled) {
  background: var(--color-primary-light);
  border-color: var(--color-primary);
}

.dt-pagination__btn:focus-visible {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(26, 107, 255, 0.12);
}

.dt-pagination__btn:disabled {
  opacity: 0.4;
  cursor: default;
}

/* The bulk action bar's clearance is not here. It was .dt-bulk-clearance;
   it is now .bulk-action-bar-clearance in style.css beside the shared bar,
   so a page with a bar but no data table (Broad Match) gets it too. */
