/* ============================================================
   CRITICAL.CSS - above-the-fold subset of theme.css
   Generated from public/css/theme.css by tools-extraction (see the
   build-critical-css.ps1 ranges). Loaded render-blocking in <head>;
   the full theme.css is loaded asynchronously. Regenerate this file
   after any edit to the sections it covers.
   ============================================================ */

:root {
  /* --- color: brand ---
     Went blue for a while (2026-07-29, several passes), then back to
     green the same day, this time to a specific client-supplied hex:
     #00B53F. That exact color only has 2.73:1 contrast against white —
     nowhere near the 4.5:1 normal text needs — and --color-primary
     doubles as both text-on-white (prices, links, badges) and button/
     header/footer backgrounds with white text on top, so using it
     everywhere as-is would make a lot of the site hard to read. Split
     two ways instead (client's choice of the options offered):
       --green-bright is #00B53F exactly, unchanged — used for hover
         states, highlights, and accents, the same "large text/UI
         component" tier that already tolerated sub-4.5:1 contrast here
         (see the nav hover pill below, and --color-primary-hover).
       --green-deep is a darker green in the same hue (not the #00802D
         floated in the original options — that was still only 5.1:1 and
         left the footer's white-text tiers failing; #005C20 clears
         8.2:1, matching the headroom the previous blue had closely
         enough that every existing --footer-* opacity below carries
         over unchanged). This is what --color-primary and the shared
         header/footer background actually use.
     Variable names are kept as `--green-*` on purpose (back to their
     literal meaning now): they're referenced by var() in ~100+ places
     across theme.css and inline styles in admin/profile Blade views. */
  --green-deep: #005C20;
  --green-bright: #00B53F;
  --green-pale: #DCF3E3;
  --green-pale-faint: #EFFAF2;
  --coral: #FF6E4A;
  --gold: #F2B705;
  /* The header/footer surface color — went through two intermediate
     values (var(--green-deep) #005C20, then a toned-down #00802C) before
     landing here at the exact client hex, var(--green-bright) #00B53F,
     per an explicit "make it brighter" follow-up. #00B53F only holds
     2.73:1 against white — well below the usual 4.5:1 AA target — and a
     dark-ink-text version was tried specifically to fix that, but the
     client asked to keep white text/icons regardless (found it "fine and
     visible" in practice), so .site-footer's --footer-* tokens and
     .nav-links (below) stayed white-based. This is a deliberate,
     client-directed exception to the normal contrast guideline, not an
     oversight — see each token's own comment for the actual measured
     numbers. --green-deep itself is untouched and still used everywhere
     else that needs the darker, higher-contrast shade (on-white text/
     links/badges, category tile fills, etc). */
  --footer-bg: var(--green-bright);

  /* --- color: neutrals --- */
  --cream: #FBFBF6;
  --white: #FFFFFF;
  --ink: #122720;
  --ink-soft: #4B5D57;
  --ink-faint: #6B7D77;
  --line: #E1E8E2;
  --line-strong: #C9D4CD;

  /* --- semantic aliases --- */
  --color-bg: var(--cream);
  --color-surface: var(--white);
  --color-text: var(--ink);
  --color-text-muted: var(--ink-soft);
  --color-border: var(--line);
  --color-primary: var(--green-deep);
  --color-primary-hover: var(--green-bright);
  --color-accent: var(--coral);
  --color-accent-2: var(--gold);
  /* Deliberately its own fixed value, not var(--green-bright) or
     var(--green-deep): brand green and "success" happen to both be green
     again right now, but they were split apart during the blue rebrand
     (2026-07-29) specifically so success/approved states (toasts,
     approved-ad stat, checkmarks) keep meaning "success" on their own
     terms rather than silently following whatever hue --color-primary
     is set to. Left decoupled even now that brand is green again, so a
     future rebrand away from green won't accidentally turn success
     states along with it. */
  --color-success: #12945F;
  --color-danger: #D9483A;
  --color-warning: var(--gold);

  /* --- typography --- */
  --font-display: 'Poppins', sans-serif;
  --font-body: 'Noto Sans', 'Noto Sans Tamil', 'Noto Sans Sinhala', sans-serif;

  /* --- spacing (use Bootstrap spacing as base) --- */
  --radius-sm: 10px;
  --radius-md: 16px;
  --radius-lg: 18px;
  --radius-xl: 24px;
  --radius-pill: 999px;

  /* --- shadow --- */
  --shadow-sm: 0 4px 12px -6px rgba(0, 92, 32, 0.18);
  --shadow-md: 0 10px 24px -14px rgba(0, 92, 32, 0.25);
  --shadow-lg: 0 16px 30px -18px rgba(0, 92, 32, 0.35);

  /* --- layout --- */
  --container-max: 1160px;
  --nav-height: 70px;
  --bottom-nav-height: 66px;
}

/* ------------------------------------------------------------  
   BASE OVERRIDES (on top of Bootstrap)
   ------------------------------------------------------------ */
body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--color-text);
}

a {
  color: inherit;
  text-decoration: none;
}

::selection {
  background: var(--green-pale);
  color: var(--color-primary);
}

/* Ensure all interactive elements have visible cursor */
input,
select,
textarea,
button,
a,
[role="button"] {
  cursor: pointer;
}

input,
select,
textarea {
  color: var(--color-text);
}

