* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
}

/* Author stylesheets always beat the UA stylesheet regardless of
   specificity, so any of our own rules setting `display` (e.g.
   .category-pick-bar { display:flex }) silently defeats the browser's
   default `[hidden] { display:none }` once the attribute is toggled via JS.
   Restated here so `hidden` always wins. */
[hidden] {
  display: none !important;
}

body {
  font-family: var(--font-sans);
  background: var(--stage-0);
  color: var(--text-primary);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  position: relative;
  overflow-x: hidden;
}

/* Warm ambient field: very soft, low-saturation brand washes on the cream
   ground, so glass panels always have something to blur and refract. */
body::before, body::after {
  content: "";
  position: fixed;
  border-radius: 50%;
  filter: blur(90px);
  pointer-events: none;
  z-index: 0;
}

body::before {
  width: 62vw;
  height: 62vw;
  top: -22vw;
  left: -16vw;
  background: radial-gradient(circle, rgba(30, 64, 175, 0.10), transparent 66%);
  animation: driftA 26s ease-in-out infinite alternate;
}

body::after {
  width: 52vw;
  height: 52vw;
  bottom: -16vw;
  right: -12vw;
  background: radial-gradient(circle, rgba(37, 99, 235, 0.14), transparent 66%);
  animation: driftB 32s ease-in-out infinite alternate;
}

@keyframes driftA {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(4vw, 6vw) scale(1.08); }
}
@keyframes driftB {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(-5vw, -4vw) scale(1.05); }
}

@media (prefers-reduced-motion: reduce) {
  body::before, body::after { animation: none; }
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

.page {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  padding: var(--space-5) var(--space-3) 150px;
  /* Effectively uncapped: the sidebar already reserves its own column, so the
     feed should use what is left rather than sitting in a narrow strip with
     wide empty gutters either side. */
  max-width: 1700px;
  margin: 0 auto;
}

@media (min-width: 900px) {
  /* Small, even gutters so the cards nearly meet both edges. */
  .page { padding-left: var(--space-4); padding-right: var(--space-4); }
}

/* ---- top bar ---------------------------------------------------------- */

.topbar {
  /* Both required for the topbar popovers (inbox, language) to sit above the
     rest of the page. Every .glass surface uses backdrop-filter, which creates
     a stacking context — so .search-bar, being a later sibling, painted over
     anything inside .topbar no matter how high that child's z-index was. The
     menus were rendering underneath it, which is why clicks landed on the
     search field instead of the menu. Lifting the topbar's own context fixes
     the overlap and the dead clicks together. */
  position: relative;
  z-index: 30;

  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-5);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-weight: 750;
  font-size: 18px;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}

/* Two things share this class: the brand logo, and the user avatar on
   Settings (which still renders a letter on a tinted plate). The plate below
   is for the letter case; the :has(img) rule strips it for the logo, whose
   SVG carries its own navy circle — leaving it on would draw a square behind
   a round mark. */
.brand-mark {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  background: linear-gradient(150deg, var(--ebid-accent), var(--ebid-primary-darkest));
  box-shadow: 0 4px 12px -4px rgba(30, 64, 175, 0.45);
  color: #eaf2ff;
  font-weight: 800;
  font-size: 16px;
  flex: none;
}

.brand-mark:has(img) {
  background: none;
  box-shadow: none;
  /* Matches the logo's own corner radius (112/500 of its plate), so the
     container never clips the artwork or ghosts a different shape behind it. */
  border-radius: 22%;
}

.brand-mark img {
  width: 100%;
  height: 100%;
  display: block;
}

/* Fallback for engines without :has(). The logo SVG is opaque, so it covers
   the plate anyway; this just removes the shadow that would ring it. */
@supports not selector(:has(img)) {
  .brand-mark { box-shadow: none; }
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* ---- search / inputs --------------------------------------------------- */

.search-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 12px 16px;
  margin-bottom: var(--space-4);
}

.search-bar input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  color: var(--text-primary);
  font-size: 15px;
  font-family: inherit;
}

.search-bar input::placeholder { color: var(--text-tertiary); }

.search-bar svg {
  width: 18px;
  height: 18px;
  color: var(--text-tertiary);
  flex: none;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: var(--space-4);
}

