/* ===========================================================================
   MEMBERS AREA

   Built on the site's own tokens rather than a second palette — a customer
   moving from the public pages into their account should not feel handed to a
   different company. Everything here is layout and the few components the
   public site does not already have.
   =========================================================================== */

/* [hidden] LOSES TO ANY display DECLARATION.

   The attribute only works because the UA sheet says display:none, which is
   the weakest rule there is — so .member-modal{display:grid}, .member-field
   {display:block} and the button class all quietly beat it. The result was a
   sign-in page showing an empty car modal, a Sign out button while signed
   out, and a name field in a mode that has none.

   One rule, at the top, so nothing added later has to remember. */
[hidden] { display: none !important; }

.member-whoami {
  font-size: 0.85rem;
  color: var(--text-secondary);
  margin-right: 0.5rem;
}

/* ---- The gate ---------------------------------------------------------- */

/* THE SIGNED-OUT PAGE IS NOW A PAGE, NOT A BOX IN THE MIDDLE OF NOTHING.
   It was centred in the viewport because a lone sign-in form has nowhere else
   to be. With the pitch above it the page has a top, so it stacks from there
   and the form sits at the end of the argument rather than in front of it. */
/* Layout for this element lives in dashboard.css, which loads after this file
   and therefore wins at equal specificity. Declaring it twice is what put the
   sign-in box beside the pitch instead of under it. */

.mkt { width: 100%; }

/* THE HERO: COPY BESIDE ONE CARD.
   copy  shot
   copy  gate

   The copy spans both rows on the left, so the column has no hole in it when
   the right-hand side is taller — which is what happened when the left column
   held only a headline and a paragraph.

   The price used to be a second box down here beside the sign-in box. Two boxes
   side by side made the reader compare them instead of reading them in order,
   and no amount of matching their widths and heights fixed that, because the
   problem was that there were two of them. The price is now the sign-in card's
   own header and this row holds one object, not a pair.

   minmax(0, 1fr) rather than 1fr because a 1fr track refuses to shrink below
   its content, and one long unbroken word in the headline would then push the
   right-hand column off the row. */
.mkt-hero {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-areas:
    "copy  gate"
    "shot  gate";
  /* The card on the right sets the row's total height. Row one is the copy at
     its natural height; row two is whatever is LEFT, and the photograph fills
     it — so the bottom of the picture meets the bottom of the card at any
     window size, with nothing measured in pixels. */
  grid-template-rows: auto minmax(0, 1fr);
  /* minmax(0, 1fr), not 1fr: a plain 1fr row refuses to be smaller than the
     content inside it, so the image's natural height won and the picture
     overhung the card by a hundred and fifty pixels. Zero minimum lets the
     row be exactly what is left. */
  column-gap: 2.5rem;
  row-gap: 1.5rem;
}

/* The card is the tall thing in this row, so it spans both rows on the right
   and the left side stacks to meet it: what we do, then a car we have. Putting
   the copy alone against a 600px card left either a hole under the paragraph or
   a headline floating halfway down the page, depending on how it was aligned —
   giving the column a second thing to hold fixes it properly. */
.mkt-hero-copy {
  grid-area: copy;
  align-self: start;
  padding-top: .25rem;
}

.mkt-hero .mkt-shot {
  grid-area: shot;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* THE PICTURE CANNOT SET THE ROW'S HEIGHT.
   A 1fr row in a grid whose own height is automatic still grows to fit what
   is in it, so the image's natural height kept winning and the picture
   overhung the card by 150px however the row was declared. The frame is the
   flex child that takes the leftover height; the image is pinned inside it
   and takes no part in the sizing at all. It is therefore exactly as tall as
   the space between the copy and the bottom of the card, at any width, with
   nothing measured in pixels. */
.mkt-hero .mkt-shot-frame {
  flex: 1 1 0;
  min-height: 0;
  position: relative;
}

.mkt-hero .mkt-shot-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
}

