/*
 * Internal ops dashboard: changes received and their delivery to targets.
 *
 * The shell is in ptag_*.css and the page shape in page.css; the pills and the
 * stats counters have their own files because the mapping screen renders them
 * too. What is here is only what the transfers screen adds: the filter bar,
 * the data table, and the expandable delivery detail.
 *
 * The table follows Glacier's data-grid spec (section 9.4) -- this is the part
 * of the design system that matters most here, because an operations app lives
 * in its tables. Sticky header on `--neutral-100`, horizontal rules only, blue
 * tint on row hover, tabular figures in every numeric column.
 *
 * Every colour comes from the tokens in application.css. No hex values below.
 */

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

/* `align-items: flex-end`, not baseline: each field is a stacked
   label-over-control, so baseline would hang the row off the small label. */
.dashboard__filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
  padding: var(--space-4);
  background: var(--surface-primary);
  border: 1px solid var(--border-primary);
  border-radius: var(--radius-md);
}

.dashboard__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.dashboard__field-label {
  font-size: var(--text-body-sm);
  font-weight: 500;
  color: var(--text-label);
}

/* Height, padding, border, focus, disabled and placeholder come from the one
   control treatment in form.css. Only what is specific to a filter bar is
   here: these are fixed-width controls sitting inline, not form fields. */
.dashboard__filters input[type="text"] { width: 11rem; }
/* Share-by-email on a flow (flows phase 5): an address needs more room. */
.dashboard__filters input[type="email"] { width: 18rem; }

/* A date input sizes itself from its own locale format, and the browser's
   figure is a little tight -- it clips the picker glyph at the 40px height the
   rest of the bar uses. */
.dashboard__filters input[type="date"] {
  width: 10rem;
  font-variant-numeric: tabular-nums;
}

/* Chromium paints the calendar glyph near-black in both themes, which
   disappears against the dark surface. There is no token for it, so it is
   tinted from the text colour the field already uses. */
[data-theme="dark"] .dashboard__filters input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(1) opacity(0.6);
}


/* The filter bar's submit is the one primary action on this screen. Styled
   from the button block rather than restated here -- see the view. */

.dashboard__clear {
  display: inline-flex;
  align-items: center;
  height: 40px;
  padding: 0 var(--space-4);
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}

.dashboard__clear:hover {
  background: var(--surface-tertiary);
  color: var(--text-primary);
  text-decoration: none;
}

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

.dashboard__table-wrap {
  overflow-x: auto;
  /* NOT DECORATION -- this is what stops the whole PAGE scrolling sideways.
     `overflow-x` only clips descendants whose containing block is inside this
     element. An absolutely positioned one with no positioned ancestor resolves
     against the viewport instead, so it escapes the wrapper entirely and
     widens the document: a `.visually-hidden` label on the mapping screen's
     last column sat at a static position ~1630px in, and the page gained a
     horizontal scrollbar no other screen had.
     `position: relative` makes this element the containing block, so anything
     absolutely positioned inside a table is clipped by the same scroll the
     table is. */
  position: relative;
  background: var(--surface-primary);
  border: 1px solid var(--border-primary);
  border-radius: var(--radius-md);
}

/* Fixed layout with the explicit widths below. Auto layout recomputes every
   column from the expanded detail cell, so opening one row reflows the whole
   header. */
.dashboard__table {
  width: 100%;
  min-width: 1040px;
  border-collapse: collapse;
  table-layout: fixed;
  font-size: var(--text-body-sm);
}

/* Scoped to the table: `.col-*` names are per-screen and two screens have
   already collided on one (`.col-client`, on mappings and audit). Unscoped,
   whichever file sorts later in the bundle silently wins.

   Widths are measured from content, not chosen by eye. Two kinds of cell set
   the floor: a status pill, which is an inline-flex box with nowrap and so
   cannot shrink at all, and the timestamp, which does not wrap either. A
   column narrower than those does not truncate -- it overlaps its neighbour.
   Only `Record` is deliberately under its natural width, because it truncates
   with an ellipsis (see `.dashboard__file`). */
.dashboard__table .col-file    { width: 24%; }
.dashboard__table .col-project { width: 9%; }
.dashboard__table .col-event   { width: 9%; }
/* Targets took over the old Status and "In Forma" columns, and their width. */
.dashboard__table .col-targets { width: 29%; }
.dashboard__table .col-tries   { width: 7%; }
.dashboard__table .col-time    { width: 22%; }