.field label {
  font-size: 12px;
  font-weight: 650;
  color: var(--text-secondary);
  letter-spacing: 0.02em;
}

.field input {
  padding: 13px 16px;
  border-radius: var(--r-md);
  border: 1px solid var(--stage-border);
  background: var(--surface-soft);
  color: var(--text-primary);
  font-size: 15px;
  font-family: inherit;
  outline: none;
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.field input::placeholder { color: var(--text-tertiary); }

.field input:focus {
  border-color: var(--ebid-primary);
  box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.16);
}

.field-error {
  font-size: 12px;
  color: var(--danger);
}

/* ---- buttons ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 22px;
  border-radius: var(--r-pill);
  border: none;
  font-family: inherit;
  font-weight: 700;
  font-size: 14.5px;
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), filter var(--dur-fast) var(--ease-out);
}

.btn:active { transform: scale(0.97); }

.btn-primary {
  color: #ffffff;
  background: linear-gradient(135deg, var(--ebid-accent), var(--ebid-primary));
  box-shadow: 0 8px 20px -8px rgba(37, 99, 235, 0.60);
}

.btn-primary:hover { filter: brightness(1.05); }

.btn-ghost {
  color: var(--text-primary);
  background: var(--surface-soft);
  border: 1px solid var(--stage-border);
}

.btn-ghost:hover { background: var(--surface-solid); border-color: var(--stage-border-strong); }

.btn-block { width: 100%; }

.link-btn {
  background: none;
  border: none;
  color: var(--ebid-accent);
  font-weight: 700;
  font-size: 13.5px;
  cursor: pointer;
  padding: 0;
}

/* ---- chips --------------------------------------------------------------- */

.chip-row-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: var(--space-2);
}

.chip-row {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  flex: 1;
  /* Lets the row shrink inside the flex wrap instead of pushing the drive
     button out — same reasoning as .filter-field's min-width fix. */
  min-width: 0;
  /* Extra vertical room so a chip's pop (scale-up) isn't clipped by the
     scroll container's implicit overflow-y. */
  padding: 10px 4px 16px;
  scrollbar-width: none;
}
.chip-row::-webkit-scrollbar { display: none; }

/* Drive button: press-and-hold accelerates the category row's auto-drift in
   whatever direction it's currently moving. The chevron flips to mirror the
   direction, so once the row reaches an end and reverses, the same button
   (now pointing the other way) accelerates it back. */
.chip-row-drive {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  border: 1px solid var(--stage-border);
  background: var(--stage-3);
  color: var(--ebid-primary);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}
.chip-row-drive svg {
  width: 16px;
  height: 16px;
  transition: transform var(--dur-med) var(--ease-liquid);
}
.chip-row-drive.is-reversed svg { transform: rotate(180deg); }

.chip-row-drive:hover { border-color: var(--stage-border-strong); }

/* Held down: orange fill + a brief press-in, so acceleration reads as an
   active, momentary boost rather than a toggle. */
.chip-row-drive.is-boosting {
  background: var(--ebid-orange);
  border-color: transparent;
  color: #fff;
  transform: scale(0.92);
  box-shadow: 0 6px 16px -6px var(--ebid-orange-border);
}

@media (prefers-reduced-motion: reduce) {
  .chip-row-drive svg { transition: none; }
}

.chip {
  flex: none;
  padding: 9px 16px;
  border-radius: var(--r-pill);
  border: 1px solid var(--stage-border);
  background: var(--surface-soft);
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 650;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  /* transform is driven per-frame by chip-squeeze.js while scrolling (the
     "squeeze out" at the edges); it clears the inline transform for chips in
     the middle so these hover/active pops take over. transform-origin is set
     inline toward whichever edge the chip is nearest. */
  transform-origin: center;
  transition: transform var(--dur-fast) var(--ease-liquid),
              background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
/* No transition while the squeeze script owns the transform, so scrolling
   feels 1:1 rather than lagging a frame behind the finger. */
.chip.is-squeezing { transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out); }

