:root {
  /* Heureka Group brand palette — light theme */
  --fg: #1f1d1b;
  --muted: #6b6661;
  --bg: #fdf9f4;              /* warm off-white */
  --panel: #ffffff;
  --border: #ece6dd;
  --card-hover-border: #c5c5d0;
  --image-fill: #fafafa;      /* fallback for img object-fit: contain */
  --badge-bg: #eee;
  --badge-fg: #333;
  --shadow-soft: rgba(0,0,0,0.04);
  --shadow-card: rgba(0,0,0,0.06);

  --primary: #e94e0f;         /* Heureka oranžová — CTA */
  --primary-hover: #c43e07;
  --primary-soft: #fdebe1;

  --info: #2aa4dc;            /* světle modrá — odkazy, hovers */
  --info-hover: #1d83b3;
  --info-soft: #e6f4fb;

  --accent: #e94e0f;          /* cena — totožná s primary, vizuálně odlišená velikostí + váhou */

  --live: #13a764;
  --ended: #8b8580;
  --scheduled: #c07b00;
  --cancelled: #b53434;

  --flash-success-bg: #e6f7ed;
  --flash-success-border: #a8e0be;
  --flash-success-fg: #0d5e2a;
  --flash-error-bg: #fde8e8;
  --flash-error-border: #f5b5b5;
  --flash-error-fg: #8b1717;

  /* Google sign-in CTA — white per official guidelines in light mode. */
  --google-bg: #ffffff;
  --google-fg: #1f1f1f;
  --google-border: #dadce0;
}

/* ---------- Dark theme override ---------- */
[data-theme="dark"] {
  --fg: #f1ece5;
  --muted: #9e9690;
  --bg: #181715;              /* near-black warm */
  --panel: #23211e;
  --border: #3a3631;
  --card-hover-border: #5a544c;
  --image-fill: #2a2825;
  --badge-bg: #3a3631;
  --badge-fg: #f1ece5;
  --shadow-soft: rgba(0,0,0,0.5);
  --shadow-card: rgba(0,0,0,0.6);

  --primary: #ff6b2c;         /* mírně světlejší oranžová pro lepší kontrast */
  --primary-hover: #ff8550;
  --primary-soft: #3a261c;

  --info: #59bfee;            /* světlejší modrá */
  --info-hover: #8fd2f3;
  --info-soft: #1c3140;

  --accent: #ff6b2c;

  --live: #21c47b;
  --ended: #807a72;
  --scheduled: #e09a30;
  --cancelled: #e05858;

  --flash-success-bg: #16341f;
  --flash-success-border: #2c6b3c;
  --flash-success-fg: #aee6bd;
  --flash-error-bg: #3a1818;
  --flash-error-border: #6b2828;
  --flash-error-fg: #f3b8b8;

  /* Google sign-in CTA — Google's recommended dark-mode treatment:
     dark surface, light text, subtle border. */
  --google-bg: #1f1f1f;
  --google-fg: #e3e3e3;
  --google-border: #5f6368;
}

/* Honour OS preference when the user hasn't picked a theme manually */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --fg: #f1ece5;
    --muted: #9e9690;
    --bg: #181715;
    --panel: #23211e;
    --border: #3a3631;
    --card-hover-border: #5a544c;
    --image-fill: #2a2825;
    --badge-bg: #3a3631;
    --badge-fg: #f1ece5;
    --shadow-soft: rgba(0,0,0,0.5);
    --shadow-card: rgba(0,0,0,0.6);

    --primary: #ff6b2c;
    --primary-hover: #ff8550;
    --primary-soft: #3a261c;

    --info: #59bfee;
    --info-hover: #8fd2f3;
    --info-soft: #1c3140;

    --accent: #ff6b2c;

    --live: #21c47b;
    --ended: #807a72;
    --scheduled: #e09a30;
    --cancelled: #e05858;

    --flash-success-bg: #16341f;
    --flash-success-border: #2c6b3c;
    --flash-success-fg: #aee6bd;
    --flash-error-bg: #3a1818;
    --flash-error-border: #6b2828;
    --flash-error-fg: #f3b8b8;

    --google-bg: #1f1f1f;
    --google-fg: #e3e3e3;
    --google-border: #5f6368;
  }
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
body {
  font-family: -apple-system, system-ui, Segoe UI, Roboto, sans-serif;
  margin: 0;
  color: var(--fg);
  background: var(--bg);
  line-height: 1.5;
}

header.topbar {
  display: flex; justify-content: space-between; align-items: center;
  padding: 10px 24px; background: var(--panel);
  border-bottom: 3px solid var(--primary);
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
.topbar nav { display: flex; gap: 18px; align-items: center; }
.topbar .brand {
  text-decoration: none;
  display: inline-flex; align-items: baseline; gap: 8px;
  letter-spacing: -0.01em;
}
/* Stacked, three-line brand mark recreated faithfully from the reference image:
     line 1  heureka!group           — small wordmark, blue + orange split
     line 2  AUCTION & MARKETPLACE   — caps tracking
     line 3  OhMyBid!                — the actual product name, big and blue
   Doing it in HTML/CSS (rather than dropping in a PNG) means it scales crisply,
   adapts to dark mode automatically, and stays one HTTP request lighter. */
.topbar .brand-stacked {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  line-height: 1;
  text-decoration: none;
  padding: 2px 0;
}
.topbar .brand-parent {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: baseline;
}
.topbar .brand-heureka { color: var(--info); }
.topbar .brand-bang   { color: var(--info); }
.topbar .brand-group  { color: var(--primary); }
.topbar .brand-tag {
  font-size: 8.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--muted);
  margin: 3px 0 4px;
}
.topbar .brand-name {
  font-size: 22px;
  font-weight: 800;
  color: var(--info);
  letter-spacing: -0.02em;
  line-height: 1;
}
.topbar .brand-bang-name {
  color: var(--primary);
  margin-left: 1px;
}
.topbar .brand-stacked:hover .brand-name  { color: var(--info-hover); }
.topbar .brand-stacked:hover .brand-group { color: var(--primary-hover); }
.topbar .brand-stacked:hover .brand-bang-name { color: var(--primary-hover); }
@media (max-width: 720px) {
  .topbar .brand-tag    { display: none; }     /* keep the two wordmarks, drop the tagline */
  .topbar .brand-parent { font-size: 11px; }
  .topbar .brand-name   { font-size: 18px; }
}
/* Account chip in the topbar — replaces the old "My page" + display-name pair. */
.topbar .user-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 10px 4px 4px;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--muted);
  font-weight: 500;
  text-decoration: none;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.topbar .user-chip:hover { border-color: var(--primary); color: var(--primary); }
