/*
  AgencyLadder — home board page shell
  DESIGN-SYSTEM.md §3/§4 for the fluid technique, §5 for every primitive reused from
  components.css. This file adds the LAYOUT specific to the home route — hero, filters, board
  list wrapper and right rail. Buttons, pills, chips, cards, rank, avatar, meter and skeleton are
  ALL reused from components.css, not re-authored. The header and footer moved to
  /css/chrome.css (ODO-32) — they are now shared across every page via public/js/chrome.js, not
  re-declared per route.

  No media queries (§4) — every reflow below is flex-wrap + flex:N 1 basis + min-width, the
  same technique already used in tokens.css's clamp() curves and preview.html's shell gutter.
*/

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* =========================================================================
   Hero
   ========================================================================= */
.hero-shell {
  max-width: 1200px;
  margin: 0 auto;
  width: 100%;
  padding: 44px var(--gutter) 64px;
}

.hero-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 44px;
  align-items: stretch;
}

.hero-left {
  flex: 1 1 520px;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.hero-right {
  flex: 1 1 330px;
  min-width: 300px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.live-pill {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 9px;
  background: var(--card);
  border: 1px solid var(--border-loud);
  border-radius: var(--radius-chip);
  padding: 9px 14px;
}

.live-pill-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--accent);
  animation: pls 2s ease-in-out infinite;
  flex: none;
}

.live-pill-text {
  font: 600 13.5px / 1 var(--font-mono);
  color: var(--text);
}

.hero-headline {
  font: 700 var(--fs-hero) / var(--lh-hero) var(--font-sans);
  color: var(--text);
  letter-spacing: var(--ls-hero);
  margin-top: 26px;
  text-wrap: pretty;
}

.hero-headline .accent {
  color: var(--accent);
}

.hero-sub {
  font: 400 clamp(15.5px, 13.83px + 0.427vw, 18px) / 1.55 var(--font-sans);
  color: var(--text-muted);
  margin-top: 20px;
  max-width: 520px;
  text-wrap: pretty;
}

.scarcity-box {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-top: 24px;
  padding: 16px 18px;
  background: var(--card);
  border: 1px solid var(--border-loud);
  border-radius: 11px;
  max-width: 520px;
}

.scarcity-icon {
  font: 700 15px / 1.3 var(--font-mono);
  color: var(--accent);
  flex: none;
}

.scarcity-text {
  font: 400 14.5px / 1.55 var(--font-sans);
  color: var(--text-muted);
  text-wrap: pretty;
}

.scarcity-text b {
  color: var(--text);
  font-weight: 700;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 11px;
  margin-top: 26px;
}

/* -----------------------------------------------------------------------
   Top Shoutout — lime-tinted border, 3px lime rail, drifting confetti.
   ----------------------------------------------------------------------- */
.shoutout-card {
  position: relative;
  overflow: hidden;
  background: var(--card);
  border: 1px solid var(--accent);
  border-radius: var(--radius-rail);
  padding: 22px;
  margin-top: 26px;
}

.shoutout-rail {
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--accent);
}

.confetti-fleck {
  position: absolute;
  width: 6px;
  height: 9px;
  border-radius: 1px;
  opacity: .5;
  top: -12px;
  pointer-events: none;
  animation-name: fall;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

.shoutout-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  position: relative;
}

.pill-accent-badge {
  font: 600 12.5px / 1 var(--font-mono);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: var(--accent);
  padding: 8px 10px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.shoutout-meta {
  font: 500 13px / 1 var(--font-mono);
  color: var(--text-muted);
  white-space: nowrap;
}

.shoutout-body {
  display: flex;
  gap: 14px;
  align-items: center;
  margin-top: 20px;
  position: relative;
}

.shoutout-avatar {
  width: 38px;
  height: 38px;
  border-radius: 9px;
  background-color: var(--border);
  border: 1px solid var(--border-loud);
  flex: none;
  background-size: cover;
  background-position: center;
}

.shoutout-name {
  display: block;
  font: 700 20px / 1.2 var(--font-sans);
  color: var(--text);
  letter-spacing: -.02em;
}

.shoutout-status {
  display: block;
  font: 500 13px / 1 var(--font-mono);
  color: var(--accent);
  margin-top: 8px;
}

.shoutout-desc {
  font: 400 14.5px / 1.5 var(--font-sans);
  color: var(--text-muted);
  margin-top: 15px;
  position: relative;
  text-wrap: pretty;
}

.shoutout-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin-top: 18px;
  position: relative;
}