/* "All" stays pinned at the left while the rest of the row scrolls past it. */
.chip-pinned {
  position: sticky;
  left: 0;
  z-index: 3;
  /* Solid so scrolling chips slide cleanly underneath, plus a soft right
     shadow that sells the layering. */
  box-shadow: 8px 0 12px -6px rgba(15, 30, 60, 0.18);
}
.chip-pinned:not(.is-active) { background: var(--stage-3); }
/* Never squeeze or hover-pop the pinned chip — it holds still. */
.chip-pinned, .chip-pinned:hover, .chip-pinned.is-active { transform: none; }

.chip:hover {
  border-color: var(--stage-border-strong);
  color: var(--text-primary);
  background: var(--surface-solid);
  transform: translateY(-2px) scale(1.05);
}
.chip:active { transform: translateY(-1px) scale(0.98); }

.chip.is-active {
  color: #ffffff;
  background: linear-gradient(135deg, var(--ebid-accent), var(--ebid-primary));
  border-color: transparent;
  box-shadow: 0 8px 18px -6px rgba(37, 99, 235, 0.55);
  transform: translateY(-2px) scale(1.06);
}

@media (prefers-reduced-motion: reduce) {
  .chip:hover, .chip.is-active, .chip:active { transform: none; }
}

/* ---- section heading ------------------------------------------------- */

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: var(--space-6) 0 var(--space-3);
}

.section-head h2 {
  font-size: 17px;
  margin: 0;
  font-weight: 750;
  color: var(--text-primary);
}

.section-head .count {
  font-size: 13px;
  color: var(--text-tertiary);
}

/* ---- bid card ------------------------------------------------------------ */

/* Big tender cards, two per row on wider screens (one on mobile). */
/* Denser than before: the gap was 24px and the cards sat in a 960px column,
   so each card was both small and surrounded by air. Auto-fill lets the grid
   take a third column on a wide screen instead of stretching two. */
.bid-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}

@media (min-width: 720px) {
  .bid-grid { grid-template-columns: repeat(auto-fill, minmax(460px, 1fr)); }
}

/* Cap the column count rather than the page width: past three columns the
   cards get narrow again and the feed turns into a wall of tiles. */