input::placeholder,
textarea::placeholder {
  color: var(--ink-faint);
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

::selection {
  background: var(--green-pale);
  color: var(--ink);
}

::-moz-selection {
  background: var(--green-pale);
  color: var(--ink);
}

/* ------------------------------------------------------------  
   CONTAINER
   ------------------------------------------------------------ */
.container-custom {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: clamp(16px, 5vw, 56px);
}

/* ------------------------------------------------------------  
   BUTTONS (Bootstrap overrides + custom)
   ------------------------------------------------------------ */
.btn-sb-primary {
  background: var(--color-primary);
  color: var(--white);
  border: none;
  border-radius: var(--radius-pill);
  font-weight: 600;
  padding: 10px 24px;
  transition: all 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-sb-primary:hover {
  background: var(--color-primary-hover);
  color: var(--white);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}

/* Bootstrap's base .btn:disabled rule (background-color: var(--bs-btn-disabled-bg))
   has higher specificity than a single custom class like .btn-sb-primary —
   without this override, disabling the button via JS (e.g. while an async
   action is in flight) let that Bootstrap rule win and strip the
   background entirely, leaving the button looking invisible instead of
   just dimmed. Same fix pattern already existed for .btn-sb-danger/.btn-sb-warn;
   primary and outline just never needed it until now. */
.btn-sb-primary:disabled {
  background: var(--color-primary);
  color: var(--white);
  opacity: .55;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn-sb-accent {
  background: var(--color-accent);
  color: var(--white);
  border: none;
  border-radius: var(--radius-pill);
  font-weight: 600;
  padding: 10px 24px;
  transition: all 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-sb-accent:hover {
  filter: brightness(1.06);
  color: var(--white);
  transform: translateY(-1px);
}

.btn-sb-outline {
  background: transparent;
  border: 1.5px solid var(--color-primary);
  color: var(--color-primary);
  border-radius: var(--radius-pill);
  font-weight: 600;
  padding: 10px 24px;
  transition: all 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-sb-outline:hover {
  background: var(--green-pale);
  color: var(--color-primary);
}

.btn-sb-outline:disabled {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--color-text-muted);
  opacity: .7;
  cursor: not-allowed;
}

.btn-sb-ghost {
  background: transparent;
  color: var(--color-text);
  border: none;
  border-radius: var(--radius-pill);
  font-weight: 600;
  padding: 10px 24px;
  transition: all 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-sb-ghost:hover {
  background: var(--line);
}

.btn-sb-danger {
  background: var(--color-danger);
  color: var(--white);
  border: none;
  border-radius: var(--radius-pill);
  font-weight: 600;
  padding: 10px 24px;
  transition: background 200ms ease, transform 200ms ease, box-shadow 200ms ease;
}

.btn-sb-danger:hover:not(:disabled) {
  background: #B93E30;
  color: var(--white);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(217, 72, 58, .35);
}

.btn-sb-danger:disabled {
  background: #9CA3AF;
  color: #fff;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn-sb-warn {
  background: linear-gradient(135deg, #F59E0B, #D97706);
  color: #fff;
  border: none;
  border-radius: var(--radius-pill);
  font-weight: 600;
  padding: 10px 24px;
  transition: all 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-sb-warn:hover {
  background: linear-gradient(135deg, #D97706, #B45309);
  color: #fff;
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(180, 83, 9, .3);
}

.btn-sb-warn:disabled {
  background: #9CA3AF;
  color: #fff;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn-sb-danger-dark {
  background: #991B1B;
  color: #fff;
  border: none;
  border-radius: var(--radius-pill);
  font-weight: 600;
  padding: 10px 24px;
  transition: all 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-sb-danger-dark:hover {
  background: #7F1D1D;
  color: #fff;
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(153, 27, 27, .3);
}

/* WhatsApp contact button (ad-show contact card) — brand green, always
   pill-shaped like every other .btn-sb-* variant. Was previously two
   copies of inline styles on the page itself, which is how one of them
   silently drifted to a square corner instead of a pill. */
.btn-whatsapp {
  background: #25D366;
  border-color: #25D366;
  color: #fff;
  border-radius: var(--radius-pill);
  font-weight: 600;
  transition: all 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-whatsapp:hover {
  background: #1EBE5A;
  border-color: #1EBE5A;
  color: #fff;
  transform: translateY(-1px);
}

/* ------------------------------------------------------------  
   EYEBROW / BADGES
   ------------------------------------------------------------ */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--green-pale);
  color: var(--color-primary);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
}

.eyebrow::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-accent);
}

.badge-sb {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  background: var(--green-pale);
  color: var(--color-primary);
}

.badge-sb-accent {
  background: #FFE9E2;
  color: var(--color-accent);
}

.badge-sb-gold {
  background: #FDF1CC;
  color: #8A6800;
}

.badge-sb-outline {
  background: transparent;
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
}

/* ---- Featured grid (list cards) ---- */

/* ------------------------------------------------------------  
   AD CARD — horizontal list style (image left, text right)
   ------------------------------------------------------------ */
.ad-card {
  display: flex;
  align-items: stretch;
  height: 122px;
  background: var(--color-surface);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: transform .3s cubic-bezier(.16, 1, .3, 1), box-shadow .3s cubic-bezier(.16, 1, .3, 1), border-color .3s ease;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
}

.ad-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
  border-color: var(--green-bright);
  color: inherit;
}

/* Boosted ads get a premium gold border + tinted background on the card
   itself instead of a text badge — the styling *is* the signal, so it
   needs to survive at a glance even in a dense grid. A flat gold line on
   a flat cream fill read cheap/plasticky, so this uses a soft metallic
   gradient border (double-background trick: one layer painted into the
   padding-box for the fill, one into the border-box for the edge) plus a
   warm, low ambient shadow to give the card real depth at rest. */
.ad-card--boosted {
  border: 1.5px solid transparent;
  background:
    linear-gradient(155deg, #FFFDF6 0%, #FFF6DE 100%) padding-box,
    linear-gradient(135deg, #F8D568 0%, #E8B408 45%, #B8860B 100%) border-box;
  box-shadow: 0 10px 24px -16px rgba(184, 134, 11, 0.4), 0 1px 0 rgba(255, 255, 255, 0.6) inset;
}

.ad-card--boosted:hover {
  border-color: transparent;
  box-shadow: 0 20px 36px -16px rgba(184, 134, 11, 0.5), 0 1px 0 rgba(255, 255, 255, 0.6) inset;
}

.ad-card__media {
  position: relative;
  width: 112px;
  min-width: 112px;
  background: var(--green-pale);
  overflow: hidden;
}

.ad-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .4s cubic-bezier(.16, 1, .3, 1);
}

.ad-card:hover .ad-card__media img {
  transform: scale(1.05);
}

.ad-card__placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--green-pale);
  color: var(--color-primary);
  font-size: 22px;
  opacity: .4;
}

/* When a card HAS a photo, the placeholder sits absolutely behind it (see
   the always-rendered placeholder in components/ad-card.blade.php) — a
   lazy image still shows the category icon through its transparent frame
   until the photo loads and covers it. The in-flow image (z-index 1) keeps
   defining the media box's height; the overlays above (verified badge, like
   button, condition pill) keep their own higher z-indexes untouched. */
.ad-card__media--has-image .ad-card__placeholder {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.ad-card__media--has-image img {
  position: relative;
  z-index: 1;
}

.ad-card__overlay {
  display: none;
}

/* White pill version of <x-verified-badge pill> — sized down well below
   the component's own default .pc-badge/.verified-badge--xs sizing,
   since it sits in a small corner of the card image rather than a
   full-width text row. White + backdrop-blur instead of the pale-blue
   .pc-badge-blue fill matches .ad-card__cat-badge/.ad-card__like, the
   other two badges already living on this image, so all three read as
   one consistent "image chrome" family rather than the pill looking like
   a stray card-body element that wandered onto the photo. This is the
   only verified-seller badge on the card now — an earlier version also
   duplicated it as a smaller pill in the meta row below, which was
   removed as redundant once this one existed.

   Scoped as ".ad-card__media .ad-card__verified-overlay" rather than a
   bare class — the rendered element also carries .pc-badge/.pc-badge-blue/
   .verified-pill from <x-verified-badge>, all equal-specificity single
   classes declared later in this file (search "AVATAR / PROFILE"), which
   would otherwise win the cascade tie on background/color/padding/
   font-size/gap by source order alone regardless of which rule "sounds"
   more specific to this card. Nesting under the always-present
   .ad-card__media parent settles it on specificity instead, so this
   doesn't quietly break again if either rule ever moves. */
.ad-card__media .ad-card__verified-overlay {
  position: absolute;
  top: 6px;
  left: 6px;
  z-index: 3;
  background: rgba(255, 255, 255, .92);
  border-color: transparent;
  color: var(--color-primary);
  backdrop-filter: blur(4px);
  font-size: 9px;
  padding: 3px 7px;
  gap: 3px;
  white-space: nowrap;
}

.ad-card__media .ad-card__verified-overlay .verified-badge--xs {
  width: 9px;
  height: 9px;
}

.ad-card__media .ad-card__verified-overlay .verified-badge--xs .verified-badge__seal {
  font-size: 9px;
}

.ad-card__media .ad-card__verified-overlay .verified-badge--xs .verified-badge__check {
  font-size: 4.5px;
}

.ad-card__cat-badge {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: rgba(255, 255, 255, .9);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  z-index: 3;
  transition: transform .25s ease;
}

.ad-card:hover .ad-card__cat-badge {
  transform: scale(1.1);
}

.cat-bg-land {
  color: var(--green-deep);
}

.cat-bg-real_estate {
  color: var(--green-bright);
}

.cat-bg-vehicles {
  color: var(--coral);
}

.cat-bg-pets {
  color: #8A6800;
}

.ad-card__like {
  position: absolute;
  bottom: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .9);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
  border: none;
  cursor: pointer;
  z-index: 3;
  transition: all .2s ease;
}

.ad-card__like:hover {
  transform: scale(1.15);
  color: var(--color-accent);
}

.ad-card__like.is-saved {
  color: var(--color-accent);
}

.ad-card__like i {
  font-size: 11px;
}

/* Solid, high-contrast pill overlaid on the card photo, bottom-left —
   deliberately NOT the white/blurred "image chrome" look shared by
   .ad-card__verified-overlay/.ad-card__cat-badge/.ad-card__like: a
   translucent white pill can wash out against a light or busy photo,
   and this needs to read as a clear, unmissable flag at a glance rather
   than blend in as one more piece of card furniture. Both states get a
   real, distinct color rather than black/near-black — New reuses the
   card's own primary green (a positive, fresh signal); Used gets its own
   muted slate tone (--ink-soft, not a near-black rgba() over the photo)
   so it still reads as a deliberate color choice rather than a shadow,
   and deliberately isn't a "warning" tone since a used listing isn't a
   lesser one. */
.ad-card__condition-overlay {
  position: absolute;
  bottom: 6px;
  left: 6px;
  z-index: 3;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .02em;
  padding: 3px 7px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  color: #fff;
}

.ad-card__condition-overlay--new {
  background: var(--color-primary);
}

.ad-card__condition-overlay--used {
  background: var(--ink-soft);
}

.ad-card__body {
  flex: 1;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}

.ad-card__top-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
  margin-bottom: 2px;
}

.ad-card__eyebrow {
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1;
}

.ad-card__title {
  font-weight: 600;
  font-size: 12.5px;
  color: var(--color-text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.3;
  /* Explicit top margin, not just bottom — this is now a real <h2> (was a
     plain <div>) for crawler/accessibility semantics, and h2's UA-stylesheet
     top margin would otherwise push it out of this card's fixed height. */
  margin: 0 0 4px;
}

.ad-card__price-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.ad-card__price {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 14.5px;
  color: var(--color-primary);
  min-width: 0;
}

.ad-card__nego {
  font-size: 8.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .02em;
  /* A darkened one-off, not var(--color-accent) directly — at this size
     the label is normal text under WCAG (nowhere near the "large text"
     18.66px-bold cutoff), so it needs a 4.5:1 ratio against its own
     #FFE9E2 chip. The raw accent coral only clears ~2.5:1 there; this
     shade clears ~5.1:1 while staying visibly the same coral family.
     Scoped to this one chip rather than changing --color-accent, which
     is used in plenty of other places (larger text, icon fills) where
     the brighter coral is already fine. */
  color: #B23A1D;
  background: #FFE9E2;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  flex-shrink: 0;
  white-space: nowrap;
}

.ad-card__divider {
  border-top: 1px solid var(--color-border);
  margin: 6px 0 6px;
}

.ad-card__meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.ad-card__loc,
.ad-card__time {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  color: var(--color-text-muted);
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* .ad-card__loc takes whatever space .ad-card__time (a short, fixed
   "2 hours ago"-style string) doesn't need, then truncates via its own
   min-width: 0 + .ad-card__loc-text's ellipsis — .ad-card__meta's
   justify-content: space-between above is what actually keeps them
   pinned to opposite ends of the row. (This used to split the space
   evenly instead, to center a verified-seller pill between them; that
   pill now lives on the card image only — see .ad-card__verified-overlay
   — so there's nothing left to center here.) */
.ad-card__loc {
  flex: 1;
}

.ad-card__time {
  flex: 0 0 auto;
}

.ad-card__loc i,
.ad-card__time i {
  font-size: 10px;
  flex-shrink: 0;
  opacity: .7;
}

/* The location text is the one part of this row allowed to truncate —
   the pin icon beside it stays fixed-size so it's never squeezed. */
.ad-card__loc-text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- Small/large phones — a bit more breathing room ---- */
@media (min-width: 420px) {
  .ad-card {
    height: 136px;
  }

  .ad-card__media {
    width: 128px;
    min-width: 128px;
  }

  .ad-card__body {
    padding: 10px 12px;
  }

  .ad-card__eyebrow {
    font-size: 10px;
  }

  .ad-card__title {
    font-size: 13.5px;
  }

  .ad-card__price {
    font-size: 15.5px;
  }

  .ad-card__loc,
  .ad-card__time {
    font-size: 11px;
  }
}

/* ---- Tablet and up — restore the original balanced layout ---- */
@media (min-width: 600px) {
  .ad-card {
    height: 150px;
  }

  .ad-card__media {
    width: 200px;
    min-width: 200px;
  }

  .ad-card__placeholder {
    font-size: 32px;
  }

  .ad-card__cat-badge {
    top: 8px;
    right: 8px;
    width: 28px;
    height: 28px;
    font-size: 12px;
  }

  .ad-card__like {
    bottom: 8px;
    right: 8px;
    width: 30px;
    height: 30px;
  }

  .ad-card__like i {
    font-size: 13px;
  }

  .ad-card__condition-overlay {
    bottom: 8px;
    left: 8px;
    font-size: 10px;
    padding: 3px 9px;
  }

  .ad-card__body {
    padding: 14px 16px;
  }

  .ad-card__eyebrow {
    font-size: 11px;
  }

  .ad-card__title {
    font-size: 14.5px;
  }

  .ad-card__price {
    font-size: 17px;
  }

  .ad-card__nego {
    font-size: 10px;
    padding: 2px 8px;
  }

  .ad-card__divider {
    margin: 9px 0 8px;
  }

  .ad-card__loc,
  .ad-card__time {
    font-size: 12px;
  }
}

@media (min-width:901px) {
  .ad-card {
    height: 170px;
  }

  .ad-card__media {
    width: 240px;
    min-width: 240px;
  }

  .ad-card__body {
    padding: 16px 20px;
  }

  .ad-card__eyebrow {
    font-size: 11.5px;
  }

  .ad-card__title {
    font-size: 15.5px;
  }

  .ad-card__price {
    font-size: 18px;
  }

  .ad-card__loc,
  .ad-card__time {
    font-size: 12.5px;
  }
}

/* ------------------------------------------------------------  
   CATEGORY CARD (market stall style)
   ------------------------------------------------------------ */
.category-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 22px 16px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
  transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 280ms cubic-bezier(0.16, 1, 0.3, 1);
  text-decoration: none;
}

.category-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  color: var(--color-text);
}

.category-card .icon-wrap {
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 20px;
}

.category-card .label {
  font-weight: 600;
  font-size: 14.5px;
  color: var(--ink);
  line-height: 1.3;
  display: block;
}

.category-card .ad-count {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-faint);
  display: block;
  margin-top: -4px;
}

.category-card:nth-of-type(7n+1) .icon-wrap {
  background: var(--green-deep);
}

.category-card:nth-of-type(7n+2) .icon-wrap {
  background: var(--coral);
}

.category-card:nth-of-type(7n+3) .icon-wrap {
  background: var(--green-bright);
}

.category-card:nth-of-type(7n+4) .icon-wrap {
  background: var(--gold);
}


/* ------------------------------------------------------------  
   SITE HEADER
   ------------------------------------------------------------ */
/* Flat --footer-bg — the same solid, saturated green as .site-footer,
   by request: no gradient, no decorative star field, header and footer
   are now literally the same surface color top and bottom of the page. */
.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 clamp(16px, 5vw, 56px);
  height: 60px;
  background: var(--footer-bg);
  position: sticky;
  top: 0;
  z-index: 50;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
}

/* .site-logo is shared with the admin panel's TEXT logo (layouts/
   admin.blade.php — "Sri<span class="brand-accent">Bazaar</span>" next
   to a colored .dot, both with their own inline color), so it has to
   stay usable with no background/card of its own. */
.site-logo {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 20px;
  letter-spacing: -0.01em;
  color: var(--color-text);
}

.site-logo .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-accent);
  display: inline-block;
}