.shoutout-footnote {
  font: 400 13px / 1.5 var(--font-sans);
  color: var(--text-muted);
  margin-top: 14px;
  position: relative;
  text-wrap: pretty;
}

/* -----------------------------------------------------------------------
   Hero stats — pinned to the bottom of hero-left via margin-top:auto so it
   lines up with the bottom of hero-right regardless of shoutout height.
   ----------------------------------------------------------------------- */
.hero-stats {
  display: flex;
  /* 34px between three stats is 68px of gutter on a 358px row, which is what forced them to wrap
     into a stack. A clamp keeps the airy spacing on desktop and buys the width back on a phone. */
  gap: clamp(14px, 6vw, 34px);
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 34px;
  border-top: 1px solid var(--border);
}

.hero-stat {
  display: flex;
  flex-direction: column;
  gap: 7px;
  /* Equal thirds that can shrink. `flex: 1 1 0` rather than a basis in px, so the three share the
     row evenly instead of one long label deciding the layout for the other two. min-width: 0 lets
     them actually shrink; without it a flex item refuses to go below its content width. */
  flex: 1 1 0;
  min-width: 0;
}

.hero-stat-value {
  font: 700 var(--fs-money-stat) / 1 var(--font-mono);
  color: var(--text);
  letter-spacing: -.03em;
}

.hero-stat-label {
  font: 500 13px / 1 var(--font-mono);
  color: var(--text-muted);
}

/* -----------------------------------------------------------------------
   TOP AGENCY card
   ----------------------------------------------------------------------- */
.top-agency-card {
  background: var(--card);
  border: 1px solid var(--border-loud);
  border-radius: var(--radius-rail);
  padding: 22px;
  position: relative;
  overflow: hidden;
}

.top-agency-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}

.top-agency-body {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  margin-top: 20px;
}

.top-agency-info {
  min-width: 0;
  flex: 1 1 0%;
}

.top-agency-name-row {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}

.top-agency-name {
  font: 700 18px / 1.2 var(--font-sans);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.top-agency-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 10px;
}

.top-agency-desc {
  font: 400 14px / 1.5 var(--font-sans);
  color: var(--text-muted);
  margin-top: 15px;
  text-wrap: pretty;
}

.top-agency-visit {
  display: block;
  margin-top: 15px;
  text-align: center;
}

.top-agency-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}

.top-agency-row + .top-agency-row {
  margin-top: 14px;
  padding-top: 0;
  border-top: none;
}

.top-agency-row-label {
  font: 500 14px / 1.3 var(--font-sans);
  color: var(--text-muted);
}

.top-agency-row-value {
  font: 700 var(--fs-money-stat) / 1 var(--font-mono);
  color: var(--text);
  letter-spacing: -.03em;
}

.top-agency-row-value.accent {
  color: var(--accent);
}

.top-agency-cta {
  display: block;
  width: 100%;
  margin-top: 22px;
  text-align: center;
}

.top-agency-footnote {
  margin-top: 13px;
  font: 400 13px / 1.5 var(--font-sans);
  color: var(--text-muted);
  text-align: center;
}

/* -----------------------------------------------------------------------
   WHERE THE MONEY IS
   ----------------------------------------------------------------------- */
.money-panel {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-rail);
  padding: 22px;
  flex: 1 1 0%;
}

.money-panel-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