.mkt-hero .member-gate-box { grid-area: gate; align-self: start; }

/* The lede's own bottom margin was spacing it off the cards below it. Here it
   is the end of a column, not the end of a section. */
.mkt-hero .mkt-lede { margin-bottom: 0; }

/* The cap belonged to a position this box no longer occupies: it takes its
   width from the grid track now. */
.mkt-hero .member-gate-box { max-width: none; width: auto; }

/* THE PRICE, as the card's header rather than as a rival to it.
   Full-bleed across the top of the card — hence the negative margins, which
   cancel the card's own padding — so it reads as a banner on the card and not
   as another panel stacked inside it. */
.gate-price {
  margin: -1.75rem -1.75rem 1.25rem;
  padding: 1.1rem 1.75rem 1rem;
  background: var(--accent-emerald, #0f7b46);
  color: #fff;
  border-radius: var(--radius-lg, 12px) var(--radius-lg, 12px) 0 0;
}

.gate-price-big {
  margin: 0;
  font-family: var(--font-heading);
  font-size: 2.1rem;
  line-height: 1;
  color: #fff;
}

.gate-price-big span {
  font-size: .95rem;
  font-weight: 500;
  opacity: .85;
}

.gate-price-sub {
  margin: .45rem 0 0;
  font-size: .85rem;
  line-height: 1.5;
  /* White at reduced opacity rather than a second colour token: the band has
     one background in both themes, so a theme-aware text colour would be
     wrong against it half the time. */
  color: rgba(255, 255, 255, .88);
}

.gate-price-sub strong { color: #fff; }

/* THE PHOTO.
   A real car from live stock. Same border and radius as the boxes beneath it,
   so the row reads as one set of objects rather than a picture parked above a
   form. The aspect ratio is fixed even though the widths are not: dealer
   photos come in assorted dimensions and a row that changes height when the
   image swaps in is worse than one that is briefly empty. */
.mkt-shot {
  margin: 0;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg, 12px);
  overflow: hidden;
  background: var(--bg-surface);
}

.mkt-shot img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.mkt-shot figcaption {
  padding: .6rem .85rem;
  font-size: .78rem;
  color: var(--text-secondary);
  border-top: 1px solid var(--border-subtle);
}

.mkt-shot figcaption strong {
  display: block;
  color: var(--text-primary);
  font-weight: 600;
  margin-bottom: .1rem;
}

/* Below this the two columns stop fitting side by side without squeezing the
   headline into a ribbon. One column, and the form comes near the top: on a
   phone the pitch is a long scroll and a returning member should not have to
   make it to sign in. */
@media (max-width: 900px) {
  .mkt-hero {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "gate"
      "shot"
      "copy";
    grid-template-rows: none;
    row-gap: 1.5rem;
  }
  /* Stacked, there is no card beside it to match, so the picture takes its
     natural shape again rather than stretching to a row that no longer
     exists. */
  .mkt-hero .mkt-shot-frame { flex: none; aspect-ratio: 4 / 3; }
}

/* One small uppercase label, once, at the top. Used sparingly on purpose —
   an eyebrow over every section is the tell of a templated page. */
.mkt-eyebrow {
  margin: 0 0 .5rem;
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent-cyan);
}

.mkt-h1 {
  font-family: var(--font-heading);
  font-size: clamp(1.8rem, 5vw, 2.9rem);
  line-height: 1.08;
  margin: 0 0 .9rem;
  max-width: 18ch;
  text-wrap: balance;
}

.mkt-lede {
  margin: 0 0 2.25rem;
  max-width: 60ch;
  font-size: 1.05rem;
  line-height: 1.65;
  color: var(--text-secondary);
}

.mkt-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
  margin-bottom: 2.5rem;
}

/* Deliberately quiet: a border and a little padding, no shadow and no hover
   lift. Six cards that each shout are six cards nobody reads. */
.mkt-card {
  border: 1px solid var(--border-subtle);
  border-radius: 12px;
  padding: 1.1rem 1.2rem;
  background: var(--bg-surface);
}