.dashboard__table th,
.dashboard__table td {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  vertical-align: top;
  /* Horizontal rules only. Glacier makes vertical borders opt-in for dense
     numeric grids; this table is mostly prose and reads better without them. */
  border-bottom: 1px solid var(--border-primary);
}

/* `top: 0`, not the header height. `.dashboard__table-wrap` sets `overflow-x`,
   which makes it the sticky containing block -- so any other offset pushes the
   header down *inside* the wrapper and parks it on top of the first row. */
.dashboard__table thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--surface-tertiary);
  color: var(--text-label);
  font-size: var(--text-body-sm);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* A fixed-layout cell whose content is wider than its column overflows it and
   lands on top of the next column -- unreadable, and the failure mode is
   silent. Clipping instead means the worst case is a cut-off value, which is
   visible and honest. The detail row is exempt: it spans every column and
   holds the expanded panel, which is meant to be full width. */
.dashboard__table tbody tr:not(.dashboard__detail-row) > td {
  overflow: hidden;
}

/* Glacier's row hover and the table's own reading rhythm. Scoped to the data
   rows: the detail row beneath is part of the row above it, not a row of its
   own, and highlighting it separately makes the pair look unrelated. */
.dashboard__table tbody tr:not(.dashboard__detail-row):hover {
  background: var(--ptag-blue-light);
}

.dashboard__file {
  font-weight: 500;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dashboard__tag {
  display: inline-flex;
  align-items: center;
  height: 20px;
  margin-left: var(--space-1);
  padding: 0 var(--space-2);
  border-radius: var(--radius-full);
  background: var(--status-neutral-bg);
  color: var(--status-neutral-fg);
  font-size: var(--text-overline);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.dashboard__event { color: var(--text-tertiary); }
/* Glacier 9.4: "Numeric columns: right-aligned, tabular figures." The
   alignment is the half that makes a column of counts scannable -- tabular
   figures only line the digits up within a cell.

   Qualified by the table so it outranks `.dashboard__table td { text-align:
   left }` above -- unqualified, that rule won on specificity and every
   numeric column in the app rendered left-aligned. */
.dashboard__table .dashboard__num,
.dashboard__num {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.dashboard__na { color: var(--text-tertiary); }

.dashboard__ref,
.dashboard__ref code {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-caption);
}

/* A timestamp is one atom: wrapping it across three lines is unreadable and
   makes every row in the table taller. */
.dashboard__time {
  white-space: nowrap;
}

.dashboard__time time {
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

/* --- expandable detail -------------------------------------------------- */

.dashboard__detail-row td {
  padding: 0;
  border-bottom: 1px solid var(--border-primary);
}

.dashboard__detail-row summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  color: var(--ptag-blue);
  font-size: var(--text-caption);
  font-weight: 500;
  cursor: pointer;
}

.dashboard__detail-row summary:hover {
  background: var(--surface-hover);
}

.dashboard__detail-row summary:focus-visible {
  outline: 2px solid var(--ptag-blue);
  outline-offset: -2px;
}

.detail {
  padding: var(--space-4);
  background: var(--surface-secondary);
  border-top: 1px solid var(--border-primary);
}

.detail__subhead {
  margin: var(--space-4) 0 var(--space-2);
  font-size: var(--text-overline);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

.detail-empty {
  margin: 0;
  color: var(--text-tertiary);
  font-size: var(--text-body-sm);
}

.detail__meta,
.attempt__meta-list {
  display: grid;
  grid-template-columns: minmax(7rem, max-content) 1fr;
  gap: var(--space-1) var(--space-4);
  margin: 0;
  font-size: var(--text-caption);
}

.detail__meta dt,
.attempt__meta-list dt { color: var(--text-tertiary); }

.detail__meta dd,
.attempt__meta-list dd { margin: 0; overflow-wrap: anywhere; }

/* Refs, hashes and correlation ids are read character by character when
   something is wrong, so they take the monospace face. */
.detail__meta code,
.attempt__meta-list code,
.dashboard__ref code {
  font-family: var(--font-mono);
}

/* --- one delivery attempt ---------------------------------------------- */

.attempt {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border-primary);
}

.attempt:last-child { border-bottom: 0; }

.attempt__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
}

.attempt__meta {
  color: var(--text-tertiary);
  font-size: var(--text-caption);
}

.attempt__hint {
  color: var(--text-tertiary);
  font-size: var(--text-caption);
}

/* Glacier's toast treatment applied inline: a 3px accent bar in the danger
   colour rather than a box outlined on all four sides. */
.error-text {
  margin: var(--space-2) 0;
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--status-danger);
  border-radius: var(--radius-sm);
  background: var(--status-danger-bg);
  color: var(--status-danger-fg);
  font-size: var(--text-caption);
  overflow-wrap: anywhere;
}

