
/* #389 — align-items:start (not the grid default of stretch) so a compact NO BID row keeps its own
   intrinsic height instead of being stretched to match a taller row-mate — grid row stretching was
   silently undoing the whole compaction whenever a short row shared a track with a tall one. */
.buy-grid{display:grid;gap:var(--sp-3);align-items:start}
/* A2 — an OPEN terminal panel earns the full grid row: the pan-scroll chart and the aligned
   spread block need viewport width, not a third of it. Graceful without :has() support — the
   panel simply opens inside its own column. */
.buy-grid>article:has(details[open]){grid-column:1/-1}
.buy-tile{display:flex;gap:var(--sp-3);align-items:flex-start;min-width:0;padding:var(--sp-3);border:1px solid var(--line);border-radius:var(--r-2);background:var(--surface)}
.buy-tile[hidden]{display:none}
.buy-art{flex:0 0 96px;display:flex;align-items:center;justify-content:center}
.buy-art img{width:96px;height:auto;border-radius:var(--r-1)}
/* #389 — a smaller thumb on a compact row: at full 96px width a card image's own 400:559 aspect
   (~134px tall) had become the height floor even after the text content shrank under it. */
.buy-tile-compact{padding:var(--sp-2)}
.buy-tile-compact .buy-art{flex-basis:64px}
.buy-tile-compact .buy-art img{width:64px}
.buy-body{flex:1 1 auto;min-width:0}
.buy-name{margin:0 0 var(--sp-0);font-size:1rem}
.buy-lang{font-size:.72rem;border:1px solid var(--line);border-radius:var(--r-1);padding:0 var(--sp-1);vertical-align:middle}
.buy-kind{margin:0 0 var(--sp-1)}
.buy-price{margin:var(--sp-0) 0}
/* A2 — the one large number: mono, tabular, row-value weight (DESIGN-BIBLE §1). */
.buy-price .price{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:var(--fs-row-value);font-weight:650}
.buy-price-stale .price-stale{opacity:.7;text-decoration:none}
.buy-delta{margin:var(--sp-0) 0;font-size:.92rem}
.buy-preorder{margin:var(--sp-0) 0}
/* A2 — the freshness dot: filled = fresh, half = aging, outlined = stale/never-checked (§6 pip
   grammar, muted ink only — an age signal, never a deal hue). Exact stamp on the title. */
.buy-dot{display:inline-block;width:8px;height:8px;border-radius:999px;border:1px solid var(--muted);vertical-align:1px;cursor:default}
.buy-dot-ok{background:var(--muted)}
.buy-dot-mid{background:linear-gradient(90deg,var(--muted) 50%,transparent 50%)}
.buy-dot-off{background:transparent;border-style:dashed;border-color:var(--line)}
/* A2 — the n=0-solds raindrop, hollow: no recent rain, nothing to measure against. */
.buy-noref{margin:var(--sp-0) 0}
.buy-drop{vertical-align:-2px;margin-right:var(--sp-0);color:var(--muted)}
.buy-actions{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin:var(--sp-1) 0 0}
/* A2 — every interactive target ≥44px (ruling), the pill/button paddings stay visual. */
.buy-cta{display:inline-flex;align-items:center;min-height:44px;padding:var(--sp-1) var(--sp-3);border:1px solid var(--line);border-radius:var(--r-2);text-decoration:none}
.buy-cta-primary{border-color:var(--accent)}
.buy-add{min-height:44px;padding:var(--sp-1) var(--sp-3);border:1px solid var(--line);border-radius:var(--r-2);background:transparent;color:inherit;cursor:pointer}
.buy-suspect-list{margin:var(--sp-1) 0 var(--sp-2);padding-left:1.1rem}
.buy-suspect-list li{margin:var(--sp-1) 0}
.buy-rails{margin:var(--sp-2) 0 0;padding-left:1.1rem}
.buy-rails li{margin:var(--sp-0) 0}
.buy-rails-details{margin:var(--sp-2) 0 0;padding:var(--sp-2) var(--sp-3);border:1px dashed var(--line);border-radius:var(--r-2)}
.buy-rails-summary{cursor:pointer;font-size:.9rem;color:var(--muted);list-style:revert}
.buy-rails-summary:hover{color:inherit}
.buy-rails-details .buy-rails{margin-top:var(--sp-2)}
/* #387 — row 1 (search, full-bleed at every breakpoint, count folded into its trailing edge) + row
   2+ (a WRAPPING chip rail: segmented groups, toggle chips, the sort chip, Clear — flex-wrap, never
   a horizontal scroll). Sticky positioning is unchanged/out of scope for this pass (#387 ticket
   scope note) — it still sticks at the same measured offset, just over a now taller two-row block. */
