/* contrib-list-redesign-v1 — W-72-1 — Phase D parent contributions audit. */
/*
 * Planning: .archon/queued-builds/WAVE-72-contributions-list-redesign.md
 *
 * Targets the markup rendered by src/views/dashboard/child-contributions.ejs:
 *   .contrib-list                          — <section> wrapper
 *   .contrib-list__header                  — eyebrow + heading + lead
 *   .contrib-list__eyebrow                 — uppercase "Contributions" label
 *   .contrib-list__heading                 — serif page heading
 *   .contrib-list__lead                    — supporting copy
 *   .contrib-list__back                    — "Back to your children" link
 *   .contrib-list__banner                  — success / error flash
 *   .contrib-list__filters                 — filter panel <section>
 *   .contrib-list__filters-heading         — h3 above the filter form
 *   .contrib-list__filter-form             — the GET form
 *   .contrib-list__filter-grid             — auto-fit grid of form fields
 *   .contrib-list__filter-actions          — Apply + Clear row
 *   .contrib-list__filter-submit           — submit button alias
 *   .contrib-list__filter-clear            — clear link
 *   .contrib-list__filter-clear--idle      — disabled-look clear link
 *   .contrib-list__summary                 — "Showing N contributions" copy
 *   .contrib-list__empty                   — empty-state callout
 *   .contrib-list__slug                    — inline saadjie.com/<slug>
 *   .contrib-list__rows                    — <ul> of contribution rows
 *   .contrib-list__row                     — <li> wrapper per contribution
 *   .contrib-list__row--<status>           — per-status accent stripe
 *   .contrib-list__row-head                — amount + status pill row
 *   .contrib-list__row-meta                — name + date row
 *   .contrib-list__amount                  — bold amount
 *   .contrib-list__status                  — uppercase status pill
 *   .contrib-list__name                    — contributor name
 *   .contrib-list__date                    — timestamp
 *   .contrib-list__message                 — contributor note
 *   .contrib-list__tx                      — yoco transaction line
 *   .contrib-list__tx-id                   — code element with charge/checkout id
 *   .contrib-list__refund-form             — inline refund form
 *   .contrib-list__refund-btn              — refund button alias
 *
 * WHY a NEW stylesheet (not appended to dashboard.css): Phase D of the
 * redesign system carves each parent-facing surface into a focused
 * stylesheet that sits cleanly on the W56-W67 token + primitive layers.
 * The legacy dashboard.css still hosts the manage-children list and the
 * legacy contribution-row rules; this file is the dedicated W72 layer.
 * Both class taxonomies are emitted side-by-side on each element so the
 * legacy selectors keep landing styles until a future cleanup wave
 * removes them.
 *
 * WHY no raw hex / rgba in this file: ANTI-RAW-VALUE proof-gate (W56)
 * rejects raw colour literals in any non-token file. Every colour goes
 * through var(--color-*), every shape via var(--radius-*) /
 * var(--shadow-*), every spacing via var(--space-*), every duration /
 * easing via the compound --transition-* presets.
 *
 * WHY mobile-first stack: the W26 mobile-responsiveness baseline (and
 * the W83 R-t11 slow-3G audit) target 320-414px Android viewports first.
 * The page stacks header → banner → filter panel → summary → row list as
 * a single column on mobile; tablet+ flips the filter grid into a 2-up
 * (640px) and 3-up (960px) layout, and the row's amount + status pill
 * pin to opposite ends of the head row.
 *
 * WHY the filter form uses a CSS Grid (not flex auto-wrap): grid gives
 * every field the same width regardless of label length, which matters
 * when "From date" sits next to "Search contributor". Flex with
 * `flex: 1 1 12rem` would let the longer label tip the layout
 * asymmetrically.
 *
 * WHY each row stays a card (not a real <table>): on 320px viewports a
 * <table> with 5+ columns either wraps unreadably or scrolls
 * horizontally. The card layout keeps the amount + status as the
 * headline and pushes contributor / date / message / tx id underneath
 * — same pattern as the legacy dashboard__contrib block.
 *
 * FLOW: tokens/* → reset.css → cards.css → motion.css → radius-shadow.css
 *       → dashboard.css → contributions-list.css (this file).
 *       contributions-list.css sits ABOVE the legacy dashboard.css so
 *       the .contrib-list-scoped selectors can override the legacy
 *       .dashboard__contrib rules without specificity gymnastics.
 *
 * CONSTRAINT: WCAG 1.4.11 — every coloured text + background pair below
 * stays above the 4.5:1 AA floor by composing only token pairs that
 * have been pre-audited (the W58 contrast audit pinned the safe
 * pairings).
 */

