/* =====================================================
   MUBSELL — chrome.css
   Shared site chrome: unified header, mobile bottom tab
   bar (with centre Sell FAB) and unified footer.

   Self-contained on purpose: every colour reads a page
   token with a hard fallback, e.g. var(--marigold,#1A73E8),
   so this file works on pages that still carry their own
   inline :root block as well as on pages using base.css.
   ===================================================== */

/* ------------------------------------------------------
   1 · UNIFIED HEADER
   Logo left · search centre · actions right.
   ------------------------------------------------------ */
.mb-header{
  position:sticky; top:0; z-index:50;
  background:var(--paper-card,#fff);
  border-bottom:1px solid var(--line,#E0E6EF);
}
.mb-header-in{
  display:flex; align-items:center; gap:14px;
  max-width:1180px; margin:0 auto; padding:11px 18px;
}

/* one logo lock-up (mark + wordmark), used on every page */
.mb-logo{
  display:inline-flex; align-items:center; gap:8px;
  font-family:'Sora',sans-serif; font-weight:800; font-size:20px;
  color:var(--ink,#0D1B2A); letter-spacing:-.02em; white-space:nowrap;
  text-decoration:none; flex:0 0 auto;
}
.mb-logo em{ color:var(--marigold,#1A73E8); font-style:normal; }
.mb-logo-mark{ width:30px; height:30px; display:block; flex:0 0 auto; }
@media (max-width:768px){
  .mb-logo{ font-size:17px; gap:6px; }
  .mb-logo-mark{ width:26px; height:26px; }
}

/* header search (desktop + tablet) */
.mb-hsearch{ flex:1; display:flex; align-items:center; gap:8px;
  background:var(--blue-tint,#EAF2FF);
  border:1px solid var(--line,#E0E6EF);
  border-radius:999px; padding:6px 6px 6px 14px; max-width:520px; margin:0 auto;
  min-height:42px;
}
.mb-hsearch input{
  flex:1; border:0; background:transparent; outline:none;
  font-family:inherit; font-size:14px; color:var(--ink,#0D1B2A); min-width:0;
}
.mb-hsearch input::placeholder{ color:var(--placeholder,#6B7688); opacity:1; }
.mb-hsearch-go{
  flex:0 0 auto; border:0; border-radius:999px; cursor:pointer;
  background:var(--marigold,#1A73E8); color:#fff;
  font-family:inherit; font-weight:700; font-size:var(--fs-sm,13px);
  padding:7px 16px; margin:-4px -8px -4px 0;
}
.mb-hsearch-go:hover{ background:var(--marigold-dark,#1557B0); }
.mb-hsearch svg{ color:var(--charcoal,#5B6B79); flex:0 0 auto; }

.mb-hactions{ display:flex; align-items:center; gap:9px; margin-left:auto; }

.mb-btn{
  display:inline-flex; align-items:center; gap:6px;
  border-radius:999px; padding:9px 16px; font-size:14px; font-weight:700;
  font-family:inherit; border:1px solid transparent; cursor:pointer;
  white-space:nowrap; text-decoration:none;
}
.mb-btn-primary{ background:var(--marigold,#1A73E8); color:#fff; }
.mb-btn-primary:hover{ background:var(--marigold-dark,#1557B0); }
.mb-btn-ghost{
  background:transparent; color:var(--ink,#0D1B2A);
  border-color:var(--line,#E0E6EF);
}
.mb-btn-ghost:hover{ border-color:var(--marigold,#1A73E8); color:var(--marigold,#1A73E8); }

/* avatar chip for logged-in users */
.mb-avatar{
  width:36px; height:36px; border-radius:50%; flex:0 0 auto;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--marigold,#1A73E8); color:#fff;
  font-family:'Sora',sans-serif; font-weight:700; font-size:13px;
  background-size:cover; background-position:center; text-decoration:none;
}

/* theme toggle button in the header */
.mb-icon-btn{
  width:38px; height:38px; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center;
  background:transparent; border:1px solid var(--line,#E0E6EF);
  color:var(--charcoal,#5B6B79); cursor:pointer; flex:0 0 auto;
}
.mb-icon-btn:hover{ color:var(--marigold,#1A73E8); border-color:var(--marigold,#1A73E8); }

/* ── Header badges: messages and the notification bell ──────────────
   The bell and the message counter live here now. They used to live in
   components/navbar.php, which stopped being included when
   site-header.php replaced it — so notification rows were being written
   with nothing anywhere in the app able to show them. */
.mb-badge-wrap{ position:relative; text-decoration:none; }

.mb-badge{
  position:absolute; top:-4px; right:-4px;
  min-width:17px; height:17px; padding:0 4px;
  border-radius:9px; background:#EF4444; color:#fff;
  font-size:10px; line-height:17px; text-align:center; font-weight:700;
  /* The header can sit on white or on a card edge, so the badge carries
     its own ring rather than relying on whatever is behind it. */
  box-shadow:0 0 0 2px var(--paper-card,#fff);
  pointer-events:none;
}
/* [hidden] must win. An author rule with a class selector outranks the
   UA sheet's [hidden]{display:none}, which is exactly how the install
   banner's close button ended up doing nothing — same bug, twice. */
.mb-badge[hidden]{ display:none; }

.mb-bell-wrap{ position:relative; }

.mb-bell-panel{
  position:absolute; top:calc(100% + 10px); right:0; z-index:60;
  width:min(340px, calc(100vw - 28px));
  background:var(--paper-card,#fff); border:1px solid var(--line,#E0E6EF);
  border-radius:14px; box-shadow:0 18px 44px rgba(13,27,42,.16);
  overflow:hidden;
}
.mb-bell-panel[hidden]{ display:none; }

.mb-bell-head{
  padding:12px 16px; font-family:'Sora',sans-serif; font-weight:700;
  font-size:14px; color:var(--ink,#0D1B2A);
  border-bottom:1px solid var(--line,#E0E6EF);
}

/* Capped so a busy account gets a scrolling list rather than a panel
   taller than the screen. */
.mb-bell-list{ max-height:min(400px, 60vh); overflow-y:auto; }

.mb-bell-item{
  display:flex; gap:10px; align-items:flex-start; justify-content:space-between;
  padding:12px 16px; border-bottom:1px solid var(--line,#E0E6EF);
  font-size:13.5px; line-height:1.5; color:var(--ink,#0D1B2A);
  text-decoration:none;
}
.mb-bell-item:last-child{ border-bottom:0; }
a.mb-bell-item:hover{ background:var(--paper,#F4F8FF); }
.mb-bell-item time{ color:var(--charcoal,#8A94A6); font-size:11.5px; white-space:nowrap; padding-top:2px; }

/* Unread carries a colour bar rather than a coloured background: the
   panel is read at a glance and a tinted row is still legible when the
   theme changes, where a tinted background is not. */
.mb-bell-item.is-unread{ box-shadow:inset 3px 0 0 var(--marigold,#1A73E8); font-weight:600; }

.mb-bell-empty{
  padding:26px 20px; margin:0; text-align:center;
  color:var(--charcoal,#8A94A6); font-size:13px; line-height:1.6;
}

@media (max-width:768px){
  /* The header's own bell and message icons are .mb-hide-sm — on phones
     the tab bar carries the message badge instead. Nothing to restyle,
     but the panel would otherwise be positioned against a hidden button. */
  .mb-bell-panel{ right:-8px; }
}

/* ── "Show the count on my app icon" opt-in ─────────────────────────
   Shown only inside the installed app, and only until answered once —
   see assets/js/modules/notify-badge.js. */
.badge-optin{
  margin:12px auto 0; max-width:1120px; padding:0 14px;
}
/* [hidden] must win over the flex below. Fourth time in this codebase. */
.badge-optin[hidden]{ display:none; }

.badge-optin-in{
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  background:var(--blue-tint,#EAF2FF); border:1px solid rgba(26,115,232,.24);
  border-radius:14px; padding:12px 14px;
}
.badge-optin-ic{
  flex:0 0 auto; width:36px; height:36px; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--paper-card,#fff); color:var(--marigold,#1A73E8);
}
.badge-optin-txt{
  flex:1 1 220px; margin:0; font-size:13.5px; line-height:1.5;
  color:var(--charcoal,#5B6B79);
}
.badge-optin-txt strong{ display:block; color:var(--ink,#0D1B2A); font-size:14px; margin-bottom:2px; }

.badge-optin-acts{ display:flex; gap:8px; flex:0 0 auto; margin-left:auto; }
.badge-optin-yes, .badge-optin-no{
  /* 44px, Apple's minimum. This element only ever appears inside the
     installed app on a phone, so it is the one place where an undersized
     tap target is guaranteed to be felt. */
  min-height:44px; padding:0 16px; border-radius:99px;
  font-size:13.5px; font-weight:700; cursor:pointer; border:1px solid transparent;
}
.badge-optin-yes{ background:var(--marigold,#1A73E8); color:#fff; }
.badge-optin-no{
  background:transparent; color:var(--charcoal,#5B6B79);
  border-color:var(--line,#E0E6EF);
}
.badge-optin-no:hover{ color:var(--ink,#0D1B2A); }

[data-theme="dark"] .badge-optin-in{ background:rgba(26,115,232,.12); }

/* on phones the header slims down — search lives on the page itself */
@media (max-width:768px){
  /* Search used to be display:none here, which left phones with no
     way to search at all once the old hero search was removed.
     It now wraps onto its own full-width row under the logo. */
  .mb-header-in{ padding:10px 14px; gap:10px; flex-wrap:wrap; }
  /* Full-width and a proper 46px touch target — it was 36px tall
     with a 20px input, which is under the 44px minimum and felt
     cramped and hard to hit. */
  .mb-hsearch{
    order:3; flex:1 0 100%; max-width:none; margin:4px 0 0;
    padding:0 6px 0 14px; min-height:46px; gap:10px;
  }
  .mb-hsearch input{ padding:12px 0; min-height:46px; }
  .mb-hsearch svg{ width:19px; height:19px; }
  .mb-hsearch-go{ padding:10px 18px; margin:0; min-height:36px; }
  .mb-hactions{ margin-left:auto; }
  .mb-hide-sm{ display:none !important; }
}

/* ------------------------------------------------------
   2 · MOBILE BOTTOM TAB BAR  (+ raised centre Sell FAB)
   Primary navigation on phones. Hidden ≥769px.
   ------------------------------------------------------ */
:root{
  /* The bar's CONTENT height. The home-indicator inset is added on top
     of this, never taken out of it — see the note below. Declared here
     so the body padding that reserves space for the bar and the bar
     itself can never drift apart. */
  --tabbar-h:64px;
  /* How far the raised Sell button sticks up out of the bar. It is
     top:-26px plus its 4px white ring, so it clears the bar by 30px, not
     26 — reserving only 26 left the last two pixels of every page
     tucked under the button. */
  --tabbar-lift:30px;
}

.mobile-tabbar{
  position:fixed; left:0; right:0; bottom:0; z-index:60;
  display:none; align-items:flex-end; justify-content:space-around;

  /* THE SAFE-AREA INSET IS ADDED TO THE HEIGHT, NOT TAKEN OUT OF IT.
     This read `height:64px; padding-bottom:env(safe-area-inset-bottom)`,
     and everything on this site is border-box — so on any iPhone with a
     home indicator the 34px inset was subtracted FROM the 64px instead
     of extending it. That left 30px of usable bar for tab contents that
     measure 54px (a 24px icon, an 11px label, and their padding), so the
     labels overflowed upward and printed on top of the page behind them.

     It looked perfect in every desktop browser and in device emulation,
     because there the inset is 0 and the bug is invisible. It only ever
     appeared on real notched hardware. */
  height:calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  padding-bottom:env(safe-area-inset-bottom);

  background:var(--paper-card,#fff);
  border-top:1px solid var(--line,#EEF0F4);
  box-shadow:0 -6px 24px rgba(16,24,40,.06);

  /* PIN IT DURING THE SCROLL, not just after it.
     iOS Safari repaints plain position:fixed elements only when a
     momentum scroll settles, so the bar detached mid-flick and painted
     across the middle of the page with content still visible below it.
     Promoting it to its own compositing layer hands it to the GPU, which
     tracks the viewport continuously and keeps it welded to the bottom.

     The transform is on the fixed element itself, which is safe. A
     transform on an ANCESTOR is the thing that breaks position:fixed —
     that is why this stays here and must not move to a wrapper. */
  transform:translateZ(0);
  -webkit-backface-visibility:hidden;
          backface-visibility:hidden;
}
@media (max-width:768px){
  .mobile-tabbar{ display:flex; }
  /* Off screen while the soft keyboard is up — see the note in
     components/mobile-tabbar.php. display:none rather than a slide: a
     transition is one more state the bar can be caught halfway through,
     and the whole complaint is that it turns up in places it should not
     be. Two classes beats the one above it, so no !important is needed. */
  .mobile-tabbar.kb-open{ display:none; }
  /* Room for the bar, the raised Sell button, and the home indicator —
     so the end of a page is never trapped underneath any of them. The
     extra 6px is breathing room: reserving the exact measured height put
     the last line of the footer flush against the Sell button, which
     reads as a layout collision even though nothing is actually cut off. */
  body{ padding-bottom:calc(var(--tabbar-h) + var(--tabbar-lift) + 6px + env(safe-area-inset-bottom)) !important; }
}

.mobile-tabbar .tab{
  flex:1; display:flex; flex-direction:column; align-items:center; gap:2px;
  padding:8px 0 6px; font-size:11px; font-weight:600;
  color:var(--charcoal,#94A3B8); text-decoration:none;
  -webkit-tap-highlight-color:transparent;
}
.mobile-tabbar .tab.is-active{ color:var(--marigold,#2563EB); }
.mobile-tabbar .tab svg{ flex:0 0 auto; }

/* centre Sell FAB — the primary action, biggest target */
.mobile-tabbar .tab-sell{ position:relative; }
.mobile-tabbar .fab{
  position:absolute; top:-26px; left:50%; transform:translateX(-50%);
  width:58px; height:58px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:var(--marigold,#2563EB); color:#fff;
  box-shadow:0 8px 20px rgba(37,99,235,.45);
  border:4px solid var(--paper-card,#fff);
}
.mobile-tabbar .tab-sell:active .fab{ transform:translateX(-50%) scale(.94); }
.mobile-tabbar .fab-label{ margin-top:34px; color:var(--marigold,#2563EB); }

/* unread badge on Messages */
.tab-icon-wrap{ position:relative; display:inline-flex; }
.tab-icon-wrap .badge{
  position:absolute; top:-6px; right:-8px; min-width:16px; height:16px;
  padding:0 4px; border-radius:8px; background:#EF4444; color:#fff;
  font-size:10px; line-height:16px; text-align:center; font-weight:700;
}

/* REMOVED: a mobile rule that forced
     .sw-fab, .sw-launch, .settings-fab, .sd-fab { bottom:84px !important }

   It dated from when .sw-fab was itself the fixed-position element. Once
   support-widget.php grew a .sw-stack wrapper, the fab became a flex
   child with position:relative — so `bottom` no longer positioned it,
   it OFFSET it, shifting the button 84px up out of its own stack and
   onto the back-to-top button. The other three selectors no longer exist
   anywhere in the app.

   Clearance above the tab bar is now handled once, by --sw-bottom in
   components/support-widget.php. */

/* ------------------------------------------------------
   3 · UNIFIED FOOTER
   ------------------------------------------------------ */
.mb-footer{
  background:var(--surface-dark,#0D1B2A); color:#C6D0DC;
  padding:42px var(--page-pad,40px) 30px; margin-top:50px;
}
.mb-footer-in{
  max-width:1180px; margin:0 auto;
  display:grid; grid-template-columns:1.6fr 1fr 1fr 1fr; gap:30px;
}
.mb-footer h4{
  font-family:'Sora',sans-serif; font-size:14px; color:#fff;
  margin:0 0 12px; letter-spacing:.02em;
}
.mb-footer a{ color:#C6D0DC; text-decoration:none; font-size:14px; }
.mb-footer a:hover{ color:#fff; text-decoration:underline; }
.mb-footer ul{ list-style:none; margin:0; padding:0; display:grid; gap:9px; }
.mb-footer .mb-flogo{
  font-family:'Sora',sans-serif; font-weight:800; font-size:20px; color:#fff;
  display:inline-flex; align-items:center; gap:8px; margin-bottom:9px;
  text-decoration:none;
}
.mb-footer .mb-flogo img{ width:26px; height:26px; display:block; }
.mb-footer .mb-flogo em{ color:var(--marigold,#4C8DFF); font-style:normal; }
.mb-footer p{ font-size:14px; line-height:1.6; margin:0; color:#9FADBD; }
.mb-footer-bottom{
  max-width:1180px; margin:26px auto 0; padding-top:18px;
  border-top:1px solid rgba(255,255,255,.12);
  display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;
  font-size:13px; color:#9FADBD;
}
/* The company credit sits between the copyright and the safety line.
   Slightly brighter than its neighbours so it reads as a statement
   rather than more small print, but not so bright that it competes with
   the marketplace's own name directly beside it. */
.mb-powered{ color:#C8D4E0; }
.mb-powered strong{ color:#fff; font-weight:700; }
@media (max-width:768px){
  .mb-footer{ padding:32px 20px 26px; }
  .mb-footer-in{ grid-template-columns:1fr 1fr; gap:24px; }
  .mb-footer-in > :first-child{ grid-column:1 / -1; }
}

/* ------------------------------------------------------
   4 · NOTHING MOVES WHEN YOU TAP A FIELD
   Tapping an input used to zoom the page in and slide it
   sideways. That is FOUR separate mechanisms, not one —
   fixing only the first (as was done twice before) leaves
   the page still visibly jumping:

     (a) font-size under 16px  → iOS Safari scales the page
     (b) keyboard opens        → only the VISUAL viewport
                                 shrinks, so the browser pans
                                 and scales to keep the field
                                 on screen. Fixed by
                                 interactive-widget=resizes-content
                                 in the viewport meta (all pages).
     (c) double-tap            → tap-to-zoom gesture
     (d) any sideways overflow → the pan in (b) has somewhere
                                 to travel, so the page lands
                                 off-centre

   Pinch-to-zoom stays enabled throughout: never set
   user-scalable=no — it breaks zoom for people who need it.

   !important is deliberate: several pages load chrome.css
   BEFORE their own inline <style>, so a normal rule loses.
   ------------------------------------------------------ */

/* (a) 16px is the exact threshold iOS uses. This is a
   deny-list, not an allow-list — the old rule named nine
   input types and so missed time/month/week and
   contenteditable, which zoomed anyway. */
@media (max-width:768px), (pointer:coarse) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]),
  textarea, select, [contenteditable]:not([contenteditable="false"]) {
    font-size:16px !important;
  }
}

/* Stop the OS bumping text up in landscape, which drags
   layout around independently of any zoom. */
html{ -webkit-text-size-adjust:100%; text-size-adjust:100%; }

/* (c) kill the double-tap zoom gesture on things meant to be
   tapped once. Single tap, pinch and scroll all still work. */
a, button, input, select, textarea, label, [role="button"], .chip, .mx-card{
  touch-action:manipulation;
}

@media (max-width:768px), (pointer:coarse) {
  /* (d) hard stop on sideways travel. `clip` rather than
     `hidden` so it cannot silently turn an ancestor into a
     scroll container and break position:sticky on the header. */
  html, body{ overflow-x:clip; max-width:100%; }

  /* The header is position:sticky, so when the browser scrolls
     a focused field into view it parks it UNDER the header and
     then scrolls further to compensate — which reads as the
     page lurching. Reserve the header's height instead.
     Two rows on mobile: logo row + search row. */
  html{ scroll-padding-top:120px; }
}

/* ------------------------------------------------------
   5 · AUTH GATE  (components/auth-gate.php)
   Browsing stays open; interacting opens this.
   ------------------------------------------------------ */
.ag-backdrop{
  position:fixed; inset:0; z-index:200;
  background:rgba(9,14,28,.62); backdrop-filter:blur(3px);
  display:flex; align-items:center; justify-content:center; padding:20px;
  animation:agFade .18s ease;
}
.ag-backdrop[hidden]{ display:none; }
@keyframes agFade{ from{opacity:0} to{opacity:1} }
.ag{
  position:relative; width:100%; max-width:390px; text-align:center;
  background:var(--paper-card,#fff); border-radius:20px;
  padding:30px 26px 22px; box-shadow:0 24px 60px rgba(4,12,60,.34);
  animation:agRise .22s cubic-bezier(.2,.9,.3,1);
}
@keyframes agRise{ from{transform:translateY(14px);opacity:0} to{transform:none;opacity:1} }
.ag-x{
  position:absolute; top:12px; right:12px; width:32px; height:32px;
  border:0; border-radius:50%; background:transparent; cursor:pointer;
  color:var(--charcoal,#5B6B79); font-size:15px; line-height:1;
}
.ag-x:hover{ background:var(--blue-tint,#EAF2FF); color:var(--ink,#0D1B2A); }
.ag-logo{ display:block; margin:0 auto 12px; }
.ag-title{
  font-family:'Sora',sans-serif; font-weight:800; font-size:var(--fs-xl,20px);
  color:var(--ink,#0D1B2A); margin:0 0 6px;
}
.ag-sub{
  font-size:var(--fs-sm,13px); line-height:1.55;
  color:var(--charcoal,#5B6B79); margin:0 0 18px;
}
.ag-or{
  display:flex; align-items:center; gap:10px; margin:14px 0;
  color:var(--charcoal,#8A94A6); font-size:var(--fs-xs,12px);
}
.ag-or::before, .ag-or::after{ content:''; flex:1; height:1px; background:var(--line,#E0E6EF); }
.ag-btn{
  display:block; width:100%; border-radius:99px; padding:13px;
  font-family:'Sora',sans-serif; font-weight:700; font-size:var(--fs-base,14px);
  text-decoration:none; margin-bottom:9px; border:1.5px solid transparent; cursor:pointer;
}
.ag-btn-primary{ background:var(--marigold,#1A73E8); color:#fff; }
.ag-btn-primary:hover{ background:var(--marigold-dark,#1557B0); }
.ag-btn-ghost{ background:transparent; color:var(--ink,#0D1B2A); border-color:var(--line,#E0E6EF); }
.ag-btn-ghost:hover{ border-color:var(--marigold,#1A73E8); color:var(--marigold,#1A73E8); }
.ag-skip{
  background:none; border:0; cursor:pointer; margin-top:4px;
  color:var(--charcoal,#5B6B79); font-size:var(--fs-sm,13px);
  font-weight:600; text-decoration:underline; font-family:inherit;
}
.ag-skip:hover{ color:var(--marigold,#1A73E8); }
.ag-fine{
  font-size:var(--fs-xs,12px); line-height:1.5;
  color:var(--charcoal,#8A94A6); margin:14px 0 0;
}

/* ------------------------------------------------------
   6 · "Continue with Google" button (components/google-button.php)
   Standard Google-branded styling. Disabled until OAuth is wired.
   ------------------------------------------------------ */
.gbtn{
  display:flex; align-items:center; justify-content:center; gap:10px;
  width:100%; padding:12px 16px; border-radius:99px;
  background:#fff; border:1.5px solid #DADCE0; color:#3C4043;
  font-family:'Inter',system-ui,sans-serif; font-weight:600;
  font-size:var(--fs-base,14px); cursor:pointer; position:relative;
}
.gbtn:hover:not([disabled]){ background:#F8F9FA; box-shadow:0 1px 3px rgba(60,64,67,.24); }
.gbtn[disabled]{ opacity:.62; cursor:not-allowed; }
.gbtn-ic{ display:flex; flex:0 0 auto; }
.gbtn-soon{
  position:absolute; right:12px; top:50%; transform:translateY(-50%);
  background:var(--blue-tint,#EAF2FF); color:var(--marigold,#1A73E8);
  font-size:var(--fs-3xs,10px); font-weight:700; letter-spacing:.04em;
  text-transform:uppercase; padding:3px 7px; border-radius:5px;
}
/* the Google button keeps its light styling in dark mode — that is the
   brand requirement, and it reads fine against the dark card */
[data-theme="dark"] .gbtn{ background:#fff; color:#3C4043; }

/* ── Verified-seller tick ─────────────────────────────────
   One rule so the mark is identical wherever it appears. A trust
   badge that renders slightly differently in three places trains
   people to ignore it. Blue, like the convention people already
   recognise from other apps. */
.vtick{
  display:inline-flex; align-items:center; justify-content:center;
  color:#1D9BF0; vertical-align:middle; flex:0 0 auto;
  margin-left:4px; line-height:0;
}
/* The mark is now assets/img/verified.png rather than an inline SVG.
   The sizes are repeated here per variant because an <img> with no CSS
   width falls back to its natural 71px — which, mid-sentence next to a
   seller's name, is a badge the size of the avatar. The width attribute
   on the tag covers the same case if this stylesheet never arrives. */
.vtick img{ display:block; flex:0 0 auto; }
.vtick-sm img{ width:14px; height:14px; }
.vtick-md img{ width:17px; height:17px; }
.vtick-lg img{ width:22px; height:22px; }
/* cursor:help signals there is an explanation on hover, which matters
   because the badge's limits are in the tooltip. */
.vtick[title]{ cursor:help; }

/* ── The shared back control (components/back-button.php) ──────────
   Sits between the header and the page content on every page, so no
   screen is a dead end — which matters most on a phone, where the
   header carries a logo and a Sell button and nothing else. */
.mb-back-row{
  max-width:1120px; margin:0 auto; padding:12px 14px 0;
}
.mb-back{
  display:inline-flex; align-items:center; gap:6px;
  font-size:13.5px; font-weight:700; text-decoration:none;
  color:var(--charcoal,#5B6B79);
  /* 44px tall including the padding — it is a primary navigation
     control on a touch screen, not a footnote. */
  padding:11px 12px 11px 6px; margin-left:-6px; border-radius:10px;
}
.mb-back:hover{ color:var(--marigold,#1A73E8); background:var(--paper,#F4F8FF); }
.mb-back svg{ flex:0 0 auto; }
[data-theme="dark"] .mb-back:hover{ background:rgba(255,255,255,.06); }

/* The word beside the tick, where there is room for it. An icon on its
   own has to be learned — somebody meeting the badge for the first time
   cannot tell a verification mark from decoration. */
.vtick-labelled{ gap:4px; }
.vtick-word{
  font-size:11.5px; font-weight:700; letter-spacing:.01em;
  color:#1D9BF0; line-height:1;
}
.vtick-lg .vtick-word{ font-size:13px; }

/* The standalone pill, for places where the badge IS the statement
   rather than an ornament on a name. */
.vchip{
  display:inline-flex; align-items:center; gap:5px;
  padding:4px 10px 4px 7px; border-radius:99px;
  background:rgba(29,155,240,.12); color:#1D9BF0;
  font-size:12px; font-weight:700; line-height:1;
  vertical-align:middle; white-space:nowrap;
}
.vchip img{ display:block; flex:0 0 auto; width:15px; height:15px; }
.vchip[title]{ cursor:help; }
/* The tint is nearly invisible on a dark card; the text stays legible
   either way because it carries its own colour. */
[data-theme="dark"] .vchip{ background:rgba(29,155,240,.18); }

/* Admin console button — only rendered for admins (site-header.php).
   Deliberately distinct from the Sell button so an admin can tell at a
   glance which one takes them off the public site. */
.mb-btn-admin{
  background:var(--surface-dark,#0D1B2A); color:#fff; border-color:transparent;
}
.mb-btn-admin:hover{ background:#000; color:#fff; }

/* ── Dark mode: primary buttons take DARK text ─────────────
   Measured: white on the dark-theme blue (#4C8DFF) is 3.2:1 — under the
   4.5 needed for button text. The same blue with near-black text is
   5.44:1.

   Flipping the text is the right fix rather than darkening the blue,
   because --marigold doubles as the link/accent colour ON dark
   backgrounds, where it needs to stay bright. Darkening it to pass on
   buttons would have made every link harder to read. */
/* Background and colour are set TOGETHER, never colour alone.
   Setting only the colour broke blog.php: its .btn-primary had a
   transparent background, so dark text landed on the dark page and
   measured 1.13:1 — invisible. Pairing them means the dark text can
   only ever appear on the blue it was measured against.

   html[data-theme=…] rather than [data-theme=…] so this also beats the
   inline <style> blocks that several pages still carry their own
   .btn-primary in. */
html[data-theme="dark"] .mb-btn-primary,
html[data-theme="dark"] .mb-hsearch-go,
html[data-theme="dark"] .btn-primary,
html[data-theme="dark"] .submit-btn,
html[data-theme="dark"] .btn-msg,
html[data-theme="dark"] a.cta{
  background:var(--marigold,#4C8DFF);
  color:#0D1B2A;
}
html[data-theme="dark"] .mb-btn-primary:hover,
html[data-theme="dark"] .mb-hsearch-go:hover,
html[data-theme="dark"] .btn-primary:hover,
html[data-theme="dark"] .submit-btn:hover,
html[data-theme="dark"] .btn-msg:hover,
html[data-theme="dark"] a.cta:hover{
  background:var(--marigold-dark,#6FA6FF);
  color:#0D1B2A;
}
/* The admin chip inverts instead — it is a dark surface in light mode. */
html[data-theme="dark"] .mb-btn-admin{ background:#F3F5FA; color:#0D1B2A; }

/* Status pills: white on the dark-theme green measured 1.91:1.
   These are small, high-importance labels, so they take dark text. */
/* .apill-ok deliberately NOT listed here. It is an ADMIN class, and
   admin.css gives it a dark background in dark mode — forcing dark text
   from this file made it dark-on-dark (measured 1.43:1). Only the
   public-site pills, which keep a light green fill, belong here. */
html[data-theme="dark"] .avail-pill,
html[data-theme="dark"] .status-pill{
  color:#0A1F14;
}

/* Buttons that carry the brand blue on signed-in pages. Same measured
   reason as the primary buttons above: white on #4C8DFF is 3.2:1.
   These classes live in individual page <style> blocks, so they are
   listed here rather than each page being edited. */
html[data-theme="dark"] .b-primary,
html[data-theme="dark"] .btn-export,
html[data-theme="dark"] .tab.is-active,
html[data-theme="dark"] .count-badge.is-active{
  background:var(--marigold,#4C8DFF);
  color:#0D1B2A;
}

/* The delete-account button is a light red in dark mode; white on it
   measured 2.05:1. Deep red with white text is the safer pairing for a
   destructive action, which must never be ambiguous. */
html[data-theme="dark"] .da-btn{ background:#B3261E; color:#FFFFFF; }

/* Theme toggle: some pages set color:var(--ink) on a --paper background,
   which inverted to near-black on near-black. */
html[data-theme="dark"] .theme-toggle,
html[data-theme="dark"] .bell-btn{
  background:var(--paper-card,#17171D);
  color:var(--ink,#F3F5FA);
  border-color:var(--line,#26262E);
}

/* Last of the brand-blue fills that live in per-page <style> blocks:
   the sidebar promo link, the avatar chip and card action buttons.
   All measured white-on-#4C8DFF at 3.2:1. */
html[data-theme="dark"] .promo a,
html[data-theme="dark"] a.avatar,
html[data-theme="dark"] .card button,
html[data-theme="dark"] .empty-state .btn{
  color:#0D1B2A;
}

/* ══════════════════════════════════════════════════════════
   TOKEN SAFETY NET

   Several pages carry their own inline :root palette and never load
   base.css. Any var() they use WITHOUT a fallback — e.g.
   `background:var(--paper-card)` on seller-dashboard's .gauge-btn —
   then resolves to nothing in dark mode, which measured 1.03:1.

   These are wrapped in :where() so they carry ZERO specificity: any
   page that defines its own palette still wins, in both themes. This
   only fills gaps, it never overrides a deliberate choice.
   ══════════════════════════════════════════════════════════ */
:where(:root){
  --ink:#0D1B2A; --paper:#F4F8FF; --paper-card:#FFFFFF;
  --line:#E0E6EF; --charcoal:#5B6B79;
  --marigold:#1A73E8; --marigold-dark:#1557B0;
  --teal:#27AE60; --coral:#FF6B57; --gold:#F2C94C; --purple:#8E44AD;
  --blue-tint:#EAF2FF; --surface-dark:#0D1B2A;
}
:where(html[data-theme="dark"]){
  --ink:#F3F5FA; --paper:#0B0B0F; --paper-card:#17171D;
  --line:#26262E; --charcoal:#A9ADBB;
  --marigold:#4C8DFF; --marigold-dark:#6FA6FF;
  --teal:#2FD673; --coral:#FF8271; --gold:#FFC24C; --purple:#B685D1;
  --blue-tint:#1E2433; --surface-dark:#20202A;
}

/* ── Feature switched off, still on show ─────────────────────
   Applied to boost controls while BOOST_ENABLED is false. They keep
   their shape so the layout is unchanged and sellers can see what is
   coming, but they are visibly inert: dimmed, no hover lift, and the
   cursor says "not now" rather than "click me".

   The elements themselves are already non-interactive (an <a> with no
   href, or a <span>) — this only makes that visible. Styling alone
   would be a lie you can still click. */
.is-soon{
  opacity:.55;
  cursor:not-allowed;
  filter:grayscale(.35);
  pointer-events:none;
}
/* pointer-events:none also kills the tooltip, so the wrapper keeps it. */
.is-soon-wrap{ cursor:not-allowed; display:inline-block; }

/* ── Placeholders ────────────────────────────────────────────
   Browsers do NOT derive the placeholder from the input's text
   colour: Chrome uses a semi-transparent BLACK of its own. On a dark
   input that is invisible — measured at 1.0:1 against #17171D, which
   is why placeholders vanished in dark mode while the typed text was
   fine.

   So it has to be set explicitly, per theme. Both values clear 4.5:1
   against the surfaces they sit on (light 4.6:1, dark 6.9:1).
   opacity:1 is required because Firefox dims placeholders by default
   and would undo the contrast we just bought. */
:root{ --placeholder:#6B7688; }
[data-theme="dark"]{ --placeholder:#98A1B2; }

input::placeholder,
textarea::placeholder,
input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder{
  color: var(--placeholder, #6B7688);
  opacity: 1;
}
/* Some browsers style a disabled field's placeholder separately. */
input:disabled::placeholder,
textarea:disabled::placeholder{ color: var(--placeholder, #6B7688); opacity:.6; }

/* ── UI ICONS ───────────────────────────────────────────────
   Inline SVG replacing the emoji the interface used to use. An emoji
   is a font glyph: every platform drew its own, none matched the line
   weight of the UI, several fell back to an empty box on phones
   missing that font block, and none could be coloured — `color` does
   nothing to an emoji, so a warning could not be red.

   These take currentColor and the surrounding font-size, so one icon
   serves light theme, dark theme and an error state. */
.ic{
  display:inline-block; vertical-align:-.18em; flex:0 0 auto;
  /* -.18em, not middle: aligns the optical centre of a 24-box glyph
     with the x-height of the text beside it. `middle` sits too high
     next to lowercase and looks like it is floating. */
}
.ic + *{ margin-left:.35em; }
/* Rating stars. Filled ones take the brand gold; empty ones a light
   outline, so the score reads at a glance without counting. */
.stars{ display:inline-flex; gap:1px; vertical-align:-.15em; }
.stars .st-on{ color:var(--gold,#F5A524); }
.stars .st-off{ color:var(--line,#D8DEE8); }