.money-panel-title {
  font: 600 12.5px / 1 var(--font-mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.money-panel-sub {
  font: 500 13px / 1 var(--font-mono);
  color: var(--text-muted);
}

.money-rows {
  display: flex;
  flex-direction: column;
  gap: 15px;
  margin-top: 20px;
}

.money-row {
  cursor: pointer;
  padding: 4px 0;
  border-radius: 6px;
  background: none;
  border: none;
  text-align: left;
  width: 100%;
  font: inherit;
  color: inherit;
}

.money-row.is-active .money-row-name {
  color: var(--accent);
}

.money-row-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}

.money-row-name {
  font: 600 14.5px / 1.3 var(--font-sans);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text);
}

.money-row-figures {
  display: flex;
  gap: 12px;
  align-items: baseline;
  flex: none;
}

.money-row-count {
  font: 500 13px / 1 var(--font-mono);
  color: var(--text-muted);
}

.money-row-total {
  font: 700 15px / 1 var(--font-mono);
  color: var(--text);
  letter-spacing: -.02em;
}

.money-row .meter {
  margin-top: 9px;
  height: 5px;
}

/* =========================================================================
   Filters
   ========================================================================= */
.filters-shell {
  max-width: 1200px;
  margin: 0 auto;
  width: 100%;
  padding: 0 var(--gutter);
}

/* Category chips — a horizontally scrollable row on any width (KING JOE, 2026-08-21: "Category
   chips overflow. Seven chips do not fit, and more categories are coming"). flex-wrap:wrap would
   just take six rows on a phone (the directory's own bug, fixed separately) — this scrolls
   instead: momentum scrolling, no visible scrollbar, chips never shrink so they stay tappable at
   44px regardless of how many exist. The active chip is scrolled into view on selection (see
   renderCategoryChips() in index.html). Still no media query — this reads identically at 390 and
   1280, it just only NEEDS to scroll when the row is narrower than its content. */
.category-chips {
  display: flex;
  flex-wrap: nowrap;
  gap: 9px;
  margin-top: 76px;
  padding: 44px 2px 6px;
  border-top: 1px solid var(--border);
  align-items: center;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.category-chips::-webkit-scrollbar {
  display: none;
}

.category-chips .chip {
  flex: none;
}

.filter-spacer {
  flex: 1 1 0%;
}

.live-updated {
  font: 500 13px / 1 var(--font-mono);
  color: var(--text-muted);
  white-space: nowrap;
}

.search-row {
  display: flex;
  flex-wrap: wrap;
  gap: 11px;
  margin-top: 16px;
  align-items: center;
}

.search-field {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--border-loud);
  border-radius: var(--radius-input);
  padding: 0 14px;
  flex: 1 1 220px;
  max-width: 340px;
}

/* Country select + live-updated status travel together as ONE wrappable unit, so at any width
   where they end up on their own line (below the search field), they read as a deliberate
   two-ends split — selector left, live status pinned to the far right edge of the row — instead
   of the old layout where an invisible spacer's growth left a dead gap floating in the middle of
   a narrow line (KING JOE, 2026-08-21: filters "unarranged... stacked with no rhythm"). At wide
   viewports this group sits beside the search field exactly as before; nothing changes at 1280. */
.search-row-trailing {
  display: flex;
  align-items: center;
  gap: 11px;
  flex: 1 1 260px;
  min-width: 0;
}

.search-field-icon {
  font: 500 14px / 1 var(--font-mono);
  color: var(--text-muted);
  flex: none;
}

.search-field input {
  flex: 1 1 0%;
  background: transparent;
  border: none;
  color: var(--text);
  font: 500 14.5px / 1 var(--font-sans);
  padding: 14px 0;
  min-width: 0;
}

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

.search-clear {
  flex: none;
  font: 500 14px / 1 var(--font-mono);
  color: var(--text-muted);
  cursor: pointer;
  padding: 4px;
  border-radius: var(--radius-micro);
}

.search-clear:hover {
  color: var(--text);
}