.site-logo .brand-accent {
  color: var(--color-primary);
}

/* The header's own image logo mark is dark navy linework (see
   .footer-logo-badge's comment in the FOOTER section) — same problem
   here as there, same fix: its own small light card so it doesn't
   disappear into the dark bar, layered on top of the shared .site-logo
   above rather than replacing it. */
.site-logo.header-logo-badge {
  display: inline-flex;
  background: var(--white);
  padding: 6px 14px;
  border-radius: 12px;
  /* Blue-tinted to match .footer-logo-badge's shadow — same light card,
     same brand tie-in, top and bottom of the page. */
  box-shadow: 0 1px 4px rgba(0, 92, 32, .28);
}

.site-logo-img {
  height: 34px;
  width: auto;
  display: block;
  object-fit: contain;
}

.site-logo-img.footer-logo-img {
  height: 56px;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 24px;
  font-weight: 500;
  font-size: 14px;
  /* White, by explicit request (client wants white nav/footer text on
     the bright #00B53F bar, not dark ink) — this measures at 2.73:1,
     below the 4.5:1 AA body-text target, since #00B53F is bright enough
     that no white opacity clears it. Kept at high opacity anyway for the
     best legibility available within "must be white." */
  color: rgba(255, 255, 255, .95);
}

.nav-links a:hover,
.nav-links button:hover {
  color: #fff;
}

.nav-links a.is-active,
.nav-links button.is-active {
  color: #fff;
  font-weight: 600;
}

/* The "Post Ad" nav trigger is a <button> (opens the choice modal) rather
   than a link — match the <a> baseline so it doesn't look out of place.
   background/border/font reset here (not as an inline style on the
   element) so the hover/is-active pill backgrounds below can actually
   apply — an inline style attribute beats any external :hover/.is-active
   rule regardless of selector specificity, which was silently keeping
   this button's background stuck at "none" through both states. */
.nav-links button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  color: inherit;
  background: none;
  border: none;
  font: inherit;
}

/* ------------------------------------------------------------  
   LANGUAGE SWITCHER
   ------------------------------------------------------------ */
.lang-switch {
  display: flex;
  align-items: center;
  background: var(--white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  padding: 2px;
}

.lang-switch button,
.lang-switch a {
  position: relative;
  border: none;
  background: transparent;
  font-family: var(--font-body);
  font-size: 11.5px;
  font-weight: 600;
  padding: 4px 9px;
  border-radius: var(--radius-pill);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: color 200ms ease, background 200ms ease;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}

.lang-switch button:hover,
.lang-switch a:hover {
  color: var(--color-primary);
  background: var(--green-pale);
}

/* Soft divider between locale options — sits in the gap so it never
   touches the hover/active pill background. */
.lang-switch button:not(:last-child),
.lang-switch a:not(:last-child) {
  margin-right: 7px;
}

.lang-switch button:not(:last-child)::after,
.lang-switch a:not(:last-child)::after {
  content: '';
  position: absolute;
  top: 50%;
  right: -4px;
  width: 1.5px;
  height: 12px;
  background: var(--line-strong);
  transform: translateY(-50%);
}

.lang-switch button.active,
.lang-switch a.active {
  background: var(--color-primary);
  color: var(--white);
}

/* ------------------------------------------------------------  
   BOTTOM NAV (Mobile)
   ------------------------------------------------------------ */
.bottom-nav {
  display: none;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: transparent;
  border-top: none;
  z-index: 50;
  padding: 8px 16px;
  padding-bottom: max(8px, env(safe-area-inset-bottom));
  pointer-events: none;
}

.bottom-nav .nav-pill {
  pointer-events: auto;
}

/* Plain straight-top pill — no notch/cutout. The "+" button (below) simply
   floats above it via absolute positioning; position:relative here is what
   anchors that. */
.bottom-nav .nav-pill {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 6px 8px;
  background: var(--white);
  border: 1.5px solid rgba(0, 92, 32, 0.35);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-md);
}

.bottom-nav .nav-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  font-size: 10px;
  font-weight: 600;
  color: var(--color-text-muted);
  text-decoration: none;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  transition: all 200ms ease;
}

/* Active/hover state now matches the top nav bar's own background
   (--footer-bg, the client's bright #00B53F green) rather than the darker
   --color-primary, so the "current page" signal reads as the same brand
   green a visitor already saw in the header above. */
.bottom-nav .nav-item:hover,
.bottom-nav .nav-item.is-active {
  color: var(--footer-bg);
}

.bottom-nav .nav-item i {
  font-size: 18px;
}

/* Unread-chat count dot on the "Chat" nav link — same small circular badge
   in both the desktop header nav and the mobile bottom nav, just anchored
   differently since one is a horizontal icon+label row and the other is a
   stacked icon-over-label column. position:relative on the link (not
   display) is what lets the badge sit absolutely without being pulled
   into either layout's own flex flow. Server-rendered on first load (see
   $navUnreadChatCount / ChatBadgeComposer) and kept live afterwards by
   public/js/push-notifications.js. */
.nav-chat-link {
  position: relative;
}

.chat-nav-badge {
  position: absolute;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: var(--radius-pill);
  background: var(--coral);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 0 2px var(--white);
  pointer-events: none;
}

.bottom-nav .nav-item.nav-chat-link .chat-nav-badge {
  top: -2px;
  left: calc(50% + 5px);
}

/* The base white ring above is right for the bottom-nav's white pill, but
   in the header (.nav-links only exists there) it would sit on the dark
   bar as a stray white halo instead of a seamless cutout. The header is
   a flat --footer-bg now, so the ring can just match it exactly rather
   than approximate a gradient blend. */
.nav-links .chat-nav-badge {
  box-shadow: 0 0 0 2px var(--footer-bg);
}

.bottom-nav .nav-sell {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--color-accent), #ff8a6a);
  color: #fff;
  font-size: 22px;
  margin-top: -20px;
  box-shadow: 0 4px 14px rgba(255, 110, 74, 0.4);
  text-decoration: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

.mobile-only {
  display: none !important;
}

@media (max-width: 900px) {
  .bottom-nav {
    display: block;
  }

  /* No body padding-bottom here anymore — that clearance for the fixed
     bottom-nav used to live on body, which left a strip of its own cream
     background showing below the footer. .site-footer now carries the
     equivalent padding itself (see its rule further down), so that strip
     fills with the footer's dark background instead. */

  .desktop-only {
    display: none !important;
  }

  .mobile-only {
    display: block !important;
  }
}

/* ------------------------------------------------------------
   FOOTER — bright brand-green surface

   --footer-bg is the exact client hex, var(--green-bright) #00B53F. Text/
   icons are white, by explicit client request — kept even after briefly
   trying dark ink (which measured better on paper: ink @ 92% hit 5.1:1
   here, comfortably past the 4.5:1 AA target). White @ 95% only measures
   ~2.6:1 against this bright a green — below the AA body-text minimum —
   but the client found it "fine and visible" in practice and asked to
   keep white, so this is a deliberate, informed exception to the 4.5:1
   guideline rather than an oversight. Scoped as custom properties on
   .site-footer itself (not the light-theme --color-text/--color-text-
   muted/--color-border, which assume a light surface and would read as
   near-invisible here regardless of the contrast question above):

     --footer-text        white @ 95% → ~2.6:1  (links, contact details)
     --footer-text-muted  white @ 93% → ~2.5:1  (tagline, copyright line)
     --footer-heading     white @ 94% → ~2.6:1  (uppercase column labels)
     --footer-divider     white @ 12%           (decorative hairlines only)
     --footer-control-border white @ 70% → ~2.0:1 (badge/social-icon rings)
     --footer-icon-accent  white @ 90% → ~2.5:1  (contact-line icons)
   ------------------------------------------------------------ */
.site-footer {
  --footer-heading: rgba(255, 255, 255, .94);
  --footer-text: rgba(255, 255, 255, .95);
  --footer-text-muted: rgba(255, 255, 255, .93);
  --footer-divider: rgba(255, 255, 255, .12);
  --footer-control-border: rgba(255, 255, 255, .70);
  --footer-icon-accent: rgba(255, 255, 255, .90);

  background: var(--footer-bg);
  padding: 40px 0 0;
  margin-top: 60px;
}

/* Below 900px the fixed .bottom-nav pill needs the same clearance body
   used to provide on its own — carrying it here instead means the space
   is filled by the footer's own --footer-bg (extending the bright green
   surface all the way to the bottom of the page) rather than leaving a
   strip of the page's cream background showing beneath the footer's
   visible content. Nothing above this — the columns, the copyright bar —
   moves; this is pure padding added after it. */