.mkt-card h3 {
  margin: 0 0 .4rem;
  font-size: 1rem;
  font-family: var(--font-heading);
}

.mkt-card p {
  margin: 0;
  font-size: .91rem;
  line-height: 1.55;
  color: var(--text-secondary);
}

/* The price is the one place on this page allowed to be loud. */
.mkt-price {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem 2.5rem;
  align-items: center;
  padding: 1.5rem 1.6rem;
  border: 1px solid var(--accent-emerald);
  border-radius: 14px;
  background: var(--bg-surface);
  margin-bottom: 1.75rem;
}

.mkt-price-big {
  margin: 0;
  font-family: var(--font-heading);
  font-size: 2.8rem;
  line-height: 1;
  color: var(--accent-emerald);
}

.mkt-price-big span {
  font-size: 1rem;
  font-weight: 500;
  color: var(--text-secondary);
}

.mkt-price-sub {
  margin: .4rem 0 0;
  font-size: .85rem;
  color: var(--text-muted);
}

.mkt-price-list {
  margin: 0;
  padding-left: 1.1rem;
  flex: 1 1 22rem;
}

.mkt-price-list li {
  margin-bottom: .45rem;
  font-size: .94rem;
  line-height: 1.5;
  color: var(--text-secondary);
}

.mkt-price-list li::marker { color: var(--accent-emerald); }

.mkt-foot {
  margin: 0;
  max-width: 62ch;
  font-size: .92rem;
  line-height: 1.6;
  color: var(--text-muted);
}

.member-gate-box {
  width: 100%;
  max-width: 27rem;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 12px;
  padding: 2rem 1.75rem 1.5rem;
  box-shadow: 0 1px 2px rgba(11, 18, 32, .05), 0 12px 32px rgba(11, 18, 32, .06);
}

.member-gate-box h1 {
  font-family: var(--font-heading);
  font-size: 1.6rem;
  margin: 0 0 0.4rem;
}

.member-gate-note {
  color: var(--text-secondary);
  font-size: 0.92rem;
  margin: 0 0 1.5rem;
  line-height: 1.5;
}

.member-field {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 0.9rem;
}

.member-field input {
  display: block;
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.7rem 0.8rem;
  font: inherit;
  font-weight: 400;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: 7px;
}

.member-field input:focus-visible,
.member-tab:focus-visible,
.linkish:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.member-submit {
  width: 100%;
  justify-content: center;
  margin-top: 0.35rem;
}

/* Reserves its line whether or not there is a message, so the form does not
   jump when an error appears under a button somebody is about to press. */
.member-message {
  min-height: 1.3rem;
  font-size: 0.88rem;
  margin: 0.85rem 0 0;
  color: var(--accent-red);
}
.member-message.ok { color: var(--accent-emerald); }

.member-switch {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.1rem;
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-subtle);
}

.linkish {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 0.86rem;
  color: var(--accent-blue);
  cursor: pointer;
}
.linkish[aria-current="true"] {
  color: var(--text-muted);
  cursor: default;
  text-decoration: none;
}

/* ---- Signed in --------------------------------------------------------- */

.member-app { max-width: 82rem; margin: 0 auto; padding: 1.5rem 1.25rem 5rem; }

.member-tabs {
  display: flex;
  gap: 0.4rem;
  border-bottom: 1px solid var(--border-subtle);
  margin-bottom: 1.75rem;
  overflow-x: auto;
}

.member-tab {
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 0.7rem 0.9rem;
  font: inherit;
  font-weight: 600;
  font-size: 0.94rem;
  color: var(--text-secondary);
  cursor: pointer;
  white-space: nowrap;
}
.member-tab.active {
  color: var(--text-primary);
  border-bottom-color: var(--accent-red);
}