.country-select {
  position: relative;
  flex: 1 1 200px;
  min-width: 150px;
  max-width: 240px;
}

.country-select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--card);
  border-radius: var(--radius-input);
  padding: 14px;
  cursor: pointer;
  border: 1px solid var(--border-loud);
}

.country-select-trigger:hover {
  border-color: var(--text);
}

.country-select-label {
  font: 600 14.5px / 1 var(--font-sans);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.country-select-caret {
  font: 500 12px / 1 var(--font-mono);
  color: var(--text-muted);
  flex: none;
}

.country-select-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 15;
  background: var(--card);
  border: 1px solid var(--border-loud);
  border-radius: var(--radius-input);
  padding: 10px;
  max-height: 300px;
  overflow: auto;
  animation: rise var(--dur-rise) var(--ease-rise);
}

.country-select-panel[hidden] {
  display: none;
}

.country-search {
  width: 100%;
  background: var(--inset);
  border: 1px solid var(--border-loud);
  border-radius: var(--radius-micro);
  color: var(--text);
  font: 500 13.5px / 1 var(--font-sans);
  padding: 9px 10px;
  margin-bottom: 8px;
}

.country-option {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 8px;
  border-radius: var(--radius-micro);
  font: 500 13.5px / 1 var(--font-sans);
  color: var(--text);
  cursor: pointer;
}

.country-option:hover {
  background: var(--inset);
}

.country-option.is-active {
  color: var(--accent);
}

.country-option-count {
  font: 500 12.5px / 1 var(--font-mono);
  color: var(--text-dim);
}

/* =========================================================================
   Board list + right rail
   ========================================================================= */
.board-shell {
  max-width: 1200px;
  margin: 0 auto;
  width: 100%;
  padding: 22px var(--gutter) 64px;
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  align-items: flex-start;
  flex: 1 1 auto;
}