@media (max-width: 900px) {
  .site-footer {
    padding-bottom: calc(var(--bottom-nav-height) + 16px);
  }
}

/* The brand mark itself is dark navy linework (see
   public/images/sribazaar-logo-mark.png) — designed to sit on a light
   surface, so it would all but disappear directly on --ink. Rather than
   flattening it to a monochrome silhouette (losing the gold flame accent),
   it gets its own small light card to stand on, the way most brand marks
   with real color get treated on a dark footer. */
.site-logo.footer-logo-badge {
  display: inline-flex;
  background: var(--white);
  padding: 10px 20px;
  border-radius: 14px;
  /* Blue-tinted rather than plain black, so the one light-colored shape
     on this dark footer visibly belongs to the brand rather than reading
     as a generic drop shadow. */
  box-shadow: 0 2px 10px rgba(0, 92, 32, .28);
}

/* Edge-to-edge like .site-header, not boxed to --container-max like the
   page sections above it — the footer is meant to read as a full-width
   band, with the same clamp()-based side padding the header uses rather
   than a centered fixed-width column. */
.footer-inner {
  padding-inline: clamp(16px, 5vw, 56px);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.5fr repeat(3, 1fr);
  gap: 32px;
}

/* Added only when the admin has configured at least one app-store link
   (see the Get App .footer-col in layouts/app.blade.php) — an extra
   column rather than the old horizontal band, so the badges stack in
   their own list instead of interrupting the layout with a divider on
   either side of a centered row.

   The last track is pinned to at least 200px rather than a plain 1fr:
   at viewports just above the 720px mobile collapse, four equal-ish 1fr
   tracks squeezed this column narrower than the 176px-wide app badges,
   wrapping/clipping their text — minmax() keeps this one column from
   ever getting that tight, letting the others share what's left. */
.footer-grid--5col {
  grid-template-columns: 1.5fr repeat(3, 1fr) minmax(200px, 1fr);
}

.footer-col h4 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--footer-heading);
  margin-bottom: 12px;
  font-weight: 600;
}

.footer-col a {
  display: block;
  font-size: 14px;
  color: var(--footer-text);
  margin-bottom: 8px;
  transition: color 200ms ease;
}

.footer-col a:hover {
  color: #fff;
}

.footer-tagline {
  font-size: 14px;
  color: var(--footer-text-muted);
}

.footer-contact-line {
  font-size: 14px;
  color: var(--footer-text);
}

.footer-contact-line i {
  color: var(--footer-icon-accent);
  width: 14px;
  text-align: center;
}

/* The Get App column's own list of badges, stacked rather than the old
   horizontal row — each badge keeps its natural (not stretched) width so
   two different-width badges don't look mismatched sharing one column. */
.footer-app-badges {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

.footer-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 32px;
  padding: 16px 0;
  border-top: 1px solid var(--footer-divider);
  font-size: 12px;
  color: var(--footer-text-muted);
}

.footer-bottom a {
  color: var(--footer-text-muted);
}

.footer-bottom a:hover {
  color: #fff;
}

.footer-social-icon {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .08);
  border: 1px solid var(--footer-control-border);
  color: var(--footer-text);
  font-size: 15px;
  line-height: 1;
  margin-bottom: 0;
  transition: all 0.2s ease;
}
.footer-social-icon i {
  font-style: normal;
  color: inherit;
}

/* Each platform hovers to its own brand color, with the icon forced to
   white — guarantees the glyph never blends into its own background. */
.footer-social-icon:hover {
  color: #fff !important;
  transform: translateY(-2px);
}

.footer-social-icon--whatsapp:hover { background: #25D366; }
.footer-social-icon--facebook:hover { background: #1877F2; }
.footer-social-icon--instagram:hover { background: linear-gradient(135deg, #F09433, #E6683C, #DC2743, #CC2366, #BC1888); }
.footer-social-icon--youtube:hover { background: #FF0000; }
.footer-social-icon--tiktok:hover { background: #000; }
.footer-social-icon--twitter:hover { background: #000; }

/* min-content-safe: the badge's own text ("GET IT ON" / "Google Play")
   needs roughly 150-170px to never wrap, and the Get App column used to
   be an ordinary 1fr track that could get squeezed narrower than that
   between the desktop breakpoint and the 720px mobile collapse — that
   squeeze (not a missing icon or bad markup) was what made the badges
   wrap/clip and look broken. See .footer-grid--5col's minmax() fix. */
.footer-app-badge {
  /* !important because .footer-col a { display: block; } (below) also
     matches this <a> — it's nested inside a .footer-col too — and that
     selector's added element specificity (0,1,1) beats a lone class
     (0,1,0), so without this the icon and text block-stack instead of
     sitting side by side. .footer-social-icon needed the exact same fix
     for the same reason. */
  display: inline-flex !important;
  align-items: center;
  gap: 10px;
  width: 176px;
  padding: 10px 14px;
  border-radius: 10px;
  background: #111;
  /* The badge's own near-black fill reads clearly against --footer-bg
     now that it's the bright #00B53F (~6.9:1 — a near-black square
     genuinely stands out against a vivid green), so the ring below is
     more a finishing touch than a load-bearing edge at this point, but
     it's kept anyway for a crisp boundary at small sizes. */
  border: 1px solid var(--footer-control-border);
  color: #fff !important;
  font-size: 12px;
  text-decoration: none !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
  transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease;
}

.footer-app-badge:hover {
  transform: translateY(-2px);
  border-color: rgba(255, 255, 255, .55);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .32);
}

/* A fixed-width box around the glyph (not just a font-size) — the Apple
   mark and the Google Play triangle have different natural widths, so
   without this the two badges' text columns don't line up with each
   other even though the badges themselves are the same size. */
.footer-app-badge i {
  width: 22px;
  flex-shrink: 0;
  font-size: 20px;
  text-align: center;
}

.footer-app-badge > div {
  min-width: 0;
}

.footer-app-badge small,
.footer-app-badge > div > div {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.footer-app-badge small {
  font-size: 10px;
  opacity: 0.8;
  display: block;
  line-height: 1;
}

@media (max-width:720px) {
  /* Two columns instead of the old single left-aligned stack. Order flows
     row-by-row: Browse|Account, then Contact|(empty), so the last row
     leaves its right cell blank rather than stretching one link list
     across the full width. minmax(0,1fr) so a long untranslatable string
     can't push a track past the edge. */
  .footer-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 24px 20px;
  }

  /* The brand column (logo mark + tagline + social icons) leads the mobile
     footer as a full-width, centered band across the top — it's the one
     piece of pure identity, so it reads first instead of being squeezed
     into a half column next to a link list. */
  .footer-col--brand {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
  }

  /* The app badges are fixed at 176px for the desktop column (see
     .footer-app-badge); in a half-width mobile column that overflows
     phones narrower than ~410px, so they stretch to fill their cell. */
  .footer-app-badge {
    width: 100%;
  }

  .footer-bottom {
    flex-direction: column;
    gap: 12px;
    text-align: center;
  }
}

/* ------------------------------------------------------------  
   SECTION HEADERS
   ------------------------------------------------------------ */
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 20px;
}

.section-head h2 {
  font-size: clamp(20px, 3vw, 28px);
  margin: 0;
}

.section-head .see-all {
  font-size: 14px;
  font-weight: 600;
  color: var(--color-primary);
  white-space: nowrap;
}

.section-head .see-all:hover {
  text-decoration: underline;
}

/* ------------------------------------------------------------
   AD GRID — 2-up mobile grid of square tiles, 4-up on desktop
   ------------------------------------------------------------ */
.ad-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  /* Deliberately not the grid default (stretch): a taller card in one
     column shouldn't force its row-mate in the other column to stretch
     to match it. Every card sizes to its own content — a 2-line title
     is simply a bit taller than a 1-line one, by design. */
  align-items: start;
  gap: 12px;
}

/* Both the main listings grid (home's "Latest Listings", search,
   favorites) and .featured-grid's boosted-listings strip reuse the exact
   same <x-ad-card> component, and both now get the exact same tile
   treatment: .ad-card switches from its shared horizontal list-row
   layout (image left, fixed row height — see .ad-card's own rules
   above) to a vertical tile — a square image on top, details stacked
   below, height following its content. Scoped to these two grid
   containers rather than changed on .ad-card itself so any *other* place
   the component is reused (seller profile, saved ads, etc.) keeps the
   original horizontal row card unless/until it's asked for there too.

   These overrides all use a two-class selector (.ad-grid .ad-card etc.),
   which beats the plain one-class .ad-card / .ad-card__media rules —
   including their 420px/600px/901px fixed-height and fixed-media-width
   breakpoints above — on specificity alone, so none of those need
   editing or duplicating here. */
.ad-grid .ad-card,
.featured-grid .ad-card {
  flex-direction: column;
  height: auto;
}

.ad-grid .ad-card__media,
.featured-grid .ad-card__media {
  width: 100%;
  min-width: 0;
  aspect-ratio: 1 / 1;
}

.ad-grid .ad-card__body,
.featured-grid .ad-card__body {
  justify-content: flex-start;
}

/* Grid items default to min-width: auto (their content's min-content
   size), not 0 — so a nowrap-heavy descendant (the meta row's location/
   verified-pill/time trio, which doesn't wrap) could force its column
   wider than its 1fr share to fit, expanding the whole grid past the
   viewport on narrow phones. Resetting the grid item itself (whichever
   element that is — a plain wrapper <div> on the home/search pages, or
   the card's own <article> on favorites/saved) is what actually lets the
   1fr tracks shrink the card down to the column's real width; the
   already-truncating text inside (.ad-card__loc-text, etc.) only gets a
   chance to ellipsis once its container is allowed to be that narrow. */
.ad-grid > *,
.featured-grid > * {
  min-width: 0;
}

   ------------------------------------------------------------ */
.toast-container-sb {
  position: fixed;
  bottom: 80px;
  right: 16px;
  left: 16px;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
}

.toast-sb {
  pointer-events: auto;
  background: var(--white);
  color: var(--color-text);
  padding: 14px 16px;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 500;
  box-shadow: 0 4px 24px rgba(0, 0, 0, .12);
  border-left: 4px solid var(--color-primary);
  animation: toastIn 300ms ease-out;
  display: flex;
  align-items: center;
  gap: 10px;
}

.toast-sb .toast-icon {
  font-size: 16px;
  flex-shrink: 0;
}

.toast-sb .toast-msg {
  flex: 1;
}

.toast-sb .toast-close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-text-muted);
  font-size: 14px;
  padding: 4px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 150ms ease;
  flex-shrink: 0;
}

.toast-sb .toast-close:hover {
  color: var(--color-text);
}

.toast-sb.is-success {
  border-left-color: var(--color-primary);
}

.toast-sb.is-success .toast-icon {
  color: var(--color-primary);
}

.toast-sb.is-error {
  border-left-color: var(--color-danger);
}

.toast-sb.is-error .toast-icon {
  color: var(--color-danger);
}

.toast-sb.is-warning {
  border-left-color: var(--color-warning);
}

.toast-sb.is-warning .toast-icon {
  color: var(--color-warning);
}

.toast-sb.toast-exit {
  animation: toastOut 250ms ease-in forwards;
}

@keyframes toastIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(.96);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

@keyframes toastOut {
  from {
    opacity: 1;
    transform: translateY(0) scale(1);
  }

  to {
    opacity: 0;
    transform: translateY(-8px) scale(.96);
  }
}

@media (min-width:901px) {
  .toast-container-sb {
    left: auto;
    width: 380px;
  }
}

/* ------------------------------------------------------------  
   EMPTY STATE
   ------------------------------------------------------------ */
.empty-state {
  text-align: center;
  padding: 60px 20px;
  color: var(--color-text-muted);
}

.empty-state i {
  font-size: 48px;
  color: var(--line);
  margin-bottom: 16px;
}

.empty-state h3 {
  color: var(--color-text);
  font-size: 20px;
  margin-bottom: 8px;
}

.empty-state p {
  font-size: 15px;
  margin-bottom: 20px;
}


/* ------------------------------------------------------------
   MOBILE HEADER ACTIONS (lang switcher)
   ------------------------------------------------------------ */
.mobile-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

@media (min-width: 901px) {
  .mobile-header-actions {
    display: none;
  }
}

/* District filter pill, centered in the mobile nav bar independent
   of the logo/lang-switch flex row. */
.mobile-district-center {
  display: none;
}

@media (max-width: 900px) {
  .mobile-district-center {
    display: inline-flex;
    align-items: center;
    gap: 0;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 1;
  }
}

@media (min-width: 576px) {
  #postChoiceModal .modal-dialog {
    margin: auto;
  }
}

.post-choice-option {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 14px 16px;
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: var(--color-text);
  transition: border-color 150ms ease, background 150ms ease;
}

.post-choice-option:hover {
  border-color: var(--color-primary);
  background: var(--green-pale-faint);
  color: var(--color-text);
}

.post-choice-option__icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--green-pale, #F0FDF4);
  color: var(--color-primary);
  font-size: 18px;
}

