/* ============================================================
   Hello Yiwu — Mobile CSS  (revised)
   Load AFTER the page's own <style> block on every page.

   Every rule here is scoped inside a media query. Nothing in this
   file may change desktop rendering — that was the bug in the
   previous version, where a bare `nav { padding-left: 20px }`
   overrode each page's own 40–48px nav padding at all widths.

   Pages must set --hy-nav-h to their own nav height (64px or 68px)
   so the hamburger dropdown lands flush under the header.
   ============================================================ */

:root { --hy-nav-h: 64px; }

/* ── Hamburger button ── */
.hamburger {
  display: none;
  flex-direction: column;
  gap: 5px;
  cursor: pointer;
  padding: 8px;
  border-radius: 8px;
  background: none;
  border: none;
}
.hamburger span {
  display: block;
  width: 22px;
  height: 2px;
  background: #F0F2F7;
  border-radius: 2px;
  transition: transform .3s, opacity .3s;
}
.hamburger.open span:nth-child(1) { transform: rotate(45deg) translate(5px, 5px); }
.hamburger.open span:nth-child(2) { opacity: 0; }
.hamburger.open span:nth-child(3) { transform: rotate(-45deg) translate(5px, -5px); }

/* ── Hamburger dropdown ── */
.mobile-menu {
  display: none;
  position: fixed;
  top: var(--hy-nav-h, 64px);   /* was a hardcoded 68px against 64px navs */
  left: 0; right: 0;
  max-height: calc(100dvh - var(--hy-nav-h, 64px));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: #0D1220;
  border-bottom: 1px solid rgba(255,255,255,0.07);
  z-index: 49;
  padding: 16px 20px calc(24px + env(safe-area-inset-bottom));
  flex-direction: column;
  gap: 4px;
  animation: slideDown .2s ease;
}
@keyframes slideDown { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }
.mobile-menu.open { display: flex; }
.mobile-menu a {
  display: block;
  padding: 13px 16px;
  font-size: 15px;
  color: #9AA3B8;
  text-decoration: none;
  font-weight: 500;
  border-radius: 10px;
  transition: background .15s, color .15s;
}
.mobile-menu a:hover, .mobile-menu a.active { background: #161E2E; color: #F0F2F7; }
.mobile-menu-divider { height: 1px; background: rgba(255,255,255,0.07); margin: 8px 0; }
.mobile-menu-auth { display: flex; gap: 10px; padding: 8px 0 0; }
.mobile-menu-auth button { flex: 1; min-height: 44px; padding: 13px; font-size: 14px; font-weight: 700; font-family: inherit; cursor: pointer; border-radius: 10px; }
.mobile-menu-auth .m-login { background: none; border: 1px solid rgba(255,255,255,0.12); color: #F0F2F7; }
.mobile-menu-auth .m-register { background: #F1B11B; border: none; color: #2A1700; }
.mobile-menu-lang { display: flex; gap: 8px; padding: 8px 0 0; }
.mobile-menu-lang button,
.mobile-menu-lang .lang-option { flex: 1; min-height: 44px; display: flex; align-items: center; justify-content: center; padding: 9px 8px; font-size: 13px; font-weight: 600; font-family: inherit; cursor: pointer; border-radius: 8px; background: #161E2E; border: 1px solid rgba(255,255,255,0.1); color: #8892A4; }
.mobile-menu-lang button.active,
.mobile-menu-lang .lang-option.active { background: rgba(241,177,27,0.12); color: #F1B11B; border-color: rgba(241,177,27,0.2); }


@media (max-width: 900px) {

  /* ── Horizontal overflow containment ──
     `overflow-x:hidden` on <html> makes the root a scroll container and
     breaks `position:sticky` on descendants in Chrome and Safari — which
     is why the sticky nav stopped pinning to the top on phones. `clip`
     contains the overflow without creating a scroll container, so sticky
     keeps working. The `hidden` line is the fallback for older browsers,
     applied to <body> only, never <html>. */
  body { overflow-x: hidden; overflow-x: clip; }

  /* ── Safe areas (needs viewport-fit=cover in the viewport meta, or
     env() resolves to 0 and every rule below is inert) ── */
  body { padding-top: env(safe-area-inset-top); }
  nav  { padding-left: max(16px, env(safe-area-inset-left)) !important;
         padding-right: max(16px, env(safe-area-inset-right)) !important; }

  /* Show hamburger, hide desktop nav */
  .hamburger  { display: flex !important; }
  .nav-links  { display: none !important; }

  /* ── Language switcher ──
     Only the one inside the top nav is hidden, because that is the one
     the hamburger menu replaces. The switcher on dashboards lives in
     `.topbar` / `.tb-right`, where there is no hamburger and therefore no
     replacement — hiding it there left mobile users with no way to change
     language at all. */
  nav .lang-switcher { display: none !important; }
  .topbar .lang-switcher,
  .tb-right .lang-switcher { display: block !important; }
  .topbar .lang-btn,
  .tb-right .lang-btn { min-height: 40px; padding: 8px 10px !important; font-size: 12px !important; }
  /* Keep the dropdown on-screen when the button sits at the right edge. */
  .topbar .lang-menu,
  .tb-right .lang-menu { right: 0 !important; left: auto !important; max-width: 60vw; }

  /* ── Touch targets ──
     Checkbox and radio are excluded: `min-height` beats `height`, so the
     old blanket `input { min-height:40px }` stretched the registration
     Terms checkbox into a 15×40px sliver and did the same to the agent
     pricing radios. */
  button,
  select,
  textarea,
  input:not([type="checkbox"]):not([type="radio"]) { min-height: 40px; }
  a[class*="btn"], a[role="button"] { min-height: 40px; }
  .btn-ghost, .btn-gold, .btn-lg, .save-btn, .modal-btn { min-height: 44px; }
  input[type="checkbox"], input[type="radio"] { min-height: 0; }

  /* Icon buttons built as <div onclick> never matched the rule above. */
  .notif-btn, .icon-btn, .tb-icon {
    min-width: 44px; min-height: 44px;
    width: 44px !important; height: 44px !important;
  }

  /* iOS Safari zooms the page when a focused field is under 16px, which
     then leaves the layout scrolled sideways. Checkbox and radio excluded
     for the same reason as above. */
  select, textarea,
  input:not([type="checkbox"]):not([type="radio"]) { font-size: 16px !important; }

  /* ── Sidebar layouts → single column ── */
  .body-layout { grid-template-columns: 1fr !important; }
  .side-ad { display: none !important; }

  /* ── Dashboard sidebar → bottom tab bar ── */
  .sidebar {
    position: fixed !important;
    left: 0; right: 0;
    top: auto !important;
    bottom: 0;
    width: 100% !important;
    height: calc(64px + env(safe-area-inset-bottom));
    padding: 0 8px env(safe-area-inset-bottom);   /* clears the home indicator */
    flex-direction: row !important;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    border-right: none !important;
    border-top: 1px solid rgba(255,255,255,0.07) !important;
    align-items: center;
    justify-content: flex-start;
    z-index: 60;
    scrollbar-width: none;
  }
  .sidebar::-webkit-scrollbar { display: none; }
  .sidebar .sidebar-section,
  .sidebar .s-section { display: contents; }
  .sidebar .sidebar-label,  .sidebar .s-label,
  .sidebar .sidebar-footer, .sidebar .s-footer,
  .sidebar .sidebar-logo,   .sidebar .s-logo { display: none; }
  .sidebar .sidebar-section-label,
  .sidebar .s-section-label { display: none !important; }

  .sidebar .nav-item {
    flex-direction: column !important;
    gap: 3px !important;
    padding: 7px 6px !important;
    border-radius: 8px !important;
    font-size: 10px !important;
    line-height: 1.15 !important;
    min-width: 68px;
    max-width: 82px;
    min-height: 44px;
    flex: 0 0 auto;
    scroll-snap-align: start;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: flex !important;
    align-items: center;
    justify-content: center;
    position: relative;
  }
  .sidebar .nav-item .nav-icon { font-size: 20px !important; width: auto !important; }

  /* ── Notification badges ──
     The old rule hid these outright, so unread counts vanished on mobile.
     Collapse them into a corner dot instead: the signal survives, and it
     fits a 68px tab. */
  .sidebar .nav-badge,
  .sidebar .nb {
    position: absolute !important;
    top: 5px; right: 12px;
    min-width: 8px; width: 8px; height: 8px;
    padding: 0 !important;
    border-radius: 50% !important;
    font-size: 0 !important;
    line-height: 0 !important;
    overflow: hidden;
    display: block !important;
  }
  /* A badge the page has hidden must stay hidden. */
  .sidebar .nav-badge[style*="display:none"],
  .sidebar .nav-badge[style*="display: none"],
  .sidebar .nb[style*="display:none"],
  .sidebar .nb[style*="display: none"] { display: none !important; }

  .main, .main-content {
    margin-left: 0 !important;
    margin-right: 0 !important;
    padding-bottom: calc(84px + env(safe-area-inset-bottom)) !important;
  }

  /* ── Tables → horizontal scroll ── */
  .table-wrap, .tw { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .data-table th, .data-table td,
  .dt th, .dt td { white-space: nowrap; }

  /* ── Grids ── */
  .kpi-grid, .kpi-row       { grid-template-columns: 1fr 1fr !important; }
  .two-col, .three-col, .four-col { grid-template-columns: 1fr !important; }
  .product-grid             { grid-template-columns: 1fr 1fr !important; }
  .supplier-grid            { grid-template-columns: 1fr 1fr !important; }
  .who-grid                 { grid-template-columns: 1fr !important; }
  .how-grid                 { grid-template-columns: 1fr 1fr !important; }
  .plans-grid               { grid-template-columns: 1fr !important; }
  .stats-bar                { grid-template-columns: 1fr 1fr !important; }
  .footer-grid              { grid-template-columns: 1fr 1fr !important; gap: 20px !important; }
  /* These two were missed by the singular class names above. Their
     `minmax(320px,1fr)` / `minmax(300px,1fr)` tracks overflowed the
     viewport on 320–360px phones and the cards were clipped. */
  .suppliers-grid, .agents-grid { grid-template-columns: 1fr !important; }
  /* Clamped so a track can never exceed the viewport. */
  .spec-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)) !important; }

  /* ── Chat panels ──
     100vh is taller than the visible area while the browser URL bar is
     showing, which pushed the composer below the fold. dvh tracks the
     real viewport; the vh line above it is the fallback. */
  .main-content [style*="grid-template-columns:260px"] {
    grid-template-columns: 1fr !important;
    grid-template-rows: minmax(120px, 32vh) 1fr !important;
    height: calc(100vh - 200px) !important;
    height: calc(100dvh - 200px) !important;
    min-height: 460px !important;
  }
  #agent-conv-list, #sup-conv-list, #conv-list-body { max-height: none !important; }
  .main-content [style*="grid-template-columns:260px"] input[type="text"],
  .main-content [style*="grid-template-columns:260px"] textarea { font-size: 16px !important; }

  .messages-layout {
    height: calc(100vh - 190px) !important;
    height: calc(100dvh - 190px) !important;
    min-height: 380px;
  }
  .conv-list { max-height: none !important; }
  .chat-input-row, .chat-composer {
    padding-bottom: calc(10px + env(safe-area-inset-bottom)) !important;
  }

  /* ── Modals ──
     accounting-dashboard's modal had no max-height, so on a short screen
     its top and bottom were cut off with no way to scroll to them. */
  .modal-overlay { padding: 16px; }
  .modal {
    max-height: calc(100vh - 32px);
    max-height: calc(100dvh - 32px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 20px !important;
    margin: 0 !important;
  }

  /* ── Forms ── */
  .form-grid { grid-template-columns: 1fr !important; }
  .field.full { grid-column: 1 !important; }

  /* ── Top bar ── */
  .topbar { gap: 10px; padding: 0 12px !important; min-height: 56px; }
  .topbar-left, .tb-left {
    flex: 1 1 auto; min-width: 0;
    font-size: 13px !important;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .topbar-right, .tb-right { flex: 0 0 auto; gap: 6px !important; }
  .topbar-right .btn-gold, .topbar-right .btn-ghost,
  .topbar-right button, .topbar-right a,
  .tb-right .btn-gold, .tb-right .btn-ghost {
    white-space: nowrap;
    font-size: 12.5px !important;
    padding: 8px 12px !important;
  }

  /* ── Typography ── */
  h1 { font-size: 28px !important; }
  .section-title { font-size: 20px !important; }
  .page-title    { font-size: 22px !important; }

  .nav-item, .conv-item, .hy-notif-row { min-height: 44px; }

  /* ── Content padding ── */
  .content { padding: 16px !important; }
  .section, .trending, .cat-strip, .activity-ticker,
  .featured-suppliers, .how-strip, .who-section,
  .ai-section, .cta-strip { padding-left: 16px !important; padding-right: 16px !important; }
  .hero { padding: 28px 16px 20px !important; }
  .feed-banner { padding: 0 16px !important; }

  /* ── RTL corrections ──
     rtl.css has no media queries, so its hardcoded `padding-left:130px`
     on the hero search stayed at desktop size while the page's mobile
     rules adjusted padding-right — the wrong side in RTL — and the text
     ran under the search button in Arabic. */
  body.rtl .hero-search input { padding-left: 118px !important; padding-right: 44px !important; }
  body.rtl .search-btn  { left: 6px !important; right: auto !important; }
  body.rtl .camera-btn  { left: 78px !important; right: auto !important; }
  body.rtl .sidebar     { left: 0 !important; right: 0 !important; }
  body.rtl .mobile-menu-auth,
  body.rtl .mobile-menu-lang { flex-direction: row-reverse; }
}

@media (max-width: 520px) {
  .kpi-grid, .kpi-row    { grid-template-columns: 1fr 1fr !important; }
  .product-grid          { grid-template-columns: 1fr 1fr !important; }
  .supplier-grid         { grid-template-columns: 1fr !important; }
  .how-grid              { grid-template-columns: 1fr 1fr !important; }
  .footer-grid           { grid-template-columns: 1fr !important; }
}

@media (max-width: 420px) {
  .kpi-grid, .kpi-row { gap: 10px !important; }
  .kpi-value { font-size: 26px !important; }
  .kpi-label { font-size: 11px !important; }
  .topbar-left, .tb-left { font-size: 12px !important; }
  .spec-grid { grid-template-columns: 1fr !important; }
}

/* ── 320px phones and the Galaxy Fold cover screen ── */
@media (max-width: 360px) {
  .product-grid  { grid-template-columns: 1fr !important; }
  .how-grid      { grid-template-columns: 1fr !important; }
  .stats-bar     { grid-template-columns: 1fr 1fr !important; }
  .sidebar .nav-item { min-width: 62px; max-width: 72px; font-size: 9.5px !important; }
  h1 { font-size: 24px !important; }
  .hero { padding: 22px 12px 16px !important; }
  .content { padding: 12px !important; }
}

@media (prefers-reduced-motion: reduce) {
  .mobile-menu { animation: none; }
  .hamburger span { transition: none; }
}


/* ============================================================
   Round 2 — fixes from on-device review on a Galaxy Z Fold
   (folded ≈345px, unfolded ≈860px — both below the 900px
   breakpoint, so both get the mobile layout)
   ============================================================ */

@media (max-width: 900px) {

  /* ── Bottom tab bar: labels were painting over each other ──
     The label is a <span> inside a flex `.nav-item`. A flex item defaults to
     `min-width:auto`, so it refuses to shrink below its own content width and
     escapes the 82px tab. The parent's `overflow:hidden` cannot clip what has
     already been laid out past its edge, so "Deletion Requests",
     "Notifications" and "Photo Cleanup" ran together into one smear.
     Giving the label `min-width:0` lets it shrink, and then the ellipsis
     actually applies. */
  .sidebar .nav-item > span {
    min-width: 0;
    max-width: 100%;
    /* Two lines, then clip. Truncating "Deletion Requests" to "Deletion R…"
       is not readable; wrapping it to "Deletion / Requests" is. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    line-clamp: 2;
    overflow: hidden;
    white-space: normal;
    overflow-wrap: break-word;
    text-align: center;
    line-height: 1.15;
  }
  .sidebar .nav-item > span.nav-icon {
    display: block;
    overflow: visible;
    -webkit-line-clamp: none;
    line-clamp: none;
  }
  /* The badge is absolutely positioned by the rule further up, so it must not
     inherit the label's block sizing. */
  .sidebar .nav-item > span.nav-badge,
  .sidebar .nav-item > span.nb {
    display: block !important;
    max-width: none;
    -webkit-line-clamp: none;
    line-clamp: none;
  }

  /* ── Homepage trending strip ──
     `Live` + `Trending:` + `View all →` are all `flex-shrink:0`, so on a
     narrow screen they consumed the entire row and the rotating item — the
     actual content — was squeezed to a few pixels and looked empty.
     Wrap to two rows and give the item the full width of the second. */
  #trending-slider {
    flex-wrap: wrap;
    row-gap: 8px !important;
    padding: 12px 14px !important;
  }
  #trending-slider-track {
    order: 3;
    flex: 1 0 100% !important;
    height: auto !important;
    min-height: 20px;
  }
  #trending-slider-item {
    position: static !important;
    inset: auto !important;
  }

  /* ── Supplier profile: CJK company names broke one character per line ──
     `.profile-name` is a flex row holding the <h1> plus the Gold/Verified
     badges. As a flex item the h1 shrinks to min-content, and Chinese text
     may break between any two characters, so min-content is ONE character —
     "义乌市宸昊工艺品有限公司" stacked vertically down the page.
     Switching to a block on mobile lets the name use the full width and wrap
     normally; the badges follow inline underneath. */
  .profile-name {
    display: block !important;
    font-size: 22px !important;
    line-height: 1.25;
    overflow-wrap: anywhere;
  }
  .profile-name > h1 { display: block !important; margin-bottom: 8px !important; }
  .profile-name .diamond-badge,
  .profile-name .verified-badge {
    display: inline-flex !important;
    vertical-align: middle;
    margin-right: 6px;
  }
  /* Same failure mode in the breadcrumb trail. */
  .crumbs, .breadcrumb, .crumb-row {
    flex-wrap: wrap;
    row-gap: 2px;
    font-size: 12px !important;
    overflow-wrap: anywhere;
  }
  .crumbs > *, .breadcrumb > * { min-width: 0; }

  /* ── Page heroes were eating most of the first screen ── */
  .hero { padding: 22px 16px 18px !important; }
  .hero h1 { font-size: 24px !important; line-height: 1.2 !important; margin-bottom: 8px !important; }
  .hero p  { font-size: 13px !important; line-height: 1.45 !important; }
  .hero .eyebrow { font-size: 10.5px !important; margin-bottom: 8px !important; }
  /* Four stat pills wrapped into four separate lines. Two columns instead. */
  .hero-stats {
    display: grid !important;
    grid-template-columns: 1fr 1fr !important;
    gap: 8px 12px !important;
    margin-top: 12px !important;
  }
  .hero-stats .hstat { font-size: 11.5px !important; white-space: nowrap; }

  /* ── Public profile navs (agent-profile, supplier-profile) ──
     Logo + BETA + language + "Log in" + "Register Free" does not fit a
     345px screen; the button labels were wrapping onto two lines and
     pushing the bar to double height. */
  nav .btn-ghost, nav .btn-gold {
    white-space: nowrap;
    font-size: 12px !important;
    padding: 9px 12px !important;
  }
  nav .hy-beta { display: none; }
  nav .nav-logo img { height: 28px !important; }
}

/* ── Folded cover screen (~345px) ── */
@media (max-width: 400px) {
  .hero h1 { font-size: 21px !important; }
  .hero-stats { grid-template-columns: 1fr 1fr !important; }
  .profile-name { font-size: 19px !important; }
  /* Drop "Register Free" to just "Register" width-wise rather than wrapping. */
  nav .btn-ghost, nav .btn-gold { font-size: 11.5px !important; padding: 9px 10px !important; }
  #trending-slider > span:nth-of-type(2) { display: none; }  /* the "Trending:" label */
}

/* ── Unfolded inner screen (~860px) ──
   Wide enough for two columns; the single-column mobile rules made every
   card full-bleed and the page felt like a phone stretched. */
@media (min-width: 600px) and (max-width: 900px) {
  .suppliers-grid, .agents-grid { grid-template-columns: 1fr 1fr !important; }
  .product-grid { grid-template-columns: repeat(3, 1fr) !important; }
  .kpi-grid, .kpi-row { grid-template-columns: repeat(4, 1fr) !important; }
  .hero h1 { font-size: 30px !important; }
  .hero-stats { grid-template-columns: repeat(4, 1fr) !important; }
  .profile-name { font-size: 26px !important; }
}


/* ============================================================
   Round 3 — the "unshrinkable flex child" family

   All of these are the same defect wearing different clothes.
   A flex item defaults to `min-width: auto`, meaning it refuses to
   shrink below its own content width. Put two of them in a row on a
   345px screen and they don't compress — they overflow, collide, or
   get clipped by an ancestor's `overflow: hidden`, with no scrollbar
   because the scroll container never gets a chance to be narrower
   than its contents.

   `min-width: 0` is the fix in every case. It is safe to apply
   broadly: it only grants permission to shrink.
   ============================================================ */

@media (max-width: 900px) {

  /* ── Homepage "Recently verified" ticker ──
     `#verified-ticker-items` is a flex child with `overflow-x: auto`.
     Without `min-width: 0` it sized to the full width of all the pills
     inside it, overflowed the row, and got clipped by the wrapper's
     `overflow: hidden` — so the one visible supplier was cut in half at
     the screen edge and could not be scrolled to. */
  #verified-ticker-items {
    min-width: 0;
    flex: 1 1 auto;
    -webkit-overflow-scrolling: touch;
  }
  .vt-inner { padding: 10px 16px !important; gap: 10px !important; }
  /* A single long company name (Chinese names are common here) could be
     wider than the whole screen on its own. */
  .vt-pill {
    max-width: 62vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* ── Horizontal category rails ── (index.html, products.html) ── */
  .cat-scroll {
    min-width: 0;
    max-width: 100%;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }

  /* ── Section headings: title on the left, link on the right ──
     Neither child could shrink, so "All products 全部产品" and
     "Open full directory →" overlapped, as did "Browse categories" and
     "View all". Let the row wrap and keep the link intact on its own
     line rather than breaking mid-phrase. */
  .section-head {
    flex-wrap: wrap;
    gap: 4px 12px;
    align-items: baseline !important;
  }
  .section-head h2 {
    min-width: 0;
    flex: 1 1 auto;
    font-size: 19px !important;
    overflow-wrap: anywhere;
  }
  .section-head a {
    flex: 0 0 auto;
    white-space: nowrap;
    font-size: 12.5px !important;
  }

  /* ── Other title/action rows with the same shape ── */
  .toolbar, .footer-bottom, .card-header-row, .review-header,
  .campaign-footer, .rule-row, .setting-row, .toggle-row, .filter-toggle {
    flex-wrap: wrap;
    gap: 8px 12px;
  }
  /* Permission to shrink, without forcing a wrap — safe everywhere. */
  .toolbar > *, .footer-bottom > *, .card-header-row > *,
  .review-header > *, .kpi-top > *, .prod-foot > *, .prod-meta > *,
  .agent-footer > *, .card-footer > *, .rule-row > *, .setting-row > * {
    min-width: 0;
  }

  /* ── Long unbroken strings (company names, emails, URLs, booth codes) ── */
  .prod-name, .product-name, .agent-name, .supplier-name,
  .card-title, .conv-name, .msg-body, .cell-name {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  /* ── Wide inline padding on wrappers ──
     mobile.css already trimmed .hero / .section / .content, but these
     wrapper classes carry 40–48px of horizontal padding of their own.
     On a folded 345px screen that is up to 96px — over a quarter of the
     display — spent on empty margin. */
  .layout, footer, .cta-section, .how-section, .demo-section,
  .features-section, .notify-section, .upload-zone, .faq-section,
  .section-alt, .plans-section, .contact-section {
    padding-left: 16px !important;
    padding-right: 16px !important;
  }
}

/* Folded cover screen */
@media (max-width: 400px) {
  .vt-pill { max-width: 58vw; }
  .section-head h2 { font-size: 17.5px !important; }
  .layout, footer, .cta-section, .how-section, .demo-section,
  .features-section, .notify-section, .upload-zone, .faq-section,
  .section-alt, .plans-section, .contact-section {
    padding-left: 12px !important;
    padding-right: 12px !important;
  }
}


/* ============================================================
   Round 4 — bottom tab bar spacing, and the supplier name
   ============================================================ */

@media (max-width: 900px) {

  /* ── Bottom tab bar: give the tabs room to breathe ──
     They were butted against each other with no gap, so even once the
     labels stopped overlapping, "Dashboard Verifications Deletion Requests"
     read as one continuous run of text. Each tab now has its own width,
     a gap, and a hairline divider so the boundary is visible. */
  .sidebar {
    gap: 2px;
    height: calc(72px + env(safe-area-inset-bottom));
    padding: 0 6px env(safe-area-inset-bottom);
  }
  .main, .main-content {
    padding-bottom: calc(92px + env(safe-area-inset-bottom)) !important;
  }

  .sidebar .nav-item {
    min-width: 78px;
    max-width: 78px;
    min-height: 62px;
    padding: 6px 5px !important;
    gap: 4px !important;
    justify-content: flex-start !important;
    font-size: 9.5px !important;
    position: relative;
    /* The divider sits in the gap between tabs rather than on the tab
       itself, so the active tab's background does not swallow it. */
    box-shadow: 1px 0 0 rgba(255, 255, 255, 0.05);
  }
  .sidebar .nav-item:last-child { box-shadow: none; }
  .sidebar .nav-item.active { box-shadow: none; }
  .sidebar .nav-item .nav-icon { font-size: 19px !important; line-height: 1 !important; }

  /* Badge tucks into the tab's top-right without overlapping the icon. */
  .sidebar .nav-badge, .sidebar .nb { top: 3px; right: 7px; }

  /* ── Supplier profile header ──
     `.profile-name-block` is `flex:1`, which still leaves `min-width:auto`,
     so it could not shrink and the avatar beside it kept squeezing the name
     column down to about two characters wide. Chinese breaks between any
     two characters, so the company name ran straight down the page. */
  .profile-header { padding: 0 20px !important; }
  .profile-name-block { min-width: 0; width: 100%; flex: 1 1 auto; padding-bottom: 0 !important; }
  .profile-avatar-row { align-items: flex-start !important; gap: 14px !important; }
  .profile-name {
    display: block !important;
    font-size: 21px !important;
    line-height: 1.3 !important;
    word-break: normal;
    overflow-wrap: break-word;
  }
  .profile-name > h1 {
    display: block !important;
    font-size: inherit !important;
    line-height: inherit !important;
    margin: 0 0 8px 0 !important;
  }
  .profile-name .diamond-badge,
  .profile-name .verified-badge {
    display: inline-flex !important;
    vertical-align: middle;
    margin: 0 6px 4px 0;
    font-size: 11px !important;
  }
  .profile-meta { font-size: 12.5px !important; }
}

/* ── Narrow phones and the folded cover screen ──
   Stack the avatar above the name so the company name gets the full
   width of the screen instead of sharing a row with a 96px logo. */
@media (max-width: 640px) {
  .profile-avatar-row {
    flex-direction: column !important;
    align-items: flex-start !important;
    gap: 10px !important;
    margin-top: -34px !important;
  }
  .profile-name-block { width: 100% !important; }
  .avatar { width: 74px !important; height: 74px !important; font-size: 32px !important; }
}

@media (max-width: 400px) {
  .profile-header { padding: 0 14px !important; }
  .profile-name { font-size: 19px !important; }
  .sidebar .nav-item { min-width: 72px; max-width: 72px; font-size: 9px !important; }
}


/* ============================================================
   Round 5 — bottom tab bar, made markup-independent

   Five of the eight dashboards wrote their tab labels as bare text
   next to the icon span:

       <a class="nav-item"><span class="nav-icon">⊞</span>Overview</a>

   A bare text node inside a flex container becomes an ANONYMOUS flex
   item. No selector can reach it, so `.nav-item > span` fixed admin and
   supplier but did nothing at all on buyer, agent, staff, accounting and
   media-broker. Those labels are now wrapped in .nav-label, and the rules
   below are written so the bar survives either shape — including any tab
   added later that forgets the wrapper.
   ============================================================ */

@media (max-width: 900px) {

  /* Dropping flex for a plain block is what makes this markup-independent:
     in a block box a bare text node is ordinary inline content, so it wraps,
     centres and clips like any other text. The fixed height is the clamp —
     icon line plus two label lines — so a third line is cut rather than
     spilling into the neighbouring tab. */
  .sidebar .nav-item {
    display: block !important;
    text-align: center;
    height: 60px;
    overflow: hidden;
    padding: 6px 5px !important;
    font-size: 9.5px !important;
    line-height: 1.15 !important;
    white-space: normal !important;
    overflow-wrap: break-word;
    word-break: normal;
  }
  .sidebar .nav-item > .nav-icon {
    display: block !important;
    width: auto !important;
    font-size: 19px !important;
    line-height: 1.05 !important;
    margin-bottom: 3px;
  }
  .sidebar .nav-item > .nav-label,
  .sidebar .nav-item > span:not(.nav-icon):not(.nav-badge):not(.nb) {
    display: block;
    min-width: 0;
    max-width: 100%;
    overflow-wrap: break-word;
  }
  /* `margin-left:auto` from the desktop rule would shove the badge out of a
     block box, so it is reset along with the positioning. */
  .sidebar .nav-item > .nav-badge,
  .sidebar .nav-item > .nb {
    margin-left: 0 !important;
    top: 3px;
    right: 6px;
  }
}

@media (max-width: 400px) {
  .sidebar .nav-item { height: 58px; font-size: 9px !important; }
  .sidebar .nav-item > .nav-icon { font-size: 17px !important; }
}


/* ============================================================
   Round 6 — remaining items
   ============================================================ */

@media (max-width: 900px) {
  /* ── Hero search ──
     index.html tunes the input to 13px and reserves 118px on the right for
     the camera and search buttons. This stylesheet then forces 16px on every
     input (iOS zooms the page on any focused field under 16px), so the
     placeholder no longer fitted the space the padding reserved and ran under
     the buttons. Keep 16px — it is the right value — and widen the reserve to
     match the text it now has to clear. */
  .hero-search input {
    font-size: 16px !important;
    padding-right: 132px !important;
    padding-left: 16px !important;
  }
  .camera-btn { right: 92px !important; }
  .search-btn { padding: 0 14px !important; font-size: 12.5px !important; }

  /* ── Readability floor ──
     58 declarations sit at 8–9px. That is below the size at which Chinese
     glyphs resolve at all, and near-unreadable in any script on a phone.
     Raised only where the element carries running text; badges, pills and
     the tab bar keep their own sizes, set elsewhere in this file. */
  .prod-meta, .card-meta, .meta, .muted, .sub, .subtitle, .caption,
  .hint, .help-text, .field-hint, .footnote, .timestamp, .time,
  .badge-text, .cell-sub, .list-sub { font-size: 11px !important; }

  /* ── Topbar class split ──
     media-manager and media-broker-dashboard use .tb-left/.tb-right while
     every other dashboard uses .topbar-left/.topbar-right. Both are handled
     throughout this file; this keeps the container itself consistent too. */
  .tb, .topbar { min-height: 56px; }
}

@media (max-width: 400px) {
  .hero-search input { padding-right: 118px !important; }
  .camera-btn { right: 84px !important; }
  .search-btn { padding: 0 11px !important; font-size: 11.5px !important; }
}

/* ── Banner editor: pinch to zoom ──
   Zoom was wheel-only, so on a phone the crop could be dragged but never
   scaled. touch-action:none stops the browser claiming the gesture first. */
.hy-banner-canvas, #hy-banner-canvas { touch-action: none; }


/* ============================================================
   Round 7 — buyer dashboard and the category rail
   Reported on iPhone: form inputs running off the right edge,
   the welcome name wrapping one word per line, chips clipped
   mid-word at both ends of the category strip.
   ============================================================ */

@media (max-width: 900px) {

  /* ── Horizontal chip rails ──
     The strip scrolls, but with no padding at either end a chip sits
     flush against the screen edge and reads as broken rather than
     scrollable. A little inset plus scroll-padding makes the affordance
     obvious and stops a chip being sliced in half at rest. */
  .cat-scroll, .filter-chips, .chip-row {
    padding-left: 16px !important;
    padding-right: 16px !important;
    margin-left: -16px;
    margin-right: -16px;
    scroll-padding-left: 16px;
    scroll-snap-type: x proximity;
    overscroll-behavior-x: contain;
  }
  .cat-scroll > *, .filter-chips > *, .chip-row > * {
    scroll-snap-align: start;
    flex: 0 0 auto;
  }

  /* ── Any inline two-column grid ──
     Several forms are written as style="display:grid;
     grid-template-columns:1fr 1fr". An inline style cannot be reached
     by a normal rule, so these stayed two-up on a 390px screen and
     pushed every input past the right edge. Attribute selectors reach
     them without needing the markup changed everywhere. */
  [style*="grid-template-columns:1fr 1fr"],
  [style*="grid-template-columns: 1fr 1fr"] {
    grid-template-columns: 1fr !important;
  }

  /* Fields must be allowed to shrink inside any grid or flex parent. */
  .field, .field input, .field select, .field textarea {
    min-width: 0;
    max-width: 100%;
  }

  /* ── Dashboard top bar ──
     Greeting, language, bell and a full-width button competing for one
     row. The greeting takes what is left and truncates rather than
     shoving the button off-screen. */
  .topbar .btn-new, .topbar-right .btn-new {
    white-space: nowrap;
    font-size: 12.5px !important;
    padding: 9px 12px !important;
    min-height: 40px;
  }
}

@media (max-width: 520px) {
  /* DO NOT hide the "+ New request" button here. It looks like a
     duplicate of the one in the top bar, but the two do different jobs:
     the top bar button only calls showPage('requests') to navigate, while
     this one calls showNewRequestForm() and is the ONLY way to open the
     form. Hiding it left buyers on phones under 520px with no way to post
     a sourcing request at all. Instead, keep it and let it shrink. */
  #page-requests button[onclick*="showNewRequestForm"] {
    white-space: nowrap;
    font-size: 12.5px !important;
    padding: 9px 12px !important;
    min-height: 44px;
    flex: 0 0 auto;
  }

  /* A long placeholder is truncated to nonsense in a narrow select
     ("Select category 选择类..."). Shorter text, both scripts intact. */
  select[data-hy-fill="category"] { font-size: 13px !important; }
}


/* ============================================================
   Round 8 — ad slots, and the request form
   ============================================================ */

@media (max-width: 900px) {
  /* ── Oversized ad panels ──
     ad-system.js applies the broker's size_scale as
     el.style.transform = scale(n), and n can be up to 2.0. A transform
     does not change layout: the slot still occupies its original box but
     PAINTS larger, so the creative and its border spill past the edge of
     the page. Harmless on a wide desktop, obvious on a phone.

     Scaling is a desktop-only nicety, so it is neutralised here rather
     than clamped — a full-width slot on a phone has nothing to scale
     into. Inline styles need !important to override. */
  .ad-slot,
  [id^="ad-"] {
    transform: none !important;
    max-width: 100% !important;
    width: 100% !important;
    overflow: hidden;
    box-sizing: border-box;
  }
  .ad-slot img, [id^="ad-"] img { max-width: 100%; height: auto; }

  /* The rails are desktop furniture — there is no room for a 160px
     column beside the content on a phone. */
  #ad-left-rail, #ad-right-rail { display: none !important; }

  /* ── Request form: photo upload ── */
  .req-photo-drop {
    border: 1px dashed var(--border2);
    border-radius: 10px;
    padding: 18px 14px;
    text-align: center;
    cursor: pointer;
    background: var(--bg2);
    min-height: 88px;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 6px;
  }
  .req-photo-preview img { max-width: 84px; max-height: 84px; border-radius: 8px; }
}

/* Desktop styling for the same uploader. */
.req-photo-drop {
  border: 1px dashed var(--border2);
  border-radius: 10px;
  padding: 20px;
  text-align: center;
  cursor: pointer;
  background: var(--bg2);
  transition: border-color .15s;
}
.req-photo-drop:hover { border-color: var(--gold); }
.req-photo-preview { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.req-photo-preview .rp-item { position: relative; }
.req-photo-preview img {
  width: 84px; height: 84px; object-fit: cover;
  border-radius: 8px; border: 1px solid var(--border2);
}
.req-photo-preview .rp-x {
  position: absolute; top: -6px; right: -6px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--red, #A31D14); color: #fff; border: none;
  font-size: 13px; line-height: 1; cursor: pointer;
}


/* ── Quick Add modal ──
   The modal itself was overflowing horizontally on a phone: the row grid
   was fixed at four columns and the dialog had no width ceiling. */
@media (max-width: 900px) {
  #quickadd-modal .modal, #quickadd-modal > div {
    width: 100% !important;
    max-width: 100% !important;
    margin: 0 !important;
    border-radius: 14px;
    padding: 16px !important;
    max-height: calc(100dvh - 24px);
    overflow-y: auto;
    overflow-x: hidden;
  }
  #qa-products { overflow-x: hidden; }
  #qa-save-bar {
    flex-wrap: wrap; gap: 10px;
    position: sticky; bottom: 0;
    background: var(--bg2, #0D1220);
    padding: 12px 0 calc(4px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--border, rgba(255,255,255,.07));
  }
  #qa-save-bar button { flex: 1 1 auto; min-height: 44px; }
}


/* ── Back control ──
   Added by hy-back.js to every page except the homepage and the
   dashboards. Quiet by default; the destination name is hidden on
   narrow screens where only the arrow fits. */
.hy-back{
  display:inline-flex; align-items:center; gap:6px;
  font-size:13px; color:var(--muted, #8892A4);
  padding:8px 13px; border:1px solid var(--border2, rgba(255,255,255,.12));
  border-radius:9px; text-decoration:none; white-space:nowrap;
  min-height:40px; flex-shrink:0;
  /* No left margin: it now sits inside the controls group, which
     supplies its own gap. A margin here would double-space it. */
  transition:color .15s, border-color .15s;
}
.hy-back:hover{ color:var(--gold, #F1B11B); border-color:var(--gold, #F1B11B); }
.hy-back:focus-visible{ outline:2px solid var(--gold, #F1B11B); outline-offset:2px; }

/* Inside .nav-right it sits before the language switcher, so the left
   margin that separated it from the logo is wrong there. */
.hy-back.in-nav-right{ margin-left:0; margin-right:4px; }

@media (max-width: 900px){
  /* Just the arrow on a phone — a 44px target, and the nav has no room
     for "Back to Sourcing Agents" beside a logo, a language pill and an
     account button. */
  .hy-back{ padding:0; width:44px; min-height:44px;
            justify-content:center; gap:0; }
  .hy-back .hy-back-txt{ display:none; }
}


/* ── Category rail arrows (hy-rail.js) ──
   The wrapper is position:relative so the buttons can sit over the
   ends of the strip. Both are hidden until the rail actually overflows,
   and each disappears at its end of the travel — that absence is what
   tells the visitor there is nothing further that way. */
.hy-rail-wrap{ position:relative; }
/* Room for the arrows, so they do not cover the first and last chip.
   Applied only when the rail overflows and the arrows are present. */
.hy-rail-wrap.has-overflow > .cat-scroll,
.hy-rail-wrap.has-overflow > .filter-chips,
.hy-rail-wrap.has-overflow > .chip-row{
  padding-left:36px; padding-right:36px;
  scroll-padding-left:36px; scroll-padding-right:36px;
}
.hy-rail-btn{
  position:absolute; top:50%; transform:translateY(-50%);
  width:32px; height:32px; border-radius:50%;
  display:none; align-items:center; justify-content:center;
  background:var(--surface,#161E2E);
  border:1px solid var(--border2,rgba(255,255,255,.12));
  color:var(--text,#F0F2F7); font-size:17px; line-height:1;
  cursor:pointer; z-index:5; padding:0;
  box-shadow:0 2px 10px rgba(0,0,0,.45);
  transition:background .15s, border-color .15s, opacity .15s;
}
.hy-rail-wrap.has-overflow .hy-rail-btn{ display:flex; }
/* Must out-specify the rule above (3 classes), or display:flex wins and
   the arrow stays visible at the end of its travel. */
.hy-rail-wrap.has-overflow .hy-rail-btn.is-hidden{ display:none; }
.hy-rail-btn:hover{ background:var(--gold,#F1B11B); border-color:var(--gold,#F1B11B); color:#2A1700; }
.hy-rail-btn:focus-visible{ outline:2px solid var(--gold,#F1B11B); outline-offset:2px; }
.hy-rail-prev{ left:0; }
.hy-rail-next{ right:0; }

/* Fade the strip under each arrow so chips slide out of view rather
   than being cut off mid-word. */
.hy-rail-wrap.has-overflow::before,
.hy-rail-wrap.has-overflow::after{
  content:''; position:absolute; top:0; bottom:0; width:44px;
  pointer-events:none; z-index:4;
}
.hy-rail-wrap.has-overflow::before{
  left:0; background:linear-gradient(90deg, var(--bg2,#0D1220), transparent);
}
.hy-rail-wrap.has-overflow::after{
  right:0; background:linear-gradient(270deg, var(--bg2,#0D1220), transparent);
}

@media (max-width: 900px){
  /* Swiping is natural on a touch screen and the arrows would sit on
     top of the chips, so only the fade stays. */
  .hy-rail-wrap.has-overflow .hy-rail-btn{ display:none; }
  .hy-rail-wrap.has-overflow::before,
  .hy-rail-wrap.has-overflow::after{ width:26px; }
}
@media (prefers-reduced-motion: reduce){
  .hy-rail-btn{ transition:none; }
}


/* ── Image lightbox (hy-lightbox.js) ── */
.hy-lb{
  position:fixed; top:0; right:0; bottom:0; left:0;
  background:rgba(4,7,12,.94);
  display:none; align-items:center; justify-content:center;
  z-index:400; padding:56px 16px;
}
.hy-lb.is-open{ display:flex; }
.hy-lb-fig{ margin:0; max-width:100%; max-height:100%; display:flex;
  flex-direction:column; align-items:center; gap:12px; }
.hy-lb-img{
  max-width:min(1100px, 92vw); max-height:82vh;
  width:auto; height:auto; object-fit:contain;
  border-radius:10px; box-shadow:0 18px 60px rgba(0,0,0,.6);
  background:#0D1220;
}
.hy-lb-cap{ font-size:12.5px; color:var(--muted,#8892A4); text-align:center; }
.hy-lb-x{
  position:absolute; top:14px; right:16px;
  width:44px; height:44px; border-radius:50%;
  background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.16);
  color:#F0F2F7; font-size:26px; line-height:1; cursor:pointer;
}
.hy-lb-x:hover{ background:rgba(255,255,255,.16); }
.hy-lb-nav{
  position:absolute; top:50%; transform:translateY(-50%);
  width:46px; height:46px; border-radius:50%;
  background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.16);
  color:#F0F2F7; font-size:24px; line-height:1; cursor:pointer;
}
.hy-lb-nav:hover{ background:rgba(241,177,27,.9); color:#2A1700; border-color:transparent; }
.hy-lb-prev{ left:14px; }
.hy-lb-next{ right:14px; }
.hy-lb-x:focus-visible, .hy-lb-nav:focus-visible{
  outline:2px solid var(--gold,#F1B11B); outline-offset:2px;
}
/* A quiet hint that these images open. */
[data-hy-zoom]{ cursor:zoom-in; }

@media (max-width:640px){
  .hy-lb{ padding:52px 8px; }
  .hy-lb-img{ max-width:96vw; max-height:74vh; }
  .hy-lb-nav{ width:42px; height:42px; }
  .hy-lb-prev{ left:6px; } .hy-lb-next{ right:6px; }
}


/* ── Fields carried over from registration ──
   Set by hy-prefill.js (shop form) and by the QR handler on
   register.html. A quiet gold edge says "we filled this in, check it"
   without shouting — the supplier should notice and glance, not be
   alarmed. Never used to lock a field: all of these stay editable. */
.hy-prefilled,
.hy-from-qr{
  border-color:rgba(241,177,27,.45) !important;
  background:rgba(241,177,27,.05) !important;
}
.hy-prefilled:focus,
.hy-from-qr:focus{
  border-color:var(--gold,#F1B11B) !important;
  background:var(--bg2,#0D1220) !important;
}


/* ── Recently-verified ticker ──
   The strip scrolled but the last supplier was sliced mid-word with
   nothing to say more existed. hy-rail.js now wraps it, which needs
   two adjustments: the wrapper has to behave as a flex item inside
   .vt-inner, and the arrows have to fit a 30px-tall strip rather than
   the 32px circles used on the taller category rail. */
.vt-inner .hy-rail-wrap{ flex:1 1 auto; min-width:0; }
.vt-inner .hy-rail-btn{
  width:26px; height:26px; font-size:14px;
  box-shadow:0 2px 8px rgba(0,0,0,.5);
}
.vt-inner .hy-rail-wrap.has-overflow > .chip-row{
  padding-left:30px; padding-right:30px;
  scroll-padding-left:30px; scroll-padding-right:30px;
}
.vt-inner .hy-rail-wrap.has-overflow::before,
.vt-inner .hy-rail-wrap.has-overflow::after{ width:34px; }

@media (max-width:900px){
  /* No arrows on touch — swiping is natural — but keep the fade so the
     cut-off pill reads as "more this way" rather than broken. */
  .vt-inner .hy-rail-wrap.has-overflow > .chip-row{
    padding-left:0; padding-right:16px;
  }
}