/* ============================================================
 * Page-level wrapper
 * ============================================================ */

.contrib-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding-block: var(--space-5);
  padding-inline: var(--content-padding-x);
  max-width: var(--container-max-wide);
  margin-inline: auto;
  color: var(--color-text);
  font-family: var(--font-family-base);
  background-color: var(--color-bg);
}

/* ============================================================
 * Header (eyebrow + heading + lead + back link)
 * WHY a soft brand-lighter tint: matches the W70 home / W71 child-edit
 * pattern so the parent surfaces feel like one designed system.
 * ============================================================ */

.contrib-list__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  background-color: var(--color-brand-lighter);
  border: 1px solid var(--color-brand-light);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.contrib-list__eyebrow {
  margin: 0;
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  color: var(--color-brand-dark);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
}

.contrib-list__heading {
  margin: 0;
  font-family: var(--font-family-heading);
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--color-text);
  word-break: break-word;
}

.contrib-list__lead {
  margin: 0;
  font-size: var(--font-size-base);
  line-height: var(--line-height-relaxed);
  color: var(--color-text-muted);
  max-width: 60ch;
}

.contrib-list__back {
  margin: 0;
  font-size: var(--font-size-sm);
}

.contrib-list__back a {
  color: var(--color-text-link);
  text-decoration: none;
  transition: var(--transition-color);
}

.contrib-list__back a:hover,
.contrib-list__back a:focus {
  color: var(--color-text-link-hover);
  text-decoration: underline;
}

/* ============================================================
 * Flash banners
 * ============================================================ */

.contrib-list__banner {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
}

/* ============================================================
 * Filter panel
 * WHY card-shaped + on its own row: groups the six filter fields
 * into one scannable region so the parent doesn't mistake them for
 * data. The Apply + Clear actions sit at the bottom of the panel
 * so a long mobile column still puts the submit within thumb reach.
 * ============================================================ */

.contrib-list__filters {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  background-color: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

.contrib-list__filters-heading {
  margin: 0;
  font-family: var(--font-family-heading);
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-tight);
  color: var(--color-text);
}

.contrib-list__filter-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
}

.contrib-list__filter-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

.contrib-list__filter-actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: stretch;
  border-block-start: 1px solid var(--color-border-subtle);
  padding-block-start: var(--space-3);
}

.contrib-list__filter-clear--idle {
  /* WHY: render the Clear link in a disabled-look state when no
     filters are active. The link still resolves to the bare URL
     (a no-op) so non-JS users aren't blocked, but the muted colour
     tells sighted users the action is currently a no-op. */
  color: var(--color-text-subtle);
  pointer-events: none;
}

/* ============================================================
 * Summary row + empty state
 * ============================================================ */

.contrib-list__summary {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  padding-inline: var(--space-1);
}

.contrib-list__summary a {
  color: var(--color-text-link);
  text-decoration: underline;
}

.contrib-list__summary a:hover,
.contrib-list__summary a:focus {
  color: var(--color-text-link-hover);
}

.contrib-list__empty {
  margin: 0;
  padding: var(--space-6) var(--space-5);
  background-color: var(--color-bg-subtle);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
  text-align: center;
  font-size: var(--font-size-base);
  line-height: var(--line-height-relaxed);
}

