/* ═══════════════════════════════════════════════════════════════════════════
   Payment pulse + stage chips — shared by the Accounts → Unpaid Invoices page
   (18b-accounts-unpaid.js) and the Jobs list red pulse (22-jobs-page.js).
   ═══════════════════════════════════════════════════════════════════════════ */

@keyframes sp-pulse-red {
  0%   { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.55); }
  70%  { box-shadow: 0 0 0 8px rgba(239, 68, 68, 0); }
  100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
}
@keyframes sp-pulse-dot {
  0%   { transform: scale(0.96); opacity: 1; }
  70%  { transform: scale(1.10); opacity: 0.7; }
  100% { transform: scale(0.96); opacity: 1; }
}

/* Small pulsing dot used inline in a table cell / job row. */
.sp-pulse-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: #ef4444;
  /* A-806 — motion moved to body.sp-boot-pulse below. */
  flex: none;
}
.sp-pulse-dot.sp-overdue { background: #dc2626; }

/* A whole row that should pulse red (unpaid / overdue). Reduced-motion safe. */
.sp-pulse-row td:first-child,
.sp-pulse-row > *:first-child {
  position: relative;
}
/* A-806 — static. Was `animation: sp-pulse-red 1.8s infinite`, which stacked a
   second, differently-timed infinite animation on top of .is-overdue-row's own
   pulse whenever a job was BOTH overdue and behind on payment. The red tint plus
   the inset bar below already read as "money problem" without any motion.
   Semantic danger red is unchanged (CLAUDE.md: never rebrand danger red). */
.sp-pulse-row {
  background: #fef2f2 !important;
  box-shadow: inset 3px 0 0 #ef4444;
}

/* Stage chips: 5 / 45 / 45 / 5 progress-claim pills. */
.sp-stage-chips { display: inline-flex; gap: 4px; flex-wrap: wrap; align-items: center; }
.sp-stage {
  font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 999px;
  border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  line-height: 1.5; user-select: none;
}
.sp-stage:hover { filter: brightness(0.96); text-decoration: none; }
.sp-stage-paid    { background: #dcfce7; color: #15803d; border-color: #bbf7d0; }
.sp-stage-pending { background: #f3f4f6; color: #6b7280; border-color: #e5e7eb; }
.sp-stage-billed  { background: #fef3c7; color: #92400e; border-color: #fde68a; }
.sp-stage-overdue { background: #fee2e2; color: #b91c1c; border-color: #fca5a5; /* A-806 — static: up to 4 of these per row each pulsed independently. */ }
/* A-517 — customer tapped "I've made the bank transfer" in the portal but nobody
   has confirmed the funds yet. Deliberately NOT green: the stage is still
   billed-unpaid (it holds + pulses) until Accounts verifies it. Violet reads as
   "action on us" against the amber "waiting on them" billed chip. */
.sp-stage-verify  { background: #f5f3ff; color: #6d28d9; border-color: #ddd6fe; }

/* Hold badges. */
.sp-hold {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em;
  padding: 3px 8px; border-radius: 6px;
}
/* 4 payment-hold states — onboarding (deposit) · production (1st 45%) ·
   installation/delivery (2nd 45%) · recovery (final 5%, late). */
.sp-hold-onboarding   { background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe; }
.sp-hold-production   { background: #fff7ed; color: #c2410c; border: 1px solid #fed7aa; }
.sp-hold-installation { background: #fef2f2; color: #b91c1c; border: 1px solid #fca5a5; }
.sp-hold-recovery     { background: #fdf2f8; color: #9d174d; border: 1px solid #fbcfe8; }

/* Zip stage badges. */
.sp-zip { font-size: 10px; font-weight: 800; padding: 3px 9px; border-radius: 999px; }
.sp-zip-awaiting_approval { background: #fef3c7; color: #92400e; }
.sp-zip-approved          { background: #dbeafe; color: #1d4ed8; }
.sp-zip-paid_out          { background: #dcfce7; color: #15803d; }
.sp-zip-declined          { background: #fee2e2; color: #b91c1c; }

/* A-806 — motion only during the boot window (see _spBootPulseWindow in
   modules/99-init.ts). No class, no motion: the safe direction is the quiet one. */
body.sp-boot-pulse .sp-pulse-dot {
  animation: sp-pulse-dot 2.5s infinite ease-in-out;
}

@media (prefers-reduced-motion: reduce) {
  .sp-pulse-row, .sp-stage-overdue, .sp-pulse-dot { animation: none; }
  .sp-pulse-dot { opacity: 1; }
}