.post-choice-option__icon--accent {
  background: #FFF7ED;
  color: var(--color-accent);
}

.post-choice-option__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.post-choice-option__title {
  font-weight: 700;
  font-size: 15px;
}

.post-choice-option__desc {
  font-size: 12px;
  color: var(--color-text-muted);
  line-height: 1.4;
  overflow-wrap: break-word;
}

.post-choice-option__arrow {
  flex-shrink: 0;
  color: var(--color-text-muted);
  font-size: 13px;
}

.post-choice-option--locked .post-choice-option__icon {
  background: #F3F4F6;
  color: #9CA3AF;
}

.post-choice-option--locked:hover {
  border-color: #D1D5DB;
  background: #F9FAFB;
}

/* Profile nav tiles */
.profile-tiles {
  margin-top: 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

[data-reveal="card"] {
  transition-delay: var(--delay, 0ms);
}

/* ---- Section spacing ---- */
.home-section {
  padding-top: 20px;
  padding-bottom: 8px;
}

/* Breathing room before the footer now that the page ends on a listing grid */
.home-section:last-of-type {
  padding-bottom: 40px;
}

/* Tighter heading gap than the shared .section-head default (20px, 28px on
   desktop) — the home sections read as a compact, buyer-first feed. */
.home-section .section-head {
  margin-bottom: 16px;
}

/* The promo slot / placeholder each carry their own top margin as a
   stand-in for a section heading; inside the home sponsor section the
   section's own padding already provides that gap, so zero the extra. */
.home-sponsor-section .promo-slot,
.home-sponsor-section .ad-slot-placeholder {
  margin-top: 0;
}

/* ---- Hero — centered, no bg, floating icons ----
   Deliberately compact: search + district sit right below the header so
   the actual value (categories, listings) is reachable without scrolling. */
.hero-wrap {
  position: relative;
  padding: clamp(16px, 3vw, 32px) clamp(16px, 5vw, 56px) clamp(20px, 3vw, 32px);
  text-align: center;
  /* No overflow:hidden here — it would clip the search suggestion panel,
     which hangs below the search field. The .hero-floats child clips
     itself instead, so nothing escapes. */
}

.hero-search-area {
  position: relative;
  z-index: 2;
  max-width: 640px;
  margin: 0 auto;
}

/* ---- Compact seller CTA below the search bar ----
   One muted line — a deliberate reduction from the previous full card, so
   the buyer-facing search stays the hero's focus. Only the link/button is
   clickable; the surrounding line is plain text. */
.hero-sell-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 14px 0 0;
  font-size: 13px;
  line-height: 1.4;
  color: var(--color-text-muted);
}

.hero-sell-cta__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  font-weight: 700;
  color: var(--color-primary);
  cursor: pointer;
  text-decoration: none;
}

.hero-sell-cta__link:hover {
  text-decoration: underline;
}

@keyframes heroFadeUp {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Floating category icons — more visible, varied timing */
.hero-floats {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  overflow: hidden;
}

.hero-float-icon {
  position: absolute;
  font-size: 28px;
  color: var(--line-strong);
  opacity: .18;
  animation: heroFloatDrift 12s ease-in-out infinite;
}

.hero-float-icon:nth-child(1) {
  top: 12%;
  left: 6%;
  animation-delay: 0s;
  font-size: 28px;
  color: var(--green-deep);
  opacity: .1;
  animation-duration: 14s;
}

.hero-float-icon:nth-child(2) {
  top: 20%;
  right: 8%;
  animation-delay: 1.5s;
  font-size: 34px;
  color: var(--coral);
  opacity: .09;
  animation-duration: 11s;
}

.hero-float-icon:nth-child(3) {
  bottom: 18%;
  left: 12%;
  animation-delay: 3s;
  font-size: 26px;
  color: var(--gold);
  opacity: .11;
  animation-duration: 16s;
}

.hero-float-icon:nth-child(4) {
  bottom: 28%;
  right: 6%;
  animation-delay: 0.5s;
  font-size: 30px;
  color: var(--green-bright);
  opacity: .09;
  animation-duration: 13s;
}

.hero-float-icon:nth-child(5) {
  top: 38%;
  left: 2%;
  animation-delay: 2s;
  font-size: 22px;
  color: var(--ink-faint);
  opacity: .07;
  animation-duration: 15s;
}

.hero-float-icon:nth-child(6) {
  top: 8%;
  left: 40%;
  animation-delay: 4s;
  font-size: 18px;
  color: var(--coral);
  opacity: .06;
  animation-duration: 18s;
}

.hero-float-icon:nth-child(7) {
  bottom: 10%;
  right: 35%;
  animation-delay: 1s;
  font-size: 20px;
  color: var(--green-deep);
  opacity: .07;
  animation-duration: 12s;
}

@keyframes heroFloatDrift {

  0%,
  100% {
    transform: translate(0, 0) rotate(0deg);
  }

  25% {
    transform: translate(8px, -14px) rotate(4deg);
  }

  50% {
    transform: translate(-6px, 10px) rotate(-3deg);
  }

  75% {
    transform: translate(10px, 6px) rotate(5deg);
  }
}

/* Search bar — animated entrance */
.hero-search {
  display: flex;
  align-items: center;
  background: var(--white);
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--line-strong);
  padding: 4px 4px 4px 0;
  transition: border-color .2s ease, box-shadow .2s ease;
  opacity: 0;
  transform: translateY(12px);
  animation: heroFadeUp .6s .45s cubic-bezier(.16, 1, .3, 1) forwards;
}

.hero-search:focus-within {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 4px var(--green-pale), 0 4px 20px rgba(0, 92, 32, .08);
}

.hero-search-icon {
  padding: 0 16px;
  color: var(--ink-faint);
  font-size: 16px;
  flex-shrink: 0;
}

.hero-search-input {
  flex: 1;
  /* Flex items default to min-width:auto, which stops the input shrinking
     below its intrinsic width — with the clear button now sharing the row,
     that would push the field wider than its container on narrow screens. */
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font-size: 15px;
  color: var(--color-text);
  padding: 12px 0;
  font-family: var(--font-body);
  -webkit-tap-highlight-color: transparent;
  appearance: none;
  -webkit-appearance: none;
}

.hero-search-input:focus {
  outline: none;
  box-shadow: none;
}

.hero-search-input::placeholder {
  color: var(--ink-faint);
}

/* Matches the site header's own background (--footer-bg, the same bright
   green as .site-header/.site-footer) rather than the theme's default
   button green (--color-primary) — ties the search action visually to the
   nav bar it sits directly under, on both the home and search pages (this
   component is shared — see components/search-suggest.blade.php). */