.buy-controls{display:flex;flex-direction:column;gap:var(--sp-2);margin:var(--sp-3) 0 var(--sp-2)}
.buy-search-row{display:flex;align-items:center;gap:var(--sp-2)}
.buy-search{flex:1 1 auto;min-width:0;padding:var(--sp-2);border:1px solid var(--line);border-radius:var(--r-2);background:var(--surface);color:inherit;font-size:.95rem}
.buy-search-count{flex:0 0 auto;white-space:nowrap;font-variant-numeric:tabular-nums}
.buy-chip-rail{display:flex;flex-wrap:wrap;gap:var(--sp-1);align-items:center}
.buy-chips{display:flex;flex-wrap:wrap;gap:var(--sp-1)}
.buy-chip{position:relative;display:inline-block}
.buy-chip input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;margin:0}
.buy-chip label{display:inline-block;padding:var(--sp-1) var(--sp-3);border:1px solid var(--line);border-radius:999px;font-size:.85rem;color:var(--muted);cursor:pointer;user-select:none}
.buy-chip input:checked+label{border-color:var(--accent);color:inherit;font-weight:600}
.buy-chip input:focus-visible+label{outline:2px solid var(--accent);outline-offset:1px}
.buy-seg{display:inline-flex;flex-wrap:wrap;gap:var(--sp-1);padding:var(--sp-0);border:1px dashed var(--line);border-radius:999px}
/* the sort control is CHIP-SHAPED (#387: same rail, same height, same radius as its neighbours) —
   no wrapping <label> text, an aria-label carries the "Sort" name for assistive tech instead. */
.buy-sort-chip{padding:var(--sp-1) var(--sp-3);border:1px solid var(--line);border-radius:999px;background:var(--surface);color:inherit;font-size:.85rem;cursor:pointer}
.buy-sort-chip:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.buy-clear{padding:var(--sp-1) var(--sp-3);border:1px solid var(--line);border-radius:999px;background:transparent;color:var(--muted);font-size:.85rem;cursor:pointer}
.buy-clear:hover{color:inherit;border-color:var(--accent)}
/* #604 — one shell clearance shared with .card-sticky. Below 640px this is deliberately static:
   a multi-row filter stack must never become a second sticky header on a short phone. */