.member-view-head {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: 1.25rem;
}
.member-view-head h2 {
  font-family: var(--font-heading);
  font-size: 1.35rem;
  margin: 0 0 0.2rem;
}
.member-note { color: var(--text-secondary); font-size: 0.9rem; margin: 0; }

.member-filters { display: flex; flex-wrap: wrap; gap: 0.5rem; }

/* ---- Lots -------------------------------------------------------------- */

.lot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: 1rem;
}

.lot-card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  transition: border-color .12s ease, transform .12s ease;
}
.lot-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) {
  .lot-card { transition: none; }
  .lot-card:hover { transform: none; }
}

.lot-card img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  background: var(--bg-inset);
}

.lot-card-body { padding: 0.8rem 0.9rem 0.95rem; display: grid; gap: 0.3rem; }
.lot-card-title { font-weight: 600; font-size: 0.98rem; line-height: 1.3; }
.lot-card-meta { font-size: 0.84rem; color: var(--text-secondary); }

.lot-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.15rem; }
.chip {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  background: var(--bg-inset);
  color: var(--text-secondary);
}
.chip.grade { background: rgba(6, 122, 85, .1); color: var(--accent-emerald); font-weight: 600; }
.chip.soon  { background: rgba(216, 30, 70, .1); color: var(--accent-red); font-weight: 600; }

/* ---- Modal ------------------------------------------------------------- */

.member-modal { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; padding: 1.25rem; }
.member-modal-backdrop { position: absolute; inset: 0; background: var(--bg-overlay); }
.member-modal-box {
  position: relative;
  width: min(60rem, 100%);
  max-height: 88vh;
  overflow-y: auto;
  background: var(--bg-surface);
  border-radius: 12px;
  padding: 1.25rem 1.4rem 1.5rem;
}
.member-modal-head { display: flex; gap: 1rem; justify-content: space-between; align-items: flex-start; margin-bottom: 1rem; }
.member-modal-head h3 { font-family: var(--font-heading); font-size: 1.25rem; margin: 0 0 0.15rem; }

.lot-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.65rem;
  margin-bottom: 1.1rem;
}
.lot-facts > div {
  background: var(--bg-inset);
  border-radius: 7px;
  padding: 0.55rem 0.7rem;
  display: grid;
  gap: 0.1rem;
}
.lot-facts span { font-size: 0.74rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .05em; }
.lot-facts strong { font-size: 0.96rem; }

.lot-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: 0.6rem; }
.lot-gallery img { width: 100%; border-radius: 7px; display: block; background: var(--bg-inset); }

.lot-ask {
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-subtle);
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  justify-content: space-between;
}

/* BUYING IS THE LOUDEST THING IN THE DIALOG.
   It sat as one of two "Ask…" buttons in the same grey, so nothing on the
   listing looked like a way to actually buy the car. Solid green, larger than
   anything around it, and the only element of its kind here. */
.btn-buy {
  display: inline-block;
  padding: 0.7rem 1.4rem;
  border: 0;
  border-radius: 8px;
  background: var(--accent-emerald, #0f7b46);
  color: #fff;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .22);
}
.btn-buy:hover { filter: brightness(1.08); }
.btn-buy:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
@media (max-width: 520px) { .btn-buy { width: 100%; text-align: center; } }

/* The control is a <button> now rather than an <a>, because it posts a request
   instead of handing the job to a mail client. Buttons do not inherit font or
   line-height the way the anchor did, and a disabled one must stop looking
   clickable — after a request has gone it is relabelled and left disabled. */
button.btn-buy { line-height: 1.2; font-family: inherit; }
button.btn-buy:disabled {
  background: var(--bg-surface);
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
  box-shadow: none;
  cursor: default;
}
button.btn-buy:disabled:hover { filter: none; }

/* THE REQUEST FORM sits where the button was, so the eye does not have to go
   looking for it: the button hides, the form takes its place. */
.enquiry-form {
  display: flex;
  flex-direction: column;
  gap: .6rem;
  margin-top: .75rem;
}

.enquiry-form textarea {
  width: 100%;
  resize: vertical;
}

.enquiry-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.enquiry-form .member-note:empty { display: none; }

/* ---- Market + parts ---------------------------------------------------- */

.insight-table-wrap { overflow-x: auto; border: 1px solid var(--border-subtle); border-radius: 10px; }
.insight-table { border-collapse: collapse; width: 100%; font-size: 0.92rem; background: var(--bg-card); }
.insight-table th, .insight-table td { text-align: left; padding: 0.6rem 0.85rem; border-bottom: 1px solid var(--border-subtle); }
.insight-table th {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-muted); background: var(--bg-inset); white-space: nowrap;
}
.insight-table tr:last-child td { border-bottom: 0; }
.insight-table td.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; white-space: nowrap; }