.hero-search-btn {
  padding: 10px 20px;
  background: var(--footer-bg);
  color: #fff;
  border: none;
  border-radius: var(--radius-pill);
  font-size: 14px;
  cursor: pointer;
  transition: background .2s ease, transform .15s ease;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.hero-search-btn:hover {
  background: var(--color-primary);
  transform: scale(1.03);
}

/* ---- Home ad slot placeholder (below search bar) ---- */
/* Reserved space for a future randomly-shown boosted listing or
   external ad unit. No display logic wired up yet — markup + style only. */
/* Gold-toned to match the .ad-slot-placeholder__tag / .promo-slot__tag
   "Sponsored" badge (same #B8860B family) rather than a plain neutral
   dashed box — reads as "premium spot, currently empty" instead of a
   generic broken/missing-content placeholder. */
.ad-slot-placeholder {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 90px;
  margin-top: 20px;
  padding: 20px 16px;
  background-color: #FFFCF3;
  background-image:
    repeating-linear-gradient(45deg, rgba(184, 134, 11, 0.07) 0, rgba(184, 134, 11, 0.07) 1px, transparent 1px, transparent 13px),
    repeating-linear-gradient(-45deg, rgba(184, 134, 11, 0.07) 0, rgba(184, 134, 11, 0.07) 1px, transparent 1px, transparent 13px);
  border: 3px dashed rgba(184, 134, 11, .45);
  border-radius: var(--radius-lg);
  color: var(--color-text-muted);
  text-align: center;
}

.ad-slot-placeholder__tag {
  position: absolute;
  top: -7px;
  left: 16px;
  color: #3A2600;
  font-size: 8px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .3px;
  white-space: nowrap;
  overflow: visible;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  border: 1px solid rgba(154, 111, 14, .35);
  background: linear-gradient(100deg, #C9971E 0%, #E8C874 50%, #B8860B 100%);
  text-shadow: 0 1px 1px rgba(255, 255, 255, .35);
  box-shadow: 0 1px 3px rgba(120, 84, 8, .28);
}

.ad-slot-placeholder__tag i {
  font-size: 7px;
  color: #3A2600;
}

.ad-slot-placeholder__inner {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--color-text);
}

.ad-slot-placeholder__inner i {
  font-size: 18px;
  color: #B8860B;
  opacity: .7;
}

.ad-slot-placeholder__sub {
  font-size: 11.5px;
  color: var(--color-text-muted);
  line-height: 1.4;
  background: #FFFCF3;
  border: 1px solid rgba(184, 134, 11, .25);
  border-radius: var(--radius-pill);
  padding: 4px 14px;
}

@media (min-width: 901px) {
  .ad-slot-placeholder {
    min-height: 110px;
  }

  .ad-slot-placeholder__inner {
    font-size: 14.5px;
  }

  .ad-slot-placeholder__sub {
    font-size: 12.5px;
  }
}

/* ---- Home promo slot — rotating paid Promotion campaigns ---- */
/* Same slot position as .ad-slot-placeholder (below the hero search bar)
   but shown instead of it whenever at least one paid Promotion campaign
   is currently active. Every card is permanently position:absolute — only
   .is-active toggles opacity/transform, never `position` itself, so the
   browser never has to reflow mid-transition (that reflow was what made
   the earlier version stutter). Rotation is fully automatic, driven by
   public/js/promo-rotator.js — no manual dot controls. */
.promo-slot {
  position: relative;
  margin-top: 22px;
}

/* Same pill treatment as .ad-slot-placeholder__tag (the no-ads fallback)
   so the "Sponsored" label looks identical whichever state is showing.
   Static gold gradient (no shimmer animation) — an animated sweep kept
   dragging dark text through the gradient's brightest stop, tanking
   contrast at that point in the cycle. A fixed gradient position keeps
   contrast constant and still reads as "premium," just quieter. */
.promo-slot__tag {
  position: absolute;
  top: -7px;
  left: 16px;
  z-index: 2;
  color: #3A2600;
  font-size: 8px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .3px;
  white-space: nowrap;
  overflow: visible;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border: 1px solid rgba(154, 111, 14, .35);
  background: linear-gradient(100deg, #C9971E 0%, #E8C874 50%, #B8860B 100%);
  text-shadow: 0 1px 1px rgba(255, 255, 255, .35);
  box-shadow: 0 1px 3px rgba(120, 84, 8, .28);
}

.promo-slot__tag i {
  font-size: 7px;
  color: #3A2600;
}

/* Aspect-ratio (rather than a fixed pixel height) so the slot's shape
   scales consistently with its width across breakpoints — this matches
   Promotion::RECOMMENDED_WIDTH/HEIGHT (1200x300, 4:1), so a correctly
   sized upload is never cropped by object-fit: cover. min-height is only
   a floor for extremely narrow viewports. */
.promo-slot__viewport {
  position: relative;
  aspect-ratio: 4 / 1;
  min-height: 80px;
  border-radius: 10px;
}

/* Light-gray fill (not stark white, not dark) with a full rounded ring
   border — a three-color gradient (green/coral/gold, the same accent
   colors used elsewhere across the site), wrapped all the way around the
   card and slowly animated, instead of a flat solid border. */
.promotion-list-card {
  position: absolute;
  inset: 0;
  display: grid;
  /* auto (not a hardcoded px number) lets the column size itself to
     whatever width makes the media square for the row's actual height —
     see .promotion-list-card__media's aspect-ratio. The row's height
     itself is untouched (still whatever .promo-slot__viewport's 4:1
     aspect-ratio produces), so this never makes the card taller. */
  grid-template-columns: auto 1fr;
  /* Same premium cream-gold fill as .ad-card--boosted — this slot only
     ever shows boosted/sponsored content, so it gets the same "boosted"
     signal. Border stays exactly as it was: the animated gradient ring
     below is untouched. */
  background: linear-gradient(155deg, #FFFDF6 0%, #FFF6DE 100%);
  border: none;
  border-radius: 10px;
  overflow: hidden;
  opacity: 0;
  transform: scale(1.02);
  pointer-events: none;
  will-change: opacity, transform;
  transition: opacity .9s cubic-bezier(.4, 0, .2, 1), transform .9s cubic-bezier(.4, 0, .2, 1);
  text-decoration: none;
  color: var(--color-text);
  text-align: center;
  box-shadow: 0 8px 18px -14px rgba(18, 39, 32, .28);
}

/* Ring trick: paint the gradient across the whole padding-box, then mask
   out everything except a thin band at the edge (content-box XOR
   padding-box) — the result is a border that follows every rounded
   corner exactly, which a plain `border` can't do with a moving gradient. */
.promotion-list-card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  padding: 1.5px;
  background: linear-gradient(90deg, var(--green-deep) 0%, var(--coral) 50%, var(--gold) 100%);
  background-size: 200% 100%;
  animation: promoAccentFlow 5s linear infinite;
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .promotion-list-card::before {
    animation: none;
  }
}

@keyframes promoAccentFlow {
  0% { background-position: 0% 50%; }
  100% { background-position: -200% 50%; }
}

.promotion-list-card.is-active {
  opacity: 1;
  transform: scale(1);
  pointer-events: auto;
  z-index: 1;
}

.promotion-list-card:hover {
  box-shadow: 0 10px 22px -14px rgba(18, 39, 32, .38);
}

.promotion-list-card__media {
  position: relative;
  height: 100%;
  aspect-ratio: 1 / 1;
  background: var(--green-pale);
  border-right: 1px solid var(--line-strong);
  overflow: hidden;
}

.promotion-list-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 6s cubic-bezier(.16, 1, .3, 1);
}

.promotion-list-card.is-active .promotion-list-card__media img {
  transform: scale(1.08);
}

.promotion-list-card__placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--green-pale);
  color: var(--color-primary);
  font-size: 20px;
  opacity: .45;
}

/* Standalone paid Promotion banner — full-bleed media instead of the
   media+details grid used for boosted-ad cards, so images/GIFs/videos read
   as a proper sponsored banner. */
.promotion-list-card--banner {
  display: block;
  text-decoration: none;
  color: inherit;
}

.sponsored-banner__media {
  position: relative;
  width: 100%;
  height: 100%;
}

/* The always-rendered icon placeholder sits behind the banner image (see
   components/sponsored-promotion-card.blade.php) so a still-loading banner
   shows the bullhorn rather than a blank panel; handleImgError() reveals
   it if the media ever fails. */
.sponsored-banner__placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--green-pale);
  color: var(--color-primary);
  font-size: 30px;
  opacity: .5;
}

.sponsored-banner__media img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.sponsored-banner__cta {
  position: absolute;
  bottom: 10px;
  right: 10px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: var(--radius-pill);
  background: rgba(15, 23, 42, .72);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .02em;
}

.promotion-list-card__body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 9px 14px 8px 14px;
}

/* Two pill badges at opposite edges: category left, negotiable right.
   Right edge lines up with the price below, so "negotiable" reads as
   sitting directly over the price — and the category's position never
   moves whether or not a negotiable badge is present next to it. */
.promotion-list-card__badges {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 5px;
}

.promotion-list-card__cat {
  flex-shrink: 0;
  background: var(--green-pale);
  color: var(--color-primary);
  font-size: 8.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .4px;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
}

.promotion-list-card__nego-badge {
  flex-shrink: 0;
  background: var(--white);
  color: var(--ink);
  border: 1px solid var(--ink);
  font-size: 8.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .4px;
  padding: 1px 8px;
  border-radius: var(--radius-pill);
}

/* Quieter than "Negotiable" on purpose — this is the default/expected
   state, not something that needs to grab attention. */
.promotion-list-card__fixed-badge {
  flex-shrink: 0;
  background: transparent;
  color: var(--color-text-muted);
  border: 1px solid var(--line-strong);
  font-size: 8.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .4px;
  padding: 1px 8px;
  border-radius: var(--radius-pill);
}

/* Title, closed off with one hairline rule before the seller/price footer.
   Badges stay pinned to the top and the footer stays pinned to the bottom
   (see its margin removal below) — this auto top/bottom margin pair is
   what centers the title+rule as one tight unit in whatever leftover
   vertical room the (now-square, often tall) media leaves between them,
   without stretching the title away from its own hairline rule. */
.promotion-list-card__heading {
  margin-top: auto;
  margin-bottom: auto;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line-strong);
}