.board-main {
  flex: 3 1 620px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.board-header-row {
  display: flex;
  gap: 16px;
  padding: 0 18px 2px;
  font: 600 12.5px / 1 var(--font-mono);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.board-header-rank {
  width: 52px;
  flex: none;
}

.board-header-agency {
  flex: 1 1 0%;
}

.board-header-bid {
  width: 104px;
  text-align: right;
  flex: none;
}

.board-row {
  background: var(--card);
  border-radius: 11px;
  padding: 16px 18px;
  position: relative;
  overflow: hidden;
  border: 1px solid var(--border);
  transition: border-color .4s ease, box-shadow .4s ease, background .2s ease;
}

.board-row.is-leader {
  border-color: var(--medal-gold-border);
  /* The wash fades out by 55% so the description stays on plain --card and keeps its contrast
     ratio; only the rank numeral and name sit in the tinted band. */
  background: linear-gradient(90deg, var(--medal-gold-wash), transparent 55%), var(--card);
  box-shadow: var(--medal-gold-glow);
}

/* Rank movement, mirroring the prototype's "moved up 2 places - just now" strip. Rendered only
   from an OBSERVED poll-to-poll change (see movementOf() in index.html) and expired after 90s,
   because "just now" has to stay true. Never shown for money moving down: decay drifts every row
   a fraction lower on every single poll, so a down-arrow there would be permanent noise rather
   than an event. The honest daily figure is the "-$X tomorrow" pill. */
.row-move {
  margin: 9px 0 0;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 12.5px;
  line-height: 1;
  letter-spacing: .02em;
}

.row-move-up { color: var(--accent); }
.row-move-down { color: var(--decay); }

.board-row.is-decayed {
  border-color: var(--decayed-card-border);
}

.board-row.is-flashing {
  border-color: var(--accent);
  box-shadow: var(--shadow-flash);
}

.board-row-top {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}

.board-row-rank {
  width: 52px;
  flex: none;
}

.board-row-agency {
  flex: 1 1 0%;
  min-width: 0;
}

.board-row-name-line {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: baseline;
}

.board-row-name-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  cursor: pointer;
}

.board-row-name {
  font: 700 clamp(15px, 13.238px + 0.559vw, 17px) / 1.2 var(--font-sans);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.board-row-name-wrap:hover .board-row-name {
  color: var(--accent);
}

.board-row-money {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex: none;
}

.board-row-desc {
  font: 400 var(--fs-body) / var(--lh-body) var(--font-sans);
  color: var(--text-muted);
  margin-top: 10px;
  text-wrap: pretty;
  max-width: 520px;
}

.board-row-footer {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: space-between;
  align-items: center;
  margin-top: 14px;
  padding-top: 13px;
  border-top: 1px solid var(--border);
}

.board-row-chips {
  display: flex;
  gap: 7px;
  align-items: center;
  flex-wrap: wrap;
}

.board-row-actions {
  display: flex;
  gap: 9px;
  align-items: center;
  flex-wrap: wrap;
}

/* -----------------------------------------------------------------------
   Pager
   ----------------------------------------------------------------------- */
.pager {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: center;
  justify-content: space-between;
  padding: 6px 2px 2px;
}

.pager-summary {
  font: 500 13px / 1 var(--font-mono);
  color: var(--text-muted);
}

.pager-controls {
  display: flex;
  gap: 7px;
  align-items: center;
  flex-wrap: wrap;
}

.pager-btn {
  font: 600 13.5px / 1 var(--font-sans);
  padding: 15px 14px;
  border-radius: var(--radius-btn);
  cursor: pointer;
  border: 1px solid var(--border-loud);
  white-space: nowrap;
  color: var(--text);
  background: none;
}

.pager-btn:disabled {
  opacity: .4;
  cursor: default;
  pointer-events: none;
}

.pager-page {
  font: 700 13.5px / 1 var(--font-mono);
  min-width: 44px;
  text-align: center;
  padding: 15px 12px;
  border-radius: var(--radius-btn);
  cursor: pointer;
  transition: .18s;
  color: var(--text);
  background: var(--card);
  border: 1px solid var(--border-loud);
}

.pager-page.is-active {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}

/* Empty-slot strip below the pager — always visible, always names the price. */
.board-empty-strip {
  border: 1px dashed var(--border);
  border-radius: 11px;
  padding: 20px;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: center;
  justify-content: space-between;
}

.board-empty-strip-title {
  font: 600 15.5px / 1.3 var(--font-sans);
  color: var(--text);
}

.board-empty-strip-copy {
  font: 400 14px / 1.5 var(--font-sans);
  color: var(--text-muted);
  margin-top: 6px;
}

/* -----------------------------------------------------------------------
   Right rail
   ----------------------------------------------------------------------- */
.rail {
  flex: 1 1 300px;
  min-width: 280px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  position: sticky;
  top: 92px;
}

.rail-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-rail);
  padding: 18px;
}

