/*
 * SalvageFlow Design System — CSS Custom Properties
 * --------------------------------------------------
 * Single source of truth for all design tokens.
 * Loaded in base.html before Tailwind's compiled output.
 *
 * Marketing site uses dark tokens (sf-bg, sf-panel, etc.).
 * App UI uses light workspace tokens defined here.
 * Accent teal is shared between both surfaces.
 */

:root {

  /* ── Typography ─────────────────────────────────────────────── */
  --sf-font-ui:   "Inter", system-ui, -apple-system, sans-serif;
  --sf-font-mono: "JetBrains Mono", ui-monospace, monospace;

  /* ── Accent (shared with marketing site) ────────────────────── */
  --sf-accent:        #27E0D7;
  --sf-accent-hover:  #1ED6CE;
  --sf-accent-active: #12A8A1;
  --sf-accent-dim:    rgba(39, 224, 215, 0.10);
  --sf-accent-ring:   rgba(39, 224, 215, 0.20);

  /* ── Action color (C-3, owner brand call July 2026) ─────────────
     ONE primary-action teal across app + marketing. .btn-primary,
     the brand-class shims, badges, and marketing's .btn-primary all
     reference these — never the hex directly. */
  --sf-action:        #0A827D;
  --sf-action-hover:  #087A75;
  --sf-action-active: #066B67;

  /* ── Light workspace palette ────────────────────────────────── */
  --sf-bg-app:         #F6F8FA;   /* page background             */
  --sf-bg-card:        #FFFFFF;   /* card / panel surface        */
  --sf-bg-subtle:      #F0F3F6;   /* table header, chip bg       */

  --sf-text-primary:   #0B1216;   /* primary text                */
  --sf-text-muted:     #6B7680;   /* secondary / helper text     */
  --sf-text-faint:     #9BA6AF;   /* placeholder, disabled       */

  --sf-border-subtle:  #E3E8EC;   /* default border              */
  --sf-border-medium:  #CBD2D9;   /* stronger divider            */

  /* ── Spacing scale ──────────────────────────────────────────── */
  --sf-space-xs:  6px;
  --sf-space-sm:  10px;
  --sf-space-md:  16px;
  --sf-space-lg:  24px;
  --sf-space-xl:  32px;
  --sf-space-2xl: 48px;

  /* ── Radii ──────────────────────────────────────────────────── */
  --sf-radius-sm:  4px;
  --sf-radius:     6px;
  --sf-radius-md:  8px;
  --sf-radius-lg:  10px;
  --sf-radius-xl:  14px;

  /* ── Motion (app UI stays calm) ─────────────────────────────── */
  --sf-ease:          cubic-bezier(0.16, 1, 0.3, 1);
  --sf-duration-fast: 120ms;
  --sf-duration:      180ms;

  /* ── Shadows ────────────────────────────────────────────────── */
  --sf-shadow-sm:  0 1px 2px 0 rgba(11, 18, 22, 0.06);
  --sf-shadow:     0 2px 8px 0 rgba(11, 18, 22, 0.08);
  --sf-shadow-md:  0 4px 16px 0 rgba(11, 18, 22, 0.10);

  /* ── Semantic status colors ─────────────────────────────────── */
  --sf-success:       #10B981;
  --sf-success-bg:    #ECFDF5;
  --sf-success-border:#A7F3D0;

  --sf-warning:       #F59E0B;
  --sf-warning-bg:    #FFFBEB;
  --sf-warning-border:#FDE68A;

  --sf-danger:        #EF4444;
  --sf-danger-text:   #B91C1C;  /* C-14: the ONE destructive-action red;
                                   .btn-danger / .btn-ghost-danger /
                                   .rm-btn--danger all read it */
  --sf-danger-bg:     #FEF2F2;
  --sf-danger-border: #FECACA;

  --sf-info:          #3B82F6;
  --sf-info-bg:       #EFF6FF;
  --sf-info-border:   #BFDBFE;
}