.member-empty {
  background: var(--bg-card);
  border: 1px dashed var(--border-strong);
  border-radius: 10px;
  padding: 2.5rem 1.5rem;
  text-align: center;
  color: var(--text-secondary);
}
.member-empty h3 { font-family: var(--font-heading); margin: 0 0 0.4rem; color: var(--text-primary); }

@media (max-width: 640px) {
  .member-view-head { align-items: stretch; }
  .member-filters { width: 100%; }
  .member-filters .filter-input { flex: 1 1 8rem; }
}

/* ---- Favourites and alerts --------------------------------------------- */

/* The star sits on the card, not in a menu behind it: keeping a car has to be
   one gesture while scanning, or nobody builds a shortlist at all. */
.lot-card, .member-card { position: relative; }

.fav-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 2;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(12, 16, 24, 0.55);
  color: #fff;
  font-size: 16px;
  line-height: 30px;
  text-align: center;
  cursor: pointer;
}
.fav-btn:hover { background: rgba(12, 16, 24, 0.78); }
.fav-btn.is-on { color: #f6c445; }
.fav-btn:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }

/* Touch targets get the full 44px the rest of the dashboard uses. */
@media (pointer: coarse) {
  .fav-btn { width: 44px; height: 44px; line-height: 44px; font-size: 19px; }
}

.mf-check .mf-checkline {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  height: var(--ctl-h, 34px);
  font-size: 0.85rem;
}
.mf-check input { width: 16px; height: 16px; }

.alert-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.6rem;
  margin: 0.75rem 0 0.25rem;
}
.alert-bar .mf-field { flex: 1 1 16rem; }
.alert-hint { flex: 1 1 100%; margin: 0; }

.alert-list { list-style: none; margin: 0.5rem 0 0; padding: 0; }
.alert-list li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border-subtle);
  font-size: 0.87rem;
}
.alert-name { flex: 1 1 auto; font-weight: 500; }
.alert-when { color: var(--text-secondary); font-size: 0.78rem; }

/* Small failures say so without interrupting: no dialog to dismiss, no focus
   stolen mid-scan. */
.member-toast {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  transform: translateX(-50%) translateY(0.5rem);
  z-index: 60;
  max-width: min(90vw, 30rem);
  padding: 0.6rem 0.9rem;
  border-radius: 8px;
  background: rgba(12, 16, 24, 0.92);
  color: #fff;
  font-size: 0.85rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s ease, transform .15s ease;
}
.member-toast.is-on { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .member-toast { transition: none; }
}

/* Which side an alert watches. Two alerts can carry the same name and mean
   different things, so the list says so rather than leaving it to memory. */