.rail-title-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.rail-title {
  font: 600 12.5px / 1 var(--font-mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.position-figure {
  display: flex;
  align-items: baseline;
  gap: 11px;
  margin-top: 14px;
}

.position-rank {
  font: 700 40px / 1 var(--font-mono);
  color: var(--text);
  letter-spacing: -.04em;
}

.position-name {
  font: 500 15px / 1.3 var(--font-sans);
  color: var(--text-muted);
}

.position-figures {
  display: flex;
  justify-content: space-between;
  margin-top: 9px;
  font: 500 13px / 1 var(--font-mono);
  color: var(--text-muted);
}

.position-decay {
  color: var(--decay);
}

.rail-cta {
  display: block;
  width: 100%;
  margin-top: 16px;
  text-align: center;
}

.rail-secondary-link {
  margin-top: 11px;
  text-align: center;
  font: 600 13.5px / 1 var(--font-sans);
  color: var(--text-muted);
  cursor: pointer;
  padding: 15px 6px;
}

.rail-secondary-link:hover {
  color: var(--text);
}

.activity-list {
  display: flex;
  flex-direction: column;
  gap: 13px;
  margin-top: 15px;
}

.activity-row {
  display: flex;
  gap: 11px;
  align-items: baseline;
}

.activity-time {
  font: 500 13px / 1.35 var(--font-mono);
  color: var(--text-dim);
  flex: none;
  width: 42px;
}

.activity-text {
  font: 400 13.5px / 1.35 var(--font-sans);
  color: var(--text-muted);
}

.activity-empty {
  font: 400 13px / 1.5 var(--font-sans);
  color: var(--text-dim);
  margin-top: 15px;
}

/* =========================================================================
   Board list states — loading / empty / error / no results
   ========================================================================= */
.board-state {
  border: 1px dashed var(--border-loud);
  border-radius: var(--radius-card);
  padding: 34px 20px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
}

.board-state-headline {
  font: 700 var(--fs-heading) / 1.2 var(--font-sans);
  letter-spacing: var(--ls-heading);
  color: var(--text);
}

.board-state-copy {
  font: 400 var(--fs-body) / var(--lh-body) var(--font-sans);
  color: var(--text-muted);
  max-width: 420px;
}

.board-state-copy + .board-state-copy {
  margin-top: -2px;
}

.ghost-slots {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 6px;
  width: 100%;
}

.ghost-slot {
  border: 1px dashed var(--border-loud);
  border-radius: var(--radius-card);
  padding: 14px 18px;
  display: flex;
  align-items: center;
  gap: 16px;
}

.ghost-slot-rank {
  font: 700 var(--fs-rank-card) / .88 var(--font-mono);
  color: var(--text-faint);
  letter-spacing: var(--ls-rank);
  width: 52px;
}

.ghost-slot-label {
  font: 500 13.5px / 1 var(--font-sans);
  color: var(--text-dim);
}

/* =========================================================================
   Toast slot — the toast component itself lives in components.css; this
   just anchors it without affecting document flow.
   ========================================================================= */
#toastSlot {
  position: relative;
  height: 0;
}

/* Header + footer moved to /css/chrome.css (ODO-32) — shared across every page via
   public/js/chrome.js's #chromeHeader/#chromeFooter mounts, not re-declared per route. See that
   file for the full history (the two-column-vs-three-column footer fight, the Admin/404 ruling). */

/* ============================================================================
   LIVE PROOF — Latest activity + Trending right now, SIDE BY SIDE.
   Two columns, matching outbid.lol's arrangement, which is the reference
   KING JOE pointed at. They replaced the Top Shoutout tribute in the hero:
   activity proves people are paying, trending proves the clicks are real, and
   clicks are what an agency is actually buying.
   ============================================================================ */

.proof-panels {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;                       /* the between-cards rhythm, DESIGN-SYSTEM §4 */
  margin-top: 22px;
}

/* flex-basis, not a media query — at 390 they stack, at 1280 they sit side by
   side, and the handover forbids breakpoints outright (DESIGN-SYSTEM §4). */
.proof-panel {
  flex: 1 1 260px;
  min-width: 0;                    /* required or the domain ellipsis never fires */
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px;
}

.proof-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}

.proof-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  animation: pls 2s ease-in-out infinite;
  flex: none;
}

.proof-window {
  margin-left: auto;
  font: 500 12.5px/1 "JetBrains Mono", monospace;
  color: var(--text-dim);
}

.proof-rows { display: flex; flex-direction: column; gap: 10px; }

.proof-row {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  min-width: 0;
}
.proof-row:hover .proof-name { color: var(--accent); }

.proof-favicon {
  width: 20px; height: 20px;
  border-radius: 5px;
  border: 1px solid var(--border-loud);
  background: var(--border);
  flex: none;
}

.proof-name {
  font: 500 13.5px/1.2 Inter, sans-serif;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
}

.proof-meta {
  font: 500 13px/1 "JetBrains Mono", monospace;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  flex: none;
}
.proof-rate { color: var(--accent); }