.promotion-list-card__title {
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: -.1px;
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.promotion-list-card__footer {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 3px;
}

/* Outlined in the danger color — an attention-getting outline reserved
   for this one signal (where the listing actually is), now that seller
   name (not a relevant signal on a sponsored card) has been dropped. */
.promotion-list-card__loc {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  max-width: 60%;
  background: transparent;
  color: var(--color-danger);
  border: 1px solid var(--color-danger);
  font-size: 9.5px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.promotion-list-card__loc i {
  font-size: 9px;
  flex-shrink: 0;
}

.promotion-list-card__price {
  margin-left: auto;
  font-size: 13.5px;
  font-weight: 800;
  color: var(--color-primary);
  flex-shrink: 0;
}

/* Sits between .promotion-list-card__loc and .promotion-list-card__price
   in the same footer row — auto margins on both sides share the row's
   remaining free space (alongside .promotion-list-card__price's own
   margin-left:auto), which centers it in the gap between the two rather
   than crowding either one. */
.promotion-list-card__verified-pill {
  margin: 0 auto;
  flex-shrink: 0;
  padding: 1px 6px;
  gap: 3px;
  font-size: 9px;
  white-space: nowrap;
}

.promotion-list-card__verified-pill .verified-badge--xs {
  width: 10px;
  height: 10px;
}

.promotion-list-card__verified-pill .verified-badge--xs .verified-badge__seal {
  font-size: 10px;
}

.promotion-list-card__verified-pill .verified-badge--xs .verified-badge__check {
  font-size: 5px;
}

@media (min-width: 901px) {
  .promotion-list-card__verified-pill {
    font-size: 10px;
    padding: 2px 8px;
  }
}

@media (min-width: 901px) {
  .promo-slot__viewport {
    min-height: 118px;
  }

  .promotion-list-card__body {
    padding: 13px 20px 11px 20px;
  }

  .promotion-list-card__title {
    font-size: 16px;
  }

  .promotion-list-card__cat,
  .promotion-list-card__nego-badge,
  .promotion-list-card__fixed-badge {
    font-size: 10px;
  }

  .promotion-list-card__badges {
    margin-bottom: 6px;
  }

  .promotion-list-card__loc {
    font-size: 10.5px;
    padding: 3px 10px;
  }

  .promotion-list-card__price {
    font-size: 15.5px;
  }
}

/* ---- Featured — list cards ----
   Same 2-up/4-up square-tile grid as .ad-grid (see its own comment) —
   boosted listings use the exact same <x-ad-card> component, and get the
   exact same card treatment, so "Boosted Listings" and "Latest Listings"
   read as one consistent card style. A plain grid, not a horizontally-
   scrollable row, so there's nothing here to page through — the
   .featured-wrap/.featured-arrow slider controls that used to sit
   alongside this (left over from when it was a horizontal row) have been
   removed. */
.featured-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: start;
  gap: 12px;
}

/* ---- Category icon (components/category-icon.blade.php) ----
   Admin-uploaded icon image or a generic placeholder glyph, sized off
   whatever font-size the wrapping element already sets — the same sizing
   convention every fa-solid category icon used before it. */
.category-icon--placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  font-size: 1em;
  color: var(--ink-faint, #9aa0a6);
}

.category-icon--image {
  /* Deliberately bigger than the placeholder's 1em (not a mismatch — see
     .cat-row-icon/.category-page-icon for the shared font-size both
     read from): an admin-uploaded icon very often ships with its own
     built-in canvas padding around the actual glyph (most icon-set
     exports do this), so at an identical 1em box the uploaded artwork
     reads noticeably smaller than the placeholder, which fills its box
     edge-to-edge. 1.3em compensates for that typical padding so the two
     read as "the same size" in practice, which is what actually matters
     here rather than the two boxes being byte-for-byte equal. */
  width: 2em;
  height: 2em;
  object-fit: contain;
  vertical-align: middle;
}


/* ---- Category row grid ----
   Bordered tiles matching the categories page's .category-page-card — no
   fill/shadow, just the same 1.5px --line-strong edge, so a category reads
   identically whether it's in the home slider or on the full page. */
/* minmax(0, …) rather than a bare 1fr: a grid track defaults to
   min-width:auto, so a long un-breakable label (Tamil and Sinhala names
   have no "&" for short_name to trim at) would widen its track and push
   the whole strip past the page edge instead of being truncated. */
.cat-row-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px 4px;
}

.cat-row-card {
  position: relative;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Tightened from 6px so a bigger icon (see .cat-row-icon) doesn't read
     as floating further away from its own label — the label should hug
     the icon's bottom edge, not drift down as the icon grows. */
  gap: 3px;
  padding: 10px 4px;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: inherit;
  transition: transform .25s cubic-bezier(.16, 1, .3, 1), background-color .2s ease, border-color .2s ease;
  text-align: center;
}

.cat-row-card:hover {
  transform: translateY(-2px);
  background: var(--green-pale-faint);
  border-color: var(--color-primary);
  color: var(--color-text);
}

.cat-row-icon {
  position: relative;
  /* A bigger, uncoloured box around a smaller glyph reads as a deliberate
     icon slot rather than a filled badge — the old version leaned on the
     tinted circle to give each tile presence; without it, the size
     difference between box and icon has to do that job instead. Bumped
     up a step from 72px/26px, then again from 84px/34px per a "make icons
     even bigger" request — .category-page-icon below mirrors this exactly
     so the home page slider and the categories page still match. The
     icon-to-label gap (see .cat-row-card) was tightened at the same time
     so the bigger box doesn't push the label further down. */
  width: 96px;
  height: 96px;
  border-radius: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Sizes both branches of x-category-icon at once: the placeholder glyph
     reads this directly (1em) and the admin-uploaded icon image reads it
     scaled up (1.3em, see .category-icon--image) — one value drives both. */
  font-size: 40px;
  flex-shrink: 0;
  transition: transform .25s cubic-bezier(.16, 1, .3, 1);
}

.cat-row-card:hover .cat-row-icon {
  transform: scale(1.06);
}

/* No more tinted fill behind the icon (uploaded icon images ignore `color`
   entirely, so the background was the only thing these classes did for
   most categories). `color` stays: it now also tints the placeholder glyph
   (.category-icon--placeholder, a real fa-solid icon) for any category with
   no uploaded icon, plus the "All in category" pseudo-tile's fa-layer-group
   icon built in categories/index.blade.php's inline script. */
.cat-color-1 { color: #005C20; }
.cat-color-2 { color: #E85A38; }
.cat-color-3 { color: #00964F; }
.cat-color-4 { color: #A6790F; }

.cat-row-body {
  position: relative;
  min-width: 0;
  max-width: 100%;
}

/* Two lines rather than a single nowrap line: Tamil and Sinhala category
   names are routinely longer than their English source and have no
   natural trim point, so clipping them to one line leaves a label that
   can't be read. The fixed min-height keeps every tile's count row on the
   same baseline whether the name takes one line or two. */
.cat-row-name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  font-weight: 600;
  font-size: 12.5px;
  color: var(--color-text);
  line-height: 1.2;
  max-width: 100%;
  min-height: 2.4em;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* Below the point the grid narrows to 4 columns (see .cat-row-grid in the
   max-width:720px block), swap the full category name for the shortened
   one (the part before "&", e.g. "Mobile Phones & Tablets" -> "Mobile
   Phones") — there just isn't room for the long form in a quarter-width
   tile. Wider layouts keep showing the full name. */
.cat-row-name-short {
  display: none;
}

@media (max-width: 720px) {
  .cat-row-name-full {
    display: none;
  }

  .cat-row-name-short {
    display: inline;
  }
}

.cat-row-count {
  display: block;
  font-size: 10.5px;
  color: var(--color-text-muted);
  margin-top: 2px;
}

.cat-row-arrow {
  display: none;
}

/* ---- Category slider (category-slider.js) ----
   A page is exactly one .cat-row-grid's worth of tiles (8 — a full 4x2 or
   8x1 screen either way), so paging never leaves a page visibly emptier
   than the others except possibly the last one. JS clones the first/last
   page for the infinite-loop illusion and drives .cat-slider-track's
   transform directly; without JS (or with 8 or fewer categories, so JS
   no-ops), this still renders as the plain grid it always was. */
.cat-slider {
  overflow: hidden;
  position: relative;
}

.cat-slider-track {
  display: flex;
  touch-action: pan-y;
  cursor: grab;
}

.cat-slider-track.is-dragging {
  cursor: grabbing;
  user-select: none;
}

.cat-slider-page {
  flex: 0 0 100%;
  min-width: 0;
}

.cat-slider-dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
}

/* 24x24 tap target (Lighthouse/WCAG's minimum) around a visual dot that
   stays small — the button itself is the invisible hit area, ::after
   carries the actual 7px/18px pill so the row still reads exactly as
   before. Adjacent dots stay non-overlapping too: each target is 24px
   plus .cat-slider-dots' own 8px gap, a 32px pitch with room to spare. */
.cat-slider-dot {
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cat-slider-dot::after {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--line-strong);
  transition: background-color .2s ease, width .2s ease, border-radius .2s ease;
}

.cat-slider-dot.is-active::after {
  width: 18px;
  border-radius: 4px;
  background: var(--color-primary);
}

/* ---- Responsive ---- */
@media (min-width:901px) {
  .home-section {
    padding-top: 36px;
  }

  /* The promoted banner spans the container but is width-capped so the
     4:1 viewport doesn't grow into a full-bleed strip — it reads as a
     premium slot, not a takeover. */
  .home-sponsor-section .promo-slot,
  .home-sponsor-section .ad-slot-placeholder {
    max-width: 760px;
    margin-inline: auto;
  }

  .featured-grid {
    grid-template-columns: repeat(4, 1fr);
    gap: 14px;
  }

  .cat-row-grid {
    grid-template-columns: repeat(8, minmax(0, 1fr));
    gap: 6px;
  }

  .cat-row-card {
    padding: 10px 4px;
    gap: 6px;
  }

  /* Eight columns across the 1160px container leaves ~145px per tile, so
     the box can go up another step without crowding the label. Stayed
     shy of that full ~145px ceiling (rather than filling it) so the icon
     doesn't start overlapping its column at narrower widths just above
     this breakpoint, where the container hasn't reached full width yet. */
  .cat-row-icon {
    width: 114px;
    height: 114px;
    border-radius: 26px;
    font-size: 44px;
  }

  .cat-row-name {
    font-size: 13.5px;
  }
}

@media (max-width:720px) {
  .cat-row-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .hero-float-icon {
    font-size: 20px;
  }
}

@media (max-width:480px) {
  .cat-row-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .featured-grid {
    gap: 10px;
  }

  .hero-wrap {
    padding: 16px 16px 20px;
  }

  .hero-search-input {
    font-size: 14px;
    padding: 10px 0;
  }

  .hero-search-btn {
    padding: 9px 14px;
    font-size: 13px;
  }
}

/* District filter pill (navbar) */
.nav-right-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.district-filter-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--green-pale);
  color: var(--color-primary);
  border: 1px solid rgba(0, 92, 32, .15);
  border-radius: var(--radius-pill);
  padding: 5px 12px;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  transition: all 200ms ease;
  white-space: nowrap;
}

.district-filter-pill i:first-child {
  font-size: 10px;
  opacity: .7;
}

.district-filter-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 1px solid rgba(0, 92, 32, .15);
  border-radius: 50%;
  background: var(--green-pale);
  color: var(--color-text-muted);
  font-size: 11px;
  cursor: pointer;
  transition: all 200ms ease;
  margin-left: 4px;
}

.district-filter-clear:hover {
  background: #FEE2E2;
  color: #991B1B;
}

.mobile-district-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--green-pale);
  color: var(--color-primary);
  border: 1px solid rgba(0, 92, 32, .15);
  border-radius: var(--radius-pill);
  padding: 4px 10px;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  transition: all 200ms ease;
  white-space: nowrap;
}