@media (min-width: 1500px) {
  .bid-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.bid-card {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 15px 17px 0;
  cursor: pointer;
  transition: transform var(--dur-med) var(--ease-out), box-shadow var(--dur-med) var(--ease-out);
}

.bid-card:hover {
  transform: translateY(-3px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 16px 34px -14px var(--glass-shadow);
}

/* ---- header: org + save --------------------------------------------- */
.bc-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.bc-org {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.bc-avatar {
  width: 46px;
  height: 46px;
  border-radius: 13px;
  flex: none;
  display: grid;
  place-items: center;
  color: #fff;
  font-weight: 800;
  font-size: 14.5px;
  letter-spacing: 0.02em;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
  position: relative;
  overflow: hidden;
}

/* A real company logo, layered over the initials rather than replacing them.
   If the image 404s or is hotlink-blocked, bid-card.js removes it and the
   correct initials are already underneath — no broken-image icon, no flash of
   empty box. See scraper/logo.py for how these URLs are vetted server-side. */
.bc-logo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* contain, not cover: logos are usually padded artwork on their own
     background, and cropping them mangles the mark. */
  object-fit: contain;
  padding: 5px;
  background: #fff;
  z-index: 1;
}

/* White plate behind the logo so dark marks stay legible against the tinted
   avatar colour, which is otherwise chosen for contrast with white text. */
.bc-avatar.has-logo {
  background: #fff !important;
  box-shadow: inset 0 0 0 1px var(--stage-border);
}

.bc-avatar.has-logo .bc-avatar-initials { visibility: hidden; }

.bc-org-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; }

.bc-org-name {
  font-size: 13.5px;
  font-weight: 750;
  color: var(--text-primary);
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bc-source {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  color: var(--text-tertiary);
}
.bc-verified { display: inline-flex; color: var(--ebid-orange); }
.bc-verified svg { width: 12px; height: 12px; }

.bc-save {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 7px 13px;
  border-radius: var(--r-pill);
  border: 1px solid var(--stage-border);
  background: var(--stage-3);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  transition: all var(--dur-fast) var(--ease-out);
}
.bc-save svg { width: 14px; height: 14px; }
.bc-save:hover { border-color: var(--stage-border-strong); color: var(--text-primary); }
.bc-save.is-saved {
  color: var(--ebid-primary);
  border-color: transparent;
  background: var(--ebid-primary-tint);
}
.bc-save.is-saved svg { fill: currentColor; }

/* ---- badge row ------------------------------------------------------- */
.bc-badges { display: flex; flex-wrap: wrap; gap: 5px; }

.bc-badge {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 9px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
}
.bc-badge-cat {
  color: var(--ebid-orange-strong);
  background: var(--ebid-orange-soft);
  border-color: var(--ebid-orange-border);
}
.bc-badge-new {
  color: var(--ebid-primary);
  background: var(--ebid-primary-tint);
}
.bc-badge-closed {
  color: var(--text-secondary);
  background: var(--stage-1);
  border-color: var(--stage-border);
}

/* ---- title + reference ---------------------------------------------- */
.bc-title {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.36;
  color: var(--text-primary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bc-ref {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--ebid-primary);
  opacity: 0.85;
  margin-top: -4px;
}

/* ---- date boxes ------------------------------------------------------ */
.bc-dates { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }

.bc-datebox {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 7px 9px;
  border: 1px solid var(--stage-border);
  border-radius: var(--r-md);
  background: var(--stage-1);
}
.bc-datelabel {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.bc-dateval { font-size: 13.5px; font-weight: 650; color: var(--text-primary); }
.bc-dateval.is-urgent { color: var(--ebid-urgent); }

/* ---- progress -------------------------------------------------------- */
.bc-progress {
  height: 4px;
  border-radius: var(--r-pill);
  background: var(--stage-border);
  overflow: hidden;
}
.bc-progress-fill {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--ebid-accent);
}
.bc-progress-fill.is-urgent { background: var(--ebid-orange); }

.bc-progress-meta {
  display: flex;
  justify-content: space-between;
  font-size: 10.5px;
  font-weight: 650;
  color: var(--text-tertiary);
}
.bc-progress-meta .is-urgent { color: var(--ebid-urgent); font-weight: 750; }

/* ---- footer ---------------------------------------------------------- */
.bc-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 4px -17px 0;
  padding: 10px 17px;
  border-top: 1px solid var(--stage-border);
}
.bc-open {
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.05em;
  color: var(--ebid-primary);
}
.bc-open.is-closed { color: var(--text-tertiary); }
.bc-details {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ebid-orange-strong);
}
.bc-details svg { width: 13px; height: 13px; }

.empty-state, .loading-state {
  text-align: center;
  padding: var(--space-7) var(--space-4);
  color: var(--text-tertiary);
}

.spinner {
  width: 26px;
  height: 26px;
  margin: 0 auto var(--space-3);
  border-radius: 50%;
  border: 2.5px solid var(--stage-border);
  border-top-color: var(--ebid-accent);
  animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ---- category groups (categories.html) -------------------------------- */

.category-group { margin-bottom: var(--space-4); }

.category-group-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 4px 12px;
  cursor: pointer;
}

.category-group-swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: none;
}

.category-group-head h3 {
  font-size: 14.5px;
  margin: 0;
  font-weight: 750;
  flex: 1;
  color: var(--text-primary);
}

.category-group-count {
  font-size: 12px;
  color: var(--text-tertiary);
}

.category-group-chevron {
  width: 16px;
  height: 16px;
  color: var(--text-tertiary);
  transition: transform var(--dur-med) var(--ease-out);
}

.category-group.is-open .category-group-chevron { transform: rotate(180deg); }

.category-group-body {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 2px 2px 6px;
  max-height: 0;
  overflow: hidden;
  transition: max-height var(--dur-slow) var(--ease-out);
}

.category-group.is-open .category-group-body { max-height: 900px; }