/* Subhead inside one attempt. Smaller than `.detail__subhead`, which heads a
   whole section of the expanded row -- these sit one level down, inside a
   single attempt, and the nesting has to read in the type. */
.attempt__subhead {
  margin: var(--space-3) 0 var(--space-1);
  font-size: var(--text-overline);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

.json-block {
  margin: 0;
  padding: var(--space-3);
  border: 1px solid var(--border-primary);
  border-radius: var(--radius-sm);
  background: var(--surface-tertiary);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  overflow-x: auto;
}

/* The vendor's verbatim response. Bounded in height rather than truncated in
   Ruby: F6.1 wants what the target actually said, so the block scrolls instead
   of eliding. `pre-wrap` because a vendor error arrives as one long line as
   often as it arrives pretty-printed, and a horizontal-only scroll would hide
   the message past the first eighty characters. */
.json-block--verbatim {
  max-height: 18rem;
  overflow-y: auto;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- per-target outcomes ------------------------------------------------ */

/* One chip per target a change went to. The chips wrap onto new lines as the
   cell fills -- a NetSuite project has four -- but each chip keeps its own
   text on one line (a pill is nowrap), so a status is never split. */
.dashboard__targets {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.dashboard__target {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* --- links into a vendor's console -------------------------------------- */

.dashboard__console-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--ptag-blue);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  white-space: nowrap;
}

.dashboard__console-link:hover { text-decoration: underline; }

/* --- pagination / empty ------------------------------------------------- */

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  margin-top: var(--space-6);
  font-size: var(--text-body-sm);
}

/* "← Previous" is one control. On a phone the flex row squeezed it onto two
   lines; it holds its width and the count between wraps instead. */
.pagination__link {
  display: inline-flex;
  flex: none;
  white-space: nowrap;
  align-items: center;
  height: 32px;
  padding: 0 var(--space-3);
  border: 1px solid var(--border-secondary);
  border-radius: var(--radius-sm);
  color: var(--ptag-blue);
  text-decoration: none;
}

.pagination__link:hover {
  background: var(--ptag-blue-50);
  text-decoration: none;
}

.pagination__link.is-disabled {
  color: var(--text-muted);
  border-color: var(--border-primary);
  pointer-events: none;
}

.pagination__status {
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

/* "1-25 of 142" -- the secondary half of the status line, so it steps back
   from the page number rather than competing with it. */
.pagination__count { color: var(--text-tertiary); }

/* On a phone the three items do not fit one row, and letting them wrap put
   "Next" alone on a second line. The status takes its own line on top
   instead, so Previous and Next stay a pair. */
@media (max-width: 767px) {
  .pagination__status {
    order: -1;
    flex-basis: 100%;
    text-align: center;
  }
}

/* Glacier asks for an empty state with an icon, a message and a way forward --
   never a bare empty table. */
.dashboard__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-12) var(--space-6);
  background: var(--surface-primary);
  border: 1px solid var(--border-primary);
  border-radius: var(--radius-md);
  color: var(--text-tertiary);
  font-size: var(--text-body-sm);
  text-align: center;
}

.dashboard__empty-icon {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-full);
  background: var(--surface-tertiary);
  color: var(--text-muted);
}

@media (max-width: 767px) {
  .dashboard__filters { gap: var(--space-2); }
  .dashboard__filters input[type="text"],
  .dashboard__filters input[type="email"],
  .dashboard__filters input[type="date"],
  .dashboard__filters select { width: 100%; }
  .dashboard__field { flex: 1 1 8rem; }
}

/* --- action column ------------------------------------------------------
   Glacier's data-grid rule: row actions are right-aligned, icon-only ghost
   buttons. A text link here costs a column of width on a table that is
   already wider than the content area, and the icon reads faster down a
   column of identical rows. */

.dashboard__actions {
  text-align: right;
  white-space: nowrap;
}

.dashboard__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-md);
  color: var(--text-tertiary);
  transition: background var(--transition-fast), color var(--transition-fast);
}

.dashboard__action:hover {
  background: var(--surface-tertiary);
  color: var(--ptag-blue);
  text-decoration: none;
}