@media (min-width:640px) and (max-width:759.98px){
  .buy-controls{position:sticky;top:var(--shell-sticky-top);z-index:20;background:var(--bg);margin:var(--sp-3) calc(-1 * var(--sp-3)) var(--sp-2);padding:var(--sp-2) var(--sp-3)}
}
/* #337-buy-parity — the composable-filter dropdown. .gf-* names/shapes mirror /cards' own (render.js
   .gf-build block) so a future real CSS-sharing pass is a pure lift; buy's own tokens throughout. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.buy-adv{margin:var(--sp-1) 0 0;padding:var(--sp-2) var(--sp-3);border:1px dashed var(--line);border-radius:var(--r-2)}
.buy-adv-summary{cursor:pointer;font-size:.9rem;color:var(--muted);list-style:revert}
.buy-adv-summary:hover{color:inherit}
.gf-group{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);margin:var(--sp-2) 0}
.gf-label{font-size:.85rem;color:var(--muted)}
.gf-toggle{padding:var(--sp-1) var(--sp-3);border:1px solid var(--line);border-radius:999px;background:var(--surface);color:inherit;font-size:.85rem;cursor:pointer}
.gf-toggle:hover{border-color:var(--accent)}
.gf-toggle[aria-pressed="true"]{border-color:var(--accent);font-weight:600}
.gf-toggle:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.gf-build{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);margin:var(--sp-2) 0}
.gf-add,.gf-do-add{padding:var(--sp-1) var(--sp-3);border:1px solid var(--line);border-radius:var(--r-1);background:var(--surface);color:inherit;font-size:.85rem;cursor:pointer}
.gf-add:hover,.gf-do-add:hover{border-color:var(--accent)}
.gf-add:focus-visible,.gf-do-add:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.gf-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);border:1px solid var(--line);border-radius:var(--r-1);padding:var(--sp-2);margin:var(--sp-2) 0}
.gf-row[hidden]{display:none}
.gf-field,.gf-op,.gf-val,.gf-join-select{padding:var(--sp-1) var(--sp-2);border:1px solid var(--line);border-radius:var(--r-1);background:var(--surface);color:inherit;font-size:.85rem}
.gf-val-num{max-width:8rem}
.gf-field:focus-visible,.gf-op:focus-visible,.gf-val:focus-visible,.gf-join-select:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.gf-join{display:inline-flex;align-items:center;gap:var(--sp-1);font-size:.85rem;color:var(--muted);margin:var(--sp-1) 0}
.gf-join[hidden]{display:none}
.gf-chips{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin:var(--sp-1) 0 0}
.gf-chips:empty{display:none}
.gf-chip{padding:var(--sp-1) var(--sp-2);border:1px solid var(--line);border-radius:999px;background:transparent;color:inherit;font-size:.8rem;cursor:pointer}
.gf-chip:hover{border-color:var(--accent)}
.gf-chip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media (max-width:759.98px){
  .gf-row{flex-direction:column;align-items:stretch}
  .gf-row .gf-field,.gf-row .gf-op,.gf-row .gf-val,.gf-row .gf-do-add{width:100%}
  .gf-val-num{max-width:none}
  .buy-tile:has(.buy-panel[open]) .buy-art{display:none}
}
.buy-empty-section{margin:var(--sp-4) 0 0;padding:var(--sp-2) var(--sp-3);border:1px dashed var(--line);border-radius:var(--r-2)}
.buy-empty-summary{cursor:pointer;font-size:.9rem;color:var(--muted);list-style:revert}
.buy-empty-summary:hover{color:inherit}
.buy-empty-badge{display:inline-block;min-width:1.6rem;text-align:center;margin-left:var(--sp-1);padding:0 var(--sp-1);border-radius:999px;background:var(--line);font-size:.78rem;font-weight:700}
.buy-empty-section .buy-grid{margin-top:var(--sp-2)}
.buy-deal{display:inline-block;min-width:3.2rem;text-align:center;padding:0 var(--sp-2);border-radius:var(--r-1);font-weight:700;font-variant-numeric:tabular-nums;border:1px solid var(--line)}
.buy-deal-good{color:var(--ok)}
.buy-deal-bad{color:var(--warn)}
.buy-deal-mid{color:var(--muted)}
/* A2 — a thin ask sample greys the chip (the weld says "thin · n=X" beside it): the % is a guess,
   so it never wears a deal hue. */
.buy-deal-thin{color:var(--muted);border-style:dashed}
/* #389 — the NO BID state chip: an OUTLINED pill (DESIGN-BIBLE §6's "nothing cleared the trust
   filter this cycle" glyph), deliberately undyed — it is an absence signal, not a deal signal, so
   it never borrows --ok/--warn/--under/--over. */