.contrib-list__slug {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  padding: 0 var(--space-1);
  border-radius: var(--radius-sm);
  background-color: var(--color-bg-muted);
  color: var(--color-text);
}

/* ============================================================
 * Row list — each contribution is a card.
 * The left-edge stripe colour comes from the row's status modifier.
 * ============================================================ */

.contrib-list__rows {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.contrib-list__row {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  background-color: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  /* WHY a left-edge stripe (not a full border): the stripe is the
     primary status affordance at a glance; a full coloured border
     would compete with the card's neutral chrome. */
  border-inline-start: 4px solid var(--color-border-strong);
  transition: var(--transition-color);
}

.contrib-list__row:hover {
  border-color: var(--color-border-strong);
}

.contrib-list__row--succeeded { border-inline-start-color: var(--color-success); }
.contrib-list__row--pending   { border-inline-start-color: var(--color-warning); }
.contrib-list__row--failed    { border-inline-start-color: var(--color-danger); }
.contrib-list__row--refunded  { border-inline-start-color: var(--color-border-strong); }
.contrib-list__row--cancelled { border-inline-start-color: var(--color-border-strong); }

.contrib-list__row-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3);
  justify-content: space-between;
}

.contrib-list__row-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
  justify-content: space-between;
}

.contrib-list__amount {
  font-family: var(--font-family-heading);
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-text);
  letter-spacing: var(--tracking-tight);
}

.contrib-list__status {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  border-radius: var(--radius-pill);
  background-color: var(--color-bg-subtle);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  border: 1px solid var(--color-border-subtle);
}

.contrib-list__status[data-status="succeeded"] {
  background-color: var(--color-success-bg);
  color: var(--color-success);
  border-color: var(--color-success-border);
}

.contrib-list__status[data-status="pending"] {
  background-color: var(--color-warning-bg);
  color: var(--color-warning);
  border-color: var(--color-warning-border);
}

.contrib-list__status[data-status="failed"] {
  background-color: var(--color-danger-bg);
  color: var(--color-danger);
  border-color: var(--color-danger-border);
}

.contrib-list__status[data-status="refunded"],
.contrib-list__status[data-status="cancelled"] {
  background-color: var(--color-bg-muted);
  color: var(--color-text-subtle);
  border-color: var(--color-border);
}

.contrib-list__name {
  font-weight: var(--font-weight-medium);
  color: var(--color-text);
  word-break: break-word;
}

.contrib-list__date {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.contrib-list__message {
  margin: 0;
  padding: var(--space-3);
  background-color: var(--color-bg-subtle);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-style: italic;
  line-height: var(--line-height-relaxed);
  word-break: break-word;
}

.contrib-list__tx {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.contrib-list__tx-id {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-xs);
  padding: 0 var(--space-1);
  border-radius: var(--radius-sm);
  background-color: var(--color-bg-muted);
  color: var(--color-text);
  word-break: break-all;
}

/* ============================================================
 * Inline refund form
 * WHY pinned to the row card (not a separate panel): the refund
 * action belongs WITH the row it acts on so the parent can never
 * confuse which contribution they're returning. The form is a thin
 * shell over the danger button — no extra border/background.
 * ============================================================ */

.contrib-list__refund-form {
  margin: 0;
  margin-block-start: var(--space-2);
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.contrib-list__refund-btn {
  min-width: 12rem;
  min-height: var(--touch-target-min);
}

/* ============================================================
 * Tablet + desktop overrides
 * WHY 640px / 960px: matches the W26 mobile-responsiveness break
 * points used by dashboard.css / dashboard-home.css.
 * ============================================================ */

@media (min-width: 640px) {
  .contrib-list__filter-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
  }

  .contrib-list__filter-actions {
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-3);
  }

  .contrib-list__filter-submit {
    width: auto;
    min-width: 10rem;
  }

  .contrib-list__refund-btn {
    width: auto;
  }
}

@media (min-width: 960px) {
  .contrib-list__filter-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