.alert-scope {
  margin-left: 0.4rem;
  padding: 0.05rem 0.35rem;
  border: 1px solid var(--border-subtle);
  border-radius: 3px;
  font-size: 0.68rem;
  font-weight: 400;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* The six-months-free offer. Stated where it is the reason to sign up, and
   again inside where a member is using the thing it applies to — quiet enough
   not to fight the inventory for attention. */
.member-gate-offer {
  margin: 0.75rem 0 0;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border-strong, #bbb);
  border-radius: 8px;
  font-size: 0.85rem;
  line-height: 1.45;
}
.member-gate-offer strong { display: block; margin-bottom: 0.15rem; }

.member-offer-bar {
  margin: 0 0 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border-subtle);
  border-left: 3px solid var(--accent, #b45309);
  border-radius: 6px;
  font-size: 0.85rem;
  color: var(--text-secondary);
}
.member-offer-bar strong { color: var(--text-primary); }
.member-offer-bar a { margin-left: 0.4rem; white-space: nowrap; }

/* An expired membership states itself plainly rather than leaving someone to
   work out why the tabs stopped answering. */
.member-offer-bar.is-expired {
  border-left-color: var(--accent-red, #b42318);
  color: var(--text-primary);
}

/* Under or over market, on a dealer card. The word carries the meaning and the
   number backs it up, so the reading survives being skimmed. Colour follows
   the same bands the public site uses. */
.member-card-market {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  flex-wrap: wrap;
  margin: 0.3rem 0 0;
  font-size: 0.78rem;
}
.member-card-market span { font-weight: 600; }
.member-card-market small {
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.member-card-market.deal-great span,
.member-card-market.deal-good span { color: var(--accent-emerald, #0f7b46); }
.member-card-market.deal-fair span { color: var(--text-secondary); }
.member-card-market.deal-premium span { color: var(--accent-gold, #b45309); }
.member-card-market.deal-high span { color: var(--accent-red, #b42318); }

/* ---- The import expert -------------------------------------------------- */

/* No width rules of its own: the section sits in the same 82rem container as
   every other view, and switching tabs should not change the shape of the
   page. The thread is capped in HEIGHT only. */

/* The car under discussion, stated plainly so nobody wonders whether the
   expert can actually see it. */
.expert-subject {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.6rem;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--border-subtle);
  border-left: 3px solid var(--accent, #b45309);
  border-radius: 6px;
  font-size: 0.85rem;
}
.expert-subject button { margin-left: auto; }

.expert-thread {
  max-height: 52vh;
  overflow-y: auto;
  padding: 0.5rem;
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  background: var(--bg-card);
}
.expert-msg { margin: 0 0 0.75rem; font-size: 0.88rem; line-height: 1.5; }
.expert-msg:last-child { margin-bottom: 0; }
.expert-who {
  display: block;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-secondary);
  margin-bottom: 0.15rem;
}
.expert-msg.is-you > div {
  padding: 0.45rem 0.6rem;
  border-radius: 8px;
  background: var(--bg-inset, rgba(127,127,127,.08));
}
.expert-typing { color: var(--text-secondary); font-style: italic; }

/* Openers, so nobody faces an empty box wondering what this thing is for. */
.expert-starters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.6rem 0;
}
.expert-starters .header-btn { font-size: 0.78rem; }

.expert-ask { display: flex; gap: 0.5rem; align-items: flex-end; }
.expert-ask textarea {
  flex: 1 1 auto;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  background: var(--bg-surface);
  color: inherit;
  /* 16px on touch, or iOS zooms the whole page when the field is focused. */
  font: inherit;
  font-size: 0.9rem;
  resize: vertical;
}
@media (pointer: coarse) { .expert-ask textarea { font-size: 16px; } }
.expert-caveat { margin-top: 0.5rem; }

/* The nudge that appears on every listing.
   It has to carry more weight than the controls around it — it was a grey
   button among grey buttons and nobody saw it. The panel is tinted, the copy
   leads, and the button is the only filled element in the dialog. */
.lot-expert-nudge {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin: 0.9rem 0 0;
  padding: 0.75rem 0.85rem;
  border: 1px solid var(--accent, #b45309);
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent, #b45309) 8%, transparent);
  font-size: 0.87rem;
}
.lot-expert-nudge .nudge-copy { flex: 1 1 12rem; line-height: 1.4; }
.lot-expert-nudge .nudge-copy strong { display: block; }

/* Outlined, not filled: visible, but it must not compete with Buy. Two solid
   buttons side by side make neither of them the obvious next step. */
.expert-cta {
  flex: 0 0 auto;
  padding: 0.5rem 0.9rem;
  border: 1.5px solid var(--accent, #b45309);
  border-radius: 8px;
  background: transparent;
  color: var(--accent, #b45309);
  font: inherit;
  font-size: 0.86rem;
  font-weight: 600;
  cursor: pointer;
}
.expert-cta:hover { background: color-mix(in srgb, var(--accent, #b45309) 12%, transparent); }
.expert-cta:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
/* Full width on a phone, where a button beside text becomes a thin sliver. */
@media (max-width: 520px) {
  .expert-cta { width: 100%; }
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

/* The expert conversation, opened inside a listing rather than on its own tab.
   Sending someone to the tab closed the car they were reading and lost their
   place in the list behind it; the question is about this car, so it happens
   on this car. Shorter than the tab version — it sits under a dialog that is
   already scrolling. */
.lot-expert-panel {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px dashed var(--border-subtle);
}
.lot-expert-panel .expert-thread { max-height: 34vh; }
.lot-expert-panel .expert-starters { margin: 0.5rem 0; }

/* The inspection sheet itself, shown above our reading of it. A member can now
   check the inspector's own marks against what we say they mean — which is the
   whole point of publishing a sheet rather than a summary of one. */
.lot-sheet-img { margin: 0 0 0.75rem; }
.lot-sheet-img img {
  display: block;
  width: 100%;
  max-width: 34rem;
  height: auto;
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  background: #fff;
}
.lot-sheet-img a { display: inline-block; text-decoration: none; }
.lot-sheet-img p { margin: 0; }

/* Section headings inside a market panel. The movers tab now shows two tables —
   named cars, then a per-model roll-up — and they need telling apart. */
.market-sub {
  margin: 1.1rem 0 0.5rem;
  font-size: 0.9rem;
  font-weight: 600;
}
.market-sub:first-child { margin-top: 0; }

/* ---- The auction run list ---------------------------------------------- */
/*
   A run list, not a gallery: everything a bidder screens on sits on the row,
   because choosing between three hundred lots is a scanning job. Standard
   density — 30px thumbnails in roughly 40px rows — with the extra height over
   a bare table going to the photograph rather than to padding.
*/
/* The auction run list moved to css/lot-list.css, which the admin panel
   loads too — the two panels draw the same table now. */


/* On a phone the list scrolls sideways rather than reflowing: a run list that
   wraps stops being scannable, and sideways is the familiar gesture. */
@media (max-width: 640px) {
  .run-t { font-size: 12.5px; }
  .run-t td, .run-t thead th { padding: 4px 6px; }
}

/* Paying for access. Deliberately quiet — it is a renewal, not a storefront,
   and a member with months left should barely notice it. */
.member-pay {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  margin: 1rem 0;
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  background: var(--bg-surface);
}
.member-pay h3 { margin: 0 0 0.2rem; font-size: 1rem; }
.member-pay #paypal-buttons { min-width: 14rem; max-width: 22rem; flex: 1 1 14rem; }
.member-pay.is-paid { border-color: var(--accent-emerald); }


/* ---------------------------------------------------------------------------
   AUCTION MARKET BARS
   Two dozen bars drawn in divs. A charting library for this would be loaded by
   every member who never opens the tab, to draw something flexbox already does.
   The axis floor sits below the smallest value rather than at zero — these
   series never approach zero, and a zero axis would flatten every real movement
   into one indistinguishable block.
   --------------------------------------------------------------------------- */
.mkt-bars {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 140px;
  margin: .5rem 0 1.25rem;
  padding: .5rem .25rem;
  border-bottom: 1px solid var(--border-subtle);
}

.mkt-bar {
  flex: 1 1 0;
  min-width: 4px;
  background: var(--accent-emerald, #0f7b46);
  border-radius: 2px 2px 0 0;
}

/* A month still being collected is not the same fact as a finished one, and a
   chart that does not say so invites somebody to read a collection gap as a
   market collapse. */
.mkt-bar.is-partial {
  background: repeating-linear-gradient(
    45deg,
    var(--accent-emerald, #0f7b46) 0 4px,
    transparent 4px 8px
  );
  opacity: .65;
}


/* The selling-window caveat. Quiet by design — it is a footnote about data
   coverage, not a warning about a car, and it only appears when the member has
   actually looked past today. */
.auction-caveat {
  margin: .35rem 0 0;
  font-size: .82rem;
  color: var(--text-muted);
}


/* A LOCKED TAB. Still there -- it is what the membership buys, and hiding it
   would hide the reason to renew -- but plainly not available. */
.member-tab.is-locked {
  opacity: .55;
  cursor: not-allowed;
}
.member-tab.is-locked::after {
  content: " \1F512";
  font-size: .8em;
}
.member-tab.is-locked.active { border-color: transparent; }

/* One short pulse on the membership bar when a locked tab is pressed, so the
   answer to "why did nothing happen" is in view. */
@keyframes bar-nudge {
  0%, 100% { box-shadow: none; }
  40% { box-shadow: 0 0 0 3px var(--accent, #b45309); }
}
.member-offer-bar.is-nudged { animation: bar-nudge .9s ease-out; }
@media (prefers-reduced-motion: reduce) { .member-offer-bar.is-nudged { animation: none; } }


/* The bid guide row in the lot facts. Same shape as every other fact; the
   kind of number is carried in a small line beneath, because a hammer price
   and a derived-from-retail figure must not look identical. */
.lot-facts .bid-guide small { display: block; font-weight: 400; font-size: .75rem; color: var(--text-muted); margin-top: .15rem; }
.lot-facts .bid-guide-derived strong { color: var(--text-secondary); }

/* The share box under the buy buttons: same shape as the request form. */
.lot-share { margin-top: .75rem; }
.lot-share textarea { width: 100%; font: inherit; font-size: .9rem; }
.lot-share .enquiry-actions { align-items: center; flex-wrap: wrap; }

/* The member cost-quote tool: a compact editable table of cost lines. */
.quote-table { width: 100%; border-collapse: collapse; margin: .5rem 0; }
.quote-table td, .quote-table th { padding: .25rem .3rem; text-align: left; vertical-align: middle; }
.quote-table td:nth-child(2), .quote-table th:nth-child(2) { width: 8rem; }
.quote-table td:last-child { width: 2rem; text-align: center; }
.quote-table .q-label { width: 100%; font-size: .85rem; }
.quote-table .q-usd { width: 100%; font-size: .85rem; text-align: right; }
.quote-table tfoot th { border-top: 1px solid var(--border-subtle); padding-top: .5rem; }
.quote-table tfoot td { border-top: 1px solid var(--border-subtle); padding-top: .5rem; }
.quote-table .q-del { padding: .2rem .45rem; }

.ended-note { padding: 0.7rem 0.9rem; margin: 0 0 0.75rem; border: 1px solid var(--border-strong); border-left: 3px solid var(--accent-gold); border-radius: var(--radius-md); background: var(--bg-inset); color: var(--text-primary); line-height: 1.45; }

/* Service tab: two sub-tabs over a frame that holds the manuals or the parts cross-reference. */
.service-subtabs { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 0.75rem; }
.service-subtab { appearance: none; padding: 0.45rem 0.9rem; border: 1px solid var(--border-strong); border-radius: var(--radius-full); background: var(--bg-surface); color: var(--text-secondary); font: inherit; font-size: 0.9rem; cursor: pointer; }
.service-subtab.active { background: var(--text-primary); border-color: var(--text-primary); color: var(--bg-surface); }
.service-frame { display: block; width: 100%; height: calc(100vh - 17rem); min-height: 32rem; border: 1px solid var(--border-subtle); border-radius: var(--radius-md); background: var(--bg-main); }