.buy-nobid-line{margin:var(--sp-0) 0}
.buy-nobid,.buy-check-overdue{display:inline-block;padding:0 var(--sp-2);border:1px dashed var(--line);border-radius:999px;font-size:.72rem;font-weight:700;letter-spacing:.04em;color:var(--muted);cursor:default}
/* #502 — .buy-check-overdue reuses the SAME undyed outlined-pill idiom as .buy-nobid, above: an
   overdue check is an absence-of-proof signal (we cannot honestly promise this number is
   current), never a deal/alarm colour. .buy-checked-stale carries no rule of its own — it is a
   CSS/test hook only, marking the .buy-checked span that dropped its "never more than Xh old"
   promise. */
/* (A2 — the #416 .buy-trend chips left the face; their --under/--over pairs live on in the
   panel's .term-gap-* / .term-read-* below, contrast-gated under the renamed ids.) */
/* #389 — compact NO BID row sizing: a smaller CTA (44px tap floor still applies) and a smaller
   sold-median line keep the row short even inside a narrow 3-col grid track. */
.buy-tile-compact .buy-body{display:flex;flex-direction:column;gap:var(--sp-0)}
.buy-tile-compact .buy-nobid-line{font-size:.82rem;margin:0}
.buy-tile-compact .buy-cta{padding:var(--sp-1) var(--sp-2);font-size:.82rem}
.buy-tile-compact .buy-actions{margin:0}
.buy-tile-compact .buy-name{font-size:.875rem;margin:0}
/* .card-id's site-wide rule (assets/styles.css) carries a --sp-4 (16px) bottom margin sized for a
   card-page hero; a dense row needs none of that breathing room. */
.buy-identity{margin:0 0 var(--sp-1)}
.buy-tile-compact .buy-identity{margin:0}
.buy-tile-compact .buy-kind{margin:0}
/* A2 — THE TERMINAL PANEL. Summary keeps a drawn affordance (flex kills the native marker) and
   the 44px tap floor. */
.buy-panel{margin:var(--sp-2) 0 0}
.buy-panel-summary{cursor:pointer;font-size:.85rem;color:var(--muted);list-style:none;display:flex;align-items:center;gap:var(--sp-1);min-height:44px}
.buy-panel-summary::-webkit-details-marker{display:none}
.buy-panel-summary::before{content:'▸'}
.buy-panel[open]>.buy-panel-summary::before{content:'▾'}
.buy-panel-summary:hover{color:inherit}
/* #570 — Desk grouping: the open panel body is ONE bordered card; its sections are divided by
   hairlines (border, never shadow), so the 8 parts read as identity / numbers / evidence /
   actions instead of a flat same-weight stack. */
.buy-panel-body{margin-top:var(--sp-1);border:1px solid var(--line);border-radius:var(--r-1)}
.term-sec{padding:var(--sp-2) var(--sp-3)}
.term-sec+.term-sec{border-top:1px solid var(--line)}
.term-head{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);margin:0}
.term-asof{font-size:.8rem}
.term-sold{margin:var(--sp-0) 0 0;font-size:.92rem}
/* The SPREAD block: three aligned mono rows, GAP carrying its printed equation. It keeps its own
   border — inside the numbers section it is the focal instrument, one material tier above its
   stats/readout captions. */
.term-spread{display:grid;grid-template-columns:auto auto minmax(0,1fr);gap:var(--sp-0) var(--sp-3);align-items:baseline;font-family:var(--mono);font-variant-numeric:tabular-nums;margin:0 0 var(--sp-1);padding:var(--sp-2) var(--sp-3);border:1px solid var(--line);border-radius:var(--r-1);width:100%;max-width:26rem;min-width:0}
.term-k{font-size:var(--fs-row-micro);letter-spacing:.13em;color:var(--muted)}
.term-v{text-align:right;font-weight:650}
.term-eq{min-width:0;font-size:.8rem;overflow-wrap:anywhere}
.term-gap-under{color:var(--under)}
.term-gap-over{color:var(--over)}
.term-stats{display:flex;flex-wrap:wrap;gap:var(--sp-4);margin:var(--sp-1) 0 0;font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:.85rem;color:var(--muted)}
/* The readout: framing words, deal hues only when a deal claim is being made — high-value wears
   NO deal color by rule. */
