/* BidConnect — palette matched to the Waco Habitat StoreConnect storefront */
:root {
  --brand: #385988;        /* waco-blue-primary */
  --brand-dark: #2a4374;   /* waco-blue-primary-hover */
  --action: #1565c0;       /* waco-blue-action (buttons) */
  --action-dark: #0d47a1;  /* waco-blue-action-hover */
  --link: #428bca;         /* waco-blue-link */
  --accent: #ff671f;       /* waco-orange (countdown) */
  --success: #44b02b;      /* waco-green */
  --bg: #f2f2f2;           /* waco-gray-bg */
  --card: #ffffff;
  --text: #333333;         /* waco-gray-heading */
  --muted: #757575;        /* waco-gray-body */
  --border: #cbd5e1;       /* waco-gray-border */
  --danger: #d32f2f;
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 16px/1.5 "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  /* Header and footer are fixed (see below); reserve space for both so
     content never renders underneath either. */
  padding-top: 128px; padding-bottom: 76px;
}
main { width: 100%; margin: 0 auto; padding: 1rem 1.5rem; }
a { color: var(--link); }

.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 1000;
  display: flex; flex-wrap: wrap; gap: .5rem 1rem; align-items: flex-start;
  justify-content: space-between; padding: .75rem 1rem;
  background: var(--brand); color: #fff;
}
.site-header .brand {
  color: #fff; font-weight: 700; text-decoration: none;
  display: flex; flex-direction: column; align-items: flex-start; gap: .3rem;
}
.site-header .brand span { font-size: 1.3rem; }
.site-header .brand img {
  height: 58px; width: auto; display: block;
  background: #fff; padding: 6px 14px; border-radius: 8px;
}
.site-header nav { display: flex; flex-direction: column; align-items: flex-end; gap: .3rem; font-size: .9rem; }
.site-header nav a { color: #fff; text-decoration: none; }
.site-header nav .logged-in-as { color: rgb(255 255 255 / .75); text-align: right; }
.site-header nav .nav-links { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .65rem; }
.site-footer {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .5rem 1.5rem; padding: .6rem 1.5rem;
  background: var(--brand); color: #fff; text-align: left; font-size: .9rem;
}
.site-footer .footer-text { color: rgb(255 255 255 / .85); }
.site-footer .powered-by-stack { display: flex; flex-direction: column; gap: .3rem; }
.site-footer .powered-by {
  display: grid; grid-template-columns: 130px 1fr; align-items: center; gap: .4rem;
  font-size: .78rem; opacity: .85; color: #fff;
}
.site-footer .powered-by:hover { opacity: 1; }
.site-footer .powered-by img { height: 20px; width: 20px; display: block; justify-self: end; }
.site-footer .powered-by .storeconnect-logo {
  height: 26px; width: auto;
  background: #fff; padding: 4px 8px; border-radius: 5px;
}
.inline-form { display: inline; }
/* Inherits its colour from where it sits. It was hardcoded white for the one
   use in the header, and four of its five uses are on light grounds: the
   email-confirmation banner and three buttons on the account page, including
   the self-service "Turn off text alerts". White on white measured 1.00:1 --
   those controls were invisible. The header still gets white, from its own
   colour. */
.linklike {
  background: none; border: none; color: inherit; cursor: pointer;
  font: inherit; padding: 0; text-decoration: underline;
}

.countdown {
  background: var(--accent); color: #fff; text-align: center;
  padding: .4rem; font-weight: 600;
}
.banner { padding: .6rem 1rem; text-align: center; }
.banner-pre { background: #e0e7ff; }
.banner-verify { background: #fef3c7; }
.banner-setup { background: #dbeafe; }
/* The setup checklist is a reading page, not a login form. It used to reuse
   .auth-card, whose 420px was chosen for a username and a password, so six
   steps of explanation stacked into a thin ribbon with two or three words a
   line. Wider, and the steps run two across once there is room for them. */
.setup-card {
  max-width: 920px; margin: 1.5rem auto; background: var(--card);
  border-radius: 10px; padding: 1.75rem 2rem; box-shadow: 0 1px 3px rgb(0 0 0 / .1);
}
.setup-card h1 { margin-top: 0; }
.setup-card .lede { font-size: 1.05rem; }

.onboarding-steps { padding-left: 1.2rem; }
.onboarding-steps li { margin-bottom: .9rem; }
@media (min-width: 760px) {
  .onboarding-steps {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .5rem 2.5rem; padding-left: 1.4rem;
  }
  /* Each step is a self-contained instruction, so a column break inside one
     would split a heading from the text that explains it. */
  .onboarding-steps li { break-inside: avoid; margin-bottom: 1.1rem; }
}
.onboarding-steps .step-done { color: #4b5563; }

.messages { width: 100%; margin: .5rem auto 0; padding: 0 1.5rem; }
.msg { padding: .6rem .9rem; border-radius: 6px; margin-bottom: .4rem; }
.msg-success { background: #d1fae5; }
.msg-warning { background: #fef3c7; }
.msg-error { background: #fee2e2; color: var(--danger); }

/* Listing: one thin horizontal strip per item — info left, bidding right. */
.category-heading {
  margin: 1.75rem 0 .5rem; padding-bottom: .3rem;
  border-bottom: 2px solid var(--border); color: var(--brand-dark);
}
.category-heading:first-of-type { margin-top: .5rem; }
.item-list { display: flex; flex-direction: column; gap: .5rem; margin-bottom: .5rem; }
.item-row {
  display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; align-items: center;
  justify-content: space-between;
  background: var(--card); border-radius: 8px; padding: .55rem 1rem;
  box-shadow: 0 1px 2px rgb(0 0 0 / .08);
}
/* Live bid-update flash — same animation as .bb-pulse (Big Board kiosk,
   see below) reused here for visual consistency; retriggerable from JS
   via a remove/reflow/re-add cycle since a class re-add alone won't
   replay a CSS animation that's already present. */
.live-flash { animation: bb-pulse 1.3s ease-out; }
/* Price text and the item's own image flash the same --danger red on a
   live update, so the two visually tie together as "this is the item
   that just changed." Image gets a permanent transparent border as a
   baseline (not just during the animation) so the flash never shifts
   layout by suddenly adding border width that wasn't reserved before. */
@keyframes price-flash { from { color: var(--danger); } to { color: inherit; } }
.price-flash { animation: price-flash 1.3s ease-out; }
@keyframes image-border-flash { from { border-color: var(--danger); } to { border-color: transparent; } }
.image-border-flash { animation: image-border-flash 1.3s ease-out; }
.item-row-info { display: flex; gap: .75rem; align-items: center; min-width: 0; flex: 1 1 320px; }
.item-row-info img {
  width: 72px; aspect-ratio: 4/3; object-fit: cover;
  border-radius: 6px; flex-shrink: 0; border: 3px solid transparent;
}
.item-thumb { position: relative; flex-shrink: 0; line-height: 0; }
.hot-badge {
  position: absolute; top: -6px; right: -6px;
  background: var(--card); border-radius: 50%;
  width: 22px; height: 22px; display: flex; align-items: center; justify-content: center;
  font-size: .9rem; box-shadow: 0 1px 3px rgb(0 0 0 / .25);
}
.hot-badge-standalone { position: static; margin-right: .5rem; box-shadow: none; background: none; }
.item-row-text { min-width: 0; }
.item-row-info h2 { font-size: 1.05rem; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.item-row-info h2 a { color: inherit; text-decoration: none; }
.item-row-info h2 a:hover { text-decoration: underline; }
.item-row-info .description {
  margin: .1rem 0 0; color: var(--muted); font-size: .9rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.item-row-bidding {
  display: flex; flex-wrap: wrap; gap: .4rem .9rem; align-items: center;
  justify-content: flex-end;
}
.item-row-bidding .price { margin: 0; white-space: nowrap; }
.item-row-bidding .bid-count { font-size: .9rem; }

/* Compact inline bid bar */
.bid-form { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.bid-form input[type="number"] {
  width: 7.5rem; padding: .4rem .5rem; border: 1px solid var(--border);
  border-radius: 6px; font-size: .95rem;
}
.bid-form .mode-select {
  padding: .4rem .4rem; border: 1px solid var(--border); border-radius: 6px;
  font-size: .95rem; background: #fff;
}
.bid-form .max-toggle {
  margin: 0; padding: 0; border: none; font-weight: 500;
  font-size: .9rem; white-space: nowrap;
}
.bid-form .btn-primary { padding: .42rem .9rem; font-size: .95rem; }
.price { margin: .25rem 0; }
.price.big { font-size: 1.3rem; }
.price strong { color: var(--brand-dark); }
.bid-count { color: var(--muted); font-size: .9rem; margin: 0; }
.price-hidden { color: var(--muted); font-style: italic; }

.item-detail { display: grid; gap: 1.5rem; grid-template-columns: 1fr; }
@media (min-width: 720px) { .item-detail { grid-template-columns: 1fr 1fr; } }
.item-media { display: flex; flex-direction: column; gap: .6rem; }
.item-media #item-main-photo { width: 100%; border-radius: 10px; border: 3px solid transparent; order: 2; }
.item-gallery { display: flex; gap: .6rem; flex-wrap: wrap; order: 1; }
.item-gallery-thumb { padding: 0; border: 2px solid transparent; border-radius: 8px; background: none; cursor: pointer; line-height: 0; }
.item-gallery-thumb img { width: 72px; height: 72px; object-fit: cover; border-radius: 6px; display: block; }
.item-gallery-thumb:hover, .item-gallery-thumb:focus-visible, .item-gallery-thumb.active { border-color: var(--action); }
/* Thumbnails move to a column beside the main photo once there's room for
   both side by side, matching a standard product-gallery layout. Below that
   width they stay a horizontal row above the photo instead (avoids
   squeezing the main image down to a sliver on a phone-width screen). */
@media (min-width: 480px) {
  .item-media { flex-direction: row; align-items: flex-start; }
  .item-media #item-main-photo { order: 2; flex: 1; min-width: 0; }
  .item-gallery { order: 1; flex-direction: column; flex-shrink: 0; flex-wrap: nowrap; }
}


.btn-primary {
  background: var(--action); border: none; color: #fff; cursor: pointer;
  padding: .55rem 1.3rem; border-radius: 8px; font-size: 1rem;
  text-decoration: none; display: inline-block;
}
.btn-primary:hover { background: var(--action-dark); }

.winning-badge, .outbid-badge {
  display: inline-block; padding: .1rem .55rem; border-radius: 999px;
  font-size: .8rem; font-weight: 600; margin-left: .4rem;
}
.winning-badge { background: #e4f5df; color: var(--success); }
.outbid-badge { background: #fee2e2; color: var(--danger); }

.bids-table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 10px; }
.bids-table th, .bids-table td { text-align: left; padding: .6rem .8rem; border-bottom: 1px solid #e5e7eb; }

/* Account pages: log in, register, password reset, my account.

   Built only from the variables an organization's accepted theme can set
   (base.html), so each charity's page background, text, link colour and fonts
   carry through. No colour here is new to the site.

   Links in the card use the organization's link colour darkened by mixing in
   black, rather than the colour as-is: the default link blue measures 3.6:1 on
   white, below AA for small text, and the darkened mix 6.3:1. It stays the
   organization's hue whatever their theme sets.

   Forms render with form.as_p, so every rule targets that markup and no
   template had to change to get it. */
.auth-card {
  max-width: 440px; margin: 2.5rem auto; background: var(--card);
  border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
  border-radius: 14px; padding: 2rem 2.1rem 1.75rem;
  box-shadow: 0 1px 2px rgb(0 0 0 / .04), 0 14px 34px -20px rgb(0 0 0 / .25);
}
.auth-card h1 { margin: 0 0 .45rem; font-size: 1.65rem; line-height: 1.2; letter-spacing: -.01em; }
.auth-card h1 + p { color: var(--muted); margin: 0 0 1.4rem; }
.auth-card h1 + form, .auth-card h1 + dl { margin-top: 1.25rem; }

.auth-card form p { margin: 0 0 1rem; }
.auth-card label { display: block; font-weight: 600; font-size: .9rem; margin-bottom: .35rem; }
.auth-card input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]) {
  width: 100%; padding: .7rem .8rem; border: 1px solid var(--border); border-radius: 8px;
  font: inherit; font-size: 1rem; background: #fff; color: var(--text);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.auth-card input:focus-visible {
  outline: none; border-color: var(--action);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--action) 22%, transparent);
}
.auth-card .helptext { display: block; color: var(--muted); font-size: .85rem; line-height: 1.45; margin-top: .35rem; }
.auth-card .helptext ul { margin: .25rem 0 0; padding-left: 1.1rem; }
/* Django's password rules are a <ul> inside the help-text <span> inside a <p>.
   A list is not allowed in either, so the browser closes both and the list
   lands as a sibling of the field -- outside .helptext. Styled where it
   actually ends up. */
.auth-card form > ul:not(.errorlist) {
  color: var(--muted); font-size: .85rem; line-height: 1.45;
  margin: -.6rem 0 1rem; padding-left: 1.1rem;
}
.auth-card .errorlist {
  list-style: none; margin: 0 0 .45rem; padding: 0;
  color: var(--danger); font-size: .88rem; font-weight: 600;
}
.auth-card .errorlist.nonfield {
  margin-bottom: 1.1rem; padding: .65rem .85rem; border-radius: 8px;
  background: color-mix(in srgb, var(--danger) 8%, #fff);
}

/* A checkbox beside its label, not a full-width box under it. :has() rather
   than a template change, because as_p puts the label first. */
.auth-card p:has(> input[type="checkbox"]) {
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .6rem;
}
.auth-card p:has(> input[type="checkbox"]) input { order: 1; width: 1.1rem; height: 1.1rem; margin: 0; accent-color: var(--action); }
.auth-card p:has(> input[type="checkbox"]) label { order: 2; margin: 0; font-weight: 500; }
.auth-card p:has(> input[type="checkbox"]) .helptext { order: 3; flex-basis: 100%; margin-top: 0; }

.auth-card form .btn-primary { width: 100%; padding: .75rem 1rem; font-weight: 600; margin-top: .35rem; }
.auth-card form ~ p { text-align: center; color: var(--muted); font-size: .93rem; margin: .55rem 0 0; }
.auth-card form + p {
  margin-top: 1.4rem; padding-top: 1.2rem;
  border-top: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
}
.auth-card a:not(.btn-primary), .auth-card .linklike {
  color: color-mix(in srgb, var(--link) 72%, #000); font-weight: 600;
}
.auth-card a:not(.btn-primary) { text-decoration: none; }
.auth-card a:not(.btn-primary):hover { text-decoration: underline; }
.auth-card a:focus-visible, .auth-card button:focus-visible {
  outline: 2px solid var(--action); outline-offset: 2px; border-radius: 3px;
}

/* My Account: a label/value list rather than run-on text. */
.auth-card dl { margin: 0; }
.auth-card dt {
  font-size: .76rem; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted);
}
.auth-card dd { margin: .2rem 0 1.05rem; }
.auth-card dd .inline-form { display: block; margin-top: .3rem; }
.auth-card dl + p { margin-top: 1.4rem; }

@media (max-width: 520px) {
  .auth-card { margin: 1.25rem .75rem; padding: 1.5rem 1.25rem 1.35rem; }
}

/* SMS toast (demo) — phone-notification banners, top right. Starts below
   the fixed header (see body's padding-top) so it never covers the admin
   nav links, rather than sitting at the very top of the viewport. */
.sms-toast-stack {
  position: fixed; top: 140px; right: 1rem; z-index: 900;
  display: flex; flex-direction: column; gap: .6rem;
  width: min(360px, calc(100vw - 2rem));
}
.sms-toast {
  background: rgba(28, 28, 30, .96); color: #fff;
  border-radius: 14px; padding: .7rem .9rem;
  box-shadow: 0 8px 28px rgb(0 0 0 / .35);
  transform: translateX(120%); opacity: 0;
  transition: transform .35s cubic-bezier(.2, .9, .3, 1.1), opacity .35s;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
.sms-toast.show { transform: translateX(0); opacity: 1; }
.sms-toast-header {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: .3rem;
}
.sms-toast-app { font-weight: 700; font-size: .85rem; letter-spacing: .02em; }
.sms-toast-to { color: #9ca3af; font-size: .75rem; }
.sms-toast-body { font-size: .92rem; line-height: 1.35; overflow-wrap: break-word; }
.sms-toast-link { color: #6cb2ff; }

.post-auction { text-align: center; padding: 3rem 1rem; }
.hint { color: var(--muted); }

/* The SMS opt-in notice on the account page. Same treatment as the same
   notice's help text on the registration form (.auth-card .helptext above),
   because it is the same wording being agreed to in both places. */
/* The mobile-number field on the account page: an inline edit next to the
   value, not a form that looks like a second page. */
.phone-form { display: inline-flex; gap: .4rem; align-items: center; margin-left: .5rem; }
.phone-form input { width: 12rem; padding: .25rem .4rem; font-size: .9rem; }

.sms-notice {
  display: block; color: var(--muted); font-size: .85rem; line-height: 1.45;
  margin: .5rem 0 .75rem; max-width: 62ch;
}

/* Analytics dashboard */
.kpi-row { display: flex; flex-wrap: wrap; gap: 1rem; margin: 1rem 0 1.5rem; }
.kpi-tile {
  background: var(--card); border-radius: 10px; padding: 1rem 1.5rem;
  box-shadow: 0 1px 3px rgb(0 0 0 / .1); min-width: 140px; text-align: center;
}
.kpi-value { display: block; font-size: 2rem; font-weight: 700; color: var(--brand-dark); }
.kpi-label { display: block; color: var(--muted); font-size: .85rem; margin-top: .2rem; }

.chart-card {
  background: var(--card); border-radius: 10px; padding: 1.25rem 1.5rem;
  box-shadow: 0 1px 3px rgb(0 0 0 / .1); margin-bottom: 1.25rem;
}
.chart-card h2 { margin-top: 0; font-size: 1.1rem; }
.chart-svg-wrap { width: 100%; overflow-x: auto; }
.chart-svg { width: 100%; height: 160px; display: block; }
.chart-area { fill: color-mix(in srgb, var(--action) 18%, transparent); stroke: none; }
.chart-line { fill: none; stroke: var(--action); stroke-width: 2; }

.bars { display: flex; flex-direction: column; gap: .6rem; }
.bar-row { display: grid; grid-template-columns: 160px 1fr 160px; gap: .75rem; align-items: center; }
.bar-label { font-size: .9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-track { background: var(--bg); border-radius: 999px; height: 10px; overflow: hidden; }
.bar-fill { background: var(--action); height: 100%; border-radius: 999px; transition: width .4s ease; }
.bar-value { font-size: .85rem; color: var(--muted); white-space: nowrap; }
@media (max-width: 640px) {
  .bar-row { grid-template-columns: 1fr; gap: .25rem; }
}

/* Donut charts (category / geography breakdowns) */
.chart-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; }
.chart-row .chart-card { margin-bottom: 0; }
@media (max-width: 800px) {
  .chart-row { grid-template-columns: 1fr; }
}
.donut-wrap { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: center; }
.donut-svg { width: 200px; height: 200px; flex-shrink: 0; }
.donut-total { font-size: 2rem; font-weight: 700; fill: var(--text); }
.donut-total-label { font-size: .7rem; fill: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.donut-legend { list-style: none; margin: 0; padding: 0; flex: 1 1 220px; min-width: 200px; }
.donut-legend li { display: flex; align-items: center; gap: .5rem; font-size: .9rem; padding: .3rem 0; }
.donut-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }

/* Big Board — venue TV/projector kiosk. Deliberately a different (dark,
   fullscreen, oversized-type) register from the rest of the light, compact
   site: this fills an entire screen from across a room, not a laptop tab. */
body.big-board {
  margin: 0; min-height: 100vh; background: #0b0b0f; color: #fff;
  font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  display: flex; flex-direction: column; padding: 2.5rem 3.5rem;
}
.big-board-header { display: flex; align-items: center; gap: 1.5rem; margin-bottom: 2rem; }
.big-board-header img { height: 56px; background: #fff; padding: 6px 14px; border-radius: 8px; }
.big-board-header h1 { font-size: 2.1rem; margin: 0; font-weight: 700; letter-spacing: .01em; }
.big-board-list { flex: 1; display: flex; flex-direction: column; gap: 1rem; overflow-y: auto; }
.big-board-row {
  display: grid; grid-template-columns: 70px 1fr 260px 180px; align-items: center;
  gap: 1.5rem; background: rgba(255, 255, 255, .07); border-radius: 14px;
  padding: 1.4rem 2rem;
}
.bb-rank { font-size: 2.2rem; font-weight: 700; color: var(--accent); text-align: center; }
.bb-name { font-size: 1.9rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bb-flame { font-size: 1.4rem; }
.bb-bid { font-size: 2.6rem; font-weight: 700; color: #4ade80; text-align: right; white-space: nowrap; }
.bb-count { font-size: 1.15rem; color: rgba(255, 255, 255, .55); text-align: right; white-space: nowrap; }
.big-board-empty { font-size: 1.6rem; color: rgba(255, 255, 255, .55); text-align: center; margin-top: 4rem; }
@keyframes bb-pulse {
  from { box-shadow: 0 0 0 4px rgba(255, 159, 26, .95); }
  to { box-shadow: 0 0 0 0 rgba(255, 159, 26, 0); }
}
.bb-pulse { animation: bb-pulse 1.3s ease-out; }
@media (max-width: 900px) {
  .big-board-row { grid-template-columns: 50px 1fr; grid-template-areas: "rank name" "rank bid" "rank count"; }
  .bb-bid, .bb-count { text-align: left; }
}

/* Theme review: comparing what a site uses now with what was read off the
   organization's own website. */
.theme-table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
.theme-table th, .theme-table td {
  text-align: left; padding: .55rem .6rem; border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.theme-table th { font-size: .8rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.swatch {
  display: inline-block; width: 1.1rem; height: 1.1rem; border-radius: 4px;
  border: 1px solid var(--border); vertical-align: -.2rem; margin-right: .35rem;
}
.theme-note {
  background: #fef3c7; color: #78350f; border-radius: 8px;
  padding: .7rem .9rem; margin: 1rem 0;
}

/* The way back into settings, from the public site. Marked out because it
   leaves the auction for the administration area, which is a different place
   with different navigation. */
.nav-admin { font-weight: 700; }
.nav-admin::before { content: "⚙ "; }

/* Plan and cancellation screens. */
.plan-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; margin: 1.5rem 0; }
.plan { border: 1px solid var(--border); border-radius: 10px; padding: 1.1rem 1.25rem; }
.plan--current { border-color: var(--accent); border-width: 2px; }
.plan h2 { margin-top: 0; }
.plan__price { font-size: 1.5rem; font-weight: 700; margin: .2rem 0 .8rem; }
.plan__current { font-weight: 700; color: var(--muted); }
.plan ul { padding-left: 1.1rem; }
.plan li { margin-bottom: .35rem; }

/* Loud on purpose: this is the one screen where skimming costs someone their
   configuration, weeks later, when nothing can be recovered. */
.danger-panel { background: #fef2f2; border: 1px solid #fecaca; color: #7f1d1d; border-radius: 10px; padding: 1rem 1.25rem; margin: 1.25rem 0; }
.danger-panel h2 { margin-top: 0; }
.rescue-panel { background: #ecfdf5; border: 1px solid #a7f3d0; color: #065f46; border-radius: 10px; padding: 1rem 1.25rem; margin: 1.25rem 0; }
.rescue-panel h2 { margin-top: 0; }
.btn-danger { background: #b91c1c; color: #fff; border: 0; border-radius: 8px; padding: .6rem 1.1rem; font-weight: 700; cursor: pointer; }
.cancel-link { margin-top: 2rem; }
.cancel-link a { color: var(--muted); font-size: .9rem; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* The cancellation confirmation. Wide enough to read the whole sentence back:
   a default input scrolls it out of view as you type, on the one screen where
   reading carefully is the point. */
.confirm-phrase {
  display: block; width: 100%; max-width: 34rem; box-sizing: border-box;
  padding: .7rem .8rem; font-size: 1.05rem; margin: .5rem 0 1rem;
  border: 2px solid var(--border); border-radius: 8px;
}
.confirm-phrase:focus { outline: 2px solid #b91c1c; outline-offset: 1px; }

/* --- Bidder UX notes, 2026-09-21 (plans/bidder-ux-notes-findings.md) ----
   Appended rather than edited in place: develop carries styling work on
   earlier lines of this file, and additions here merge cleanly with it. */

/* Note 4: the winning/outbid badge now leads the price line, so its spacing
   flips. Scoped to the slot, so My Bids' trailing badges are unchanged. */
.standing .winning-badge, .standing .outbid-badge { margin-left: 0; margin-right: .45rem; }

/* Note 4, continued: a badge makes the bidding side of a row wider, and at
   the original 320px floor for the item name and description a row with a
   badge wrapped its bid controls onto a second line while its neighbours did
   not (seen at 1200px). The text column already truncates with an ellipsis,
   so letting it give way sooner keeps rows alike. */
.item-row-info { flex-basis: 240px; }

/* Note 3: a large, obvious way back from an item to the auction. */
.back-to-auction { margin: 0 0 1rem; }
.btn-back-to-auction { font-size: 1.05rem; font-weight: 600; padding: .7rem 1.4rem; }
@media (max-width: 600px) {
  .btn-back-to-auction { display: block; text-align: center; }
}

/* Note 3: the anchor it links to lands with a little room above the row. */
.item-row { scroll-margin-top: 1rem; }

/* Note 5: collapsible category sections (native <details>). */
.category-section { margin-top: 1.25rem; }
.category-section:first-of-type { margin-top: .5rem; }
.category-section > summary.category-heading {
  margin: 0 0 .5rem; cursor: pointer; list-style: none;
  display: flex; align-items: baseline; gap: .6rem;
  font-size: 1.5rem; font-weight: 700;
}
.category-section > summary::-webkit-details-marker { display: none; }
.category-section > summary::before {
  content: "▸"; display: inline-block; width: 1em; transition: transform .15s ease;
}
.category-section[open] > summary::before { transform: rotate(90deg); }
.category-section > summary:focus-visible { outline: 2px solid var(--action); outline-offset: 3px; }
.category-count { font-size: .9rem; font-weight: 400; color: var(--muted); }
@media (prefers-reduced-motion: reduce) {
  .category-section > summary::before { transition: none; }
}

/* Cancel link and phrase in red (Keith, 2026-09-22). #b91c1c is .btn-danger's
   red: 6.3:1 on white, readable as text as well as on the button. The link
   stays small and last on the page; red marks it as destructive, not as a
   call to action. */
.danger-text, .cancel-link a.danger-text { color: #b91c1c; font-weight: 600; }
.btn-danger[disabled] { opacity: .45; cursor: not-allowed; }

/* Back to Auction: green while the auction runs (Keith, 2026-09-22).
   #2e7d32 rather than the site's #44b02b: white text on #44b02b is ~2.8:1,
   too faint for a label; on #2e7d32 it is ~5.1:1. */
.btn-back-to-auction--live { background: #2e7d32; }
.btn-back-to-auction--live:hover { background: #1b5e20; }

/* The bidder's own bid, max bid and tiebreaker on an item page. */
.my-bid-summary { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: .6rem .9rem; margin: .5rem 0 1rem; }
.my-bid-summary h3 { margin: 0 0 .3rem; font-size: 1rem; }
.my-bid-summary dl { display: grid; grid-template-columns: max-content 1fr; gap: .25rem 1rem; margin: 0; }
.my-bid-summary dt { color: var(--muted); }
.my-bid-summary dd { margin: 0; font-variant-numeric: tabular-nums; }
.my-bid-summary .hint { display: block; font-size: .85rem; }

/* Listing rows: the item name and its description sit together beside the
   photo (Keith, 2026-09-22). The row's name is an <h3>, but the older rules
   above target .item-row-info h2, so the h3 kept the browser's default
   heading margins (~1em above and below), which pushed the description down
   below the photo. Only the spacing is fixed here; the name keeps its
   current size and link style. */
.item-row-info h3 { margin: 0; line-height: 1.25; }
/* Up to two lines of description before it's cut off, rather than one:
   the older rule cut it to a single line with "...", which at narrower
   widths (bid controls beside it) hid most of it. */
.item-row-info .description {
  margin-top: .2rem; white-space: normal;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
  overflow: hidden;
}

/* Bid errors on the auction page itself (Keith, 2026-09-22): the box at
   fault turns red and the reason appears in red under the bid fields.
   #b91c1c is .btn-danger's red (6.3:1 on white). */
.bid-form input.field-error { border-color: #b91c1c; background: #fef2f2; box-shadow: 0 0 0 1px #b91c1c; }
.bid-form input.field-error:focus { outline: 2px solid #b91c1c; outline-offset: 1px; }
/* The fields are their own row (.bid-fields) and the message sits below it,
   outside that row. Inside the row, the message's width and its gap were
   added to the form's width (a wrapping flex row sums its items), so the form
   grew, the fields jumped left out of line with every other row and "Current
   bid" dropped (Keith's screenshot, 2026-09-22). contain: inline-size keeps a
   long message from widening the form; it wraps under the fields instead. */
.bid-form { display: block; }
.bid-fields { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.bid-feedback { margin: .3rem 0 0; font-size: .9rem; font-weight: 600; contain: inline-size; }
/* Keep "Current bid" level with the bid fields' text, not with the middle of
   a form that grows a line when a message appears. */
.item-row-bidding { align-items: baseline; }
.bid-feedback--error { color: #b91c1c; }
.bid-feedback--ok { color: #2e7d32; }
.bid-feedback--warn { color: #92400e; }
/* The tiebreaker is required whenever "+ max bid" is ticked. */
.required-mark { color: #b91c1c; font-weight: 700; margin-left: .1rem; }

/* Category sections: + when closed, − when open, instead of the arrow
   (Keith, 2026-09-22). Overrides the arrow and its rotation above. The
   heading can't be text-selected, so a double-click toggles the section
   without highlighting the name. */
.category-section > summary { user-select: none; -webkit-user-select: none; }
.category-section > summary::before {
  content: "+"; transform: none; transition: none;
  width: 1em; text-align: center;
  font-weight: 400; /* not bold (Keith, 2026-09-22); the heading itself is 700 */
}
.category-section[open] > summary::before { content: "\2212"; transform: none; }