.topbar .user-chip:hover .user-chip-avatar { background: var(--primary); }
.topbar .user-chip-avatar {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--info);
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
  flex-shrink: 0;
  transition: background 0.15s ease;
}
.topbar .user-chip-name { font-size: 14px; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar .link { background: none; border: 0; color: var(--info); cursor: pointer; font: inherit; padding: 0; }
.topbar .link:hover { color: var(--info-hover); }
.topbar a { color: var(--fg); text-decoration: none; font-weight: 500; }
.topbar a:hover { color: var(--primary); }
.topbar a.cta { background: var(--primary); color: #fff; padding: 8px 14px; border-radius: 6px; font-weight: 600; }
.topbar a.cta:hover { background: var(--primary-hover); color: #fff; }

/* Wider container — internal tool used on full-size monitors. 1080px
   was a holdover from the early reading-friendly draft; with the
   admin tables, the bid history grid, and now the pricing meta row
   with typical-market-price added, the content needs more breathing
   room. Capped at 1400px so the line length stays readable for long
   item descriptions but the meta rows finally fit on one line. */
main { max-width: 1400px; margin: 0 auto; padding: 24px; }
footer { text-align: center; padding: 24px; color: var(--muted); }

/* default inline links — světle modrá */
a { color: var(--info); }
a:hover { color: var(--info-hover); }

h1 { margin-top: 0; }
.muted { color: var(--muted); }
.small { font-size: 13px; font-weight: 400; }

/* Profile page */
.profile-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 4px solid var(--primary);
  border-radius: 8px;
  padding: 18px 22px;
  margin-bottom: 24px;
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr auto;
}
.profile-meta { display: grid; gap: 4px; align-content: start; }
.profile-meta .display-name { color: var(--primary); font-weight: 600; }
.inline-form { display: flex; flex-direction: column; gap: 6px; min-width: 260px; }
.inline-form label { display: flex; flex-direction: column; gap: 4px; }
.inline-form input { padding: 8px; border: 1px solid var(--border); border-radius: 6px; font: inherit; }
.inline-form .cta { align-self: start; }
@media (max-width: 600px) {
  .profile-card { grid-template-columns: 1fr; }
}

/* Slack linkage card — same overall .profile-card shell but with a
   Slack-purple left border instead of the brand orange, so it reads
   visually as a connected-services tile and not a duplicate "profile
   info" panel. The header puts a chunky # icon next to the title +
   subtitle, mirroring how Slack itself styles channel chips. */
.slack-card { border-left-color: #4a154b; }
.slack-card-header {
  display: flex; align-items: flex-start; gap: 12px;
  grid-column: 1 / -1;
}
.slack-card-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 8px;
  background: #4a154b; color: #fff;
  font-weight: 700; font-size: 18px;
  flex-shrink: 0;
}
.slack-card-title { margin: 0 0 2px; font-size: 16px; }
.slack-card-status {
  grid-column: 1 / -1;
  display: grid; gap: 4px;
}
.slack-card-status.connected strong { color: var(--success, #16a34a); }
.slack-connect-btn { align-self: start; }

/* Auction detail — "Message on Slack" deep-link button.
   Rendered inline next to the seller name (.meta > div). The button uses
   the official Slack aubergine for the badge background so it reads as
   "this is a Slack action" at a glance, but stays restrained enough not
   to compete with the bid CTA. The "(open in browser)" fallback is a
   plain underlined link, deliberately understated — most users will
   never need it, and we don't want two visually weighty buttons. */
.slack-contact-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 8px;
  padding: 3px 10px 3px 8px;
  background: #4a154b;
  color: #fff;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
  text-decoration: none;
  vertical-align: middle;
  transition: background 0.12s ease, transform 0.05s ease;
}
.slack-contact-btn:hover { background: #611f63; text-decoration: none; }
.slack-contact-btn:active { transform: translateY(1px); }
.slack-contact-btn:focus-visible {
  outline: 2px solid var(--info);
  outline-offset: 2px;
}
.slack-contact-icon { width: 14px; height: 14px; flex: none; }
.slack-contact-web {
  margin-left: 6px;
  font-size: 12px;
  color: var(--muted);
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 2px;
}
.slack-contact-web:hover { color: var(--fg); }

/* Header row above the listing — title on the left, sort selector on the right.
   Wraps under 600px so the select drops onto its own line on phones. */
.page-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin: 0 0 16px;
}
.page-head h1 { margin: 0; }
.sort-form { display: inline-flex; align-items: center; gap: 8px; }
.sort-form label { color: var(--muted); font-size: 14px; }
.sort-form select {
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--fg);
  font: inherit;
  cursor: pointer;
}
.sort-form select:hover  { border-color: var(--card-hover-border); }
.sort-form select:focus  { outline: 2px solid var(--info); outline-offset: 1px; border-color: var(--info); }

/* Marketplace-style listing rows */
.cards { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; }
.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  transition: box-shadow 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}
.card:hover { border-color: var(--card-hover-border); box-shadow: 0 4px 14px var(--shadow-card); }
.card a { text-decoration: none; color: inherit; display: flex; align-items: stretch; gap: 0; }
.card img, .card .cover {
  width: 220px;
  height: 180px;
  flex-shrink: 0;
  object-fit: contain;
  background: var(--image-fill);
  padding: 10px;
  display: block;
  border-right: 1px solid var(--border);
}
.card .body {
  flex: 1;
  min-width: 0;
  padding: 16px 20px;
  display: grid;
  grid-template-columns: 1fr auto;
  /* Four rows: title / description / optional condition chip / meta.
     Description row is the 1fr stretcher so it eats any leftover
     vertical space; the condition row is ``auto`` so it collapses
     to zero height when the chip is suppressed (NULL condition).
     Without the explicit ``condition`` area the chip used to fall
     into the empty right-column cell next to ``desc`` because grid
     auto-placement took the dead spot — gave the chip a "floating
     in dead space" look, see Petr's bug report. */
  grid-template-rows: auto 1fr auto auto;
  /* Bottom row holds ``meta`` (left, status · bids · ends) and
     ``seller`` (right) on the same baseline — they're both muted
     supporting metadata and reading them as one row keeps the card
     visually balanced ("seller na stejném řádku jako start aukce,
     jen na opačné straně" — #159). The right column under the
     price is left empty (``.``) so the bold price stays a single
     uncluttered anchor in the top-right corner. */
  grid-template-areas:
    "title      price"
    "desc       ."
    "condition  ."
    "meta       seller";
  gap: 6px 16px;
}
.card h3 {
  grid-area: title;
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--fg);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.card a:hover h3 { color: var(--info); }
.card .desc {
  grid-area: desc;
  margin: 0;
  font-size: 14px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.card .price {
  grid-area: price;
  margin: 0;
  align-self: start;
  text-align: right;
  font-size: 22px;
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.card .meta {
  grid-area: meta;
  font-size: 12px;
  color: var(--muted);
  margin: 0;
  align-self: end;
}
/* Seller line sits in the right column directly under the price
   ("decentně, aby to nenarušilo cenu" — #158). Right-aligned to track
   the price's right edge, muted + smaller font so it never competes
   visually. ``max-width: 100%`` + ellipsis keeps long
   display_names (e.g. ``"Velmi Dlouhe Jmeno"``) from blowing the
   right column wider than the price and pushing the title left.

   Font-size matches ``.card .meta`` exactly in every density — the
   user explicitly asked for "stejně velký jako začátek/konec aukce"
   (#158 follow-up) so the seller reads as the same kind of
   supporting metadata as the status · bids · ends line, not as a
   secondary headline competing with the price. No ``line-height``
   override either — inheriting the body rhythm lines up seller's
   row height with what meta already does. Density modifiers below
   mirror meta's sizes, not their own scale. */
.card .card-seller {
  grid-area: seller;
  margin: 0;
  align-self: end;
  text-align: right;
  font-size: 12px;
  color: var(--muted);
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 600px) {
  .card a { flex-direction: column; }
  .card img, .card .cover { width: 100%; height: 200px; border-right: 0; border-bottom: 1px solid var(--border); }
  /* Mobile single-column stack reorders the areas top-to-bottom.
     Desktop puts ``meta`` and ``seller`` on the same row; mobile
     can't, so they stack adjacently at the bottom — seller right
     under meta — keeping the buyer's "supporting metadata block"
     visually grouped. #159 */
  .card .body { grid-template-columns: 1fr; grid-template-areas: "title" "price" "desc" "condition" "meta" "seller"; }
  .card .price { text-align: left; }
  .card .card-seller { text-align: left; }
}

/* Medium density (5–8 listings) — slightly smaller, tighter */
.cards.density-medium .card img,
.cards.density-medium .card .cover { width: 170px; height: 140px; padding: 8px; }
.cards.density-medium .card .body { padding: 12px 16px; gap: 4px 14px; }
.cards.density-medium .card h3 { font-size: 16px; -webkit-line-clamp: 1; }
.cards.density-medium .card .desc { font-size: 13px; -webkit-line-clamp: 1; }
.cards.density-medium .card .price { font-size: 19px; }
.cards.density-medium .card .meta { font-size: 12px; }
.cards.density-medium .card .card-seller { font-size: 12px; }

/* Compact density (9+ listings) — minimal, scannable. Bottom row
   pairs ``meta`` (left) and ``seller`` (right) so the card reads as
   two horizontal lines: "title | price" on top, "status·bids·ends |
   seller" below. Mirrors the default-density grouping (#159) just
   without the description row in the middle. */
.cards.density-compact { gap: 8px; }
.cards.density-compact .card { border-radius: 8px; }
.cards.density-compact .card img,
.cards.density-compact .card .cover { width: 120px; height: 96px; padding: 6px; }
.cards.density-compact .card .body {
  padding: 10px 14px;
  /* Compact density keeps the condition chip on its own row between
     title and meta — "For parts / not working" is exactly the kind of
     info you want to spot WITHOUT clicking, especially when scanning
     a long list fast. Earlier iteration hid the chip here to save a
     row; Petr (rightly) pushed back — condition is signal, not noise.
     Cards without a condition still collapse the row to 0px via
     ``auto`` track sizing so they look the same as before. */
  grid-template-areas:
    "title      price"
    "condition  ."
    "meta       seller";
  grid-template-rows: auto auto auto;
  gap: 2px 12px;
}
.cards.density-compact .card .desc { display: none; }
/* Slightly tighter chip in compact mode so the extra row doesn't bloat
   the card much. Condition chip stays readable at this scale — the
   colour-coded background carries most of the signal anyway. */
.cards.density-compact .card-condition { margin: 0; }
.cards.density-compact .card-condition .condition-chip {
  font-size: 10.5px;
  padding: 1px 6px;
}
.cards.density-compact .card h3 { font-size: 15px; -webkit-line-clamp: 1; }
.cards.density-compact .card .price { font-size: 17px; align-self: center; }
.cards.density-compact .card .meta { font-size: 11.5px; }
.cards.density-compact .card .card-seller { font-size: 11.5px; }

@media (max-width: 600px) {
  .cards.density-medium .card a,
  .cards.density-compact .card a { flex-direction: column; }
  .cards.density-medium .card img,
  .cards.density-compact .card img { width: 100%; height: 160px; }
  /* Same single-column reorder as the default-density mobile rule:
     seller stacks right under meta at the bottom so the supporting
     metadata reads as one block. Medium also hides ``desc`` (rule
     below) so the stack collapses to price → meta → seller. #159 */
  .cards.density-medium .card .body,
  .cards.density-compact .card .body { grid-template-columns: 1fr; grid-template-areas: "title" "price" "condition" "meta" "seller"; }
  .cards.density-medium .card .desc { display: none; }
  .cards.density-medium .card .card-seller,
  .cards.density-compact .card .card-seller { text-align: left; }
}

.badge { display: inline-block; font-size: 11px; padding: 2px 8px; border-radius: 999px; background: var(--badge-bg); color: var(--badge-fg); }
.badge-live { background: var(--live); color: #fff; }
.badge-ended { background: var(--ended); color: #fff; }
.badge-scheduled { background: var(--scheduled); color: #fff; }
.badge-cancelled { background: var(--cancelled); color: #fff; }

/* Seller-declared item-condition chip ("Nové", "Velmi dobrý", …).
   Defaulted to the heavy ``.badge`` rhythm which felt out of step
   with the rest of the card on the listing — the seller's chosen
   condition is supporting context (between the description and the
   price), not a primary status, so we give it the same soft, low-
   contrast chrome we use elsewhere for tertiary metadata: tile-
   hover blue (``--info-soft`` background + ``--info`` text) at a
   reduced font size. All five condition variants render with the
   same chip — the text already carries the meaning, color would
   only add noise. The wrapper ``.card-condition`` strips the
   default paragraph margin so the chip sits flush in the card's
   vertical rhythm. */
.card-condition {
  /* Pin to the explicit ``condition`` grid area on the left column so
     the chip reads as part of the "what the item is" stack (title →
     desc → condition) rather than floating into the empty cell next
     to the price. Margin zeroed because grid ``gap`` already spaces
     the rows. */
  grid-area: condition;
  margin: 0;
}
.condition-chip {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--info-soft);
  color: var(--info);
  letter-spacing: 0.02em;
}
/* Tombstoned (anonymized) users in the admin users table.
   Kept muted but not strike-through so admins can still scan the row
   for the sentinel email + audit metadata when investigating. */
.badge-muted { background: var(--badge-bg); color: var(--muted, #6b7280); border: 1px solid var(--border); }
.row-deleted td { color: var(--muted, #6b7280); }
.row-deleted td a { color: var(--muted, #6b7280); }
.row-deleted .real-name { font-style: italic; }

.auction { background: var(--panel); border: 1px solid var(--border); padding: 24px; border-radius: 8px; }
.auction > header { display: flex; align-items: center; gap: 12px; }
.auction .gallery {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 16px 0;
}
.auction .gallery a {
  display: block;
  width: 240px;
  max-width: 100%;
  text-decoration: none;
}
.auction .gallery img {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: contain;
  background: var(--image-fill);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px;
  cursor: zoom-in;
  transition: border-color 0.15s ease;
  display: block;
}
.auction .gallery a:hover img {
  border-color: var(--info);
}

@media (max-width: 600px) {
  .auction .gallery a { width: 100%; }
}
/* User-entered description. ``overflow-wrap: anywhere`` lets the
   browser break inside long unbroken strings (URLs, repeated chars,
   long asset codes) so a 200-char "HALOOOOOOO…" can't push the card
   wider than its container — previously the row scrolled horizontally
   off-screen. ``anywhere`` (not ``break-word``) also feeds the break
   opportunities into the line-length calculation so short words on
   the same line wrap normally too. */
.auction .description {
  overflow-wrap: anywhere;
}
/* Title can also be a single Slovak/Czech word like "Ultralehkýnotebook…"
   pasted without spaces. Same fix, scoped to the auction header so we
   don't accidentally break navigation H1s. */
.auction > header h1 {
  overflow-wrap: anywhere;
  min-width: 0;
}
/* Long asset-tag codes are wrapped in <code> inside the meta grid;
   keep them inside their cell instead of forcing the column wider. */
.auction .meta code {
  overflow-wrap: anywhere;
}
/* Mirror the fix on the listing cards. The desc is already truncated
   server-side to ~217 chars, but 217 of a single character would still
   blow out the card; this keeps the grid honest. */
.card .desc,
.card h3 {
  overflow-wrap: anywhere;
}
/* Two-row meta layout: ``meta-row-info`` (who/what/when) sits on top,
   ``meta-row-pricing`` (starting price + min increment + market ref)
   underneath. A faint divider line separates them so the user reads
   them as two distinct groups without visual noise. Each row still
   uses an auto-fit grid internally — items wrap onto a second line
   only when the viewport is narrow enough to need it. */
.auction .meta {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 16px 0;
  padding: 12px;
  background: var(--bg);
  border-radius: 6px;
  min-width: 0;
}
.auction .meta-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  min-width: 0;
}
.auction .meta-row-pricing {
  border-top: 1px solid var(--border);
  padding-top: 10px;
}

/* The section wrapper is purely structural (HTMX swap target + SSE
   listener) — no visual treatment. All styling stays on .bid-panel. */
.bid-panel-shell { display: block; }
.bid-panel { margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--border); }
/* One-shot success flash after a bid lands. Auto-fades after ~3.5s so the
   panel returns to a clean state without requiring user dismissal. */
.bid-flash {
  margin: 0 0 12px;
  animation: bid-flash-fade 3.5s ease forwards;
}
@keyframes bid-flash-fade {
  0%   { opacity: 0; transform: translateY(-4px); }
  10%  { opacity: 1; transform: translateY(0); }
  80%  { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}
/* Inline error slot above the bid form. Hidden by default; populated by
   hx-on::response-error when the bid endpoint returns a 4xx. */
#bid-error[hidden] { display: none; }
#bid-error { margin: 0 0 12px; }
.bid-panel .current { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 16px; }
.bid-panel .current .label { color: var(--muted); }
.bid-panel .current .amount { font-size: 32px; font-weight: 700; color: var(--accent); letter-spacing: -0.02em; }
.bid-panel form { display: flex; gap: 12px; align-items: end; margin-bottom: 16px; }
.bid-panel form label { flex: 1; display: flex; flex-direction: column; gap: 4px; }
.bid-panel input[type=number] { padding: 8px; font-size: 16px; border: 1px solid var(--border); border-radius: 6px; }
.bid-panel .cta { padding: 10px 16px; font-size: 16px; }
.bid-list { list-style: none; padding: 0; margin: 0; }
.bid-list li { display: grid; grid-template-columns: 150px 1fr auto auto; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 14px; }
.bid-list .amount { font-weight: 600; }
.bid-list .when { color: var(--muted); font-variant-numeric: tabular-nums; }
.bid-list .admin-reveal { color: var(--muted); font-size: 12px; margin-left: 4px; }
/* Cancelled bids stay in the audit history but are visually demoted —
   the amount is struck through and the row is dimmed so it's obvious
   it doesn't count toward the current price. Pairs with the
   `.badge-cancelled` tag rendered in place of the "leading" badge. */
.bid-list li.bid-cancelled { opacity: 0.55; }
.bid-list li.bid-cancelled .amount,
.bid-list li.bid-cancelled .who { text-decoration: line-through; }

/* Admin-only "Active bidders" panel: surfaces real identity + e-mail
   for each unique participant. Visually marked with a tinted background +
   "admin view" tag so it's obvious this isn't shown to regular users. */
.admin-bidders {
  margin: 20px 0;
  padding: 14px 16px;
  border: 1px dashed var(--primary);
  border-radius: 8px;
  background: color-mix(in srgb, var(--primary) 6%, var(--panel));
}
.admin-bidders > header {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 10px;
}
.admin-bidders > header h2 { margin: 0; font-size: 16px; }
.admin-bidders .admin-only-tag {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--primary); font-weight: 700;
  border: 1px solid var(--primary); border-radius: 999px;
  padding: 2px 8px;
}
.bidders-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.bidder-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px 16px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  align-items: center;
}
.bidder-row.is-leading { border-color: var(--live); box-shadow: inset 3px 0 0 var(--live); }
.bidder-row .bidder-id { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.bidder-row .real-name { font-weight: 600; }
.bidder-row .nick { color: var(--muted); font-size: 13px; }
.bidder-row .email { color: var(--info); font-size: 13px; text-decoration: none; }
.bidder-row .email:hover { text-decoration: underline; }
.bidder-row .bidder-stats { display: flex; gap: 8px; align-items: baseline; font-size: 13px; }
.bidder-row .bidder-stats .amount { font-weight: 700; font-variant-numeric: tabular-nums; }
@media (max-width: 600px) {
  .bidder-row { grid-template-columns: 1fr; }
  .bidder-row .bidder-stats { flex-wrap: wrap; }
}

button, .cta { background: var(--primary); color: #fff; border: 0; padding: 6px 12px; border-radius: 6px; cursor: pointer; font: inherit; }
button:hover, .cta:hover { background: var(--primary-hover); }

form.stacked { display: flex; flex-direction: column; gap: 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 24px; }
form.stacked label { display: flex; flex-direction: column; gap: 4px; }
/* Inputs, selects and textareas share one rule so they read as a
   family. We pin explicit ``background`` + ``color`` (instead of
   letting the UA pick) because in dark mode without a declared
   ``color-scheme`` Chrome paints <input> with light UA chrome (white
   on the dark panel) but paints <select> with the OS-themed dark
   chrome — so the picker came out near-black while every input next
   to it was white. Pinning them to the same light values keeps the
   form readable and consistent in both themes. See Task #133. */
form.stacked input,
form.stacked select,
form.stacked textarea {
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font: inherit;
  background: #ffffff;
  color: #1f1d1b;
}
/* Native dropdown arrow on the select uses the OS theme too — force
   it to a light scheme so the arrow stays dark on the white field
   regardless of the user's OS dark-mode preference.
   ``width: 100%`` because ``<select>`` doesn't honour ``align-items:
   stretch`` the way ``<input>`` does — it stays at its intrinsic
   content width and renders visibly narrower than its row siblings
   (most obvious on the new-auction Currency dropdown sitting next to
   Starting price / Min increment / Buy Now). Explicit 100% makes the
   four pricing-row cells line up the same width. #152 */
form.stacked select {
  color-scheme: light;
  width: 100%;
}
form.stacked .row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }

/* Tiny helper text under a form input, e.g. "Pre-filled to next 5-min slot".
   Reset margins so spacing is driven by the parent form's flex gap, not by
   the browser's default <p> margins (which created asymmetric whitespace
   above vs. below row hints — visible as inconsistent gaps in the form). */
.field-hint { font-size: 12px; line-height: 1.4; margin: 0; }
/* When the hint is a <p> immediately after a .row, pull it tight against
   the row above and add a touch of breathing room before the next row.
   Combines with form.stacked's 12px gap → ~4px tight above, ~18px below. */
form.stacked > p.field-hint { margin: -8px 0 6px 0; }

/* Currency code with a hoverable name tooltip. The money_html Jinja
   filter wraps just the trailing 3-char code (FID / CZK / EUR …) in
   this span and stuffs the human-readable label (e.g. "Fidorka") into
   the native ``title`` attribute, so bidders who don't recognise an
   admin-invented code can hover to learn what it means. The dotted
   underline + help cursor are the only visual affordance — without
   them the tooltip is undiscoverable, since most users don't try
   hovering on plain text. Underline uses ``currentColor`` so it
   inherits the surrounding price's colour in both light and dark
   modes without a separate dark-mode override. #157 */
.cur-tip {
  border-bottom: 1px dotted currentColor;
  cursor: help;
}

/* Required-field indicator. Inline asterisk after the label text — same
   font-size as the label, brand-accent colour. NOT red: we want the *
   to read as "this matters", not "this is broken". The actual error
   highlight (red border) is gated behind user interaction below. */
.req {
  color: var(--accent, #ff6a13);
  margin-left: 2px;
  font-weight: 700;
  /* Slight nudge up so the asterisk sits visually centred on the cap-line
     instead of the baseline — looks more like a footnote, less like an
     ASCII multiplication sign. */
  vertical-align: 1px;
  font-size: 0.95em;
}
/* Generic "label text + .req" wrapper. Every required field in
   ``form.stacked`` packs its label text and the trailing ``.req``
   asterisk into a single inline span (``.label-text`` — or the older
   ``.iban-label-text`` / ``.country-label-text`` siblings, which do
   the same thing for the IBAN + country fields). The wrapper becomes
   ONE flex item in the label's flex-column layout, so ``Title*`` sits
   on a single row with no detached asterisk hovering above the input.
   No display switch needed — a plain inline ``<span>`` already lays
   out its inner text + nested ``.req`` inline, which is exactly what
   we want. Centralised here so all three classes read as a family.
   #156 (replaces the negative-margin ``align-self: flex-end`` hack
   from #153 that pinned the asterisk to the bottom-right of the label
   box; that was technically inline-with-the-input but visually too
   detached from the label text — users read it as a stray decoration
   instead of as a required marker). */
form.stacked label > .label-text,
form.stacked label > .iban-label-text,
form.stacked label > .country-label-text {
  /* Inline-block keeps the wrapper's intrinsic height (no stretch to
     row width) so the .req stays right next to the text rather than
     getting nudged anywhere by the parent's flex packing. */
  display: inline-block;
}
.form-required-note {
  font-size: 12.5px;
  margin: 0 0 12px 0;
}

/* Error-only validation feedback. We deliberately avoid styling
   ``:invalid`` directly because every required field is :invalid on
   page load before the user has typed anything — that would make the
   whole form open looking pre-broken.

   ``:user-invalid`` (Chrome 119+, Firefox 88+, Safari 16.5+) only
   fires AFTER the user has interacted with the field, so empty fields
   stay neutral until the user actually leaves them blank on a real
   attempt. For pre-:user-invalid browsers, the ``.was-submitted``
   class — added by JS on first submit attempt — falls back to a
   classic :invalid scope, same outcome with one extra click. */
form.stacked :user-invalid,
form.stacked.was-submitted :invalid {
  border-color: var(--flash-error-border) !important;
  box-shadow: 0 0 0 1px var(--flash-error-border) inset;
}

/* Duration preset chips — quick-pick auction length so the user doesn't
   have to fight the native time spinner. Sits under the ends_at field. */
.time-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}
.time-chip {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--fg);
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  line-height: 1.2;
  transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.time-chip:hover {
  border-color: var(--card-hover-border);
  background: var(--bg);
}
.time-chip.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.time-chip.active:hover {
  background: var(--primary);
  border-color: var(--primary);
}
/* Human-readable end-time preview, e.g. "↳ Sunday, May 3 at 14:30". */
.end-preview {
  font-size: 13px;
  color: var(--muted);
  margin-top: 6px;
  font-style: italic;
  min-height: 1.2em;  /* reserve space so layout doesn't jump as it appears */
}

table { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; margin-bottom: 24px; }
th, td { text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border); }
th { background: var(--bg); font-weight: 600; }

.flash { padding: 10px 14px; border-radius: 6px; margin: 12px 0; }
.flash.success { background: var(--flash-success-bg); border: 1px solid var(--flash-success-border); color: var(--flash-success-fg); }
.flash.error { background: var(--flash-error-bg); border: 1px solid var(--flash-error-border); color: var(--flash-error-fg); }
/* Neutral informational variant — used for the prefilled-relist banner
   on the new-auction form. Borrows the panel/card colors so it sits
   quietly above the form without competing with success/error cues. */
.flash.info { background: var(--panel); border: 1px solid var(--border); color: var(--text); }

/* Relist callout on the auction detail page. Compact card-shaped block
   directly above the bid panel — sellers see it where their attention is
   already focused after the auction's status reads "Ended". */
.relist-callout {
  margin: 16px 0;
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
}
.relist-callout p { margin: 0; }
.relist-banner a { font-weight: 600; }

/* 24h winner Cancel callout. Same overall card shape as the relist
   callout so post-win actions all sit on a consistent visual baseline,
   but tinted with a soft red wash to flag that the contained action is
   destructive (re-opens the auction, gives up the win). The actual
   Cancel button uses the existing `.cta-danger` red-outline style. */
.cancel-win-callout {
  border-color: rgba(224, 71, 58, 0.35);
  background: linear-gradient(
    180deg,
    rgba(224, 71, 58, 0.08) 0%,
    var(--panel) 100%
  );
}
.cancel-win-callout h2 {
  margin: 0 0 4px;
  font-size: 1.05rem;
}
.cancel-win-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
}
.cancel-win-reason {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.9rem;
  color: var(--muted);
}
.cancel-win-reason textarea {
  width: 100%;
  min-height: 56px;
  resize: vertical;
  padding: 8px 10px;
  font: inherit;
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.cancel-win-reason textarea:focus {
  outline: 2px solid var(--primary);
  outline-offset: -1px;
  border-color: transparent;
}
.cancel-win-form .cta-danger { align-self: flex-start; }

/* Thumbnail strip shown on the relist form above the file input. Tells
   the seller exactly what's being carried over — file inputs can't be
   prefilled in HTML so this preview is the only visible evidence that
   the originals will follow. Square 80px thumbs wrap if there are many. */
.relist-images {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 6px;
}
.relist-image-thumb {
  width: 80px;
  height: 80px;
  object-fit: cover;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
}

/* Image picker (new-auction form). The native file input stays visible
   above the list; we add a thumbnail strip below it so the seller can
   see every file they've picked, in order, and remove individual ones.
   The accumulator JS in auction_form.html keeps an internal selection
   array and re-syncs input.files via DataTransfer on every change. */
.image-picker-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 10px;
  margin: 10px 0;
}
.image-picker-list:empty {
  display: none;
}
.image-picker-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px 6px 6px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
}
.image-picker-thumb {
  width: 56px;
  height: 56px;
  object-fit: cover;
  border-radius: 6px;
  background: var(--bg);
  flex-shrink: 0;
}
.image-picker-meta {
  flex: 1;
  min-width: 0; /* allow .image-picker-name truncation */
}
.image-picker-name {
  font-size: 0.9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.image-picker-size {
  font-size: 0.8rem;
}
.image-picker-remove {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.image-picker-remove:hover {
  background: var(--flash-error-bg);
  border-color: var(--flash-error-border);
  color: var(--flash-error-fg);
}

/* Admin auction-edit image manager. Two-block layout:
     1. Existing images grid — square thumbnails with a single X toggle in
        the corner. Clicking marks the card for deletion (greys it out,
        appends a hidden delete_image_id input, swaps the icon to ↺).
        Clicking again undoes the marker before submit.
     2. Add new images picker — re-uses the .image-picker-* classes from
        the new-auction form, so we don't need to restyle anything for
        that block.
   Sized so eight images fit on a typical 1440-wide admin viewport. */
.image-edit-block {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px 16px;
  margin: 6px 0;
  background: var(--panel);
}
.image-edit-block > legend {
  font-weight: 600;
  padding: 0 6px;
}
.image-edit-subhead {
  font-size: 0.95rem;
  font-weight: 600;
  margin: 8px 0 6px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.existing-images-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 10px;
  margin-bottom: 10px;
}
.existing-image-card {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  overflow: hidden;
  aspect-ratio: 1 / 1;
}
.existing-image-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: opacity 0.15s ease, filter 0.15s ease;
}
.existing-image-toggle {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.92);
  color: var(--text);
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.existing-image-toggle:hover {
  background: var(--flash-error-bg);
  border-color: var(--flash-error-border);
  color: var(--flash-error-fg);
}
.existing-image-deleted-tag {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 4px 6px;
  font-size: 0.75rem;
  font-weight: 600;
  text-align: center;
  color: var(--flash-error-fg);
  background: var(--flash-error-bg);
  border-top: 1px solid var(--flash-error-border);
  display: none;
}
.existing-image-card.is-deleting .existing-image-thumb {
  opacity: 0.35;
  filter: grayscale(1);
}
.existing-image-card.is-deleting .existing-image-deleted-tag {
  display: block;
}
.existing-image-card.is-deleting .existing-image-toggle {
  background: var(--flash-success-bg, var(--panel));
  border-color: var(--border);
  color: var(--text);
}

/* Lightbox — full-screen overlay above auction images. The whole
   overlay sits at z-index 1000 so it covers the top nav, the bid
   panel, and any HTMX-driven swaps. ``body.lightbox-open`` locks
   page scroll while the overlay is up. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
}
.lightbox.is-open {
  opacity: 1;
  pointer-events: auto;
}
.lightbox[hidden] {
  display: none;
}
.lightbox-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.82);
  cursor: zoom-out;
}
.lightbox-figure {
  position: relative;
  max-width: 92vw;
  max-height: 88vh;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.lightbox-image {
  max-width: 92vw;
  max-height: 82vh;
  border-radius: 8px;
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.6);
  background: #111;
  /* Pixel-art guard: the image is shown 1:1 if it fits, scaled down
     proportionally otherwise. We never upscale — small thumbs stay
     small rather than turning blurry. */
  object-fit: contain;
}
.lightbox-counter {
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}
.lightbox-close,
.lightbox-nav {
  position: absolute;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 50%;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.15s ease;
}
.lightbox-close:hover,
.lightbox-nav:hover {
  background: rgba(0, 0, 0, 0.7);
}
.lightbox-close {
  top: 16px;
  right: 16px;
  font-size: 1.8rem;
}
.lightbox-nav {
  top: 50%;
  transform: translateY(-50%);
  font-size: 2.4rem;
}
.lightbox-prev { left: 16px; }
.lightbox-next { right: 16px; }
.lightbox-nav:hover { transform: translateY(-50%) scale(1.06); }
.lightbox-nav[hidden] { display: none; }

body.lightbox-open {
  /* Keep the scroll position but freeze it — overflow:hidden alone
     causes a layout shift on Windows scrollbars; the padding-right
     compensation is conditional via scrollbar-gutter where available. */
  overflow: hidden;
}

@media (max-width: 600px) {
  .lightbox-close { top: 8px; right: 8px; }
  .lightbox-prev  { left: 8px; }
  .lightbox-next  { right: 8px; }
  .lightbox-nav, .lightbox-close { width: 38px; height: 38px; }
}

/* Gavel watermark — repeating SVG pattern behind the login page only.
   The icon mimics the classic auction-gavel silhouette: head with two
   end-cap pills, angled handle, separate sounding block underneath.
   Light mode uses near-black at low opacity, dark mode uses near-white;
   both sit on top of the body's solid bg color so they read as a tinted
   texture, not a separate layer. SVG is inlined as a data URI so there's
   zero extra HTTP fetch.

   Tile is 180x180, matching the SVG viewBox so there's no scaling. The
   gavel itself is rotated 28° clockwise (handle points down-right). */
body.login-page {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 180'><g fill='%23000' fill-opacity='0.055'><g transform='rotate(28 90 80)'><rect x='42' y='30' width='96' height='18' rx='9'/><rect x='42' y='100' width='96' height='18' rx='9'/><rect x='66' y='48' width='48' height='52' rx='3'/><rect x='110' y='65' width='66' height='18' rx='9'/></g><rect x='42' y='148' width='96' height='10' rx='2'/><rect x='52' y='138' width='76' height='12' rx='3'/></g></svg>");
  background-repeat: repeat;
  background-size: 180px 180px;
}
[data-theme="dark"] body.login-page {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 180'><g fill='%23ffffff' fill-opacity='0.05'><g transform='rotate(28 90 80)'><rect x='42' y='30' width='96' height='18' rx='9'/><rect x='42' y='100' width='96' height='18' rx='9'/><rect x='66' y='48' width='48' height='52' rx='3'/><rect x='110' y='65' width='66' height='18' rx='9'/></g><rect x='42' y='148' width='96' height='10' rx='2'/><rect x='52' y='138' width='76' height='12' rx='3'/></g></svg>");
}
/* OS-level dark preference, only when the user hasn't picked a theme. */
@media (prefers-color-scheme: dark) {
  html:not([data-theme]) body.login-page {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 180'><g fill='%23ffffff' fill-opacity='0.05'><g transform='rotate(28 90 80)'><rect x='42' y='30' width='96' height='18' rx='9'/><rect x='42' y='100' width='96' height='18' rx='9'/><rect x='66' y='48' width='48' height='52' rx='3'/><rect x='110' y='65' width='66' height='18' rx='9'/></g><rect x='42' y='148' width='96' height='10' rx='2'/><rect x='52' y='138' width='76' height='12' rx='3'/></g></svg>");
  }
}

/* Login page — single centred card, BambooHR / Linear-style: brand on
   top of the card, hero Google CTA, "or" divider, then a small text
   link to reveal the username/password form. Sized like a normal login
   surface, not a billboard. */
.login-shell {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 32px 16px 64px;
}
.login-card {
  width: 100%;
  max-width: 460px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 36px 36px 32px;
  box-shadow: 0 4px 18px var(--shadow-card);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 18px;
  box-sizing: border-box;
}
.login-card .flash { width: 100%; box-sizing: border-box; text-align: left; }

/* Hero brand mark — same stacked HTML as the topbar logo, just slightly
   larger so the page has a recognisable identity without dominating it. */
.brand-hero {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  line-height: 1;
  margin: 4px 0 6px;
}
.brand-hero .brand-parent {
  font-size: 28px;
  font-weight: 800;
  letter-spacing: -0.01em;
  display: inline-flex; align-items: baseline;
  line-height: 1;
}
.brand-hero .brand-heureka { color: var(--info); }
.brand-hero .brand-bang   { color: var(--info); }
.brand-hero .brand-group  { color: var(--primary); }
.brand-hero .brand-tag {
  font-size: 9px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.28em;
  color: var(--muted);
  margin: 8px 0 6px;
}
.brand-hero .brand-name {
  font-size: 22px; font-weight: 800; color: var(--info);
  letter-spacing: -0.02em;
}
.brand-hero .brand-bang-name { color: var(--primary); margin-left: 2px; }

/* Google CTA — pill-shaped primary button. Defensive sizing on the SVG
   inside so it can never blow up if the stylesheet fails to load. */
.google-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  padding: 13px 22px;
  background: var(--primary);
  color: #fff;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.05s ease;
  cursor: pointer;
  box-sizing: border-box;
  box-shadow: 0 1px 3px var(--shadow-soft);
}
.google-cta:hover  {
  background: var(--primary-hover);
  box-shadow: 0 3px 10px var(--shadow-card);
  color: #fff;
}
.google-cta:active { transform: translateY(1px); }
/* The Google "G" mark needs a white plate on a coloured pill button so
   the multicolour logo stays legible against the purple background. */
.google-cta .google-cta-icon {
  background: #fff;
  border-radius: 999px;
  padding: 2px;
  box-sizing: content-box;
}
.google-cta-icon {
  /* Belt-and-braces: explicit width AND max-width so neither user-agent
     defaults nor inherited flex stretching can blow this up. */
  width: 18px;
  height: 18px;
  max-width: 18px;
  max-height: 18px;
  flex-shrink: 0;
  display: block;
}
.google-cta-disabled {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}
.login-google-setup { font-size: 12px; margin: 8px 0 0; }

/* "or" divider — thin rules either side of a small uppercase label.
   Same convention as GitHub / Notion / BambooHR. */
.login-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin: 4px 0;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.18em;
}
.login-divider::before,
.login-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}
.login-divider span { flex: 0 0 auto; }

/* "Log in another way" disclosure — text link by default, expands to
   reveal the local username + password form. <details>-based so it
   works without JS. */
.login-other {
  width: 100%;
  text-align: center;
}
.login-other-toggle {
  display: inline-block;
  list-style: none;
  cursor: pointer;
  color: var(--primary);
  font-size: 14px;
  font-weight: 600;
  padding: 6px 4px;
  border-radius: 4px;
  user-select: none;
  transition: color 0.15s ease;
}
.login-other-toggle::-webkit-details-marker { display: none; } /* hide default ▶ */
.login-other-toggle:hover { color: var(--primary-hover); text-decoration: underline; }
.login-other[open] .login-other-toggle {
  color: var(--muted);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 600;
}
.login-other[open] .local-form { margin-top: 14px; }

/* Local username + password form — appears inside the <details>. */
.local-form { text-align: left; gap: 10px; }
.local-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--muted);
  font-weight: 500;
}
.local-form input {
  font-size: 14px;
  padding: 8px 10px;
}
.local-form-submit {
  width: 100%;
  margin-top: 4px;
  padding: 9px 16px;
  font-size: 14px;
}
.local-form-hint {
  font-size: 12px;
  margin: 10px 0 0;
  text-align: center;
  line-height: 1.45;
}
.cta-secondary {
  background: transparent;
  color: var(--fg);
  border: 1px solid var(--border);
}
.cta-secondary:hover { background: var(--panel); border-color: var(--card-hover-border); }

.cta.disabled { opacity: 0.5; pointer-events: none; }

/* ----------------------- Buy Now feature ------------------------------- */

/* Inline buy-now field — sits in the pricing row alongside starting
   price / increment / currency. We style the label tint so it still
   reads as an optional add-on without breaking the row's grid layout. */
.buy-now-inline .buy-now-label {
  display: inline-flex; align-items: center; gap: 5px;
  font-weight: 600;
}
.buy-now-inline input::placeholder {
  font-size: 12px;
  font-style: italic;
  opacity: 0.7;
}
/* Keep every pricing-row input baseline-aligned regardless of label-text
   height. Each label is a flex column packed from the top, so any line-
   height delta between sibling labels (e.g. Buy Now's icon-bearing
   label-span vs. a plain "Currency*" wrapper) would otherwise leave one
   input visibly higher than the others. `margin-top: auto` glues every
   field control to the bottom of its label so they line up across the
   row no matter how the label-text wraps. */
form.stacked .pricing-row label > input,
form.stacked .pricing-row label > select {
  margin-top: auto;
}
/* Legacy alias — historical buy-now-specific spacing now matches every
   other row hint. Kept as a no-op so existing markup doesn't break;
   actual layout is driven by `form.stacked > p.field-hint` above. */
.buy-now-row-hint { font-size: 12px; }

/* Read-only inputs (e.g. admin auction edit's Starting price once bids
   exist) — render with the same disabled-looking treatment as native
   ``disabled`` so the user can see the field is non-editable without
   us shoving a "(locked)" suffix into the label that would wrap the
   row on narrow widths. We can't actually use ``disabled`` because
   that would drop the value from the POST body. The cursor + colour
   change is the entire UX story; the rest of the lock semantics is
   enforced server-side. */
input[readonly],
textarea[readonly] {
  background: var(--surface-alt, color-mix(in srgb, var(--muted) 12%, transparent));
  color: var(--muted);
  cursor: not-allowed;
  opacity: 0.75;
}
input[readonly]:focus,
textarea[readonly]:focus {
  /* Suppress the usual focus-ring colour shift — focusing a locked
     field shouldn't look like an editing affordance. */
  outline-color: var(--muted);
  box-shadow: none;
}
.buy-now-icon { font-size: 1em; line-height: 1; }

/* Inline tag inside the bid panel — sits next to the current price. */
.bid-panel .buy-now-tag {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 10px;
  padding: 3px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  color: var(--primary);
  font-size: 13px; font-weight: 600;
  vertical-align: middle;
  white-space: nowrap;
}

/* Buy-now button: visually distinct from the regular Place-bid CTA so
   users notice the extra option without it looking dangerous. */
.buy-now-form { margin-top: 8px; }
.cta-buy-now {
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(135deg, #f59e0b, #ef4444);
  color: #fff;
  padding: 10px 16px;
  font-weight: 700;
  font-size: 15px;
  border-radius: 6px;
  border: 0;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(245, 158, 11, 0.25);
  transition: transform 0.1s ease, box-shadow 0.15s ease;
}
.cta-buy-now:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(245, 158, 11, 0.35);
  background: linear-gradient(135deg, #f59e0b, #dc2626);
}

/* Compact corner badge on the index card. Anchored to the TOP-LEFT of the
   card so it always sits over the image (which is the left column on desktop
   and the top edge on mobile / narrow viewports). The price lives in the
   top-right of the body grid, so this corner can never collide with it
   regardless of density mode or viewport width. */
.card { position: relative; }
/* Corner-badge cluster anchored to the top-left of the cover image
   so the badges never overlap with the price column on the right.
   Wraps both Buy Now and Premium so they sit side-by-side when both
   apply, and stack onto a new line if the card is narrow. The flex
   container itself is the only absolute element — child badges
   flow naturally inside it. */
.card-badges {
  position: absolute;
  top: 8px; left: 8px;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  /* #208 — Constrain to the image-area width so BUY NOW + PREMIUM
     can't overflow horizontally into the body column and stomp the
     title's first letter. The width has to match ``.card img`` /
     ``.card .cover`` per density; the per-density overrides below
     re-set this so each layout stays in its lane. Default density
     (220px image) accommodates both badges side-by-side comfortably;
     medium / compact wrap to two rows when needed. */
  max-width: calc(220px - 16px);
  /* Don't intercept clicks — badges are decorative; the whole card
     is the click target. ``pointer-events: auto`` is re-applied to
     individual badges below so their tooltip still fires on hover. */
  pointer-events: none;
}
.cards.density-medium .card-badges { max-width: calc(170px - 16px); }
.cards.density-compact .card-badges { max-width: calc(120px - 16px); }
@media (max-width: 600px) {
  /* Mobile single-column stack — image becomes full-width, so the
     badge cluster can take more room too. */
  .card-badges { max-width: calc(100% - 16px); }
}

.card-buy-now-badge,
.card-premium-badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 8px;
  border-radius: 999px;
  font-size: 11px; font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  /* Re-enable hover so the ``title`` tooltip can fire — the parent
     ``.card-badges`` disabled pointer-events to keep the card click
     target uninterrupted. */
  pointer-events: auto;
  cursor: help;
}
.card-buy-now-badge {
  background: linear-gradient(135deg, #f59e0b, #ef4444);
  color: #fff;
}
.card-buy-now-badge .buy-now-icon { font-size: 12px; }

/* Phase 8.A — Premium badge. Gold/amber gradient matches the brand
   premium colour. ``★`` glyph carries the meaning at compact density
   where the text label collapses. */
.card-premium-badge {
  background: linear-gradient(135deg, #f3c557 0%, #d4a017 100%);
  color: #3a2c00;
}

/* Phase 8.A — Detail page premium star. Sits before the title in
   the auction detail header. Bigger than the listing card glyph
   (the detail page has more room and the star carries more visual
   weight as a "this is a featured auction" cue). Brand gold matches
   the listing badge so the user mentally connects the two. */
.detail-premium-star {
  display: inline-block;
  margin-right: 6px;
  color: #d4a017;
  font-size: 0.85em;
  vertical-align: 0.05em;
  cursor: help;
  /* Subtle drop shadow for that "embossed" feel without going
     overboard — the page background already does the contrast work. */
  text-shadow: 0 1px 0 rgba(212, 160, 23, 0.25);
}
@media (prefers-color-scheme: dark) {
  .detail-premium-star { color: #f3c557; }
}
.card-premium-badge .premium-icon { font-size: 12px; line-height: 1; }

/* Compact density — icons alone, same convention for both badges. */
.cards.density-compact .card-buy-now-badge .buy-now-text,
.cards.density-compact .card-premium-badge .premium-text { display: none; }

section + section { margin-top: 24px; }

/* Topbar theme toggle */
.theme-toggle {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 5px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  display: inline-flex; align-items: center; gap: 6px;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.theme-toggle:hover { border-color: var(--primary); color: var(--primary); }
.theme-toggle .theme-icon {
  display: inline-block; width: 14px; height: 14px;
  background: currentColor;
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  /* Default fallback (no data-theme-pref attribute set yet — only
     happens if the head script hasn't run): monitor / "system" icon. */
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='12' rx='2'/><line x1='8' y1='20' x2='16' y2='20'/><line x1='12' y1='16' x2='12' y2='20'/></svg>");
          mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='12' rx='2'/><line x1='8' y1='20' x2='16' y2='20'/><line x1='12' y1='16' x2='12' y2='20'/></svg>");
}
/* Three-state cycle (system → light → dark → system). The icon shows
   the CURRENT selection, not the next-click destination, matching the
   button label. pref="system" keeps the default monitor icon above. */
[data-theme-pref="light"] .theme-toggle .theme-icon {
  /* Sun */
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='black'><circle cx='12' cy='12' r='4'/><g stroke='black' stroke-width='2' stroke-linecap='round'><line x1='12' y1='2' x2='12' y2='5'/><line x1='12' y1='19' x2='12' y2='22'/><line x1='2' y1='12' x2='5' y2='12'/><line x1='19' y1='12' x2='22' y2='12'/><line x1='4.2' y1='4.2' x2='6.3' y2='6.3'/><line x1='17.7' y1='17.7' x2='19.8' y2='19.8'/><line x1='4.2' y1='19.8' x2='6.3' y2='17.7'/><line x1='17.7' y1='6.3' x2='19.8' y2='4.2'/></g></svg>");
          mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='black'><circle cx='12' cy='12' r='4'/><g stroke='black' stroke-width='2' stroke-linecap='round'><line x1='12' y1='2' x2='12' y2='5'/><line x1='12' y1='19' x2='12' y2='22'/><line x1='2' y1='12' x2='5' y2='12'/><line x1='19' y1='12' x2='22' y2='12'/><line x1='4.2' y1='4.2' x2='6.3' y2='6.3'/><line x1='17.7' y1='17.7' x2='19.8' y2='19.8'/><line x1='4.2' y1='19.8' x2='6.3' y2='17.7'/><line x1='17.7' y1='6.3' x2='19.8' y2='4.2'/></g></svg>");
}
[data-theme-pref="dark"] .theme-toggle .theme-icon {
  /* Moon */
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='black' d='M21 12.8A9 9 0 0 1 11.2 3a7 7 0 1 0 9.8 9.8z'/></svg>");
          mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='black' d='M21 12.8A9 9 0 0 1 11.2 3a7 7 0 1 0 9.8 9.8z'/></svg>");
}

/* Profile: at-a-glance stats panel */
.stats-panel { margin: 18px 0 28px; }
.stats-panel h2 { margin: 0 0 12px; font-size: 18px; color: var(--muted); font-weight: 600; }
.stat-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.stat-tile {
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 4px solid var(--info);
  border-radius: 8px;
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 4px;
  box-shadow: 0 1px 2px var(--shadow-soft);
  transition: box-shadow 0.15s ease, transform 0.05s ease, border-color 0.15s ease;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  position: relative;
}
.stat-tile:hover { box-shadow: 0 4px 12px var(--shadow-card); transform: translateY(-1px); }
.stat-tile:active { transform: translateY(0); }
.stat-tile:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.stat-tile::after {
  /* tiny chevron in the top-right corner so the click affordance is visible */
  content: "›";
  position: absolute; top: 10px; right: 14px;
  color: var(--muted); font-size: 18px; line-height: 1;
  transition: color 0.15s ease, transform 0.15s ease;
}
.stat-tile:hover::after { color: var(--primary); transform: translateX(2px); }

/* Anchor scrolling — keep section heading clear of the sticky topbar height */
section[id] { scroll-margin-top: 84px; }
section[id] > h2 { transition: color 0.4s ease; }
section[id]:target > h2 {
  color: var(--primary);
  animation: section-flash 1.2s ease-out 1;
}
@keyframes section-flash {
  0%   { background: var(--primary-soft); }
  100% { background: transparent; }
}
section[id]:target > h2 {
  padding: 4px 8px; margin-left: -8px; border-radius: 4px;
}
.stat-tile .stat-label { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 600; }
.stat-tile .stat-number { font-size: 30px; font-weight: 700; color: var(--fg); line-height: 1.1; }
.stat-tile .stat-sub { font-size: 13px; color: var(--muted); margin-top: 2px; }
.stat-tile .stat-amount { color: var(--accent); font-weight: 600; }
.stat-tile .stat-amount.stat-zero { color: var(--muted); font-weight: 500; }
.stat-tile.stat-sold     { border-left-color: var(--primary); }
.stat-tile.stat-listing  { border-left-color: var(--info); }
.stat-tile.stat-bidding  { border-left-color: var(--scheduled); }
.stat-tile.stat-won      { border-left-color: var(--live); }

/* Admin: small "Seller" checkbox-pill in the user table */
.seller-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  cursor: pointer; user-select: none;
}
.seller-toggle input { accent-color: var(--primary); cursor: pointer; }
.seller-toggle input:disabled { cursor: not-allowed; }
.seller-toggle span { font-size: 13px; color: var(--muted); }

/* ----- Admin auctions: tabs + search + table ----------------------------- */
/* Tabs render as standalone button-pills (not borderless underlined links)
   so the filter is visually unmistakable even on a stale stylesheet. Active
   tab gets the brand colour fill so it reads at a glance. */
.admin-auctions { margin-top: 24px; }
.admin-tabs {
  display: flex !important;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 16px 0;
  padding: 0;
  list-style: none;
}
.admin-tabs .admin-tab {
  display: inline-flex !important;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel);
  color: var(--text);
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.admin-tabs .admin-tab:hover {
  background: var(--card-hover, var(--panel));
  border-color: var(--card-hover-border, var(--border));
}
.admin-tabs .admin-tab.is-active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.admin-tabs .admin-tab.is-active:hover {
  background: var(--primary);
  border-color: var(--primary);
}
.admin-tabs .admin-tab .tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  border-radius: 999px;
  background: var(--border);
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
}
.admin-tabs .admin-tab.is-active .tab-count {
  background: rgba(255, 255, 255, 0.25);
  color: #fff;
}

/* ---------- Company filter pills (second row under status tabs) ----------
   Same pill geometry as the status tabs so the two rows visually rhyme,
   but each pill is tinted with the company's colour: a subtle left border
   in the inactive state, the full colour fill when selected. The colour
   palette mirrors .company-chip[data-color="..."] exactly. */
.admin-tabs-companies {
  margin-top: -4px;  /* tuck closer to the status row */
  margin-bottom: 12px;
}
.admin-tabs-companies .admin-tab {
  font-size: 13px;
  padding: 6px 14px;
}
/* The "All companies" pill has no data-color and stays in the neutral
   palette — it acts as the "clear company filter" button. */
.admin-tabs-companies .company-pill {
  position: relative;
}
/* Inactive company pill: small coloured dot before the code, thin coloured
   left border. Reads as "this is a company filter" without overwhelming
   the neutral status tabs above it. */
.admin-tabs-companies .company-pill[data-color]::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--brand-orange, #ff6a00);
  margin-right: 4px;
  flex-shrink: 0;
}
.admin-tabs-companies .company-pill[data-color="orange"]::before { background: #ff6a00; }
.admin-tabs-companies .company-pill[data-color="blue"]::before   { background: #1e6fdb; }
.admin-tabs-companies .company-pill[data-color="green"]::before  { background: #2a9d3f; }
.admin-tabs-companies .company-pill[data-color="purple"]::before { background: #7c3aed; }
.admin-tabs-companies .company-pill[data-color="red"]::before    { background: #dc2626; }
.admin-tabs-companies .company-pill[data-color="teal"]::before   { background: #0f9e9e; }
.admin-tabs-companies .company-pill[data-color="amber"]::before  { background: #d97706; }
.admin-tabs-companies .company-pill[data-color="pink"]::before   { background: #db2777; }
.admin-tabs-companies .company-pill[data-color="slate"]::before  { background: #475569; }
.admin-tabs-companies .company-pill[data-color="gray"]::before   { background: #6b7280; }

/* Active company pill: drop the dot, paint the whole pill in the company
   colour. Higher specificity than the generic .admin-tab.is-active rule
   so the company colour wins over --primary. */
.admin-tabs-companies .company-pill.is-active::before { display: none; }
.admin-tabs-companies .company-pill[data-color="orange"].is-active { background: #ff6a00; border-color: #ff6a00; }
.admin-tabs-companies .company-pill[data-color="blue"].is-active   { background: #1e6fdb; border-color: #1e6fdb; }
.admin-tabs-companies .company-pill[data-color="green"].is-active  { background: #2a9d3f; border-color: #2a9d3f; }
.admin-tabs-companies .company-pill[data-color="purple"].is-active { background: #7c3aed; border-color: #7c3aed; }
.admin-tabs-companies .company-pill[data-color="red"].is-active    { background: #dc2626; border-color: #dc2626; }
.admin-tabs-companies .company-pill[data-color="teal"].is-active   { background: #0f9e9e; border-color: #0f9e9e; }
.admin-tabs-companies .company-pill[data-color="amber"].is-active  { background: #d97706; border-color: #d97706; }
.admin-tabs-companies .company-pill[data-color="pink"].is-active   { background: #db2777; border-color: #db2777; }
.admin-tabs-companies .company-pill[data-color="slate"].is-active  { background: #475569; border-color: #475569; }
.admin-tabs-companies .company-pill[data-color="gray"].is-active   { background: #6b7280; border-color: #6b7280; }
/* Keep the same colour on hover when active (no muddy --primary takeover). */
.admin-tabs-companies .company-pill[data-color].is-active:hover {
  filter: brightness(1.05);
}

/* Chip-as-shortcut link in the Title cell. Wraps the chip in an <a>, kills
   default underline, gives a subtle scale on hover so it reads as a target.
   The chip itself keeps its existing colour styling — we just decorate the
   anchor around it. */
.company-chip-link {
  display: inline-block;
  text-decoration: none !important;
}
.company-chip-link:hover .company-chip {
  filter: brightness(1.1);
  transform: scale(1.04);
}
.company-chip-link .company-chip {
  transition: filter 0.1s ease, transform 0.1s ease;
  cursor: pointer;
}

/* ---------- Country filter pills (third row under company filter) ----------
   Visually subordinate to the company row above it: same pill geometry but
   without per-pill brand colours (countries have no brand). The flag emoji
   carries enough visual identity on its own. */
.admin-tabs-countries {
  margin-top: -4px;
  margin-bottom: 12px;
}
.admin-tabs-countries .admin-tab {
  font-size: 13px;
  padding: 6px 14px;
}
.admin-tabs-countries .country-pill {
  position: relative;
  letter-spacing: 0.02em;
}

/* Country chip rendered next to the company chip in the Title cell of
   each row. Smaller and quieter than the company chip — it's a
   secondary breadcrumb, not the primary identity. Same shortcut-link
   pattern as .company-chip-link so clicking jumps to the country
   filter. */
.country-chip-link {
  display: inline-block;
  text-decoration: none !important;
  margin-left: 4px;
}
.country-chip-link:hover .country-chip {
  filter: brightness(1.1);
  transform: scale(1.04);
}
.country-chip {
  display: inline-block;
  padding: 1px 6px;
  border: 1px solid var(--border, #d4d4d8);
  border-radius: 10px;
  background: var(--surface-2, #f4f4f5);
  color: var(--text-muted, #52525b);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.4;
  transition: filter 0.1s ease, transform 0.1s ease;
  cursor: pointer;
  vertical-align: middle;
}

/* ---------- Public country filter (index/home) ----------
   Sits between the page heading and the cards grid. Visually quieter
   than the admin pill row (no per-pill brand colours, smaller
   typography) — this is end-user UI, not power-user dashboard. */
.filter-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 4px 0 16px;
}
.filter-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border: 1px solid var(--border, #d4d4d8);
  border-radius: 999px;
  background: var(--surface, #ffffff);
  color: var(--text, #18181b);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
  text-decoration: none;
  letter-spacing: 0.02em;
  transition: background 0.1s ease, border-color 0.1s ease, color 0.1s ease;
}
.filter-pill:hover {
  background: var(--surface-2, #f4f4f5);
}
.filter-pill.is-active {
  background: var(--primary, #ff6a00);
  border-color: var(--primary, #ff6a00);
  color: #ffffff;
}
.filter-pill .pill-count {
  display: inline-block;
  padding: 0 6px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.06);
  color: var(--text-muted, #52525b);
  font-size: 11px;
  font-weight: 600;
}
.filter-pill.is-active .pill-count {
  background: rgba(255, 255, 255, 0.25);
  color: #ffffff;
}

/* Per-card country chip rendered inline next to the auction title.
   Lighter and smaller than the title itself; a glance-readable
   identifier of which country pool the listing belongs to. */
.card-country-chip {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px solid var(--border, #d4d4d8);
  border-radius: 10px;
  background: var(--surface-2, #f4f4f5);
  color: var(--text-muted, #52525b);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.4;
  vertical-align: middle;
  letter-spacing: 0.02em;
}

/* Phase 8.A — Admin-set market-price reference subtitle on listing
   cards. Sits right under the bold current price as a small, muted
   line — visible enough to read at a glance, quiet enough not to
   fight with the price for attention. Hidden by default; the
   ``{% if a.market_price_cents %}`` guard in the template ensures
   the span is only emitted when set. */
.price-market {
  display: block;
  font-size: 11px;
  font-weight: 400;
  color: var(--muted);
  margin-top: 2px;
  letter-spacing: 0.01em;
  text-transform: lowercase;
  font-variant-numeric: tabular-nums;
}

/* Admin-only market-price form field — same shape as starting price
   so the form feels uniform. Width capped because typical values
   fit in 5-6 digits and we don't want a giant input next to the
   small Premium dropdown. */
.market-price-field {
  display: block;
  max-width: 280px;
  margin-top: 12px;
}
.market-price-field input {
  width: 100%;
}

/* Phase 8.A — Condition + Premium two-column row on the New Auction
   form. Condition takes the lion's share (it's the user-facing field),
   Premium is a narrow Yes/No on the right. Both selects keep the
   shared form styling. The row collapses to single-column on narrow
   viewports so the picker stays usable on mobile. */
.condition-premium-row {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  margin-bottom: 4px;
}
.condition-premium-row .condition-field { flex: 1 1 auto; min-width: 0; }
.condition-premium-row .premium-field { flex: 0 0 110px; }
.condition-premium-row label {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.condition-premium-row select {
  width: 100%;
}
@media (max-width: 540px) {
  .condition-premium-row { flex-direction: column; align-items: stretch; }
  .condition-premium-row .premium-field { flex: 1 1 auto; }
}

/* Phase 8.B — Multi-win cluster pick callout. Same shape as the
   cancel-win-callout but tinted gold to match the premium chip,
   signalling positive "wrap this up" intent. */
.cluster-callout {
  border-color: rgba(212, 160, 23, 0.45);
  background: linear-gradient(
    180deg,
    rgba(212, 160, 23, 0.12) 0%,
    var(--panel) 100%
  );
}
.cluster-callout h2 {
  margin: 0 0 4px;
  font-size: 1.05rem;
  color: var(--text, inherit);
}
.cluster-siblings {
  margin: 4px 0 12px;
  padding-left: 18px;
  font-size: 0.92rem;
  color: var(--muted);
}
.cluster-siblings li { margin: 2px 0; }
.cluster-siblings a { color: var(--text, inherit); }

/* Phase 8.A — Premium chip. Same pill shape as the country chip but
   in brand gold/amber to read as "elevated" without fighting the
   accent orange used for price. Sits inline next to the title on the
   listing card and on the auction detail header. */
.premium-chip {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 8px;
  border: 1px solid rgba(212, 160, 23, 0.45);
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(255, 200, 50, 0.18) 0%, rgba(255, 200, 50, 0.06) 100%);
  color: #b88810;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.4;
  vertical-align: middle;
  letter-spacing: 0.02em;
  /* Star glyph stays gold in dark mode too — overriding the body fg
     here because the chip is supposed to pop regardless of theme. */
}
@media (prefers-color-scheme: dark) {
  .premium-chip {
    color: #f3c557;
    border-color: rgba(243, 197, 87, 0.35);
  }
}
.premium-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  font-weight: 500;
}
.premium-toggle input[type="checkbox"] {
  width: 16px;
  height: 16px;
  cursor: pointer;
}

/* Phase 7b — Editor's pick pin. A leading 📌 next to the title makes
   picked auctions scannable down the listing column without adding a
   colour swatch that'd fight with the country chip / status badge.
   Slightly larger than the body type so the pin reads as deliberate
   rather than emoji-noise. */
.editors-pick-pin {
  display: inline-block;
  margin-right: 4px;
  font-size: 1.05em;
  line-height: 1;
  vertical-align: -0.05em;
  /* Tiny rotation echoes the way pins actually sit on a corkboard —
     subtle enough that you don't notice it consciously, just enough
     that the icon doesn't feel rubber-stamped. */
  transform: rotate(-12deg);
  transform-origin: 50% 70%;
}

/* Phase 8 — "Done" button. Mirrors the cancel-win-callout structure
   (background = gradient from a tinted top edge into --panel, so light
   and dark themes both work via the existing CSS variables) but uses
   a green tint instead of the red one, reading as "wrap up / commit"
   rather than "unwind". The container reuses the .seller-actions
   base styling for spacing + border-radius. */
.done-callout {
  border-color: rgba(47, 158, 68, 0.35);
  background: linear-gradient(
    180deg,
    rgba(47, 158, 68, 0.10) 0%,
    var(--panel) 100%
  );
}
.done-callout h2 {
  margin: 0 0 4px;
  font-size: 1.05rem;
  /* Defensive — the seller-actions H2 inherits its colour from the
     panel context; spelling it out here so the header doesn't slip
     into muted on dark mode. */
  color: var(--text, inherit);
}
.done-callout p {
  margin: 0 0 12px;
}
.done-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.done-button-icon {
  display: inline-block;
  font-weight: 700;
  /* Render the ✓ in a slightly larger size so it carries the row
     visually — it's the same checkmark people scan on todos. */
  font-size: 1.1em;
  line-height: 1;
}
.done-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-right: 6px;
  border-radius: 50%;
  background: #2f9e44;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  vertical-align: middle;
}
.done-archived-hint {
  /* Quiet confirmation row for sellers viewing an already-done auction.
     No box, no buttons — just the chip + a short text. */
  padding: 6px 0;
  margin: 8px 0 0;
}
.done-reopen {
  /* Admin reopen — dashed border + neutral panel background so the
     admin recognises this as a restorative override rather than the
     canonical positive flow. Centred content because the section has
     just a one-line status + a small button — left-aligning it leaves
     the right two-thirds of the box looking empty (Petr's report). */
  border-color: var(--muted);
  border-style: dashed;
  background: var(--panel);
  text-align: center;
  padding: 12px 16px;
}
.done-reopen .muted {
  display: inline-flex;
  align-items: center;
  margin: 0 0 8px;
}
.done-reopen .done-reopen-form {
  /* Inline-block so the button respects parent text-align: center
     instead of stretching to full width. */
  display: inline-block;
  margin: 0;
}

.admin-search {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 16px;
}
.admin-search input[type="search"] {
  flex: 1;
  min-width: 200px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
}
.admin-search input[type="search"]::placeholder { color: var(--muted); }

/* Numeric columns (bids, price) right-aligned for visual scanning down. */
.admin-auction-table th.num,
.admin-auction-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.admin-auction-table small.muted { font-size: 11px; }
/* Date column (7th cell) — keep it on one line. Title / seller / winner
   stay free to wrap if their text is long. */
.admin-auction-table td:nth-child(7) { white-space: nowrap; }
/* Slightly tighter cell padding gives the action column a bit more
   room without the row feeling cramped vertically. */
.admin-auction-table th,
.admin-auction-table td { padding: 8px 10px; }

.pager { margin-top: 16px; text-align: center; }
.empty-state { padding: 24px; text-align: center; }

/* ---------- Admin quicklinks + exports page ----------
   Quicklinks: the strip under "Admin dashboard" with Settings · Exports.
   Subtle, in-line, separated by a dot — not nav-bar fanfare. */
.admin-quicklinks {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 4px 0 20px 0;
  color: var(--muted);
  font-size: 14px;
}
.admin-quicklinks .dot { color: var(--muted); }
.admin-quicklinks a { color: var(--text); text-decoration: none; }
.admin-quicklinks a:hover { text-decoration: underline; }

/* Exports page: each format gets its own "card". Borrowed visual style
   from the rest of the admin panels — bordered, padded, rounded. */
.exports-card {
  margin: 16px 0;
  padding: 20px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
}
.exports-card h2 {
  margin: 0 0 6px 0;
  font-size: 18px;
}
.exports-card > p.muted {
  margin: 0 0 16px 0;
}
.exports-form { display: flex; flex-direction: column; gap: 14px; }
.exports-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}
.exports-row label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--muted);
}
.exports-row input[type="date"],
.exports-row select {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  min-width: 160px;
}
.exports-actions { display: flex; gap: 8px; }

/* ---------- Company entity (admin-only) ---------- */
/* Per-company pill rendered inline on admin auction rows so the owning
   entity is scannable at a glance. Colour is driven by `data-color` —
   the token comes from companies.color_token (curated palette, validated
   server-side; see COMPANY_COLOR_TOKENS in routers/admin.py). The base
   rule keeps shape + typography; the [data-color] rules below paint
   each token. Missing/unknown token falls through to the brand-orange
   default so a corrupt row still renders. */
.company-chip {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--brand-orange, #ff6a00);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.6;
  vertical-align: middle;
}
/* Curated palette. Every shade is dark enough that white 700-weight text
   stays AA-readable at 11px. Picks are deliberately spaced around the
   wheel so two adjacent companies in a table never look identical. */
.company-chip[data-color="orange"] { background: #ff6a00; }
.company-chip[data-color="blue"]   { background: #1e6fdb; }
.company-chip[data-color="green"]  { background: #2a9d3f; }
.company-chip[data-color="purple"] { background: #7c3aed; }
.company-chip[data-color="red"]    { background: #dc2626; }
.company-chip[data-color="teal"]   { background: #0f9e9e; }
.company-chip[data-color="amber"]  { background: #d97706; }
.company-chip[data-color="pink"]   { background: #db2777; }
.company-chip[data-color="slate"]  { background: #475569; }
.company-chip[data-color="gray"]   { background: #6b7280; }

/* ---------- Colour picker (admin/companies) ---------- */
/* Native radio buttons styled as round swatches so the picker stays
   keyboard-navigable (Tab to enter, arrows to switch, Space to pick).
   We hide the native input visually but keep it in the layout tree,
   and the `:checked + .color-swatch-dot` rule paints the selection
   ring. Same token list as `.company-chip[data-color="..."]`. */
.color-picker {
  border: 0;
  margin: 12px 0 8px;
  padding: 0;
}
.color-picker legend {
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 6px;
  padding: 0;
}
.color-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.color-swatches-compact { gap: 4px; }
.color-swatch {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  /* Reset label padding so the click target equals the swatch. */
  padding: 0;
}
.color-swatch input[type="radio"] {
  /* Visually hidden but still in the layout/focus tree. */
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  border: 0;
  clip: rect(0 0 0 0);
  overflow: hidden;
  white-space: nowrap;
}
.color-swatch-dot {
  display: inline-block;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #ccc;
  border: 2px solid transparent;
  box-shadow: 0 0 0 1px var(--border) inset;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.color-swatches-compact .color-swatch-dot { width: 18px; height: 18px; }
.color-swatch:hover .color-swatch-dot {
  transform: scale(1.08);
}
.color-swatch input[type="radio"]:checked + .color-swatch-dot {
  /* Outer ring uses the page text colour so the selection reads in both
     themes — black on light, white on dark. */
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--text);
}
.color-swatch input[type="radio"]:focus-visible + .color-swatch-dot {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
/* Paint each swatch with its token colour. Single source of truth: the
   same palette as .company-chip[data-color="..."]. */
.color-swatch[data-color="orange"] .color-swatch-dot { background: #ff6a00; }
.color-swatch[data-color="blue"]   .color-swatch-dot { background: #1e6fdb; }
.color-swatch[data-color="green"]  .color-swatch-dot { background: #2a9d3f; }
.color-swatch[data-color="purple"] .color-swatch-dot { background: #7c3aed; }
.color-swatch[data-color="red"]    .color-swatch-dot { background: #dc2626; }
.color-swatch[data-color="teal"]   .color-swatch-dot { background: #0f9e9e; }
.color-swatch[data-color="amber"]  .color-swatch-dot { background: #d97706; }
.color-swatch[data-color="pink"]   .color-swatch-dot { background: #db2777; }
.color-swatch[data-color="slate"]  .color-swatch-dot { background: #475569; }
.color-swatch[data-color="gray"]   .color-swatch-dot { background: #6b7280; }

/* Code input in /admin/companies mirrors the chip from /admin/auctions —
   same colour palette, same typography. Stays editable: caret/selection
   show on focus, and the focus ring keeps a high-contrast outline so
   the field remains obviously interactive. Palette mirrors
   .company-chip[data-color="..."] above (single source of truth visually).
   Selectors are deliberately specific (.admin-companies-table input.…)
   so they win over the generic .admin-companies-table input[type="text"]
   rule above without resorting to !important. */
.admin-companies-table input.company-code-input {
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #fff;
  border: 1px solid transparent;
  border-radius: 6px;
  /* Fallback if data-color is missing: brand orange — same as the chip default. */
  background: var(--brand-orange, #ff6a00);
}
.admin-companies-table input.company-code-input::placeholder {
  color: rgba(255, 255, 255, 0.75);
}
.admin-companies-table input.company-code-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Slightly dim inactive companies — matches the row dimming above. */
.admin-companies-table tr.is-inactive input.company-code-input { opacity: 0.65; }

.admin-companies-table input.company-code-input[data-color="orange"] { background: #ff6a00; }
.admin-companies-table input.company-code-input[data-color="blue"]   { background: #1e6fdb; }
.admin-companies-table input.company-code-input[data-color="green"]  { background: #2a9d3f; }
.admin-companies-table input.company-code-input[data-color="purple"] { background: #7c3aed; }
.admin-companies-table input.company-code-input[data-color="red"]    { background: #dc2626; }
.admin-companies-table input.company-code-input[data-color="teal"]   { background: #0f9e9e; }
.admin-companies-table input.company-code-input[data-color="amber"]  { background: #d97706; }
.admin-companies-table input.company-code-input[data-color="pink"]   { background: #db2777; }
.admin-companies-table input.company-code-input[data-color="slate"]  { background: #475569; }
.admin-companies-table input.company-code-input[data-color="gray"]   { background: #6b7280; }

/* Standard "visually hidden but available to AT" utility — used by the
   swatch label so screen readers announce the colour name. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
/* Inactive companies in the admin list are dimmed but still legible — they
   keep showing up because old auctions may still reference them. */
.admin-companies-table { width: 100%; border-collapse: collapse; }
.admin-companies-table th,
.admin-companies-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
}
.admin-companies-table tr.is-inactive td {
  color: var(--muted);
}
.admin-companies-table input[type="text"] {
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  min-width: 120px;
}
.companies-form .form-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: end;
  margin-bottom: 12px;
}
.companies-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }
.companies-form input[type="text"] {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  min-width: 200px;
}
.badge-inactive { background: var(--muted); color: #fff; padding: 1px 8px; border-radius: 999px; font-size: 11px; }
.badge-active { background: #2a9d3f; color: #fff; padding: 1px 8px; border-radius: 999px; font-size: 11px; }

/* ---------- Admin action cells (inline buttons) ---------- */
/* Every admin row that ends in a stack of action buttons gets the same
   horizontal flex treatment, so the buttons sit side-by-side on one
   line whenever the column gives them room. They only wrap when the
   column genuinely can't fit them (narrow viewport / many buttons).
   `nowrap` on the buttons themselves prevents mid-word breaks like
   "Toggle\nadmin" inside a too-narrow button.

   With the fluid admin container we no longer need to shrink the buttons
   themselves — we just keep them on one line with `white-space: nowrap`
   and let the row grow horizontally. The `flex-wrap` is a safety net for
   genuinely tiny viewports (it kicks in below ~700px). */
td.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  white-space: normal;
}
td.actions form { margin: 0; display: inline-flex; }
td.actions button,
td.actions .cta,
td.actions a.cta {
  white-space: nowrap;
}

/* Subtle red outline for destructive actions in admin tables.
   We keep the same bordered shape as cta-secondary so all admin
   row buttons sit on the same visual baseline; only the colour cue
   tells you which one to think twice about. */
.cta-danger {
  background: transparent;
  color: #e0473a;
  border: 1px solid #e0473a;
}
.cta-danger:hover {
  background: rgba(224, 71, 58, 0.08);
  border-color: #c93b30;
  color: #c93b30;
}

/* Extra-small variant for inline admin row actions where a full-size CTA
   would dominate the cell. Used by the payment-reset button next to the
   payment chip in the Winner column — same shape and colour as the
   parent CTA, just less weight. */
.cta-xs {
  padding: 2px 8px;
  font-size: 0.78rem;
  line-height: 1.4;
}

/* Two-button payment picker. Buttons sit side-by-side on a wide row and
   stack on narrow screens. The form itself is just a flex container so
   each button keeps its own POST submit semantics (one form, two named
   submits sharing a single endpoint). */
.payment-method-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 8px;
}
.payment-method-form .cta { flex: 0 0 auto; }
@media (max-width: 540px) {
  .payment-method-form .cta { flex: 1 1 100%; }
}

/* QR payment confirmation panel. Renders below the "Payment method:
   QR" locked-chip after the winner has picked QR. Layout: SVG on the
   left, definition list (IBAN / amount / VS) on the right, hint
   sentence underneath. Stacks vertically on narrow screens so the QR
   stays scannably large. The SVG sizes itself to its container; we
   cap its width so it doesn't blow out the panel on huge monitors. */
.qr-payment-panel {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  align-items: flex-start;
  margin-top: 14px;
  padding: 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.qr-payment-image {
  flex: 0 0 auto;
  max-width: 260px;
  /* The SVG ships with a tight 4-module quiet zone; we keep a tiny
     extra padding so the dark modules don't visually touch the card
     border in dark mode. */
  padding: 4px;
  background: #ffffff;
  border-radius: 8px;
}
.qr-payment-image svg {
  display: block;
  width: 100%;
  height: auto;
}
.qr-payment-meta {
  flex: 1 1 280px;
  margin: 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 14px;
  row-gap: 6px;
  font-size: 0.95rem;
}
.qr-payment-meta dt {
  color: var(--muted);
  font-weight: 500;
}
.qr-payment-meta dd {
  margin: 0;
  word-break: break-all;
}
.qr-payment-meta code {
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.95em;
}
.qr-payment-hint {
  flex: 1 1 100%;
  margin: 4px 0 0 0;
  font-size: 0.9rem;
}

/* ---------- "Bidding hasn't opened yet" notice on /auctions/<id> ---------- */
/* Shown in place of the bid form when the auction's status is
   ``scheduled``. Re-uses the existing .flash.info wash for colour, but
   adds vertical rhythm between the bold title and the paragraph so it
   reads as a small announcement card rather than a one-line toast. */
.bid-scheduled-notice {
  margin: 8px 0 0 0;
}
.bid-scheduled-notice strong {
  display: block;
  margin-bottom: 4px;
  font-size: 1rem;
}
.bid-scheduled-notice p {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.4;
}

/* ---------- Inline Company / IBAN row on /auctions/new ---------- */
/* The IBAN input used to live in its own full-width panel under the
   Company picker, with display toggled between hidden + visible based
   on whether the user picked the "Personal" company. That layout was
   bulky (a single-input "card" eats vertical space and reads as more
   important than it is) and the field didn't visually correspond to
   the picker that controlled it.
   The current layout pairs Company + IBAN side-by-side in a 2:1 grid,
   with the IBAN input always visible. The JS in auction_form.html
   adds one of three state classes to .iban-field on each change:
     * .is-company         — disabled, shows the company's IBAN, muted
     * .is-company-missing — disabled + empty, amber-tinted warning
     * .is-personal        — editable + required, accent tint
   The states map to the same hint text that updates below the row. */

/* Strict 50/50 split — Title/Asset-tag and S/N/FO rows above use
   .row's auto-fit grid which can drift when the row only has two
   children (the picker ends up wider than the IBAN because the
   select's intrinsic min-width is larger). We pin the columns
   explicitly here so the Company select matches the width of every
   other field on the form. The IBAN <label> historically also had
   an inline `style="flex:1"` left over from the flex era — that
   doesn't do anything inside a grid, but it's also been removed in
   the template. See Task #132. */
.company-iban-row {
  grid-template-columns: 1fr 1fr !important;
  align-items: end;
}

/* The IBAN label uses .iban-field as its hook. Border + padding only
   become visible in the personal/missing states via the modifiers
   below — in the default .is-company state we want the field to feel
   quiet and read-only so it doesn't compete with the picker. */
.iban-field {
  position: relative;
  border-radius: 6px;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.iban-field input[type="text"] {
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  letter-spacing: 0.04em;
  background: #ffffff;
  color: #1f1d1b;
}
/* Disabled appearance — muted text on a very-light-gray field. We
   anchor every state in this section to a WHITE base (rather than
   var(--panel)) because the surrounding form.stacked inputs are
   pinned to white-on-dark in dark mode (see the form.stacked rule
   above); if the IBAN field used the themed --panel it ended up
   near-black next to its white siblings (Task #133 follow-up). */
.iban-field input[type="text"]:disabled {
  background: color-mix(in oklab, #1f1d1b 5%, #ffffff);
  color: #6b6661;
  -webkit-text-fill-color: #6b6661;
  opacity: 1;                /* override Safari's faded disabled look */
  cursor: not-allowed;
}
/* Company-with-IBAN: quiet, read-only. No extra chrome — the disabled
   styling above is enough; this rule is here so future tweaks have a
   single hook. */
.iban-field.is-company input[type="text"]:disabled {
  /* inherits the muted look above */
}
/* Company-without-IBAN: amber accent on the input edge to nudge the
   user toward "ask an admin to set this". We don't enable the input
   because the missing IBAN belongs to the company, not the seller. */
.iban-field.is-company-missing input[type="text"]:disabled {
  border-color: color-mix(in oklab, #f59e0b 50%, var(--border));
  background: color-mix(in oklab, #f59e0b 10%, #ffffff);
}
/* Personal: editable + required. Soft accent tint on the input so it
   reads as "this is the live one" without shouting. */
.iban-field.is-personal input[type="text"] {
  border-color: color-mix(in oklab, var(--accent) 45%, var(--border));
  background: color-mix(in oklab, var(--accent) 5%, #ffffff);
  color: #1f1d1b;
}

/* ---------- Country picker (mirrors .iban-field) ---------- */
/* Same three-state pattern as IBAN above, applied to the country
   <select> instead of an <input type="text">. The select is always
   visible; the wrapping label.country-field gets one of
   .is-company / .is-company-missing / .is-personal applied by the
   JS in auction_form.html on every Company-picker change. */
.country-field {
  position: relative;
  border-radius: 6px;
  transition: background-color 120ms ease, border-color 120ms ease;
}
/* Anchor base background to white so the rule still reads as a
   form input in dark mode where form.stacked pins inputs to
   white-on-dark (same rationale as .iban-field above — Task #133). */
.country-field select {
  background: #ffffff;
  color: #1f1d1b;
}
.country-field select:disabled {
  background: color-mix(in oklab, #1f1d1b 5%, #ffffff);
  color: #6b6661;
  -webkit-text-fill-color: #6b6661;
  opacity: 1;
  cursor: not-allowed;
}
/* Company-with-country: quiet read-only. The disabled treatment above
   carries it; this rule is a hook for future tweaks. */
.country-field.is-company select:disabled {
  /* inherits the muted look above */
}
/* Company-without-country: same amber accent as the matching IBAN
   state so the two warnings read together. */
.country-field.is-company-missing select:disabled {
  border-color: color-mix(in oklab, #f59e0b 50%, var(--border));
  background: color-mix(in oklab, #f59e0b 10%, #ffffff);
}
/* Personal: editable + required. Soft accent tint matches the IBAN
   personal state so the two "live" fields visually pair up. */
.country-field.is-personal select {
  border-color: color-mix(in oklab, var(--accent) 45%, var(--border));
  background: color-mix(in oklab, var(--accent) 5%, #ffffff);
  color: #1f1d1b;
}

/* ---------- Pickup location row (mirrors .country-field) ---------- */
/* Two sibling fields: the dropdown holds the city / "Anywhere" preset,
   the text input holds optional additional detail. Both share the
   three-state visual language with .country-field above so the rows
   read as a connected block — when the country isn't resolved yet,
   both the country selector and the pickup row light up the same
   amber warning state, giving the seller a single obvious "pick a
   company" instruction (#206). */
.pickup-preset-field,
.pickup-input-field {
  position: relative;
  border-radius: 6px;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.pickup-preset-field select,
.pickup-input-field input[type="text"] {
  background: #ffffff;
  color: #1f1d1b;
}
.pickup-preset-field select:disabled,
.pickup-input-field input[type="text"]:disabled {
  background: color-mix(in oklab, #1f1d1b 5%, #ffffff);
  color: #6b6661;
  -webkit-text-fill-color: #6b6661;
  opacity: 1;
  cursor: not-allowed;
}
/* No company / company-without-country: amber warning so the user
   sees at a glance that this needs a company pick before it's
   editable. Matches .country-field.is-company-missing exactly. */
.pickup-preset-field.is-company-missing select:disabled,
.pickup-input-field.is-company-missing input[type="text"]:disabled {
  border-color: color-mix(in oklab, #f59e0b 50%, var(--border));
  background: color-mix(in oklab, #f59e0b 10%, #ffffff);
}
/* Personal sale: soft accent tint, editable. */
.pickup-preset-field.is-personal select,
.pickup-input-field.is-personal input[type="text"] {
  border-color: color-mix(in oklab, var(--accent) 45%, var(--border));
  background: color-mix(in oklab, var(--accent) 5%, #ffffff);
  color: #1f1d1b;
}
/* Company picked + country known: plain white-on-dark, no tint. The
   default ``.pickup-preset-field select`` rule above already covers
   this; the empty selector exists as a hook for future tweaks. */
.pickup-preset-field.is-company select,
.pickup-input-field.is-company input[type="text"] {
  /* inherits the base look */
}

/* ---------- Personal-sale payment panel on /auctions/<id> ---------- */
/* Replaces the salary/invoice/qr picker for personal sales. Same outer
   chrome as `.relist-callout` (the post-win callout) but tinted toward
   the QR/payment hue so it visually groups with the IBAN + QR block
   underneath rather than the cancellation block above. */
.personal-payment-panel h2 {
  margin: 0 0 6px 0;
  font-size: 1.05rem;
}
/* Text-only variant for non-CZ IBANs: no QR image, just the IBAN /
   amount / VS table. Drop the flex column reservation that the QR
   variant uses so the table can take the full width. */
.personal-payment-textonly {
  display: block;
}
.personal-payment-textonly .qr-payment-meta {
  margin: 0;
}

/* Short sequential auction number, shown next to the title on the
   detail page. Small, muted, mono — the visual rank of a serial number
   so it sits behind the title without competing for the eye. The
   `#` is in the markup so screen readers say "hash twelve" rather
   than the literal number; matches how people write "#1234" in chat. */
.auction-number {
  margin-left: 8px;
  padding: 2px 8px;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.7em;
  font-weight: 500;
  color: var(--muted);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  vertical-align: middle;
  white-space: nowrap;
}

/* ---------- Admin pages: fluid container ---------- */
/* The global main { max-width: 1080px } is right for the public auction
   grid (long pages of cards read better with a comfy reading column),
   but the admin shell is a dense data view that benefits from every
   pixel of horizontal real estate. Override on admin pages only.
   `clamp(...)` gives narrow viewports a sane 20px gutter and grows the
   side padding gracefully on huge monitors without ever pegging the
   content to a fixed max width. */
body.admin-shell-body main {
  max-width: none;
  padding: 24px clamp(20px, 3vw, 56px);
}

/* ---------- Admin sidebar layout ---------- */
/* Two-column shell used by every /admin/* page. Left rail is a fixed-width
   category list; right pane carries the actual content. Collapses to a
   single column on narrow viewports — the left rail becomes a horizontal
   strip so admins don't have to scroll past it to reach the content. */
.admin-shell {
  display: grid;
  grid-template-columns: 188px 1fr;
  gap: 20px;
  align-items: start;
}
.admin-sidebar {
  position: sticky;
  top: 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 12px;
}
.admin-sidebar-title {
  margin: 0 0 8px 4px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.admin-sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.admin-sidebar-link {
  display: block;
  padding: 8px 12px;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  line-height: 1.3;
}
.admin-sidebar-link:hover { background: var(--bg); }
.admin-sidebar-link.is-active {
  background: var(--brand-orange, #ff6a00);
  color: #fff;
  font-weight: 600;
}
.admin-content { min-width: 0; }   /* allow table overflow scroll inside grid cell */
.admin-content > h1:first-child { margin-top: 0; }

@media (max-width: 760px) {
  .admin-shell { grid-template-columns: 1fr; }
  .admin-sidebar { position: static; }
  .admin-sidebar-nav { flex-direction: row; flex-wrap: wrap; }
  .admin-sidebar-link { flex: 1 1 auto; text-align: center; min-width: 100px; }
}

/* ---------- Admin overview stat tiles ---------- */
/* Each tile is a link straight into the relevant section so the overview
   also works as a launcher. Bigger minmax so tiles never get squashed to
   the point of being unreadable; hover lifts + shadows to advertise the
   click affordance more clearly. Generous internal padding gives the
   value figure room to breathe — these are the page's hero numbers. */
.admin-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 18px;
  margin: 28px 0 36px;
}
.admin-tile {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 14px;
  min-height: 132px;
  padding: 20px 22px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
  color: var(--text);
  text-decoration: none;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.02);
  transition: transform 0.12s ease-out,
              border-color 0.12s ease-out,
              box-shadow 0.12s ease-out;
}
.admin-tile:hover {
  transform: translateY(-2px);
  border-color: var(--brand-orange, #ff6a00);
  box-shadow: 0 6px 18px rgba(255, 106, 0, 0.12);
}
.admin-tile-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.admin-tile-value {
  font-size: 38px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text);
}
.admin-tile-sub {
  font-size: 13px;
  color: var(--muted);
  line-height: 1.4;
}

/* Tighter on small screens — keep the breathing room but stop the
   gigantic value font from dominating the card. */
@media (max-width: 520px) {
  .admin-tiles {
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 12px;
  }
  .admin-tile {
    min-height: 108px;
    padding: 16px 18px;
    gap: 10px;
  }
  .admin-tile-value { font-size: 30px; }
}

/* ---------- Mobile cards for the auctions admin table ---------- */
/* Below ~880px the 8-column table is unreadable on narrow viewports.
   Instead of horizontal scroll, we reflow each <tr> as a stacked card,
   prefixing every cell with the column label (pulled from data-label
   on the <td>). The HTML doesn't change — only the visual layout does. */
@media (max-width: 880px) {
  .admin-auction-table,
  .admin-auction-table thead,
  .admin-auction-table tbody,
  .admin-auction-table tr,
  .admin-auction-table td {
    display: block;
    width: 100%;
  }
  /* The header row would just look like noise once cells are stacked.
     Off-screen instead of display:none so screen readers still announce
     it for users navigating row by row. */
  .admin-auction-table thead {
    position: absolute;
    left: -9999px;
    top: -9999px;
  }
  .admin-auction-table tr {
    margin-bottom: 14px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--panel);
  }
  .admin-auction-table tr + tr { margin-top: 0; }
  .admin-auction-table td {
    border: none;
    padding: 6px 0;
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 10px;
    align-items: baseline;
    text-align: left;
  }
  .admin-auction-table td::before {
    content: attr(data-label);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
    align-self: center;
  }
  /* Title cell gets visual emphasis as the card's "headline". */
  .admin-auction-table td:first-child {
    grid-template-columns: 1fr;
    padding: 4px 0 10px;
    border-bottom: 1px dashed var(--border);
    margin-bottom: 6px;
  }
  .admin-auction-table td:first-child::before { display: none; }
  .admin-auction-table td:first-child a {
    font-size: 16px;
    font-weight: 600;
  }
  /* num cells should still right-align values on mobile. */
  .admin-auction-table td.num {
    justify-items: end;
    text-align: right;
  }
  .admin-auction-table td.num > *:not(::before) { justify-self: end; }
  /* Actions cell: wrap buttons onto multiple lines without the label
     stealing valuable width. */
  .admin-auction-table td.actions {
    grid-template-columns: 1fr;
    padding-top: 10px;
    border-top: 1px dashed var(--border);
    margin-top: 6px;
  }
  .admin-auction-table td.actions::before {
    display: block;
    margin-bottom: 6px;
  }
  .admin-auction-table td.actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .admin-auction-table td.actions::before {
    flex-basis: 100%;
  }
  /* Hide the pager pseudo-row "—" placeholder if winner empty. */
}

/* ---------- Admin recent activity list ---------- */
.admin-recent { margin-top: 8px; }
.admin-recent-list {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.admin-recent-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
}
.admin-recent-list a { font-weight: 600; }

/* -------- /admin/audit ------------------------------------------------ */
/* Filter row: each <label> is a column with caption + control stacked.
   Wraps gracefully on narrow viewports; the action buttons stick to the
   right via the auto-margin trick. */
.audit-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px 16px;
  margin: 16px 0 12px;
  padding: 12px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel);
}
.audit-filters label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.9em;
}
.audit-filters label > span {
  color: var(--muted);
  font-weight: 600;
  font-size: 0.85em;
}
.audit-filters select,
.audit-filters input[type="date"] {
  min-width: 160px;
}
.audit-filter-actions {
  display: flex;
  gap: 8px;
  margin-left: auto;
}

.audit-summary {
  margin: 8px 0 12px;
  font-size: 0.92em;
}

.audit-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 12px;
}
.audit-table th,
.audit-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
  font-size: 0.92em;
}
.audit-table th {
  background: var(--bg);
  color: var(--muted);
  font-weight: 600;
  position: sticky;
  top: 0;
  z-index: 1;
}
.audit-col-when   { white-space: nowrap; width: 1%; color: var(--muted); }
.audit-col-who    { white-space: nowrap; width: 1%; font-weight: 600; }
.audit-col-action { white-space: nowrap; width: 1%; }
.audit-col-summary { word-break: break-word; }
.audit-col-ip     { white-space: nowrap; width: 1%; font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace); }
.audit-col-ip code { background: transparent; padding: 0; }

/* Chip per category. Backgrounds are tinted so categories are
   distinguishable at a glance but not loud — this page is a wall of
   rows, anything saturated would fatigue fast. */
.audit-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.82em;
  font-weight: 600;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--border);
  line-height: 1.4;
}
.audit-chip[data-category="bid"]     { background: #e0f2fe; color: #075985; border-color: #bae6fd; }
.audit-chip[data-category="auction"] { background: #ecfccb; color: #3f6212; border-color: #d9f99d; }
.audit-chip[data-category="admin"]   { background: #fef3c7; color: #92400e; border-color: #fde68a; }
.audit-chip[data-category="payment"] { background: #fae8ff; color: #86198f; border-color: #f5d0fe; }
.audit-chip[data-category="auth"]    { background: #e0e7ff; color: #3730a3; border-color: #c7d2fe; }

@media (prefers-color-scheme: dark) {
  .audit-chip[data-category="bid"]     { background: rgba(56, 189, 248, 0.18); color: #7dd3fc; border-color: rgba(56, 189, 248, 0.4); }
  .audit-chip[data-category="auction"] { background: rgba(132, 204, 22, 0.18); color: #bef264; border-color: rgba(132, 204, 22, 0.4); }
  .audit-chip[data-category="admin"]   { background: rgba(251, 191, 36, 0.18); color: #fde68a; border-color: rgba(251, 191, 36, 0.4); }
  .audit-chip[data-category="payment"] { background: rgba(217, 70, 239, 0.18); color: #f5d0fe; border-color: rgba(217, 70, 239, 0.4); }
  .audit-chip[data-category="auth"]    { background: rgba(99, 102, 241, 0.18); color: #c7d2fe; border-color: rgba(99, 102, 241, 0.4); }
}
html[data-theme="dark"] .audit-chip[data-category="bid"]     { background: rgba(56, 189, 248, 0.18); color: #7dd3fc; border-color: rgba(56, 189, 248, 0.4); }
html[data-theme="dark"] .audit-chip[data-category="auction"] { background: rgba(132, 204, 22, 0.18); color: #bef264; border-color: rgba(132, 204, 22, 0.4); }
html[data-theme="dark"] .audit-chip[data-category="admin"]   { background: rgba(251, 191, 36, 0.18); color: #fde68a; border-color: rgba(251, 191, 36, 0.4); }
html[data-theme="dark"] .audit-chip[data-category="payment"] { background: rgba(217, 70, 239, 0.18); color: #f5d0fe; border-color: rgba(217, 70, 239, 0.4); }
html[data-theme="dark"] .audit-chip[data-category="auth"]    { background: rgba(99, 102, 241, 0.18); color: #c7d2fe; border-color: rgba(99, 102, 241, 0.4); }

.audit-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 12px 0 24px;
}
.audit-pager-current {
  color: var(--muted);
  font-size: 0.92em;
  min-width: 60px;
  text-align: center;
}
.btn.is-disabled {
  opacity: 0.45;
  pointer-events: none;
  cursor: default;
}

@media (max-width: 720px) {
  .audit-filters { flex-direction: column; align-items: stretch; }
  .audit-filters label { width: 100%; }
  .audit-filters select,
  .audit-filters input[type="date"] { width: 100%; }
  .audit-filter-actions { margin-left: 0; }
  .audit-table { font-size: 0.86em; }
  .audit-col-summary { min-width: 200px; }
}