/* =============================================================
 * COMPATIBILITY SHIMS
 * Maps legacy class names → design-system tokens.
 * Lets existing templates work without a rewrite.
 * Migrate templates to sf-* classes over time.
 * ============================================================= */

/* ── Color utilities ─────────────────────────────────────────── */
.text-surface-800  { color: var(--sf-text-primary) !important; }
.text-surface-700  { color: #2D3B45 !important; }
.text-surface-600  { color: #404D57 !important; }
.text-surface-500  { color: var(--sf-text-muted) !important; }
.text-surface-400  { color: var(--sf-text-faint) !important; }
.text-surface-300  { color: #B8C4CC !important; }
.text-brand-600    { color: var(--sf-accent-active) !important; }
.text-brand-700    { color: var(--sf-accent-active) !important; }
.text-brand-800    { color: var(--sf-accent-active) !important; }
.bg-surface-50     { background-color: var(--sf-bg-app) !important; }
.bg-surface-100    { background-color: var(--sf-bg-subtle) !important; }
.bg-surface-200    { background-color: #E3E8EC !important; }
.border-surface-100 { border-color: var(--sf-border-subtle) !important; }
.border-surface-200 { border-color: var(--sf-border-subtle) !important; }
.border-surface-300 { border-color: var(--sf-border-medium) !important; }
.bg-brand-50       { background-color: var(--sf-accent-dim) !important; }
.bg-brand-100      { background-color: rgba(39,224,215,0.15) !important; }
.border-brand-200  { border-color: rgba(39,224,215,0.30) !important; }
.border-brand-300  { border-color: rgba(39,224,215,0.50) !important; }
/* C-2 (quality sweep): ONE action/selected color family. These shims used
   to render near-black (#0B1216), giving the app two primary colors —
   teal .btn-primary/nav-active vs black Tailwind-class buttons and
   selected chips — and a broken hover (bg-brand-600 rest was black but
   hover:bg-brand-700 fell through to compiled teal). Now the same family
   as .btn-primary: --sf-action rest / --sf-action-hover on hover
   (white text = 4.66:1, passes AA). */
.bg-brand-500, .bg-brand-600 { background-color: var(--sf-action) !important; }
.border-brand-600 { border-color: var(--sf-action) !important; }
.hover\:bg-brand-700:hover { background-color: var(--sf-action-hover) !important; }
.hover\:border-brand-300:hover { border-color: rgba(39,224,215,0.50) !important; }
.hover\:bg-brand-50\/50:hover  { background-color: rgba(39,224,215,0.08) !important; }
.hover\:bg-brand-100:hover     { background-color: rgba(39,224,215,0.15) !important; }
.group:hover .group-hover\:text-brand-500 { color: var(--sf-accent-active) !important; }
.group:hover .group-hover\:text-brand-700 { color: var(--sf-accent-active) !important; }
.divide-surface-100 > * + * { border-color: var(--sf-border-subtle) !important; }

/* Dialog scroll lock (shared dialog behavior, C-1/C-7/W-1): applied to
   <html> by dialog.js while any [data-sf-dialog] overlay is open. */
.sf-dialog-lock { overflow: hidden; }

/* ── Overlay visual shell (C-7) ──────────────────────────────────
   One dimming voice + one positioning shell for every overlay, taken
   from the review modal (the surface that already solved centered
   desktop dialog / mobile bottom sheet / safe-area):

   .sf-backdrop        dialog dim — the review modal's slate ink.
   .sf-backdrop-media  photo viewing — near-black, like the lightbox.
   .sf-overlay         fixed full-screen flex shell, centered, 16px
                       gutter. Metrics identical to .rm-overlay.
   .sf-overlay-sheet   + bottom-sheet alignment on phones (pair the
                       card with rounded top corners).

   This file loads AFTER the compiled Tailwind build, so a bare
   .sf-overlay would out-cascade Tailwind's .hidden display toggle —
   the .sf-overlay.hidden guard keeps hidden-class modals closed. */
.sf-backdrop { background-color: rgba(2, 6, 23, 0.5); }
.sf-backdrop-media { background-color: rgba(2, 6, 23, 0.85); }
.sf-overlay { position: fixed; inset: 0; z-index: 50; display: flex;
  align-items: center; justify-content: center; padding: 16px; }
.sf-overlay.hidden { display: none; }
@media (max-width: 640px) {
  .sf-overlay-sheet { align-items: flex-end; padding: 0; }
}

/* ── Card ────────────────────────────────────────────────────── */
.card {
  background: var(--sf-bg-card);
  border: 1px solid var(--sf-border-subtle);
  border-radius: var(--sf-radius-lg);
  box-shadow: var(--sf-shadow-sm);
}
.card-body {
  padding: 1.25rem;
}

/* ── Buttons ─────────────────────────────────────────────────── */
.btn-primary {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  font-size: 0.8125rem; font-weight: 500; line-height: 1.4;
  border-radius: var(--sf-radius);
  background: var(--sf-action); color: #ffffff;
  border: 1px solid var(--sf-action);
  cursor: pointer; text-decoration: none;
  transition: background var(--sf-duration-fast), border-color var(--sf-duration-fast);
  white-space: nowrap;
}
.btn-primary:hover:not(:disabled)  { background: var(--sf-action-hover); border-color: var(--sf-action-hover); }
.btn-primary:active:not(:disabled) { background: var(--sf-action-active); border-color: var(--sf-action-active); }
.btn-primary:focus-visible { box-shadow: 0 0 0 3px rgba(18, 168, 161, 0.35); outline: none; }
.btn-secondary {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  font-size: 0.8125rem; font-weight: 500;
  border-radius: var(--sf-radius);
  background: white; color: var(--sf-text-primary);
  border: 1px solid var(--sf-border-medium);
  cursor: pointer; text-decoration: none;
  transition: border-color var(--sf-duration-fast);
}
.btn-secondary:hover { border-color: var(--sf-accent); }
.btn-danger {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  font-size: 0.8125rem; font-weight: 500;
  border-radius: var(--sf-radius);
  background: var(--sf-danger-bg); color: var(--sf-danger-text);
  border: 1px solid var(--sf-danger-border);
  cursor: pointer; text-decoration: none;
  transition: background var(--sf-duration-fast),
              border-color var(--sf-duration-fast),
              box-shadow var(--sf-duration-fast);
}
/* Explicit interaction states. Soft-red BASE (light tint, dark-red text), but
   hover/active fill to a saturated dark red with WHITE text — a filled
   destructive affordance the moment you engage it, and white-on-dark-red is
   well above 4.5:1 (never a low-contrast red-on-red). Focus keeps an accessible
   red ring. */
.btn-danger:hover {
  background: var(--sf-danger-text);      /* filled dark red */
  border-color: var(--sf-danger-text);
  color: #fff;                            /* white text on hover */
}
.btn-danger:active {
  background: #991B1B;                     /* darker red */
  border-color: #991B1B;
  color: #fff;                            /* white text on active */
}
.btn-danger:focus-visible {
  outline: none;
  border-color: var(--sf-danger-text);
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.35);   /* accessible red ring */
}
/* Ghost — used widely in templates as a low-emphasis but still
   button-shaped control (Quick action bar, summary band controls,
   row-level secondary actions). Without this rule, `btn-ghost`
   would render as bare text and lose the affordance of being a
   button. The companion `.sf-btn-ghost` exists in components.css
   for the sf-* prefixed track; both must stay in sync. */
.btn-ghost {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  font-size: 0.8125rem; font-weight: 500;
  border-radius: var(--sf-radius);
  background: #F6F8FA;
  color: #404D57;
  border: 1px solid #CBD2D9;
  cursor: pointer; text-decoration: none;
  transition: background var(--sf-duration-fast),
              border-color var(--sf-duration-fast),
              box-shadow var(--sf-duration-fast);
}
.btn-ghost:hover {
  background: #EEF4F7;
  border-color: #9BA6AF;
  color: #1a2328;
  box-shadow: 0 0 0 3px rgba(39, 224, 215, 0.12);
}
.btn-ghost-danger {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  font-size: 0.8125rem; font-weight: 500;
  border-radius: var(--sf-radius);
  background: var(--sf-danger-bg);
  color: var(--sf-danger-text);
  border: 1px solid var(--sf-danger-border);
  cursor: pointer; text-decoration: none;
  transition: background var(--sf-duration-fast),
              border-color var(--sf-duration-fast),
              box-shadow var(--sf-duration-fast);
}
.btn-ghost-danger:hover {
  background: #FEE2E2;
  border-color: #FCA5A5;
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.12);
}
.btn-sm { padding: 5px 10px; font-size: 0.75rem; }
.btn-lg { padding: 10px 20px; font-size: 0.9375rem; }

/* ── Form controls ───────────────────────────────────────────── */
.form-label, label.form-label {
  display: block;
  font-size: 0.8125rem; font-weight: 500;
  color: var(--sf-text-primary);
  margin-bottom: 4px;
}
.form-input, .form-select, .form-textarea,
input[type="text"].form-control,
input[type="email"].form-control,
input[type="password"].form-control,
select.form-control, textarea.form-control {
  display: block; width: 100%;
  padding: 7px 10px;
  font-size: 0.875rem;
  background: white;
  border: 1px solid var(--sf-border-medium);
  border-radius: var(--sf-radius);
  color: var(--sf-text-primary);
  transition: border-color var(--sf-duration-fast), box-shadow var(--sf-duration-fast);
  appearance: none;
}
.form-input:focus, .form-select:focus, .form-textarea:focus,
input[type="text"].form-control:focus,
select.form-control:focus {
  outline: none;
  border-color: var(--sf-accent);
  box-shadow: 0 0 0 3px var(--sf-accent-ring);
}
.form-hint, .form-help { font-size: 0.75rem; color: var(--sf-text-muted); margin-top: 3px; }
/* Select dropdown caret — appearance:none removes native arrow */
.form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%236B7680'%3E%3Cpath fill-rule='evenodd' d='M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z' clip-rule='evenodd'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 16px;
  padding-right: 30px;
}
.form-error { font-size: 0.75rem; color: #DC2626; margin-top: 3px; }

/* ── Board filter row scoping ────────────────────────────────────
 * UI Hotfix r1 — the global `.form-input, .form-select { display:
 * block; width: 100% }` rule above made every filter take the full
 * row width. Combined with `flex-wrap`, that meant the search input,
 * status select, and tag select each took their own row — no
 * single-row layout was possible regardless of viewport.
 *
 * `[data-board-filter-row]` is the marker on the flex container of
 * the board filter row. Inside that container, form children grow
 * naturally to their flex-defined size, NOT to 100% of the row. The
 * search wrapper still sets `flex-1 min-w-[200px] max-w-sm` to
 * dominate width; selects fall to their intrinsic width.
 *
 * Scoped via attribute selector — does not affect any form layout
 * outside the parts board filter bar. */
[data-board-filter-row] .form-input,
[data-board-filter-row] .form-select,
[data-board-filter-row] .sf-input-group {
  display: inline-flex;
  width: auto;
}
/* Search wrap inside the filter row keeps growing to fill remaining
 * space; the `flex-1 min-w-[200px] max-w-sm` Tailwind utilities on
 * the wrapper provide the width — we just need to override the
 * default block-100% above. */
[data-board-filter-row] .sf-input-group[data-board-search-wrap] {
  display: inline-flex;
  flex: 1 1 200px;
}

/* ── Input groups (input with leading icon or text prefix) ───────
 * UI Hotfix r1 — switched from absolute-positioned prefix to
 * inline-flex layout. The previous absolute-positioned approach
 * required the `.sf-input-group` parent to render as a block-level
 * positioning context AND required the input to have left padding
 * matching the prefix offset. In practice the structure was
 * fragile — empty space between prefix and input, prefix
 * positioning above the input on its own line, and brittle
 * cascade against the `.form-input` shorthand.
 *
 * New structure: `.sf-input-group` is `inline-flex`. Prefix is a
 * fixed-width flex item; input is `flex: 1` and grows to fill the
 * remaining width. No position:absolute, no padding-left tricks,
 * no cascade fights. Vertical alignment is guaranteed because both
 * children share the flex baseline.
 *
 * Templates: the existing class names are preserved. Templates
 * that already wrap with `.sf-input-group` and add either
 * `.sf-input--with-icon-left` or `.sf-input--with-prefix-left`
 * keep working without HTML changes. The padding-left helpers
 * are now no-ops (the prefix is a real flex item, not an overlay)
 * but they still apply harmlessly. */
.sf-input-group {
  display: inline-flex;
  align-items: stretch;
  width: 100%;
  /* Match form-input border so the group reads as one control */
  border: 1px solid var(--sf-border, #d1d5db);
  border-radius: var(--sf-radius, 6px);
  background: #fff;
  overflow: hidden;
  /* Defensive: a bare margin-zero so design-system.css contributors
   * can't accidentally land us back in stacking territory. */
  margin: 0;
}
.sf-input-group:focus-within {
  border-color: var(--sf-brand-400, #5eead4);
  box-shadow: 0 0 0 1px var(--sf-brand-300, #99f6e4);
}
/* The prefix slot — fixed-width flex item, never grows or shrinks.
 * align-items:center keeps icon/text vertically centered against
 * the input's natural height. */
.sf-input-group__prefix-left {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  /* Width is set via the icon size rule below for icon prefixes,
   * or via padding for text prefixes (e.g. "$"). */
  padding: 0 8px 0 10px;
  pointer-events: none;
  color: var(--sf-text-muted, #6b7280);
  font-size: 0.875rem;
  line-height: 1;
}
/* Icon prefix: explicit size on the SVG/icon. flex:none guarantees
 * the icon never stretches inside its flex parent. */
.sf-input-group__prefix-left svg,
.sf-input-group__prefix-left .sf-search-icon {
  width: 16px;
  height: 16px;
  flex: none;
}
/* The input slot — grows to fill remaining width. We strip the
 * input's own border because the group wrapper already provides
 * one (cleaner visual, no double-border). */
.sf-input-group .form-input,
.sf-input-group input.sf-input--with-icon-left,
.sf-input-group input.sf-input--with-prefix-left {
  flex: 1 1 0;
  min-width: 0;       /* allow shrink below intrinsic content width */
  border: none !important;
  background: transparent !important;
  /* Padding-left helpers are now no-ops because the prefix is a
   * real flex item that already takes its own horizontal space.
   * Setting padding-left to 0 explicitly stops any leftover rule
   * from creating a visible gap between prefix and text. */
  padding-left: 0 !important;
}
/* Focus state moves to the wrapper (focus-within above). Strip
 * the inner input's focus ring to avoid double rings. */
.sf-input-group .form-input:focus,
.sf-input-group input:focus {
  outline: none !important;
  box-shadow: none !important;
}
/* Legacy padding helpers retained for backward-compatibility, but
 * intentionally weaker than the override above. Kept so any older
 * template that still relies on the old absolute layout doesn't
 * crash visually if the wrapper class is missing.
 *
 * If you see these helpers winning over the new layout, search
 * for HTML using these classes WITHOUT `.sf-input-group` parent —
 * those are stragglers that should be migrated. */
.sf-input--with-icon-left {
  padding-left: 32px;
}
.sf-input--with-prefix-left {
  padding-left: 26px;
}
.form-section-header {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--sf-text-primary);
  padding-top: 24px;
  padding-bottom: 8px;
  margin-bottom: 8px;
  border-top: 1px solid var(--sf-border-subtle, #e5e7eb);
}
.form-section-header:first-child { border-top: none; padding-top: 0; }
.form-group { margin-bottom: 16px; }
.form-group:last-child { margin-bottom: 0; }
.form-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-top: 20px;
  margin-top: 8px;
  border-top: 1px solid var(--sf-border-subtle, #e5e7eb);
}

/* ── Badges ──────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center;
  padding: 2px 8px;
  font-size: 0.6875rem; font-weight: 500; line-height: 1.4;
  border-radius: 999px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge-draft     { background: #F0F3F6; color: #6B7680; border-color: rgba(107, 118, 128, 0.4); }
.badge-published { background: #ECFDF5; color: #059669; border-color: rgba(5, 150, 105, 0.4); }
.badge-sold      { background: #EFF6FF; color: #3B82F6; border-color: rgba(59, 130, 246, 0.4); }
.badge-archived  { background: #F0F3F6; color: #9BA6AF; border-color: rgba(155, 166, 175, 0.4); }

/* ── Alerts ──────────────────────────────────────────────────── */
.alert-success, .alert-info, .alert-error, .alert-warning {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 14px;
  border-radius: var(--sf-radius);
  border: 1px solid transparent;
  font-size: 0.875rem;
}
.alert-success { background: var(--sf-success-bg); border-color: var(--sf-success-border); color: #065f46; }
.alert-warning { background: var(--sf-warning-bg); border-color: var(--sf-warning-border); color: #78350f; }
.alert-error   { background: var(--sf-danger-bg);  border-color: var(--sf-danger-border);  color: #991b1b; }
.alert-info    { background: var(--sf-info-bg);    border-color: var(--sf-info-border);    color: #1e40af; }

/* ── Page background ─────────────────────────────────────────── */
body { background-color: var(--sf-bg-app); }

/* ── Disclosure (`<details>` with custom chevron) ────────────────
 * Used in the canonical drawer "Price matches" section and any
 * other place we want a visible expand/collapse affordance. The
 * native marker is hidden in favour of an inline svg the template
 * controls; we just rotate it 90° when [open]. Use class
 * `.sf-disclosure` on the <details> and `list-none` on the
 * <summary> to suppress the native marker in webkit/firefox. */
.sf-disclosure summary { list-style: none; }
.sf-disclosure summary::-webkit-details-marker { display: none; }
.sf-disclosure summary::marker { content: ""; }
.sf-disclosure[open] > summary .sf-disclosure__chevron { transform: rotate(90deg); }

/* ── Shared process-state animation (UX spec: ANY live status text that
   ends in "…" uses this same animated ellipsis, so users get consistent
   "work is happening" feedback across Evaluation, Parts Board, catalog
   build, pricing, and future workflows). Usage:
     <span class="sf-ellipsis">Evaluation running</span>
   The class supplies and animates the dots — do NOT also type "…". ── */
.sf-ellipsis::after {
  content: "\2026";            /* … — STATIC, fixed width. The width-stepping
  animation shipped in the button-reset hotfix made the element grow/shrink
  every cycle (layout jump). Liveness motion comes from .sf-dot-pulse next to
  the text; the ellipsis just reads as "in progress" without moving. */
  display: inline-block;
  width: 1.15em;
  vertical-align: bottom;
}

/* Stronger sibling of Tailwind's animate-pulse for status dots — visible
   scale + opacity so the indicator clearly reads as "alive". Stagger with
   inline animation-delay on consecutive dots. */
.sf-dot-pulse { animation: sf-dot-pulse 1s ease-in-out infinite; }
@keyframes sf-dot-pulse {
  0%, 100% { opacity: 0.25; transform: scale(0.7); }
  50%      { opacity: 1;    transform: scale(1.15); }
}
/* WCAG 2.3.3 (quality sweep W-5): liveness decoration goes static under
   reduced motion — the dot stays visible, the ellipsis stops cycling. */
@media (prefers-reduced-motion: reduce) {
  .sf-dot-pulse { animation: none; }
  .sf-ellipsis::after { animation: none; content: "…"; }
}