.category-pick-bar {
  position: fixed;
  left: 50%;
  bottom: 104px;
  transform: translateX(-50%);
  width: min(92vw, 520px);
  /* Only `bottom` is constrained (no `top`), so this MUST shrink-to-fit -
     otherwise position:fixed's auto height resolution stretches it from the
     viewport top down to the bottom offset, covering the page. */
  height: fit-content;
  z-index: 35;
  padding: var(--space-3) var(--space-4);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.category-pick-count {
  font-size: 13px;
  font-weight: 750;
  color: #1e3a8a;
}

/* ---- utility ------------------------------------------------------------ */

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.mt-0 { margin-top: 0; }
.muted { color: var(--text-tertiary); }

/* ---- tenders status tabs + filter panel ------------------------------- */

.status-tabs {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  padding: 8px 4px 12px;
  scrollbar-width: none;
}
.status-tabs::-webkit-scrollbar { display: none; }

.status-tab {
  flex: none;
  padding: 8px 15px;
  border-radius: var(--r-pill);
  border: 1px solid var(--stage-border);
  background: var(--surface-soft);
  color: var(--text-secondary);
  font-size: 12.5px;
  font-weight: 650;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-liquid),
              background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}

.status-tab:hover { background: var(--surface-solid); color: var(--text-primary); transform: translateY(-2px) scale(1.05); }
.status-tab:active { transform: translateY(-1px) scale(0.98); }

.status-tab.is-active {
  background: linear-gradient(135deg, var(--ebid-primary), var(--ebid-primary-dark));
  border-color: transparent;
  color: #fff;
  box-shadow: 0 8px 18px -7px rgba(30, 64, 175, 0.65);
  transform: translateY(-2px) scale(1.06);
}

@media (prefers-reduced-motion: reduce) {
  .status-tab:hover, .status-tab.is-active, .status-tab:active { transform: none; }
}

.filter-panel { padding: 16px 18px; margin-bottom: var(--space-3); }

.filter-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

@media (min-width: 620px) { .filter-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 960px) { .filter-grid { grid-template-columns: repeat(3, 1fr); } }

/* min-width:0 lets the field shrink inside its grid track — without it a
   select with long option text (Type, Sort) keeps its intrinsic width and
   spills out of the panel. */
.filter-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }

.filter-field span {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
}

.filter-field select {
  width: 100%;
  max-width: 100%;
  padding: 10px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--stage-border);
  background: var(--surface-soft);
  color: var(--text-primary);
  font-size: 13.5px;
  font-family: inherit;
  outline: none;
  /* Keep a long selected option from stretching the control. */
  text-overflow: ellipsis;
}

.filter-field select:focus {
  border-color: var(--ebid-primary);
  box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.16);
}

.filter-actions { display: flex; justify-content: flex-end; margin-top: var(--space-3); }

/* --- bid card: commercial terms -------------------------------------------
   These replaced the old "REF <bid_id>" line. A bid_id is an internal key —
   it told a bidder nothing. The document fee and CPO decide whether a tender
   is worth pursuing at all, so they get the prominent slot. Rendered only
   when the notice actually states them; a missing fee is left out rather
   than shown as 0, which would be a different (and wrong) claim. */

.bc-terms {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 2px;
}

.bc-term {
  flex: 1 1 120px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 6px 9px;
  border-radius: var(--r-sm);
  background: var(--ebid-bg-tint);
  border: 1px solid var(--ebid-primary-tint);
}

.bc-term-label {
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ebid-primary);
  opacity: 0.75;
}

.bc-term-value {
  font-size: 12.5px;
  font-weight: 800;
  color: var(--ebid-primary-darkest);
  line-height: 1.2;
  overflow-wrap: anywhere;
}

/* Secondary descriptive facts — type, region, language, document count. */
.bc-facts {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
}

.bc-fact {
  font-size: 10.5px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: var(--r-pill);
  background: var(--stage-0);
  color: var(--text-secondary);
  border: 1px solid var(--stage-border);
}

/* E-chereta's own mark on its own listings. The SVG is a full-bleed plate, so
   it fills the avatar tile — the padding and white backing below exist for
   third-party logos, which are loose artwork on transparent backgrounds and
   would otherwise touch the tile edges or vanish against the tint. */
.bc-logo.is-own {
  padding: 0;
  background: none;
  border-radius: inherit;
}

.bc-avatar:has(.bc-logo.is-own) {
  background: none !important;
  box-shadow: none;
}

/* Card summary — the notice's own opening lines. It was being fetched by
   /bids and never rendered, which is part of why the cards felt sparse
   despite their size. Two lines: enough to judge relevance, not enough to
   turn the feed into a wall of text. */
.bc-summary {
  margin: 0;
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
