/* =============================================================================
   Fluxology Wardrobe — app-specific styling
   -----------------------------------------------------------------------------
   The shell, cards, badges, controls and dialog all come from the shared
   design-system layer (ds-tokens.css + ds-dashboard.css). Only what is unique
   to the wardrobe dashboard lives here: the lane badge, the trigger legend,
   and the vendor ledger below the buying queue.
   ============================================================================= */

/* Six filter selects plus the active-only checkbox. The search box keeps the
   larger share; it is the primary control. */
.controls {
  grid-template-columns: minmax(240px, 1.8fr) repeat(6, minmax(118px, 1fr)) auto;
}

/* The trigger legend reuses the shared .target block, but its headline carries
   two figures rather than one, so it needs to wrap instead of overflowing. */
.target strong {
  display: block;
  text-wrap: balance;
}

/* --- Offer media ----------------------------------------------------------- */

.image {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--dash-sunken);
  border-bottom: var(--border-width-hairline) solid var(--dash-border);
}

.image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Badges float over the product photo, so they need their own backing to stay
   legible against arbitrary vendor imagery instead of the card surface. */
.image .badges {
  position: absolute;
  inset: var(--spacing-sm) var(--spacing-sm) auto var(--spacing-sm);
  justify-content: flex-start;
}

.image .badges .badge {
  background: rgba(4, 10, 16, 0.72);
  backdrop-filter: blur(4px);
  border-color: rgba(242, 233, 214, 0.4);
  color: #FFFFFF;
}

/* Most offers carry no imageUrl. Rendering .image anyway would leave a large
   empty slot on every card, so an image-less card gets a plain badge strip. */
.badges.nomedia {
  justify-content: flex-start;
  padding: var(--spacing-lg) var(--spacing-lg) 0;
}

/* Retired offers read as history, not as live inventory. */
.card.inactive { opacity: 0.72; }
.card.inactive:hover { opacity: 1; }
.card.inactive .image { opacity: 0.62; }

/* --- Trigger tones ---------------------------------------------------------- */

/* under_cad_40 and discount_30 — the strong signals. */
.badge.killer {
  color: var(--dash-accent-text);
  border-color: var(--dash-accent);
  background: var(--dash-accent-soft);
}

/* under_cad_60 and discount_20 — the standard pair. */
.badge.good {
  color: var(--dash-success-text);
  border-color: var(--dash-success);
  background: var(--dash-success-soft);
}

/* Stale or partially-verified evidence. */
.badge.warn {
  color: var(--dash-warn-text);
  border-color: var(--dash-warn);
  background: var(--dash-warn-soft);
}

.badge.purchased {
  color: var(--dash-success-text);
  border-color: var(--dash-success);
  background: var(--dash-success-soft);
}

.badge.pipeline {
  color: var(--dash-accent-text);
  border-color: var(--dash-accent);
  background: var(--dash-accent-soft);
}

/* --- Lane badge ------------------------------------------------------------- */

/* The two lanes buy different things for different reasons, so they must never
   be confusable at a glance. Every card carries exactly one lane badge, and the
   two tones are deliberately unlike the trigger tones above. */
.badge.lane-personal,
.badge.lane-inventory,
.badge.lane-unset {
  font-family: var(--current-font-technical);
  letter-spacing: var(--letter-spacing-wide);
}

.badge.lane-personal {
  color: var(--dash-heading);
  border-color: var(--dash-border-strong);
  background: transparent;
}

.badge.lane-inventory {
  color: var(--dash-muted);
  border-color: var(--dash-border);
  background: var(--dash-sunken);
}

/* A lane the writer never declared. The connector refuses this on an active
   offer, so it can only appear on a retired record — say so rather than
   letting it read as one of the two real lanes. */
.badge.lane-unset {
  color: var(--dash-danger-text);
  border-color: var(--dash-danger);
  background: transparent;
}

/* The dialog headline carries the same "landed / personalized, MOQ n" caption
   the card does. It is a qualifier, not part of the figure, so it must not
   inherit the headline's size. */
.dp span {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-regular);
  letter-spacing: var(--letter-spacing-normal);
  color: var(--dash-muted);
}

/* --- Wardrobe-specific text -------------------------------------------------- */

.kicker {
  font-family: var(--current-font-technical);
  font-size: var(--font-size-xs);
  letter-spacing: var(--letter-spacing-wide);
  text-transform: uppercase;
  color: var(--dash-muted);
}

/* Product names vary from one line to three; a floor keeps the price rows of
   neighbouring cards on the same line. */
.title { min-height: 2.6em; }

/* The landed-cost arithmetic and the unresolved-question list, verbatim, so a
   figure stays auditable months later. */
.calc {
  margin-top: var(--spacing-sm);
  padding: var(--spacing-sm);
  border-radius: var(--radius-sm);
  background: var(--dash-sunken);
  font-family: var(--current-font-technical);
  font-size: var(--font-size-xs);
  line-height: 1.6;
  color: var(--dash-muted);
}

/* --- Vendor ledger ----------------------------------------------------------- */

.vendors { padding: var(--spacing-lg); }

.vendor-rows {
  display: grid;
  gap: var(--spacing-md);
}

.vendor-row {
  display: grid;
  gap: var(--spacing-xs);
  padding-bottom: var(--spacing-md);
  border-bottom: var(--border-width-hairline) solid var(--dash-border);
}

.vendor-row:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.vendor-row > div:first-child {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  flex-wrap: wrap;
}

/* An excluded vendor stays visible on the board rather than disappearing: the
   exclusion is the record. */
.vendor-row.excluded b { text-decoration: line-through; }

.vendor-facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm) var(--spacing-lg);
  font-family: var(--current-font-technical);
  font-size: var(--font-size-xs);
  color: var(--dash-muted);
}

/* --- Storage-failure notice --------------------------------------------------- */

.savemsg {
  margin: var(--spacing-sm) 0 0;
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  color: var(--dash-danger-text);
}

.workspace-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--spacing-sm);
  margin-top: var(--spacing-sm);
}

@media (max-width: 1180px) {
  .controls { grid-template-columns: repeat(3, 1fr); }
  .search { grid-column: 1 / -1; }
}

@media (max-width: 670px) {
  .controls { grid-template-columns: 1fr; }

  /* Hidden visually but still announced: this is an aria-live region. */
  .live {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}