.mobile-district-pill:hover {
  background: var(--green-pale);
}

.mobile-district-pill i:first-child {
  font-size: 10px;
}

.mobile-district-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: 1px solid rgba(0, 92, 32, .15);
  border-radius: 50%;
  background: var(--green-pale);
  color: var(--color-text-muted);
  font-size: 10px;
  cursor: pointer;
  transition: all 200ms ease;
  margin-left: 4px;
}

.mobile-district-clear:hover {
  background: #FEE2E2;
  color: #991B1B;
}

.mobile-district-pill i:first-child {
  font-size: 10px;
}

/* ============================================================
   LOCATION SELECTOR (Home Hero)
   ============================================================ */

.hero-location-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-bottom: 12px;
}

.hero-location-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: #fff;
  border: 1px solid #E5E7EB;
  border-radius: var(--radius-pill);
  padding: 8px 18px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  color: var(--color-text);
  cursor: pointer;
  transition: all 250ms ease;
  box-shadow: 0 1px 2px rgba(0,0,0,.04);
}

.hero-location-btn:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.hero-location-chevron {
  font-size: 10px;
  opacity: .6;
  transition: transform 200ms ease;
}

.hero-location-btn:hover .hero-location-chevron {
  transform: translateY(2px);
}

.hero-location-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .85);
  border: none;
  color: var(--color-text-muted);
  font-size: 12px;
  cursor: pointer;
  transition: all 200ms ease;
}

.hero-location-clear:hover {
  background: #FEE2E2;
  color: #991B1B;
}

/* District Modal Options */
.district-option {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 5px 20px;
  background: none;
  border: none;
  font-family: var(--font-body);
  font-size: 13.5px;
  color: var(--color-text);
  cursor: pointer;
  transition: background 150ms ease;
  text-align: left;
}

.district-option:hover {
  background: var(--green-pale-faint);
}

.district-option.is-active {
  background: var(--green-pale);
}

.district-option-icon {
  display: none;
}

.district-option-name {
  flex: 1;
  font-weight: 500;
}

.district-option-count {
  margin-left: auto;
  background: rgba(0, 92, 32, .08);
  color: var(--color-text-muted);
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
}

.district-option-check {
  color: var(--color-primary);
  font-size: 16px;
}

.district-divider {
  height: 1px;
  background: var(--color-border);
  margin: 0 20px;
}

/* Fixed (not max-) height for the district modal's step 1 (districts) and
   step 2 (cities) lists — both use this same class so switching steps,
   filtering down to a handful of matches, or hitting an empty state never
   changes the modal's overall footprint. Internal scroll handles overflow
   when a step's content is taller than this. */
.district-modal-list-area {
  height: 320px;
  overflow-y: auto;
}

@media (max-width: 480px) {
  .hero-location-btn {
    font-size: 13px;
    padding: 7px 14px;
  }

  #districtModal .modal-dialog {
    margin: auto;
    max-width: calc(100vw - 24px) !important;
  }

  #districtModal .modal-content {
    border-radius: var(--radius-lg) !important;
  }
}

   GLOBAL CONFIRM MODAL — replaces native confirm() everywhere (see
   confirmDialog() in app.js). Centered icon-circle layout, same visual
   language as the chat-notification invite modal, so every custom modal
   in the app reads as one consistent, deliberate design instead of a mix
   of the plain Bootstrap default and a few hand-styled ones.
   ============================================================ */
.confirm-modal-content {
  border-radius: var(--radius-lg);
  border: none;
  position: relative;
}

.confirm-modal-close {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 1;
}

.confirm-modal-body {
  padding: 36px 28px 22px;
}

.confirm-modal-icon {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 16px;
  font-size: 24px;
}

.confirm-modal-icon--danger {
  background: #FDECEA;
  color: var(--color-danger);
  box-shadow: 0 0 0 6px rgba(217, 72, 58, .08);
}

.confirm-modal-icon--safe {
  background: var(--green-pale);
  color: var(--color-primary);
  box-shadow: 0 0 0 6px rgba(0, 92, 32, .08);
}

.confirm-modal-title {
  font-size: 17px;
  margin-bottom: 8px;
}

.confirm-modal-text {
  font-size: 14px;
  color: var(--color-text-muted);
  margin-bottom: 0;
}

.confirm-modal-footer {
  border-top: 1px solid var(--color-border);
  padding: 14px 20px 20px;
  gap: 10px;
}

/* ============================================================
   GLOBAL MODAL CENTERING (mobile)
   ============================================================ */
@media (max-width: 575.98px) {
  .modal.show .modal-dialog {
    display: flex !important;
    align-items: center !important;
    margin: 0 auto !important;
    max-width: calc(100vw - 32px) !important;
  }
  .modal.show .modal-content {
    border-radius: var(--radius-lg) !important;
  }
}

/* =====================================================================
   Two-Factor Authentication
   ===================================================================== */

/* Site-wide reminder strip for a verified seller who hasn't finished 2FA
   setup yet — shown on every page (layouts/app.blade.php) until they do. */
/* partials/announcements.blade.php — bg/text colors are admin-set per row
   (inline style, see Admin\AnnouncementController), everything else here is
   fixed layout/chrome shared by every announcement regardless of color. */
.announcement-strip {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-content: center;
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 600;
  text-align: center;
}

.announcement-strip-inner {
  flex: 1;
  min-width: 0;
}

.announcement-strip-link {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.announcement-strip-link:hover {
  opacity: .85;
}

.announcement-strip-close {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: none;
  background: rgba(255, 255, 255, 0.2);
  color: inherit;
  border-radius: 50%;
  cursor: pointer;
  font-size: 11px;
  padding: 0;
  transition: background 150ms ease;
}

.announcement-strip-close:hover {
  background: rgba(255, 255, 255, 0.35);
}

.tfa-grace-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-content: center;
  background: #FFF8E1;
  color: #92600A;
  border-bottom: 1px solid #FDE9B8;
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none !important;
}

.tfa-grace-banner:hover {
  background: #FFF3CD;
}

.tfa-grace-banner.is-expired {
  background: #FEF2F2;
  color: #B91C1C;
  border-bottom-color: #FECACA;
}

.tfa-grace-banner i:last-child {
  font-size: 11px;
  opacity: .7;
}

.search-suggest {
  position: relative;
  /* Above the hero's floating icons and the promo slot below it, so the
     open panel is never overlapped by decoration. Stays under the sticky
     header (z-index 50) — scrolling the bar up should tuck it away, not
     have it ride over the nav. */
  z-index: 40;
  text-align: left;
}

/* The field keeps its full pill shape while the panel is open. Squaring
   off the bottom corners only reads as "one connected surface" when the
   panel is flush against the field — this one floats 8px below it, so
   flattening the pill just looked like a clipped shape. The active border
   and ring are enough to tie the two together. */
.search-suggest.is-open .hero-search {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 4px var(--green-pale), 0 4px 20px rgba(0, 92, 32, .08);
}

.search-suggest__clear {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-right: 4px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-faint);
  font-size: 13px;
  cursor: pointer;
  flex-shrink: 0;
  transition: background .15s ease, color .15s ease;
}

/* Class-level `display` outranks the UA stylesheet's `[hidden]`, so the
   attribute has to be honoured explicitly — without this the clear button
   sits in the field permanently and pushes the input out of shape. */
.search-suggest__clear[hidden] {
  display: none;
}

.search-suggest__clear:hover,
.search-suggest__clear:focus-visible {
  background: var(--green-pale);
  color: var(--color-primary);
}

.search-suggest__panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  max-height: min(58vh, 460px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 18px 40px -18px rgba(0, 92, 32, .38), 0 2px 8px rgba(18, 39, 32, .06);
  padding: 6px;
  animation: suggestPanelIn .16s cubic-bezier(.16, 1, .3, 1);
}

.search-suggest__panel[hidden] {
  display: none;
}

@keyframes suggestPanelIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .search-suggest__panel { animation: none; }
}

.search-suggest__group + .search-suggest__group {
  border-top: 1px solid var(--color-border);
  margin-top: 4px;
  padding-top: 4px;
}

.search-suggest__group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 12px 6px;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.search-suggest__group-action {
  border: none;
  background: transparent;
  padding: 2px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--color-primary);
  cursor: pointer;
  border-radius: var(--radius-sm);
}

.search-suggest__group-action:hover,
.search-suggest__group-action:focus-visible {
  background: var(--green-pale);
}

.search-suggest__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  /* Rows are chosen by keyboard as often as by pointer, so hover and the
     keyboard-active state are deliberately identical — nothing should look
     different depending on which one you used. */
  transition: background .12s ease;
}

.search-suggest__item:hover,
.search-suggest__item.is-active {
  background: var(--green-pale-faint);
}

.search-suggest__item.is-active {
  box-shadow: inset 0 0 0 1.5px var(--green-pale);
}

.search-suggest__thumb {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: 10px;
  overflow: hidden;
  background: var(--green-pale-faint);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-primary);
  font-size: 16px;
}

.search-suggest__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.search-suggest__thumb.is-empty::after {
  content: '\f03e';
  font-family: 'Font Awesome 6 Free';
  font-weight: 900;
  color: var(--ink-faint);
  font-size: 14px;
}

.search-suggest__text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.search-suggest__label {
  font-size: 14px;
  font-weight: 600;
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.search-suggest__label mark {
  background: transparent;
  padding: 0;
  color: var(--color-primary);
  font-weight: 800;
}

.search-suggest__sub {
  font-size: 12px;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.search-suggest__badge {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: var(--radius-pill);
  background: var(--green-pale);
  color: var(--green-deep);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
}

.search-suggest__badge--boost {
  background: rgba(242, 183, 5, .16);
  color: #8A6A00;
}

.search-suggest__go {
  flex-shrink: 0;
  font-size: 11px;
  color: var(--ink-faint);
  opacity: 0;
  transition: opacity .12s ease;
}

.search-suggest__item:hover .search-suggest__go,
.search-suggest__item.is-active .search-suggest__go {
  opacity: .7;
}

.search-suggest__empty {
  padding: 18px 14px;
  text-align: center;
  font-size: 13px;
  color: var(--color-text-muted);
}

@media (max-width: 576px) {
  .search-suggest__panel {
    max-height: min(62vh, 420px);
  }

  .search-suggest__thumb {
    width: 36px;
    height: 36px;
  }

  /* The chevron is decorative and the row is entirely tappable — dropping
     it buys back width for the title on narrow screens. */
  .search-suggest__go {
    display: none;
  }
}