.proof-time {
  font: 500 12.5px/1 "JetBrains Mono", monospace;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  flex: none;
}

/* Empty is a real state and reads as one. Never padded to look busy. */
.proof-empty {
  margin: 0;
  font: 400 13px/1.45 Inter, sans-serif;
  color: var(--text-dim);
}

/* ============================================================================
   DECAY LABEL — compact, and it TICKS.
   Replaces "Their bid drops 2% a day. That's $29 tonight. Waiting makes it
   cheaper." which was three sentences doing one job.
   Because decay is a read-time continuous function rather than a nightly cron
   (MODEL-CONFLICT ruling 4), the balance is genuinely falling every second —
   so we can show it falling. On a board whose promise is "transparent and
   real-time", that is the promise rendered rather than described.
   ============================================================================ */

.decay-tag {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 9px;
  border-radius: 6px;
  background: rgba(255, 92, 77, .10);
  border: 1px solid rgba(255, 92, 77, .32);
  font: 600 12.5px/1 "JetBrains Mono", monospace;
  letter-spacing: .06em;
  color: var(--decay);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.decay-tag-rate { opacity: .9; }

.decay-tag-live {
  font-weight: 700;
  animation: tick 2s ease-in-out infinite;   /* the existing keyframe, not a new one */
}

@media (prefers-reduced-motion: reduce) {
  .decay-tag-live, .proof-dot { animation: none; }
}

/* Hero CTAs go FULL WIDTH once they stack.
   KING JOE: "can you make it full width then on mobile so its better? since the buttons are
   stacked." A stacked button at content width leaves dead space beside it and reads as a mistake;
   full width reads as deliberate. flex-basis does the work, no breakpoint: they sit side by side
   while there is room and each take the row when there is not. */
.hero-ctas { display: flex; flex-wrap: wrap; gap: 10px; }
.hero-ctas > .btn { flex: 1 1 240px; text-align: center; justify-content: center; }

/* ── Tier lines ────────────────────────────────────────────────────────────────────────────────
   Drawn after ranks 3, 10, 20, 30, 40 and 50 (TIER_MARKS in index.html). A hairline with a small
   Mono pill sitting on it, the same treatment outbid.lol uses, and for the same reason: fifty
   undifferentiated rows give a reader at #37 nothing to aim at, whereas a line just above them
   turns their position into "inside the top forty" and makes the next band a visible target.

   aria-hidden on the element itself. The rank numeral on every row already states the position, so
   a screen reader announcing "TOP 20" between rows would be repeating information it just read in
   a form that sounds like a heading it can navigate to. It is decoration for the eye. */
.tier-line {
  display: flex;
  align-items: center;
  gap: var(--space-14, 14px);
  margin: var(--space-10, 10px) 0;
  /* Cancels the flex `gap` the board list puts between cards, so the line reads as a divider
     BETWEEN two rows rather than as a third item with air on both sides. */
  margin-block: 2px;
}

.tier-line::before,
.tier-line::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--border);
}

.tier-pill {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 11.5px;
  line-height: 1;
  letter-spacing: .14em;
  color: var(--text-dim);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 6px 11px;
  white-space: nowrap;
}

/* The first line sits directly under the podium, so it carries the gold hairline rather than the
   neutral one. It is the boundary of the only band with its own colour treatment. */
.tier-line:first-of-type .tier-pill {
  color: var(--medal-gold);
  border-color: var(--medal-gold-border);
}

/* ── FILTER BAR: three controls, one row ───────────────────────────────────────────────────────
   Search, category and country are now the same kind of control and share a line. Previously the
   category filter was a scrolling chip row sitting ABOVE this, which at nineteen categories showed
   about three on mobile and overflowed on desktop, and the whole block took three stacked rows.

   The "live · updated just now" label used to sit inline after the country select, pushed out by a
   flex spacer. On mobile that left it stranded on its own line, half off the edge, which is what
   KING JOE meant by "the live, updated just now, not even properly put, its a mess". It is meta,
   not a control, so it drops below the controls and aligns right, out of the way of the three
   things a reader actually operates. */