.term-read{margin:var(--sp-1) 0 0;font-size:var(--fs-small);font-weight:700;letter-spacing:.06em}
.term-read-good{color:var(--under)}
.term-read-bad{color:var(--over)}
.term-read-mid{color:var(--muted)}
.term-read-hv{font-weight:600;letter-spacing:0}
/* The pan-scroll chart strip: direction:rtl RESTS the scroll on the right edge (newest sales),
   zero JS; the A1 asset is self-contained so no page CSS reaches into the image document.
   #570 — the strip now lives INSIDE the evidence section, welded (sp-1) to the receipt rows it
   plots, instead of floating between the stats and the receipts as its own block. */
.term-chart{overflow:hidden;margin:0 0 var(--sp-1)}
.term-chart img{width:100%;max-width:640px;height:auto;display:block}
.term-cta-text{min-height:44px;display:inline-flex;align-items:center;text-decoration:underline}
.term-history{min-height:44px;display:inline-flex;align-items:center}
.buy-panel-sales{margin:0;padding-left:1.1rem;font-size:.88rem}
.buy-panel-sales li{margin:var(--sp-0) 0}
.buy-panel-date{color:var(--muted)}
.buy-panel-price{font-weight:600;font-family:var(--mono);font-variant-numeric:tabular-nums}
/* ≥12px dead margin around the wrapped CTA (ruling) — the 12px flex gap guards the sides, and
   inside the #570 card the footer's own sp-3 PADDING (which never margin-collapses, unlike the
   pre-#570 sp-3 margin review F1 pinned) plus the hairline above it keep the top clearance. */
.buy-panel-body>.buy-panel-actions{display:flex;flex-wrap:wrap;gap:var(--sp-3);align-items:center;margin:0;padding:var(--sp-3);border-top:1px solid var(--line)}
.buy-list-toggle{position:sticky;bottom:var(--sp-2);float:right;padding:var(--sp-2) var(--sp-3);border:1px solid var(--line);border-radius:999px;background:var(--surface);color:inherit;cursor:pointer;box-shadow:var(--shadow-1);z-index:5}
.buy-drawer{position:sticky;bottom:var(--sp-2);margin-top:var(--sp-3);padding:var(--sp-3);border:1px solid var(--line);border-radius:var(--r-2);background:var(--surface);box-shadow:var(--shadow-2);z-index:6}
.buy-drawer-head{margin:0 0 var(--sp-2);font-size:1.05rem}
.buy-line{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center;padding:var(--sp-1) 0;border-top:1px solid var(--line)}
.buy-line-name{flex:1 1 12rem;min-width:0}
.buy-qty{width:4rem;padding:var(--sp-1);border:1px solid var(--line);border-radius:var(--r-1);background:transparent;color:inherit}
.buy-drawer-step{margin:var(--sp-2) 0 var(--sp-1)}
.buy-drawer-extras{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-top:var(--sp-2)}
@media (min-width:760px){.buy-grid{grid-template-columns:1fr 1fr}}
/* #386/#387 fold: at >=1200px there is room for a 3rd tile column, which is what finally lands the
   3rd deal tile (row 1, not row 2) above the 720px fold line on a 1280px viewport — a priced tile's
   own height (~300px, decision panel + sparkline) means no further header/controls compression
   alone could close this last gap. */
@media (min-width:1200px){.buy-grid{grid-template-columns:1fr 1fr 1fr}}
