/* =============================================================================
   feedback.css — loading, toasts, empty and error states.
   Token-only, so it works unchanged on both surfaces.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   Skeletons. Shapes mirror the real components so nothing shifts on arrival.
   ----------------------------------------------------------------------------- */
@keyframes rovo-shimmer {
  from { background-position: -340px 0; }
  to { background-position: 340px 0; }
}

.sk {
  background-color: var(--skeleton);
  background-image: linear-gradient(90deg, transparent, var(--skeleton-sheen) 50%, transparent);
  background-size: 340px 100%;
  background-repeat: no-repeat;
  animation: rovo-shimmer 1.15s ease-in-out infinite;
  border-radius: var(--radius-sm);
  color: transparent;
  user-select: none;
  pointer-events: none;
}

.sk-text { height: 12px; }
.sk-title { height: 20px; }
.sk-pill { height: 22px; width: 90px; border-radius: var(--radius-pill); }
.sk-w40 { width: 40%; }
.sk-w60 { width: 60%; }
.sk-w80 { width: 80%; }

/* Matches .vehicle-card exactly. If that grid changes, change this with it —
   a skeleton that does not match is worse than none, because the content
   visibly jumps at the moment it arrives. */
.sk-vehicle {
  display: grid;
  grid-template-columns: 280px 1fr auto;
  gap: var(--space-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
  align-items: center;
}

.sk-vehicle .sk-thumb { height: 168px; border-radius: var(--radius); }
.sk-vehicle .sk-body { display: grid; gap: var(--space-3); }
.sk-vehicle .sk-price { width: 90px; height: 40px; justify-self: end; }

.sk-tile {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  display: grid;
  gap: var(--space-3);
}

.sk-row { height: 52px; border-radius: var(--radius); margin-bottom: var(--space-2); }
.sk-gallery { height: 380px; border-radius: var(--radius-lg); }

@media (max-width: 1040px) {
  .sk-vehicle { grid-template-columns: 220px minmax(0, 1fr); }
  .sk-vehicle .sk-price { grid-column: 1 / -1; justify-self: start; height: 30px; width: 120px; }
}

@media (max-width: 720px) {
  .sk-vehicle { grid-template-columns: 1fr; }
  .sk-vehicle .sk-thumb { height: 190px; }
  .sk-gallery { height: 230px; }
}

@media (prefers-reduced-motion: reduce) {
  .sk { animation: none; background-image: none; }
}

/* -----------------------------------------------------------------------------
   Busy buttons
   ----------------------------------------------------------------------------- */
@keyframes rovo-spin { to { transform: rotate(360deg); } }

.btn[aria-busy='true'] {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}

.btn[aria-busy='true']::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-color: color-mix(in srgb, var(--ink) 30%, transparent);
  border-top-color: var(--ink);
  animation: rovo-spin 0.65s linear infinite;
}

.btn-primary[aria-busy='true']::after,
.btn-whatsapp[aria-busy='true']::after {
  border-color: color-mix(in srgb, var(--accent-on-fill) 35%, transparent);
  border-top-color: var(--accent-on-fill);
}

/* -----------------------------------------------------------------------------
   Toasts. Errors differ from confirmations in colour, icon and dwell time —
   previously every outcome shared one style.
   ----------------------------------------------------------------------------- */
.toast {
  position: fixed;
  left: 50%;
  bottom: var(--space-5);
  transform: translateX(-50%) translateY(8px);
  z-index: 90;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  max-width: min(440px, calc(100vw - 32px));
  padding: var(--space-3) var(--space-5);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  color: var(--ink);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition), transform var(--transition);
}

.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

.toast::before { font-weight: var(--weight-bold); flex: 0 0 auto; }

.toast.is-success { border-color: var(--ok); }
.toast.is-success::before { content: '✓'; color: var(--ok); }
.toast.is-error { border-color: var(--bad); }
.toast.is-error::before { content: '!'; color: var(--bad); }
.toast.is-info::before { content: 'i'; color: var(--accent); font-style: italic; }

/* -----------------------------------------------------------------------------
   Empty and error states. "No results" and "the request failed" are different
   problems and get different wording.
   ----------------------------------------------------------------------------- */
.state {
  text-align: center;
  padding: var(--space-8) var(--space-5);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.state-icon { font-size: 28px; line-height: 1; margin-bottom: var(--space-3); opacity: 0.8; }
.state h3 { font-size: var(--text-md); margin-bottom: var(--space-2); }
.state p {
  font-size: var(--text-sm);
  color: var(--ink-2);
  max-width: 46ch;
  margin: 0 auto var(--space-4);
}
.state-error { border-style: solid; border-color: var(--bad); background: var(--bad-soft); }

/* -----------------------------------------------------------------------------
   Progress
   ----------------------------------------------------------------------------- */
.progress {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--skeleton);
  overflow: hidden;
  margin-block: var(--space-3) var(--space-2);
}
.progress-bar {
  height: 100%;
  width: 0;
  border-radius: var(--radius-pill);
  background: var(--accent-fill);
  transition: width 0.25s ease;
}
.progress-label { font-size: var(--text-xs); color: var(--ink-2); }

/* Only appears after 180ms — a flash on a fast response is more distracting
   than showing nothing, because the user cannot interpret it. */
.route-progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--accent-fill);
  transform-origin: 0 50%;
  transform: scaleX(0);
  opacity: 0;
  z-index: 95;
  transition: transform 0.2s ease, opacity 0.3s ease;
}
.route-progress.is-loading {
  opacity: 1;
  transform: scaleX(0.7);
  transition: transform 1.4s cubic-bezier(0.1, 0.8, 0.2, 1);
}
.route-progress.is-done { opacity: 0; transform: scaleX(1); }