.filter-select {
  flex: 1 1 9rem;
  min-width: 0;
  /* Matches .country-select-trigger's box so the three controls read as one set rather than as a
     native select wedged between two custom ones. */
  padding: 12px 13px;
  font-size: 14px;
}

.search-field { flex: 1 1 11rem; min-width: 0; }

.search-row-trailing {
  flex: 2 1 18rem;
  gap: 9px;
  /* MUST wrap. `.live-updated` lives inside THIS container, not .search-row, and takes width:100%
     so it drops to its own line. Without flex-wrap here its 100% simply overflowed the container
     and widened the whole document by 180px at 390. My previous fix set width:100% on the child and
     changed nothing, because the child was never the problem: a 100%-wide item in a nowrap flex
     row has nowhere to go. Verified by walking the box tree on the deployed page rather than
     reading the file again. */
  flex-wrap: wrap;
  min-width: 0;
}

/* The spacer existed to push the live label to the far right of the row. With the label no longer
   on that row, it would just add dead width. */
.filter-spacer { display: none; }

.live-updated {
  /* `flex: 1 0 100%` here caused a 180px horizontal overflow on the whole site.
     ------------------------------------------------------------------------------------------
     flex-shrink: 0 means the element can NEVER go below its basis, and the basis was 100% of the
     flex container. 100% plus the row's gap is wider than the row, and since it could not shrink,
     the document widened to fit it: documentElement.scrollWidth 570 against a 390 viewport. The
     off-canvas nav drawer then appeared to overflow too, but it is position:fixed and was only
     following the widened document. One bad shorthand, whole-site symptom.

     `width: 100%` with `flex: none` says the same thing about intent (take the full row) without
     creating an unshrinkable floor. min-width: 0 lets the text itself shrink rather than push. */
  flex: 1 1 100%;
  min-width: 0;
  text-align: right;
  margin-top: 2px;
  /* nowrap on a full-width label is fine once it can shrink; without min-width:0 above, a nowrap
     child sets an unshrinkable minimum equal to its text and pushes the container open. */
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (min-width: 860px) {
  /* On desktop there is room for the label back on the same line, where it reads as a status for
     the row rather than a caption under it. */
  .live-updated { flex: 0 0 auto; width: auto; margin-top: 0; }
  .filter-spacer { display: block; flex: 1 1 auto; }
}

/* "Your spot" — the signed-in viewer's own row.
   The CTA on that row already changed to "Top up", so the board DID know who they were, but
   nothing said so. KING JOE: "if a user is signed in then his card should have a label Your Spot.
   Cos the card literally recognized me and the cta is top up." Lime outline, not a lime fill:
   a filled element competes with the actual action next to it, and this is a label, not a button. */
.pill-mine {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(198, 242, 78, .08);
  white-space: nowrap;
}

/* The live decay countdown on the leader card. Mono and tabular so the digits do not jitter as
   they tick, which is the whole reason a countdown looks cheap when it is set in a proportional
   face. --decay because it is money leaving, the same colour as every other decay figure. */
.decay-tick {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--decay);
  white-space: nowrap;
}

/* The right rail's first card sits level with the board's first ROW, not with the board's column
   header. Measured: .board-main and .rail both start at the same y, but the board then spends
   ~25px on its RANK / AGENCY / BID header row, so the rail's first card floated above the first
   listing and read as misaligned. KING JOE raised it twice. */
.rail { padding-top: 25px; }

@media (max-width: 900px) {
  /* Stacked, so there is no column to align to and the offset would just be a gap. */
  .rail { padding-top: 0; }
}

/* The visitor pill's DIGITS, lime; the words around them stay muted.
   tabular-nums so the pill does not shuffle sideways every time a count ticks over, which is the
   detail that separates a live figure from a jittery one. */
.live-figure {
  color: var(--accent);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
