/* AccountHab — Marketplace & Buyer Dashboard styles. Extracted verbatim
   from the original Buyer.html design file (do not redesign — this is
   the source of truth). The :root block below fills in design tokens
   (--white, --blue-900, --border, --shadow-md, --text-muted, --blue-700,
   --success, --blue-50, --blue-500, --blue-800, --border-soft) that the
   original inline styles reference but never defined — values chosen to
   match the navy/blue/green palette already used in Admin.html/Seller.html. */
:root{
  --white:#fff;--text:#202124;--text-muted:#777;
  --blue-900:#092e6b;--blue-800:#123f86;--blue-700:#1769e0;--blue-500:#3b82f6;--blue-50:#eef4ff;
  --success:#16a34a;--border:#e3e5e8;--border-soft:#eee;
  --shadow-md:0 4px 16px rgba(24,55,100,.08);
  /* Global AccountHab site background — the one place this color is
     defined; body and .product-group's own gap background (see that
     rule further down) both read from this same token, so this is the
     only line to change to update the site's background everywhere it
     appears. Previously a plain #f6f7f9 hardcoded in two separate
     places; now a single source of truth. */
  --page-bg:#EEF4FF
}
*{box-sizing:border-box}
body{margin:0;font-family:Arial,Helvetica,sans-serif;background:var(--page-bg);color:#202124}
a{text-decoration:none;color:inherit}
button,input,select{font:inherit}
.header{height:64px;background:#fff;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;padding:0 28px;gap:16px;position:sticky;top:0;z-index:20}
.logo{font-size:22px;font-weight:700}
/* Marketplace Header Navigation Redesign — Marketplace/About/Sell on
   AccountHab used to be plain <a> text (.nav a:hover only). Same .nav
   container, same three hrefs/routes — only the link markup gets a
   class (.nav-link for Marketplace/About, .nav-cta for the one primary
   action among them) plus a small inline icon, so the header keeps its
   existing height/structure while the links stop reading as bare text.
   Colors/hover treatment reuse this file's own existing convention
   (--blue-50/--blue-800, the same pair .side-link/.header-icon-btn/
   .header-user-chip already hover to) rather than introducing a new
   visual language. */
.nav{display:flex;align-items:center;gap:4px;font-size:14px}
.nav-link{display:inline-flex;align-items:center;gap:6px;padding:8px 12px;border-radius:8px;color:#555;font-weight:600;transition:background-color .18s ease,color .18s ease}
.nav-link-icon{width:16px;height:16px;fill:currentColor;flex:0 0 auto;opacity:.8;transition:opacity .18s ease}
.nav-link:hover{background:var(--blue-50);color:var(--blue-800)}
.nav-link:hover .nav-link-icon{opacity:1}
.nav-link.active{background:var(--blue-50);color:var(--blue-800);font-weight:700}
.nav-link.active .nav-link-icon{opacity:1}
.nav-cta{display:inline-flex;align-items:center;gap:6px;margin-left:6px;padding:9px 16px;border-radius:999px;background:var(--blue-700);color:#fff;font-weight:700;font-size:13.5px;white-space:nowrap;transition:background-color .18s ease,transform .18s ease}
.nav-cta-icon{width:15px;height:15px;fill:#fff;flex:0 0 auto}
.nav-cta:hover{background:var(--blue-800)}
.nav-cta:active{transform:scale(.96)}
/* Narrow desktop/tablet — the same three links stay visible down to the
   existing 900px cutoff below (.nav{display:none} there, untouched);
   this just trims their own gap/padding first so they reach that
   cutoff gracefully instead of visibly crowding right before it.
   Threshold widened from 1180px to 1220px as part of the Buyer header
   responsive overflow fix (see the new @media(min-width:901px) block
   near the end of this file for the rest of that fix, and why it had
   to live there instead of here). */
@media(max-width:1220px){
  .nav{gap:0}
  .nav-link{padding:8px 9px}
  .nav-cta{padding:8px 13px;margin-left:2px}
  .header{padding:0 18px;gap:10px}
}
/* Mobile Top Navigation Links — Marketplace/About/Sell on AccountHab
   disappear on mobile because .nav{display:none} at <=900px below. This is
   a separate, compact mobile-only row (same three links/routes/icons/
   active-state logic, duplicated markup placed right after </header> and
   above the Categories section in marketplace.blade.php/about.blade.php)
   rather than trying to reflow .nav itself, so .header/.nav/.nav-link/
   .nav-cta above stay completely untouched. Hidden here by default
   (desktop/tablet); switched on only inside the existing
   @media(max-width:900px)/@media(max-width:600px) blocks below, the same
   cutoffs the rest of the mobile header already uses. */
.mobile-subnav{display:none}
/* Reference-design header — search icon inside the same existing
   .search input (behavior/placeholder/Enter-to-search unchanged), plus
   a notification bell and a user avatar/role chip (both additive, see
   .header-icon-btn/.header-user-chip below). */
.search-wrap{position:relative;margin-left:auto;width:300px;flex:0 1 300px}
.search-wrap .search-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);width:15px;height:15px;fill:#9aa1ac;pointer-events:none}
.search{width:100%;height:38px;border:1px solid #d8dce1;border-radius:6px;padding:0 12px 0 32px}
/* Mobile Search Icon Redesign — .header-search-toggle (the compact
   magnifying-glass button, reusing .header-icon-btn for its sizing/
   hover/border styling) and .search-close-btn (the small X inside
   .search-wrap) only ever appear on mobile; both stay hidden here by
   default so desktop and tablet are completely unaffected, and are
   switched on only inside the existing @media(max-width:600px) block
   below. */
/* .header-icon-btn.header-search-toggle (both classes) rather than just
   .header-search-toggle — needs to out-specificity the shared
   .header-icon-btn{display:flex} rule just below, which would otherwise
   win on source order alone and show this button on desktop/tablet
   too. */
.header-icon-btn.header-search-toggle{display:none}
.search-close-btn{display:none}
.dashboard-link{font-size:14px;font-weight:600;white-space:nowrap}
/* Header Pills Redesign — Login/Register/Seller (renderNav() in
   public/js/api.js), guest-only. Same rounded-pill language as the
   existing .nav-cta ("Sell on AccountHab") control: --outline is the
   light, blue-bordered look for Login/Seller, --filled reuses .nav-cta's
   own solid blue treatment for Register. No new color tokens added. */
.nav-pill{display:inline-flex;align-items:center;gap:6px;padding:8px 14px;border-radius:999px;font-weight:700;font-size:13.5px;white-space:nowrap;transition:background-color .18s ease,border-color .18s ease,transform .18s ease}
.nav-pill-icon{width:14px;height:14px;fill:currentColor;flex:0 0 auto}
.nav-pill--outline{background:var(--white);border:1px solid var(--blue-500);color:var(--blue-800)}
.nav-pill--outline:hover{background:var(--blue-50);border-color:var(--blue-700)}
.nav-pill--filled{background:var(--blue-700);color:#fff;border:1px solid var(--blue-700)}
.nav-pill--filled:hover{background:var(--blue-800)}
.nav-pill:active{transform:scale(.96)}
@media (max-width:600px){
  .nav-pill{padding:7px 11px;font-size:12.5px;gap:4px}
}
.header-icon-btn{position:relative;width:38px;height:38px;border-radius:8px;border:1px solid #e3e5e8;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#4b5563;flex:0 0 auto;padding:0}
.header-icon-btn:hover{background:var(--blue-50);color:var(--blue-800);border-color:var(--blue-500)}
.header-icon-btn svg{width:18px;height:18px;fill:currentColor}
.header-icon-badge{position:absolute;top:-4px;right:-4px;min-width:16px;height:16px;padding:0 4px;border-radius:999px;background:#dc2626;color:#fff;font-size:10px;font-weight:700;line-height:16px;text-align:center}
.header-icon-badge:empty{display:none}
.header-user-chip{display:flex;align-items:center;gap:8px;padding:5px 10px 5px 5px;border-radius:999px;border:1px solid #e3e5e8;cursor:pointer;flex:0 0 auto;color:var(--text)}
.header-user-chip:hover{background:var(--blue-50);border-color:var(--blue-500)}
.header-user-avatar{width:28px;height:28px;border-radius:50%;background:var(--blue-700);color:#fff;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.header-user-meta{display:flex;flex-direction:column;line-height:1.2}
.header-user-name{font-size:12.5px;font-weight:700;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.header-user-role{font-size:10.5px;color:var(--text-muted)}
.header-user-chevron{width:14px;height:14px;fill:#9aa1ac;flex:0 0 auto}
/* Professional Header Redesign — Wallet Balance chip. Same visual
   language as .header-icon-btn/.header-user-chip just above (soft
   background, rounded, subtle border, blue hover) rather than a new
   style, kept deliberately small/subtle per the "compact, elegant...
   not oversized" requirement. Compact mobile sizing (icon + amount only,
   "Wallet:" label hidden) lives in the existing @media(max-width:600px)
   block further down, next to this component's other mobile rules. */
.header-wallet-chip{display:flex;align-items:center;gap:6px;padding:6px 12px;border-radius:999px;background:var(--blue-50);border:1px solid var(--blue-500);color:var(--blue-800);font-size:12.5px;font-weight:700;cursor:pointer;flex:0 0 auto;white-space:nowrap}
.header-wallet-chip:hover{background:#e0edff;border-color:var(--blue-700)}
.header-wallet-chip svg{width:15px;height:15px;fill:currentColor;flex:0 0 auto}
.header-wallet-amount{font-variant-numeric:tabular-nums}
/* Mobile Wallet Menu — reuses the existing .order-overlay/.order-modal
   shell (see .order-overlay/.order-modal/.order-modal-header/
   .order-modal-close further down) rather than a new overlay system;
   these rules only add the wallet-specific content inside that shell
   plus a taller z-index (the live-chat widget's own #ahLiveChatWidget
   sits at z-index:9500, higher than .order-overlay's base 50 — without
   this override the chat bubble would float on top of the wallet menu
   instead of being covered by its backdrop, exactly the "hidden behind
   the chat button" problem this was asked to avoid). Built and opened
   only on phone-width taps — see renderBuyerNav()/openWalletMenu() in
   public/js/api.js — so none of this is reachable on desktop/tablet. */
#walletMenuOverlay{z-index:9700}
.wallet-menu-modal{max-width:360px;padding:0;overflow:hidden;transform:translateY(-10px);opacity:0;transition:transform .18s ease,opacity .18s ease}
.order-overlay.show .wallet-menu-modal{transform:translateY(0);opacity:1}
.wallet-menu-modal .order-modal-header{padding:16px 18px;margin:0;border-bottom:1px solid var(--border-soft)}
.wallet-menu-modal .order-modal-header h3{margin:0;font-size:17px;font-weight:800;color:var(--blue-900)}
.wallet-menu-balance-card{margin:16px 18px;padding:16px;background:var(--blue-50);border:1px solid var(--blue-500);border-radius:12px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.wallet-menu-balance-icon{width:40px;height:40px;border-radius:10px;background:var(--blue-700);display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.wallet-menu-balance-icon svg{width:20px;height:20px;fill:#fff}
.wallet-menu-balance-info{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.wallet-menu-balance-label{font-size:12px;color:var(--text-muted);font-weight:600}
.wallet-menu-balance-amount{font-size:22px;font-weight:800;color:var(--blue-900);font-variant-numeric:tabular-nums}
.wallet-menu-add-funds-btn{flex:0 0 auto;display:inline-flex;align-items:center;gap:4px;height:36px;padding:0 14px;border-radius:999px;background:var(--success);color:#fff;font-size:13px;font-weight:700;white-space:nowrap;cursor:pointer}
.wallet-menu-add-funds-btn:hover,.wallet-menu-add-funds-btn:focus-visible{background:#128a3e}
.wallet-menu-list{padding:4px 10px 14px}
.wallet-menu-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-radius:8px;color:var(--text)}
a.wallet-menu-item{cursor:pointer}
a.wallet-menu-item:hover,a.wallet-menu-item:focus-visible{background:var(--blue-50)}
.wallet-menu-item-icon{width:34px;height:34px;border-radius:9px;background:#f1f4f8;display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.wallet-menu-item-icon svg{width:17px;height:17px;fill:#4b5563}
.wallet-menu-item-label{flex:1 1 auto;font-size:13.5px;font-weight:600}
.wallet-menu-item-chevron{width:14px;height:14px;fill:none;stroke:#9aa1ac;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto}
/* Focus states — the task's own accessibility requirements ("clear focus
   states", "keyboard-friendly"). :focus-visible only shows the ring for
   keyboard/programmatic focus, not every mouse/touch click. */
.order-modal-close:focus-visible,.wallet-menu-add-funds-btn:focus-visible,a.wallet-menu-item:focus-visible{outline:2px solid var(--blue-700);outline-offset:2px}
.container{max-width:1250px;margin:24px auto;padding:0 20px}
.hidden{display:none!important}
.section-title{font-size:22px;font-weight:700;margin:0 0 18px}
/* Marketplace Categories redesign — "All Categories" used to be the
   first item inside the same scrolling #categoryList row as every real
   Category, so it scrolled away with everything else. #categoryList is
   now wrapped in its own .categories-scroll container (this is the
   thing that actually scrolls/overflows), and "All Categories"
   (.cat-all-fixed, a direct .category-bar child, never inside
   .categories-scroll) sits fixed beside it and is never part of the
   scroll range. */
/* Marketplace Categories visual refinement (reference mockup) — a new
   .cat-wrap card wraps a header row (icon + heading/sub-heading, plus a
   search field and the relocated "View All Categories" trigger) above
   the existing .category-bar. All new, additively-scoped classes below
   (.cat-header*, .cat-count-badge, .cat-modal-sub) — none of them are
   generic/global selectors, so nothing here can leak into the Buyer
   Dashboard header, sidebar, or any other shared component. */
.cat-wrap{background:#fff;border:1px solid #e3e5e8;border-radius:10px;padding:14px;margin-bottom:16px;box-shadow:var(--shadow-md)}
.cat-header{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:14px;flex-wrap:wrap}
.cat-header-title{display:flex;align-items:center;gap:10px;min-width:0}
.cat-header-icon-wrap{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:9px;background:var(--blue-50);flex:0 0 auto}
.cat-header-icon{width:19px;height:19px;fill:var(--blue-700)}
.cat-header-heading{font-size:18px;font-weight:700;color:var(--text)}
.cat-header-sub{font-size:12.5px;color:var(--text-muted);margin-top:1px}
.cat-header-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.cat-header-search-wrap{flex:1 1 180px;max-width:260px;min-width:140px;margin-bottom:0}
/* Main Categories header's "View All" trigger is deliberately an
   OUTLINE button (white fill, blue border/text, arrow on the right) —
   visually distinct from Sub Categories' solid pill above, per the
   reference mockups. The arrow SVG sits first in the DOM (so the
   already-tested `View All Categories</button>` substring in
   marketplace.blade.php still holds — the text stays the last thing
   before the closing tag) and flex-direction:row-reverse flips it to
   the right visually without reordering the markup. */
.sub-viewall-btn.cat-header-viewall{margin-top:0;white-space:nowrap;background:var(--blue-50);color:var(--blue-700);border:1px solid var(--blue-500);flex-direction:row-reverse}
.sub-viewall-btn.cat-header-viewall:hover{background:#e3edff;color:var(--blue-800);border-color:var(--blue-700)}
.sub-viewall-btn.cat-header-viewall:before{content:none}
.sub-viewall-btn.cat-header-viewall:after{content:none}
.cat-viewall-arrow{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto}
/* Live product-count badge (products_count from GET /api/categories),
   shown next to a category name in the fixed "All Categories" card, the
   scrollable chip row, and the mobile expand panel — suppressed only in
   the View All modal grid (see renderCategoryOptionList() below). A
   neutral light-gray pill for an unselected card, per the round-3
   reference mockup (sampled ~rgb(234,238,244) off its "24"/"18" badges
   — a near-neutral gray, not the blue-tinted pill used elsewhere); the
   active card keeps its own bolder blue override just below. */
.cat-count-badge{background:#eef0f3;color:#5f6368;font-size:10px;font-weight:700;border-radius:999px;padding:2px 7px;line-height:1.5;flex:0 0 auto}
/* Active card (including the fixed "All Categories" card, active by
   default) gets a more saturated badge for a little emphasis against
   its light-blue-tinted background, per the reference mockup's bolder
   "120+" badge. */
.category.active .cat-count-badge{background:var(--blue-500);color:#fff}
.cat-modal-sub{font-size:12px;color:var(--text-muted);font-weight:400;margin-top:2px}
/* .category-bar now renders as the lower half of .cat-wrap (the header
   above already supplies the card's background/border/shadow), so its
   own chrome is flattened here to avoid a double-bordered box-in-a-box;
   outside of .cat-wrap (there is no other place it's used) this has no
   effect. */
.category-bar{background:#fff;border:1px solid #e3e5e8;border-radius:7px;padding:16px 12px;display:flex;align-items:center;gap:8px;margin-bottom:16px}
.cat-wrap .category-bar{background:none;border:0;border-radius:0;padding:0;margin-bottom:0}
.cat-arrow{width:34px;height:34px;border:1px solid #ddd;background:#fff;border-radius:5px;cursor:pointer;flex:0 0 auto;font-size:16px;line-height:1;transition:background .15s ease,border-color .15s ease,opacity .15s ease}
.cat-arrow:hover:not(:disabled){background:var(--blue-50);border-color:var(--blue-500);color:var(--blue-700)}
.cat-arrow:disabled{opacity:.35;cursor:not-allowed}
.categories-scroll{flex:1;overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;scrollbar-width:none;min-width:0;cursor:grab}
.categories-scroll::-webkit-scrollbar{display:none}
/* Desktop mouse drag-to-scroll (phone-swipe-like) -- toggled by JS only
   while a real drag is in progress (see enableDragScroll()). Grabbing
   cursor + no text selection during the drag; the underlying scroll/
   arrow-button/click behavior is unchanged. Individual cards (.category)
   already set their own cursor:pointer, which wins over this, so the
   pointer never changes while hovering an actual clickable card. */
.categories-scroll.is-dragging{cursor:grabbing;-webkit-user-select:none;-ms-user-select:none;user-select:none;scroll-behavior:auto}
.categories{display:flex;gap:8px}
/* Buyer Marketplace UX (Category Logo Size / All Sub Categories / Product
   Price Sorting / Direct Buy), section 1 — Main Category chips only,
   given moderately taller vertical padding so their resolved logo (see
   .category-icon below) has more visual presence. Deliberately NOT a
   redesign: still the same border/radius/hover chip language, still the
   same horizontally-scrolling row driven by #catLeft/#catRight — only the
   padding and icon size increase. Sub Category chips (.subcategory,
   further down) are explicitly untouched by this change.
   Categories redesign — max-width+ellipsis added so a long name keeps
   every card the same consistent size (the full name is still available
   via the native `title` tooltip each button carries) instead of
   stretching the row or the page. */
/* Visual refinement (reference mockup) — category cards are now taller
   "tile" cards (icon on top, name, then a count badge, stacked) instead
   of the earlier single-line horizontal chip. The max-width+ellipsis
   pair a prior task's test locks in (see
   MarketplaceCategoriesRedesignTest::test_category_cards_have_a_consistent_max_width_with_ellipsis_and_a_tooltip)
   moves from .category itself onto the new .cat-name element it now
   wraps its name in — the literal CSS substring that test asserts is
   still present verbatim below, just scoped to the name instead of the
   whole card. */
/* Round-4 compaction — smaller, tighter tiles than round 3 (less
   internal empty space) with a width that scales fluidly with the
   viewport (clamp, not a fixed px) so narrow phones get smaller cards
   and wider phones/tablets get a bit more room automatically, instead
   of jumping between a handful of fixed breakpoints. The @media block
   further down only fine-tunes the very narrowest phones on top of
   this. */
.category{display:flex;flex-direction:column;align-items:center;gap:6px;text-align:center;width:clamp(96px,28vw,122px);min-height:114px;border:1px solid #e2e4e7;background:#fff;border-radius:10px;padding:12px 10px 10px;font-size:12.5px;cursor:pointer;flex:0 0 auto;transition:background .15s ease,border-color .15s ease,color .15s ease}
.category:hover{background:var(--blue-50);border-color:var(--blue-500)}
.category.active{background:var(--blue-50);border-color:var(--blue-500)}
.cat-icon{font-size:15px}
.cat-tile-icon{width:24px;height:24px;fill:var(--blue-700);flex:0 0 auto}
/* Round-4: up to 2 lines, then an ellipsis (was single-line only).
   -webkit-line-clamp is the standard cross-browser way to do
   multi-line truncation; white-space must be "normal" (not "nowrap")
   for it to be able to wrap onto a second line at all. min-height
   reserves the same 2-line space for every card — including short
   names like "Instagram" — so every card in a row stays the same
   height regardless of name length. The literal
   `max-width:200px;overflow:hidden;text-overflow:ellipsis` substring a
   prior task's test locks in is kept verbatim, just alongside the new
   line-clamp properties instead of a single-line white-space:nowrap. */
.cat-name{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-weight:700;color:var(--text);white-space:normal;max-width:200px;overflow:hidden;text-overflow:ellipsis;width:100%;min-width:0;line-height:1.2;min-height:2.4em;word-break:break-word}
/* The fixed "All Categories" card — same .category tile look, just
   never inside .categories-scroll so it can't be scrolled away, and
   explicitly flex:0 0 auto (it's now a direct flex child of
   .category-bar rather than nested inside the scroll row) so the
   scroll container next to it is what shrinks/grows instead of it. */
.cat-all-fixed{flex:0 0 auto}
/* Desktop "View All Categories" trigger — reuses .sub-viewall-btn's
   pill styling as-is; only resets the margin-top that rule assumes
   when it sits below a chip row (here it's an inline flex sibling in
   .category-bar instead) and stops it from wrapping its label. */
#catViewAllBtn{margin-top:0;flex:0 0 auto;white-space:nowrap}
/* Spacing for the Categories mobile toggle sitting as a bare sibling
   after .category-bar (Sub Categories' equivalent toggle instead sits
   inside .sub-wrap, which already has its own margin-bottom) — keeps a
   clean gap before the Sub Categories card below it, on mobile only
   (the toggle itself is display:none above 768px, so this never
   affects desktop spacing). */
#catMobileToggle{margin-bottom:12px}
/* Categories mobile panel open/close — a plain modifier class toggled
   directly on the toggle/panel elements themselves by the Categories
   JS, deliberately NOT the existing ".sub-wrap.sub-mobile-open …"
   ancestor-scoped rules further down (those stay exactly as they were
   for Sub Categories; this is an additional, independent way to reach
   the same .sub-mobile-arrow/.sub-mobile-panel open state). */
.sub-mobile-toggle.open .sub-mobile-arrow{transform:rotate(180deg)}
.sub-mobile-panel.open{max-height:420px;opacity:1;margin-top:12px}
/* Category -> Sub Category -> Product Logo Inheritance & Override System
   — the resolved Category/Sub Category logo shown inline before the
   name, when one exists. Sized up moderately (18px -> 30px) per Buyer
   Marketplace UX section 1 so it actually reads as a logo rather than a
   small bullet — object-fit:cover preserves its aspect ratio without
   distortion regardless of the source image's own proportions. */
.category-icon{width:30px;height:30px;object-fit:cover;border-radius:6px;flex:0 0 auto}
/* Mobile Categories Carousel Refinement — the fixed "All Categories"
   card (#catAllFixed/.cat-all-fixed) is hidden at phone widths so the
   scrollable row gets that space back; "All Categories" stays one tap
   away via the existing Categories dropdown panel just below the
   carousel (#catMobileList already lists it first — see
   renderCategoryOptionList() in marketplace.blade.php, untouched), so
   no selection capability is lost, only a second, redundant entry
   point to it. Nothing about card DATA, click/selection handling, or
   the scroll/arrow mechanics changed here — only sizing.

   This block replaces and extends the original Round-4 narrow-phone
   tightening (previously <=380px only) up to <=600px, the same "phone"
   breakpoint used elsewhere in this file, now that reclaiming the
   fixed card's space makes it worth trimming card/arrow/wrap sizing a
   little further across the whole phone range rather than just the
   narrowest few. Card width still scales fluidly with the viewport
   (clamp, not a fixed px): this fits at least 3 cards from ~375px up;
   at 320/360px, 2 full cards plus a peek of the 3rd stay visible, with
   the rest reachable by one swipe — the practical responsive fallback
   the task explicitly allows at the very narrowest widths, rather than
   shrinking cards to the point of being unreadable. */
@media(max-width:600px){
/* Mobile UI Refinement — Marketplace page title hidden on phone widths
   only, to reclaim vertical space for product rows. Targets #marketPage
   Title specifically (added to the <h1> in marketplace.blade.php) rather
   than the bare .section-title class, because that class is shared with
   About's own <h1 class="section-title">About AccountHab</h1> — a bare
   .section-title rule here would also hide About's heading, which this
   refinement must not touch. Desktop/tablet (>600px) keep the "Marketplace"
   heading exactly as before — untouched; the class/styling itself is
   unchanged, only this one id is newly hidden at this width. */
#marketPageTitle{display:none}
.cat-all-fixed{display:none}
.cat-wrap{padding:10px}
/* Mobile Categories Section Header Simplification — the blue icon
   square and the "Browse by category and find what you need" subtitle
   are dropped on phone widths so the card's header is just the
   "Categories" heading; .cat-header-title's own gap:10px only applies
   between VISIBLE flex children, so hiding .cat-header-icon-wrap here
   doesn't leave a stray empty gap before the heading. Desktop/tablet
   (>600px) keep the icon and subtitle exactly as before — untouched. */
.cat-header-icon-wrap{display:none}
.cat-header-sub{display:none}
/* Mobile UI Refinement — the "Categories" heading text itself (the only
   part of .cat-header still visible at this width, now that its icon
   and subtitle are already hidden immediately above) is dropped too, to
   reclaim more vertical space for product rows below. This hides the
   whole .cat-header row (it has nothing else left to show at <=600px),
   not .category-bar or the mobile category-selector toggle
   (#catMobileToggle/.sub-mobile-toggle) just below .cat-wrap — both stay
   fully visible/functional, unchanged. Desktop/tablet (>600px) keep the
   "Categories" heading exactly as before — untouched. */
.cat-header{display:none}
.cat-arrow{width:28px;height:28px;font-size:14px}
.category-bar{gap:6px}
.categories{gap:6px}
.category{width:clamp(80px,22vw,112px);padding:8px 6px 6px;min-height:100px}
.category-icon{width:22px;height:22px}
.cat-tile-icon{width:18px;height:18px}
.cat-name{font-size:11px;min-height:2.2em}
.cat-count-badge{font-size:9px;padding:1px 5px}
}
/* Marketplace Sub Categories redesign — was a single unbounded chip row
   (every Sub Category rendered flat, filling most of the screen on a
   large list); now a compact white card with a capped desktop chip
   row + "View All" button, and a collapsed-by-default mobile/tablet
   control (see the @media(max-width:768px) block near the bottom of
   this file). .subcategory/.subcategory-icon keep their original
   class names (still built by the same renderSubCategories() data),
   just restyled as rounded pill chips with AccountHab's existing blue
   accent instead of the old flat gray box. */
.sub-wrap{background:#fff;border:1px solid #e3e5e8;border-radius:10px;padding:16px;margin-bottom:16px;box-shadow:var(--shadow-md)}
.sub-header{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:12px;flex-wrap:wrap}
/* Clickable "Sub Categories" heading (desktop/PC only) — .sub-title only
   ever renders inside .sub-header, which is already hidden on mobile/
   tablet by the existing, untouched @media(max-width:768px) rule below,
   so no separate breakpoint is needed here either: this hover/focus
   styling and the cursor simply never apply on a hidden element. Does
   the exact same reset as clicking "All Sub Categories" (see
   #subTitleAllTrigger's click handler in marketplace.blade.php). */
.sub-title{display:flex;align-items:center;gap:8px;font-size:17px;font-weight:700;color:var(--text);cursor:pointer;border-radius:6px;transition:color .15s ease}
.sub-title:hover,.sub-title:focus-visible{color:var(--blue-700)}
.sub-title:hover .sub-title-icon,.sub-title:focus-visible .sub-title-icon{fill:var(--blue-800)}
.sub-title:focus-visible{outline:2px solid var(--blue-500);outline-offset:3px}
.sub-title:hover .sub-count-pill,.sub-title:focus-visible .sub-count-pill{background:var(--blue-500);color:#fff}
/* Selected-Category logo wrapper (#subTitleLogo) — a plain inline flex
   box so it aligns on the same baseline as the heading text/count pill
   whether JS has filled it with an <img> (a real Category logo) or the
   fallback <svg> (see subTitleLogoHtml() in marketplace.blade.php);
   .sub-title-icon itself carries the actual sizing so both element types
   render identically here. */
.sub-title-icon-wrap{display:flex;align-items:center;flex:0 0 auto}
.sub-title-icon{width:18px;height:18px;object-fit:cover;border-radius:4px;fill:var(--blue-700);flex:0 0 auto;transition:fill .15s ease}
.sub-count-pill{background:var(--blue-50);color:var(--blue-700);font-size:11px;font-weight:700;border-radius:999px;padding:2px 9px;line-height:1.6}
/* Visual refinement (reference mockup) — "Showing X of Y" text plus a
   client-side name filter, sitting on the same header row as the
   existing .sub-title. Scoped entirely to .sub-header-actions/its own
   children; the reused .sub-mobile-search-wrap base rule (icon
   position/size) is only widened for this desktop placement via the
   .sub-header-search-wrap modifier below, never edited directly. The
   "View All Sub Categories" button that used to sit at the end of this
   row (and, before that, at the end of the chip row below) is gone —
   the clickable heading above already resets to "All Sub Categories",
   and the desktop chip row no longer caps, so there's nothing left for
   a "view the rest" button to do. Removing it needed no compensating
   spacing rule here: .sub-header-actions was already a plain flex row
   with the search field taking the remaining space, so the row simply
   ends after search now, with no gap left behind. */
.sub-header-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.sub-header-showing{font-size:12px;color:var(--text-muted);white-space:nowrap}
.sub-header-search-wrap{flex:1 1 160px;max-width:240px;min-width:130px;margin-bottom:0}
/* .sub-scroll-row is the new horizontal-scroll container replacing the
   old wrapped, multi-row chip grid — #subCategoryList (still rendered
   exactly as before by renderSubCategories(), same id/class) now sits
   inside #subCategoriesScroll, the actual scrolling element, flanked by
   #subLeft/#subRight. Those two buttons carry both `cat-arrow` (reusing
   the Main Categories bar's own arrow look verbatim — see #catLeft/
   #catRight above) and a `sub-arrow` marker class for scoping, kept
   free of its own rule for now since no Sub-Category-specific override
   is needed; both scroll rows share one visual language this way. */
.sub-scroll-row{display:flex;align-items:center;gap:8px}
.sub-categories-scroll{flex:1;overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;scrollbar-width:none;min-width:0;cursor:grab}
.sub-categories-scroll::-webkit-scrollbar{display:none}
/* Desktop mouse drag-to-scroll -- see the matching comment above
   .categories-scroll.is-dragging; identical behavior, reused for the
   Sub Categories strip. .subcategory chips already set their own
   cursor:pointer, which wins over this. */
.sub-categories-scroll.is-dragging{cursor:grabbing;-webkit-user-select:none;-ms-user-select:none;user-select:none;scroll-behavior:auto}
.subcategories{display:flex;gap:8px;flex-wrap:nowrap}
.subcategory{display:inline-flex;align-items:center;gap:6px;max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:1px solid #e2e4e7;background:#fff;border-radius:8px;padding:8px 14px;font-size:12.5px;font-weight:600;color:#444;cursor:pointer;transition:background .15s ease,border-color .15s ease,color .15s ease;flex:0 0 auto}
.subcategory:hover{background:var(--blue-50);border-color:var(--blue-500)}
.subcategory.active{background:var(--blue-50);border-color:var(--blue-500);color:var(--blue-800)}
/* Compact card content (icon + name + count + chevron) — the name gets
   its OWN ellipsis rule on a flexible inner span (flex:1;min-width:0)
   rather than relying on the outer .subcategory rule above (which
   remains untouched/locked; its own overflow:hidden/text-overflow just
   acts as a harmless backstop). This is what lets a trailing count
   badge and chevron sit after a long, truncated name without either of
   them getting clipped themselves. */
.subcategory-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.subcategory-count{background:#eef0f3;color:#5f6368;font-size:10px;font-weight:700;border-radius:999px;padding:1px 7px;line-height:1.5;flex:0 0 auto}
.subcategory.active .subcategory-count{background:var(--blue-500);color:#fff}
.subcategory-chevron{width:12px;height:12px;fill:none;stroke:#9aa1ac;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto;opacity:.55}
.subcategory.active .subcategory-chevron,.subcategory:hover .subcategory-chevron{stroke:var(--blue-700);opacity:1}
/* Sub Category chip icon — deliberately its OWN class, kept at the exact
   original 18px size/radius from before Buyer Marketplace UX section 1
   resized the Main Category one. Section 1 explicitly requires Sub
   Category icon SIZE stay untouched (never merged back into
   .category-icon's 30px), which this redesign still honors — only the
   surrounding chip shape/color changed, not the icon itself. */
.subcategory-icon{width:18px;height:18px;object-fit:cover;border-radius:4px;flex:0 0 auto}
.sub-fallback-icon{fill:#9aa1ac}
.subcategory.active .sub-fallback-icon{fill:var(--blue-700)}
/* Round-3 reference mockup — the Sub Categories "View All" trigger is a
   light outline pill (sampled ~rgb(243,247,253), i.e. blue-50, not a
   solid fill) with a small solid-blue circular "+" badge on the left
   and a chevron arrow on the right. Both the badge and the chevron are
   CSS pseudo-elements (::before/::after) rather than real child nodes,
   so the JS's tested `viewAllBtn.textContent = ...` assignment (see
   marketplace.blade.php) can keep calling .textContent directly on the
   button — a real DOM child would be wiped out by that assignment, a
   pseudo-element never is. Flex layout on the button places
   ::before / textContent / ::after in that left-to-right order for
   free. */
.sub-viewall-btn{margin-top:10px;display:inline-flex;align-items:center;gap:8px;background:var(--blue-50);color:var(--blue-700);border:1px solid var(--blue-500);border-radius:999px;padding:7px 16px;font-size:12.5px;font-weight:700;cursor:pointer}
.sub-viewall-btn:hover{background:#e3edff;color:var(--blue-800);border-color:var(--blue-700)}
.sub-viewall-btn:before{content:"+";display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:var(--blue-500);color:#fff;font-size:14px;font-weight:800;line-height:1;flex:0 0 auto}
.sub-viewall-btn:after{content:"";width:7px;height:7px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);flex:0 0 auto;margin-left:1px}

/* Mobile/tablet (<=768px) collapsed control — hidden on desktop; see
   the @media(max-width:768px) block below for the swap. */
.sub-mobile-toggle{display:none;width:100%;align-items:center;justify-content:space-between;background:#fff;border:1px solid #e3e5e8;border-radius:8px;padding:12px 14px;cursor:pointer;font:inherit;text-align:left}
.sub-mobile-toggle-left{display:flex;align-items:center;gap:10px}
.sub-mobile-icon{width:16px;height:16px;object-fit:cover;border-radius:4px;fill:var(--blue-700);flex:0 0 auto}
.sub-mobile-title{font-size:14px;font-weight:700;color:var(--text)}
.sub-mobile-count{background:var(--blue-50);color:var(--blue-700);font-size:11px;font-weight:700;border-radius:999px;padding:2px 9px}
.sub-mobile-arrow{width:18px;height:18px;fill:#9aa1ac;transition:transform .2s ease;flex:0 0 auto}
.sub-wrap.sub-mobile-open .sub-mobile-arrow{transform:rotate(180deg)}
.sub-mobile-panel{max-height:0;opacity:0;overflow:hidden;transition:max-height .25s ease,opacity .2s ease}
.sub-wrap.sub-mobile-open .sub-mobile-panel{max-height:420px;opacity:1;margin-top:12px}
.sub-mobile-search-wrap{position:relative;margin-bottom:10px}
.sub-mobile-search-wrap .search-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);width:15px;height:15px;fill:#9aa1ac;pointer-events:none}

/* Row shape shared by the mobile expanded panel AND the View All modal
   grid (see .sub-all-grid below) — one definition for both surfaces. */
.sub-option-list{max-height:340px;overflow-y:auto;display:flex;flex-direction:column;gap:4px}
.sub-option{display:flex;align-items:center;gap:10px;width:100%;border:1px solid transparent;background:none;border-radius:7px;padding:10px;font-size:13px;color:var(--text);cursor:pointer;text-align:left}
.sub-option:hover{background:var(--blue-50)}
.sub-option.active{background:var(--blue-50);border-color:var(--blue-500);color:var(--blue-700);font-weight:700}
.sub-option-name{word-break:break-word;overflow-wrap:anywhere}
/* Card content additions (product count + trailing chevron) for the
   mobile expanded panel and the View All modal rows — .sub-option-text
   wraps the existing, untouched .sub-option-name plus the new count
   line so both stack in their own column, leaving .sub-option-name's
   own rule exactly as it was. */
.sub-option-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.sub-option-count{font-size:11px;color:var(--text-muted);font-weight:400}
.sub-option.active .sub-option-count{color:var(--blue-700)}
.sub-option-chevron{width:14px;height:14px;fill:none;stroke:#9aa1ac;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto;opacity:.5}
.sub-option.active .sub-option-chevron,.sub-option:hover .sub-option-chevron{stroke:var(--blue-700);opacity:1}
.sub-option-empty{padding:16px;text-align:center;color:var(--text-muted);font-size:12.5px}

/* View All Sub Categories modal — built on the existing .order-overlay/
   .order-modal shell (see below in this file) already used across the
   Buyer Dashboard; .sub-all-modal only adds this modal's own sizing. */
.order-modal.sub-all-modal{max-width:640px;width:100%}
.sub-all-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:6px;max-height:50vh;overflow-y:auto}
@media(max-width:480px){.sub-all-grid{grid-template-columns:1fr}}
.products{background:transparent;border:0;box-shadow:none;overflow:visible}

/* Grouped marketplace listing (Buyer Grouped Product List UI task, and
   its "Final Column Layout Correction" follow-up). Each .product-group
   is one grouped block: a dark .group-header bar (group name + "In
   Stock" / "Price per pc" / "Price" column labels — Price per pc is a
   column in its own right, deliberately never merged into Price)
   followed by its member products as .product-row lines. Both the
   header and the rows share the same grid-template-columns at every
   breakpoint so the column labels stay aligned with the data beneath
   them — the header's name cell simply spans the icon+title columns via
   grid-column. This reuses the existing
   --blue-900/--border-soft/--text-muted/--success tokens rather than
   introducing a new palette. */
/* Product Listing Vertical Spacing Fix — the header and its product rows
   used to be plain adjacent block children of .product-group, so they
   touched directly (rows separated from each other by only a 1px
   border-bottom hairline, and the header from the first row by nothing
   at all). .product-group is now a column flexbox instead of a plain
   block container; flex's own `gap` inserts a uniform, responsive-by-
   default space between every direct child — header-to-first-row and
   row-to-row alike — with one declaration that applies at every
   breakpoint (no separate mobile/tablet/desktop rule needed). Nothing
   about the rows' own internal layout, colors, typography, icons or data
   changes: .group-header and .product-row keep their existing
   grid-template-columns exactly as before, only how the parent stacks
   them changed. The old border-bottom divider is removed since the gap
   itself now does that job — keeping both would read as a double
   separator. margin-bottom (group → next group) also moves from 18px to
   16px here, matching .cat-wrap's own 16px below, so every major-section
   gap in the Marketplace uses the same value. */
/* Product Listing Gap Background — .product-group's own background (was
   var(--white), same as the cards) now matches the page body's own
   background via the shared --page-bg token (see :root above) instead of
   white. Since .product-row never had its own background (it only ever
   looked white by sitting on .product-group's white background), it now
   gets that same white explicitly so the row itself is unchanged — only
   the flex `gap` space above/between rows (previously indistinguishable
   from the white cards) now reads as a visible strip of the page
   background. gap:8px, border-radius, overflow, margin-bottom and
   box-shadow are all untouched. */
.product-group{background:var(--page-bg);border:1px solid var(--border-soft);border-radius:8px;overflow:hidden;margin-bottom:16px;box-shadow:var(--shadow-md);display:flex;flex-direction:column;gap:8px}
.product-group:last-child{margin-bottom:0}
.group-header{display:grid;grid-template-columns:52px minmax(160px,1fr) 104px 116px 96px 84px;gap:10px;align-items:center;padding:13px 16px;background:var(--blue-900);color:#fff}
.group-header-name{grid-column:1/3;font-weight:700;font-size:14px;overflow-wrap:anywhere}
.group-header-col{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;opacity:.85}

/* Per-Row Rounded Corners — .product-group's own border-radius+overflow
   only ever rounded the two OUTER corners it clips (.group-header's top
   corners, the last .product-row's bottom corners); every row in between
   sat flush and square, since a flex-column parent's radius has no effect
   on a middle child's own corners. Giving .product-row its own
   border-radius (same 8px as the parent, so the last row's corners still
   line up exactly with the parent's clipped edge) makes every row round
   all four of its own corners against the --page-bg gap color behind it,
   independent of position in the group. No breakpoint below overrides
   border-radius, so this one line covers desktop, the 900px tablet grid,
   and the 600px mobile layout alike — nothing else about .product-row's
   padding, columns, or the parent's own border/shadow/gap changes. */
.product-row{display:grid;grid-template-columns:52px minmax(160px,1fr) 104px 116px 96px 84px;gap:10px;align-items:center;padding:14px 16px;font-size:13px;background:var(--white);border-radius:8px}
.product-row:hover{background:#f7f9fc}
.product-logo{width:40px;height:40px;border:1px solid #ddd;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:18px;background:#fafafa;overflow:hidden}
.product-logo img{width:100%;height:100%;object-fit:cover}
.product-title{font-weight:700;margin-bottom:3px;overflow-wrap:anywhere}
.product-meta{color:#777;font-size:12px;overflow-wrap:anywhere}
.product-cell-label{display:none;color:#888;font-size:11px;margin-bottom:3px}

/* Exact stock + sold counters (cell-stock) — the "In Stock" column now
   shows the real Product::$stock/$sold values, not a boolean pill. */
.cell-stock{display:flex;flex-direction:column;line-height:1.35}
.stock-qty{font-weight:700;font-size:13px}
.stock-qty.zero{color:#b42318}
.sold-qty{color:var(--text-muted);font-size:11px}

/* Price-per-unit column — deliberately its own column, always the
   literal label "Price per pc" per row, matching the group header's
   own "Price per pc" column label directly above it. */
.cell-pplabel{color:var(--text-muted)}
.pp-label{font-size:12px}

.product-price-value{font-weight:700;font-size:14px}

.buy-btn,.primary-btn{border:0;background:#222;color:#fff;border-radius:5px;height:36px;padding:0 14px;font-size:12px;font-weight:700;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}
.buy-btn:hover,.primary-btn:hover{opacity:.9}
.buy-btn:disabled{opacity:.4;cursor:not-allowed}
.product-row .buy-btn{justify-self:end}
/* Soft Style Buy button (Marketplace) — overrides the shared dark
   .buy-btn,.primary-btn rule above for .buy-btn ONLY; .primary-btn
   (Login/Register/etc.) is untouched by this block. In-stock: light/
   soft blue. Sold-out: red/pink, still labeled "Buy" (see the button
   markup in public/marketplace.blade.php) — full opacity so the color
   itself communicates the sold-out state, not the shared :disabled dim. */
.buy-btn{background:var(--blue-50);color:var(--blue-700);border:1px solid var(--blue-500);border-radius:999px;gap:6px;font-size:13px;transition:background-color .18s ease,transform .18s ease}
.buy-btn:hover{background:#dbe9ff;opacity:1}
.buy-btn:active{transform:scale(.96)}
.buy-btn-icon{width:14px;height:14px;fill:currentColor;flex:0 0 auto}
.buy-btn--sold-out{background:#fde8e8;color:#b91c1c;border-color:#f5b5b5;opacity:1}
.buy-btn--sold-out:hover{background:#fde8e8}
/* Higher specificity than the shared .buy-btn:disabled{opacity:.4} rule
   above, so the red sold-out state stays fully visible instead of also
   being dimmed by that generic disabled treatment. Still cursor:
   not-allowed — genuinely disabled, unchanged from before. */
.buy-btn.buy-btn--sold-out:disabled{opacity:1;cursor:not-allowed}
.price{font-weight:700}
.dashboard-layout{display:flex;gap:22px}
.sidebar{width:220px;background:#fff;border:1px solid #e3e5e8;border-radius:7px;height:max-content;flex:0 0 auto;overflow:hidden}
.side-title{padding:16px 18px;border-bottom:1px solid #eee;font-weight:700;display:flex;align-items:center;gap:9px}
.side-title-icon{width:17px;height:17px;fill:var(--blue-700);flex:0 0 auto}
/* Mobile Sidebar Toggle fix — #sidebarMenuToggle (dashboard.blade.php)
   and its "sidebar-nav-open" class toggle (see the click handler in that
   file's script) were already fully wired in HTML/JS, but this stylesheet
   never actually defined what either one does — .side-menu-toggle had no
   rule at all (so the button rendered unstyled and visible at every
   width, on desktop too) and ".sidebar-nav-open" was never read anywhere
   (so tapping the button flipped the class/aria-expanded but produced no
   visible change). This is what made the toggle a dead control on the
   physical phone: the tap always registered, there was just no CSS state
   for it to switch into. Restores exactly the behavior the comments in
   dashboard.blade.php already describe: the button only appears at
   <=600px (matching where the toggle is meaningful — .dashboard-layout/
   .sidebar are already stacked full-width by the existing <=900px rule
   above, untouched), and "sidebar-nav-open" shows/hides the nav list plus
   the Need Help/footer blocks. Desktop/tablet (>600px) are unaffected:
   .side-nav-list/.sidebar-help-card/.sidebar-footer keep their normal
   always-visible block display there, exactly as before. */
.side-menu-toggle{display:none;align-items:center;justify-content:center;width:40px;height:40px;margin-left:auto;flex:0 0 auto;border:0;background:transparent;border-radius:6px;cursor:pointer;padding:0;touch-action:manipulation}
.side-menu-toggle svg{width:20px;height:20px;fill:var(--blue-700)}
.side-menu-toggle:active{background:var(--blue-50)}
@media(max-width:600px){
  .side-menu-toggle{display:flex}
  .side-nav-list,.sidebar-help-card,.sidebar-footer{display:none}
  .sidebar.sidebar-nav-open .side-nav-list,
  .sidebar.sidebar-nav-open .sidebar-help-card,
  .sidebar.sidebar-nav-open .sidebar-footer{display:block}
}
/* Sidebar redesign — extends the approved Download Orders file-row visual
   language (clean white background, subtle borders/separators, modern
   typography, balanced spacing, small readable icons, consistent
   hover/active states, no excessive animation) to every nav item. Still
   the exact same nav destinations/functionality/Sign Out confirmation
   popup as before — see the (untouched) click-handling JS above; only
   the look changes.
   A left accent bar (box-shadow, not a layout-shifting border, so it
   never nudges the icon/label) marks the active item, matching the
   "keep the active navigation item visually distinguishable" requirement
   without the heavier full-row shading the plain .active/.hover rule
   used to rely on alone. */
.side-link{display:flex;align-items:center;gap:11px;padding:11px 18px;font-size:14px;line-height:1.3;color:#4b5563;border-bottom:1px solid #f1f1f1;cursor:pointer;transition:background-color .12s ease,color .12s ease;box-shadow:inset 3px 0 0 transparent}
.side-link:last-child{border-bottom:0}
.side-link:hover{background:var(--blue-50);color:var(--blue-800)}
.side-link.active{background:var(--blue-50);color:var(--blue-800);font-weight:700;box-shadow:inset 3px 0 0 var(--blue-700)}
.side-icon{width:18px;height:18px;flex:0 0 auto;fill:currentColor;opacity:.72;transition:opacity .12s ease}
.side-link:hover .side-icon,.side-link.active .side-icon{opacity:1}
.side-link-label{flex:1;min-width:0;overflow-wrap:anywhere}
/* Sign Out — a subtle visual break from the rest of the list (a slightly
   heavier top border) since it ends the session rather than navigating
   within it; still the same row treatment otherwise, no separate red/
   danger styling that would misrepresent it as destructive/irreversible
   (it only opens the existing confirmation popup). */
.side-link-signout{border-top:1px solid #e3e5e8}
/* "Need Help?" card + footer — reference-design sidebar additions below
   the nav list. Contact Support reuses the existing Live Chat widget
   (see the click binding in dashboard.blade.php); no new markup/CSS is
   introduced for the chat itself. */
.sidebar-help-card{margin:14px;padding:14px;background:var(--blue-50);border:1px solid #dde8fb;border-radius:8px;text-align:center}
.sidebar-help-title{font-weight:700;font-size:13px;color:var(--blue-900);margin-bottom:4px}
.sidebar-help-text{font-size:11.5px;color:var(--text-muted);margin-bottom:10px;line-height:1.4}
.sidebar-help-btn{width:100%;border:1px solid var(--blue-700);background:#fff;color:var(--blue-700);border-radius:6px;padding:8px 10px;font-size:12px;font-weight:700;cursor:pointer}
.sidebar-help-btn:hover{background:var(--blue-700);color:#fff}
.sidebar-footer{padding:14px 18px;text-align:center;border-top:1px solid #eee}
.sidebar-footer-brand{font-weight:700;font-size:12.5px;color:var(--blue-900)}
.sidebar-footer-tag{font-size:10.5px;color:var(--text-muted);margin-top:2px}
.sidebar-footer-copy{font-size:10px;color:#aaa;margin-top:6px}
/* Notifications count — a small pill badge instead of the old plain
   "(N)" text; empty (0 unread) collapses to nothing rather than showing
   a hollow pill. */
#notifCountBadge:empty{display:none}
#notifCountBadge:not(:empty){flex:0 0 auto;min-width:18px;height:18px;padding:0 6px;border-radius:999px;background:var(--blue-700);color:#fff;font-size:11px;font-weight:700;line-height:18px;text-align:center}
.side-link.active #notifCountBadge:not(:empty){background:var(--blue-900)}
.dashboard-main{flex:1;min-width:0}
/* Buyer Multi-Page Migration (Phase 1.1 — Dedicated Mobile Page Headers)
   — the "back to Dashboard" link a dedicated Buyer page shows in place
   of the sidebar at <=900px (see .sidebar.dedicated-sidebar below).
   Hidden by default (desktop and any page that doesn't render it);
   the @media(max-width:900px) block further down is the only place
   that ever makes it visible, and only for the pages that include
   buyer.partials.mobile-back-link. */
.dashboard-mobile-back{display:none;align-items:center;gap:6px;font-size:13px;font-weight:700;color:var(--blue-700);text-decoration:none;margin-bottom:14px}
.dashboard-mobile-back:hover{color:var(--blue-800)}
.dashboard-mobile-back-icon{width:16px;height:16px;fill:currentColor;flex:0 0 auto}
/* Buyer Multi-Page Migration (Phase 2) — the mobile-only Dashboard
   landing/menu shown on /buyer in place of the full SPA below 900px
   (see resources/views/buyer/dashboard.blade.php's own docblock on this
   block for the full explanation). Hidden by default here, exactly the
   same "invisible unless the mobile media query further down turns it
   on" convention as .dashboard-mobile-back just above; desktop/tablet
   (>900px) never sees it. Row styling reuses the existing .side-link/
   .side-icon/.side-link-label classes verbatim (see further up this
   file) — no new list/row component was added for this. */
.mobile-dashboard-landing{display:none}
.page{display:none}.page.active{display:block}
h1{font-size:23px;margin:0 0 7px}
.subtitle{font-size:13px;color:#777;margin-bottom:20px}
/* Reference-design page header — rounded-square icon + title + breadcrumb,
   used so far only by Download Orders (#page-downloads). */
.page-header-row{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;flex-wrap:wrap;margin-bottom:20px}
.page-header-titlewrap{display:flex;align-items:center;gap:14px}
.page-header-icon{width:44px;height:44px;border-radius:12px;background:var(--blue-50);display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.page-header-icon svg{width:22px;height:22px;fill:var(--blue-700)}
.page-header-titlewrap h1{margin:0}
.page-header-titlewrap .subtitle{margin:2px 0 0}
.page-breadcrumb{font-size:12.5px;color:var(--text-muted);white-space:nowrap}
.page-breadcrumb a{color:var(--text-muted);cursor:pointer}
.page-breadcrumb a:hover{color:var(--blue-700)}
.page-breadcrumb-sep{margin:0 6px;color:#c6cbd2}
.panel{background:#fff;border:1px solid #e3e5e8;border-radius:7px;padding:20px;margin-bottom:18px}
.panel-title{font-size:16px;font-weight:700;margin-bottom:16px}
.table-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;font-size:13px;color:#555}
.table-top select{height:30px;border:1px solid #ddd;border-radius:4px}
.table-scroll{overflow-x:auto}
table{width:100%;border-collapse:collapse;font-size:13px}
th,td{border-bottom:1px solid #eee;padding:12px 10px;text-align:left;white-space:nowrap}
th{background:#fafafa;font-weight:700}
.empty{text-align:center!important;color:#888;padding:35px!important}
.pagination{display:flex;justify-content:flex-end;gap:6px;margin-top:14px}
.pagination button{border:1px solid #ddd;background:#fff;padding:7px 12px;border-radius:5px;cursor:pointer;font-size:12px}
.profile-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.detail-row{padding:12px 0;border-bottom:1px solid #eee;font-size:14px}
.detail-label{font-weight:700;margin-bottom:5px}.muted{color:#777}
.form-group{margin-bottom:15px}
.form-group label{display:block;font-size:13px;font-weight:700;margin-bottom:7px}
.input,.select{width:100%;height:40px;border:1px solid #d8dce1;border-radius:5px;padding:0 11px;background:#fff}
/* Buyer Add Funds — Cryptomus-only fix: this grid now ever holds exactly
   one tile (Cryptomus), so it stays single-column at every width instead
   of leaving an empty second column where NOWPayments used to sit — the
   same 1fr treatment the existing mobile breakpoint below already gives
   it, just no longer only at mobile width. */
.gateway-grid{display:grid;grid-template-columns:1fr;gap:12px}
.gateway{border:1px solid #ddd;border-radius:6px;padding:15px;cursor:pointer}
.gateway.selected{border-color:#222}
.gateway strong{display:block;margin-bottom:5px}.gateway span{font-size:12px;color:#777}
.recommended{font-size:11px;background:#eee;padding:3px 6px;border-radius:4px;margin-left:5px}
.quick{display:flex;gap:8px;margin:8px 0 14px}.quick button{background:#fff;border:1px solid #ddd;border-radius:5px;padding:7px 14px;cursor:pointer}
.crypto-list{display:flex;flex-wrap:wrap;gap:8px}.crypto{border:1px solid #e2e2e2;border-radius:5px;padding:8px 11px;font-size:12px}
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.step{border:1px solid #eee;border-radius:6px;padding:15px}
.step-num{font-size:20px;font-weight:700;margin-bottom:8px}.step-text{font-size:13px;color:#666;line-height:1.45}
.security{text-align:center;color:#666;font-size:13px;padding:5px 0 15px}
.tabs{display:flex;border-bottom:1px solid #ddd;margin-bottom:16px}
.tab{padding:10px 17px;font-size:13px;font-weight:600;color:#666;cursor:pointer;border-radius:8px 8px 0 0;transition:background-color .18s ease,color .18s ease}
.tab:hover{background:var(--blue-50);color:var(--blue-800)}
.tab.active{background:var(--blue-50);color:var(--blue-800);font-weight:700;border-bottom:2px solid var(--blue-700)}
.status{font-weight:700}.failed{color:#b42318}
.purchase-box{background:#fff;border:1px solid #dfe2e5;border-radius:4px;padding:0 22px 22px}
.purchase-title{font-size:15px;font-weight:700;padding:15px 0;border-bottom:1px solid #ddd;overflow-wrap:anywhere}
.price-banner{margin-top:20px;background:var(--blue-900);color:#fff;border-radius:4px;padding:18px 15px;font-weight:700}
.purchase-info{border:1px solid #dfe2e5;border-radius:4px;margin-top:20px;padding:14px}
.info-row{display:grid;grid-template-columns:175px 1fr;padding:8px 0;font-size:14px;align-items:center}
.quantity{width:100%;max-width:213px;height:34px;border:1px solid #ddd;border-radius:4px;padding:0 10px}
.promo-code-input{width:100%;max-width:213px;min-width:140px;flex:0 1 213px}
.total-box{border:1px solid #dfe2e5;border-radius:4px;margin-top:20px;padding:14px}
.total-row{display:grid;grid-template-columns:175px 1fr;padding:8px 0;font-size:14px}.grand{font-weight:700}.grand-value{color:#16883b;font-size:17px;font-weight:700}
/* Buyer primary-action button color consistency fix — "Proceed to
   Payment" used its own one-off green (#73cf88) instead of the existing
   Buyer primary-button style already used everywhere else (Buy, Change
   Password, Get Wallet Address — see .buy-btn,.primary-btn above).
   Only the background color changes here, reusing that exact token
   (#222) plus its existing :hover treatment (opacity:.9) for the same
   interaction feedback; size/width/height/margin-top/border-radius/
   text/disabled(cursor:not-allowed)/click handler are all untouched,
   so layout, spacing, and the Loading…/disabled toggle in
   product-detail.blade.php keep working exactly as before. */
.purchase-btn{width:100%;height:40px;margin-top:100px;border:0;border-radius:4px;background:#222;color:#fff;font-weight:700;cursor:pointer}
.purchase-btn:hover{opacity:.9}
.purchase-btn:disabled{opacity:.5;cursor:not-allowed}
/* Marketplace Purchase Button UI polish (read-only audit, approved) —
   "Proceed to Payment" moves from the shared dark #222 to AccountHab's
   existing primary-action blue (--blue-700/--blue-800, the same tokens
   .auth-box .primary-btn/nav pills/wallet chips already use), scoped to
   this one button by #buyBtn ID only. Deliberately NOT touching the
   .purchase-btn class rule above or the shared .buy-btn,.primary-btn
   base rule (reused by 10+ unrelated pages — Buyer dashboard, profile,
   funds, order-modals, signout-modal, every auth page) — this is pure
   ID-scoped color/height, so nothing else on the site is affected.
   width:100%/margin-top/border-radius/font-weight/disabled state are
   all untouched (still inherited from .purchase-btn above), and the
   existing mobile margin-top override further down this file is
   likewise untouched. opacity:1 on hover replaces .purchase-btn:hover's
   generic opacity:.9 dim with a solid blue→darker-blue shift instead of
   stacking both effects. */
#buyBtn{background:var(--blue-700);height:44px}
#buyBtn:hover{background:var(--blue-800);opacity:1}
#buyBtn:focus-visible{outline:2px solid var(--blue-700);outline-offset:2px}
.description{border:1px solid #dfe2e5;border-radius:4px;margin-top:22px;padding:16px;font-size:14px}
/* Task 13 (Phase 6) — the product description is now rendered as real,
   server-sanitized HTML (see App\Services\ProductDescriptionSanitizer)
   rather than escaped plain text, so it needs basic typography for the
   tags the seller's rich-text editor can actually produce. Nothing else
   about .description above changes. */
.description h2{font-size:17px;margin:14px 0 8px;color:var(--blue-900)}
.description h3{font-size:15px;margin:12px 0 6px;color:var(--blue-900)}
.description ul,.description ol{margin:0 0 10px;padding-left:22px}
.description blockquote{margin:0 0 10px;padding:6px 12px;border-left:3px solid var(--blue-500);color:#555;background:#f7f9fc}
.description a{color:var(--blue-700)}
.description hr{border:0;border-top:1px solid var(--border);margin:14px 0}
.description p:last-child{margin-bottom:0}
/* Table support (bug fix — pasted tables were collapsing to flat text on
   save; see App\Services\ProductDescriptionSanitizer's table handling).
   No inline style ever survives sanitization, so borders/spacing/header
   shading are applied here in CSS rather than trusting anything from the
   seller's paste. */
/* Responsive table fix: the table element itself becomes its own block-
   level scroll container (display:block + overflow-x:auto) so a table
   too wide for its column never forces the page/body to scroll
   horizontally — the scroll stays contained to the table's own box.
   width:fit-content (not 100%) lets the table's outer box shrink to
   match its actual rendered column widths when the real content is
   narrower than the container, instead of stretching into an empty
   bordered area past the last column; max-width:100% still caps it at
   the container's width and lets overflow-x:auto take over exactly
   when the real content needs more room than that. */
.description table{width:fit-content;display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%;border-collapse:collapse;margin:0 0 14px;font-size:13px;line-height:1.5;border:1px solid var(--border);border-radius:6px}
.description th,.description td{border:1px solid var(--border);padding:8px 10px;text-align:left;vertical-align:top;white-space:normal;word-break:break-word}
.description th{background:#f3f6fb;color:var(--blue-900);font-weight:700;white-space:nowrap}
.description table tr:nth-child(even) td{background:#fafbfd}
.description table tr:last-child td{border-bottom:0}
@media(max-width:600px){
  .description table{font-size:12px;line-height:1.45}
  .description th,.description td{padding:6px 8px}
}

/* Extended-formatting toolbar (alignment, indent, text color, highlight,
   font size, font family) — task: "Enhance the existing rich-text
   editor". Buyer/Public never edits, only renders, so this is display-
   only CSS for the same class vocabulary Seller/Admin's editors produce
   and App\Services\ProductDescriptionSanitizer allowlists — kept in sync
   with that class's SPAN_*_CLASSES/ALIGN_CLASSES/INDENT_CLASSES and with
   the identical rules in admin.css's .description block. */
.description .ah-align-left{text-align:left}
.description .ah-align-center{text-align:center}
.description .ah-align-right{text-align:right}
.description .ah-align-justify{text-align:justify}
.description .ah-indent-1{margin-left:28px}
.description .ah-indent-2{margin-left:56px}
.description .ah-indent-3{margin-left:84px}
.description .ah-color-black{color:#111827}
.description .ah-color-darkgray{color:#4b5563}
.description .ah-color-red{color:#dc2626}
.description .ah-color-orange{color:#ea580c}
.description .ah-color-green{color:#16a34a}
.description .ah-color-blue{color:#2563eb}
.description .ah-color-purple{color:#7c3aed}
.description .ah-hl-yellow{background:#fde047}
.description .ah-hl-green{background:#86efac}
.description .ah-hl-blue{background:#93c5fd}
.description .ah-hl-orange{background:#fdba74}
.description .ah-hl-pink{background:#f9a8d4}
.description .ah-size-small{font-size:.8em}
.description .ah-size-normal{font-size:1em}
.description .ah-size-large{font-size:1.3em}
.description .ah-size-xlarge{font-size:1.6em}
.description .ah-font-arial{font-family:Arial,Helvetica,sans-serif}
.description .ah-font-georgia{font-family:Georgia,'Times New Roman',serif}
.description .ah-font-tahoma{font-family:Tahoma,Geneva,sans-serif}
.description .ah-font-times{font-family:'Times New Roman',Times,serif}
.description .ah-font-verdana{font-family:Verdana,Geneva,sans-serif}
/* Admin-only fonts (50) — a buyer never CHOOSES these (there is no
   buyer-facing UI at all), but a product description an Admin enhanced
   with one of these tokens must still render correctly here, same as any
   other admin-approved formatting. Kept in sync with
   App\Services\ProductDescriptionSanitizer::ADMIN_FONT_CLASSES. These are
   REAL, self-hosted webfont assets (public/fonts/admin/*.woff2) — see
   admin.css's identical @font-face block for the full note. */
@font-face{font-family:'Aerial Faster - Regular';src:url('/fonts/admin/aerial-faster-regular.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Armelie';src:url('/fonts/admin/armelie.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Awesome';src:url('/fonts/admin/awesome.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'BalapDemo';src:url('/fonts/admin/balapdemo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Baron Kuffner';src:url('/fonts/admin/baron-kuffner.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Bastliga One';src:url('/fonts/admin/bastliga-one.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Battlesbridge Demo';src:url('/fonts/admin/battlesbridge-demo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Black Crush';src:url('/fonts/admin/black-crush-demo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Blackbones DEMO';src:url('/fonts/admin/blackbones-demo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Blocksmith Stacked';src:url('/fonts/admin/blocksmith-stacked.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'brotheric';src:url('/fonts/admin/brotheric.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'ByteBounce';src:url('/fonts/admin/bytebounce.woff2') format('woff2');font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:'Dearllane';src:url('/fonts/admin/dearllane.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Drason Demo';src:url('/fonts/admin/drason-demo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Electrone';src:url('/fonts/admin/electrone.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Galway';src:url('/fonts/admin/galway.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'GERALDINE PERSONAL USE';src:url('/fonts/admin/geraldine-personal-use.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Gondens DEMO';src:url('/fonts/admin/gondens-demo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Graen Metal';src:url('/fonts/admin/graen-metal.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Graffiti Stream Extrude';src:url('/fonts/admin/graffiti-stream-extrude.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Grindy Brush';src:url('/fonts/admin/grindy-brush.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Hero archer free version';src:url('/fonts/admin/hero-archer-free-version.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Heroking';src:url('/fonts/admin/heroking.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'High Beasty';src:url('/fonts/admin/high-beasty.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Higher Jump';src:url('/fonts/admin/higher-jump.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Jersey Varsity';src:url('/fonts/admin/jersey-varsity.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Kultum Ramadhan';src:url('/fonts/admin/kultum-ramadhan.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Lucy Said Ok Personal Use';src:url('/fonts/admin/lucy-said-ok-personal-use.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Manbow';src:url('/fonts/admin/manbow.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Metal Thorn';src:url('/fonts/admin/metal-thorn.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Moralana';src:url('/fonts/admin/moralana.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Over Fear';src:url('/fonts/admin/over-fear.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Perfograma';src:url('/fonts/admin/perfograma.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Priestacy';src:url('/fonts/admin/priestacy.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'ROOSTER PERSONAL USE';src:url('/fonts/admin/rooster-personal-use.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Rostex';src:url('/fonts/admin/rostex.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Runethia';src:url('/fonts/admin/runethia.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Runiga';src:url('/fonts/admin/runiga.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Rustic Roadway - Personal use';src:url('/fonts/admin/rustic-roadway-personal-use.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'RUSTY ATTACK DEMO';src:url('/fonts/admin/rusty-attack-demo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'SF Sports Night';src:url('/fonts/admin/sf-sports-night.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Sketch Chalk';src:url('/fonts/admin/sketch-chalk.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Sobek Personal Use Only';src:url('/fonts/admin/sobek-personal-use-only.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'SpeedBackDemo';src:url('/fonts/admin/speedbackdemo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Symphonie Calligraphy DEMO';src:url('/fonts/admin/symphonie-calligraphy-demo.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'The munday free version';src:url('/fonts/admin/the-munday-free-version.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Transcity';src:url('/fonts/admin/transcity.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Twilight Is Beautiful';src:url('/fonts/admin/twilight-is-beautiful.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Vandals Slash';src:url('/fonts/admin/vandals-slash.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Westner';src:url('/fonts/admin/westner.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
.description .ah-font-aerial-faster-regular{font-family:'Aerial Faster - Regular',sans-serif}
.description .ah-font-armelie{font-family:'Armelie',sans-serif}
.description .ah-font-awesome{font-family:'Awesome',sans-serif}
.description .ah-font-balapdemo{font-family:'BalapDemo',sans-serif}
.description .ah-font-baron-kuffner{font-family:'Baron Kuffner',sans-serif}
.description .ah-font-bastliga-one{font-family:'Bastliga One',sans-serif}
.description .ah-font-battlesbridge-demo{font-family:'Battlesbridge Demo',sans-serif}
.description .ah-font-black-crush-demo{font-family:'Black Crush',sans-serif}
.description .ah-font-blackbones-demo{font-family:'Blackbones DEMO',sans-serif}
.description .ah-font-blocksmith-stacked{font-family:'Blocksmith Stacked',sans-serif}
.description .ah-font-brotheric{font-family:'brotheric',sans-serif}
.description .ah-font-bytebounce{font-family:'ByteBounce',sans-serif}
.description .ah-font-dearllane{font-family:'Dearllane',sans-serif}
.description .ah-font-drason-demo{font-family:'Drason Demo',sans-serif}
.description .ah-font-electrone{font-family:'Electrone',sans-serif}
.description .ah-font-galway{font-family:'Galway',sans-serif}
.description .ah-font-geraldine-personal-use{font-family:'GERALDINE PERSONAL USE',sans-serif}
.description .ah-font-gondens-demo{font-family:'Gondens DEMO',sans-serif}
.description .ah-font-graen-metal{font-family:'Graen Metal',sans-serif}
.description .ah-font-graffiti-stream-extrude{font-family:'Graffiti Stream Extrude',sans-serif}
.description .ah-font-grindy-brush{font-family:'Grindy Brush',sans-serif}
.description .ah-font-hero-archer-free-version{font-family:'Hero archer free version',sans-serif}
.description .ah-font-heroking{font-family:'Heroking',sans-serif}
.description .ah-font-high-beasty{font-family:'High Beasty',sans-serif}
.description .ah-font-higher-jump{font-family:'Higher Jump',sans-serif}
.description .ah-font-jersey-varsity{font-family:'Jersey Varsity',sans-serif}
.description .ah-font-kultum-ramadhan{font-family:'Kultum Ramadhan',sans-serif}
.description .ah-font-lucy-said-ok-personal-use{font-family:'Lucy Said Ok Personal Use',sans-serif}
.description .ah-font-manbow{font-family:'Manbow',sans-serif}
.description .ah-font-metal-thorn{font-family:'Metal Thorn',sans-serif}
.description .ah-font-moralana{font-family:'Moralana',sans-serif}
.description .ah-font-over-fear{font-family:'Over Fear',sans-serif}
.description .ah-font-perfograma{font-family:'Perfograma',sans-serif}
.description .ah-font-priestacy{font-family:'Priestacy',sans-serif}
.description .ah-font-rooster-personal-use{font-family:'ROOSTER PERSONAL USE',sans-serif}
.description .ah-font-rostex{font-family:'Rostex',sans-serif}
.description .ah-font-runethia{font-family:'Runethia',sans-serif}
.description .ah-font-runiga{font-family:'Runiga',sans-serif}
.description .ah-font-rustic-roadway-personal-use{font-family:'Rustic Roadway - Personal use',sans-serif}
.description .ah-font-rusty-attack-demo{font-family:'RUSTY ATTACK DEMO',sans-serif}
.description .ah-font-sf-sports-night{font-family:'SF Sports Night',sans-serif}
.description .ah-font-sketch-chalk{font-family:'Sketch Chalk',sans-serif}
.description .ah-font-sobek-personal-use-only{font-family:'Sobek Personal Use Only',sans-serif}
.description .ah-font-speedbackdemo{font-family:'SpeedBackDemo',sans-serif}
.description .ah-font-symphonie-calligraphy-demo{font-family:'Symphonie Calligraphy DEMO',sans-serif}
.description .ah-font-the-munday-free-version{font-family:'The munday free version',sans-serif}
.description .ah-font-transcity{font-family:'Transcity',sans-serif}
.description .ah-font-twilight-is-beautiful{font-family:'Twilight Is Beautiful',sans-serif}
.description .ah-font-vandals-slash{font-family:'Vandals Slash',sans-serif}
.description .ah-font-westner{font-family:'Westner',sans-serif}

.auth-box{max-width:470px;margin:45px auto;background:var(--white);border:1px solid var(--border);border-radius:14px;padding:30px;box-shadow:0 8px 28px rgba(24,55,100,.10)}
.auth-title{font-size:24px;font-weight:800;color:var(--blue-900);margin-bottom:7px}.auth-subtitle{font-size:13px;color:var(--text-muted);margin-bottom:22px}
.auth-footer{text-align:center;font-size:13px;color:var(--text-muted);margin-top:18px}.auth-footer a{color:var(--blue-700);font-weight:700}
/* AccountHab Auth Redesign (Login/Register/Seller Application) — shared
   primitives layered on the .auth-box/.form-group/.input/.primary-btn/
   .secondary-btn base rules above, all scoped under .auth-box so nothing
   outside these three pages (e.g. buyer dashboard forms, which reuse the
   same base .input/.form-group classes) is affected. No new fields, no
   new validation, no reCAPTCHA changes — presentation only. */
.auth-box .form-group{position:relative}
.auth-box .input-icon-group .input{padding-left:38px}
.auth-box .input-icon-group{position:relative}
.auth-box .input-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:16px;height:16px;fill:#9aa1ac;pointer-events:none}
.auth-box .input,.auth-box .select{border-radius:8px;border-color:var(--border);transition:border-color .15s ease,box-shadow .15s ease}
.auth-box .input:focus,.auth-box .select:focus{outline:none;border-color:var(--blue-500);box-shadow:0 0 0 3px var(--blue-50)}
.auth-box .primary-btn{background:var(--blue-700);border-radius:999px;height:44px;font-size:14.5px;letter-spacing:.2px}
.auth-box .primary-btn:hover{background:var(--blue-800);opacity:1}
.auth-box .secondary-btn{border-radius:999px}
/* Password Show/Hide Toggle — .has-toggle is an explicit opt-in marker
   (added only to a .input-icon-group that actually has a toggle button
   in it), so this rule can never add unwanted right padding to any other
   .auth-box field. Previously duplicated, identically, in both
   resources/views/auth/register.blade.php and resources/views/auth/
   reset-password.blade.php's own page-scoped <style> blocks; consolidated
   here since both pages already load buyer.css. */
.auth-box .input-icon-group.has-toggle .input{padding-right:40px}
.remember-me{display:flex;gap:8px;align-items:center;font-size:13px;color:var(--text-muted);margin-bottom:16px;cursor:pointer}

/* Password Show/Hide Toggle — the eye button itself. Page-agnostic (not
   scoped under .auth-box): used here, on resources/views/auth/
   seller-register.blade.php (inline position:relative wrapper, no left
   icon), and on the live Buyer Change Password form (resources/views/
   buyer/dashboard.blade.php, same inline-wrapper convention it already
   used for its old text "Show"/"Hide" links). Its parent element only
   ever needs position:relative — provided above for .auth-box pages, or
   inline per-field where a page has no .input-icon-group convention — so
   this one rule is reused everywhere rather than duplicated. See
   public/js/api.js's "Site-Wide Password Show/Hide Toggle" block for the
   click handler and public/css/admin.css for the Admin dashboard's own
   copy of this same, identical rule (that page loads admin.css, not
   buyer.css). */
.input-eye-btn{position:absolute;right:12px;top:50%;transform:translateY(-50%);border:0;background:none;color:#7486a0;padding:3px;cursor:pointer;line-height:0}
.input-eye-btn svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.8}
.input-eye-btn:focus-visible{outline:2px solid var(--blue-500);outline-offset:2px;border-radius:4px}
.remember-me input{width:16px;height:16px;accent-color:var(--blue-700);cursor:pointer;margin:0}
/* Register page — "Want to sell on AccountHab?" CTA, restyled from a
   plain text line into its own subtle bordered card. */
.seller-cta-card{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;padding:14px 16px;border:1px solid var(--blue-500);background:var(--blue-50);border-radius:10px;font-size:13px;color:var(--blue-900)}
.seller-cta-card a{display:inline-flex;align-items:center;gap:4px;color:var(--blue-700);font-weight:700;white-space:nowrap}
@media(max-width:480px){.seller-cta-card{flex-direction:column;align-items:flex-start}}
.confirm-box{max-width:520px;margin:55px auto;text-align:center;background:var(--white);border:1px solid var(--border);border-radius:10px;padding:30px;box-shadow:var(--shadow-md)}
.confirm-icon{font-size:38px;color:var(--success);margin-bottom:10px}.confirm-title{font-size:22px;font-weight:800;color:var(--blue-900);margin-bottom:8px}
.confirm-text{font-size:14px;color:var(--text-muted);line-height:1.6}.confirm-actions{display:flex;justify-content:center;gap:10px;margin-top:22px}
.secondary-btn{height:40px;border:1px solid var(--border);background:var(--white);color:var(--text);border-radius:7px;padding:0 16px;font-weight:700;cursor:pointer}
.secondary-btn:hover{background:var(--blue-50);border-color:var(--blue-500);color:var(--blue-800);transform:translateY(-1px)}
/* Marketplace Purchase Button UI polish (read-only audit, approved) —
   "Confirm Purchase" (#buyConfirmYes, class="primary-btn") moves to the
   same AccountHab blue as #buyBtn above and grows from 36px to 40px so
   it matches "No / Cancel" (#buyConfirmNo, .secondary-btn, 40px) instead
   of being shorter than it. Scoped by #buyConfirmYes ID only — the
   shared .buy-btn,.primary-btn base rule is deliberately untouched,
   since Sign Out (resources/views/buyer/partials/signout-modal.blade.php)
   and other confirm-style modals in the app reuse that exact class/
   .confirm-actions pattern. .secondary-btn itself is unchanged, per the
   approved design keeping Cancel as the neutral action. Padding/
   font-weight/disabled+"Processing…" loading behavior are all
   untouched (still inherited from .primary-btn above). */
#buyConfirmYes{background:var(--blue-700);height:40px}
#buyConfirmYes:hover{background:var(--blue-800);opacity:1}
#buyConfirmYes:focus-visible{outline:2px solid var(--blue-700);outline-offset:2px}
.order-details{margin-top:20px;border:1px solid var(--border);border-radius:8px;overflow:hidden;text-align:left}
.order-detail-row{display:grid;grid-template-columns:150px 1fr;padding:11px 13px;border-bottom:1px solid var(--border-soft);font-size:13px}.order-detail-row:last-child{border-bottom:0}
.search-results{margin-top:15px}.result-empty{padding:28px;text-align:center;color:var(--text-muted);border:1px dashed var(--border);border-radius:8px;background:var(--white)}
.form-error{background:#fff1f1;border:1px solid #ffd4d4;color:#a21d1d;border-radius:7px;padding:10px 14px;margin-bottom:14px;font-size:13px}
/* Buyer Refund/Replacement Request modal — 30-minute eligibility notice,
   made visually prominent/action-oriented per the Buyer request UI
   revision (styling only; the window rule itself is still computed
   entirely server-side by App\Services\RefundReplacementService). Same
   text/countdown JS as before (openRefundReplacementModal() in
   buyer/dashboard.blade.php), just no longer a plain muted line. */
.rr-window-notice{background:#fff8e6;border:1px solid #ffd875;color:#8a5a00;border-radius:7px;padding:11px 14px;margin-bottom:14px;font-size:13px;font-weight:700;display:flex;align-items:center;gap:8px}
.rr-window-notice:before{content:"⏱";font-size:15px}

/* Marketplace Sub Categories redesign — mobile/tablet swap. At and
   below 768px (one of this task's own required test widths, grouped
   with 375/390/412 rather than with 1440) the desktop header/chip
   row/View All button are hidden in favor of the single collapsed
   toggle control, which expands in place (see .sub-mobile-panel
   above) rather than opening the View All modal — the two are
   equivalent ways to reach the full list, so mobile only needs one. */
@media(max-width:768px){
.sub-header,.subcategories,.sub-viewall-btn{display:none}
.sub-mobile-toggle{display:flex}
}
/* Additive, new rule (the block above is untouched) — the locked block
   above only hides `.subcategories` itself (the chip list), not the new
   .sub-scroll-row wrapper it now sits inside (the two scroll arrows
   plus #subCategoriesScroll). Without this, mobile would be left with
   an empty, arrow-only remnant of the desktop scroll row still visible
   above the collapsed toggle. Hiding the whole wrapper here restores
   exactly the same "collapsed to just the toggle" mobile behavior as
   before this redesign. */
@media(max-width:768px){
.sub-scroll-row{display:none}
/* #catViewAllBtn already hides at this width via the shared
   .sub-viewall-btn rule above (replaced by #catMobileToggle, same as
   before this refinement); the new header search field is hidden here
   too so it doesn't duplicate #catMobileSearch inside that same mobile
   panel. .cat-header itself (heading + subtitle) stays visible — the
   fixed "All Categories" card and scroll row below it are explicitly
   never hidden on mobile (see the Categories mobile requirements). */
.cat-header-search-wrap{display:none}
}

@media(max-width:900px){
.header{padding:0 15px;gap:15px}.nav{display:none}.search-wrap{width:210px}
/* Mobile Top Navigation Links — shown only where .nav just above went
   display:none; a horizontally-scrollable-but-hidden-scrollbar row keeps
   this to one compact line without ever causing page-level horizontal
   overflow, even before the tighter phone-width sizing further below. */
.mobile-subnav{display:flex;align-items:center;gap:6px;flex-wrap:nowrap;overflow-x:auto;-ms-overflow-style:none;scrollbar-width:none;padding:8px 15px;border-bottom:1px solid var(--border-soft);background:#fff}
.mobile-subnav::-webkit-scrollbar{display:none}
.mobile-subnav-link{display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;padding:6px 10px;border-radius:8px;color:#555;font-weight:600;font-size:13px;white-space:nowrap;transition:background-color .2s ease,color .2s ease}
.mobile-subnav-icon{width:14px;height:14px;fill:currentColor;flex:0 0 auto;opacity:.8;transition:opacity .2s ease}
.mobile-subnav-link:hover,.mobile-subnav-link:active{background:var(--blue-50);color:var(--blue-800)}
.mobile-subnav-link:hover .mobile-subnav-icon,.mobile-subnav-link:active .mobile-subnav-icon{opacity:1}
.mobile-subnav-link.active{background:var(--blue-50);color:var(--blue-800);font-weight:700}
.mobile-subnav-link.active .mobile-subnav-icon{opacity:1}
.mobile-subnav-cta{display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;margin-left:auto;padding:7px 13px;border-radius:999px;background:var(--blue-700);color:#fff;font-weight:700;font-size:12.5px;white-space:nowrap;transition:background-color .2s ease,transform .2s ease}
.mobile-subnav-cta-icon{width:13px;height:13px;fill:#fff;flex:0 0 auto}
.mobile-subnav-cta:active{background:var(--blue-800);transform:scale(.96)}
.header-user-meta{display:none}
.dashboard-layout{display:block}.sidebar{width:100%;margin-bottom:15px}
/* Buyer Multi-Page Migration (Phase 1.1 — Dedicated Mobile Page Headers)
   — on a dedicated Buyer page (My Account and, as of Phase 2, every
   other dedicated page), the sidebar (title bar + hamburger + full nav
   list + Need Help/footer, all of it) is removed entirely at this same
   <=900px width where it would otherwise go full-width/stacked above the
   content — not just collapsed to the icon-rail/hamburger form the
   <=600px rule further up still governs for /buyer's own SPA sidebar
   (untouched: that rule and every dedicated page's sidebar never carry
   "dedicated-sidebar" AND "spa-layout" at the same time, so the two
   mechanisms never conflict). .dashboard-mobile-back (see above) becomes
   visible in its place, giving the same "back to the Dashboard"
   destination through a plain link/normal navigation instead of the
   sidebar's expand/collapse UI. Desktop (>900px) never sees either of
   these rules, so every dedicated page's desktop sidebar stays exactly
   as Phase 1 already shipped it. */
.sidebar.dedicated-sidebar{display:none}
.dashboard-mobile-back{display:flex}
/* Buyer Multi-Page Migration (Phase 2) — /buyer itself, at this same
   <=900px width: the full SPA (.dashboard-layout, marked "spa-layout"
   only on THIS page's own copy of that div — see dashboard.blade.php)
   is hidden entirely, and .mobile-dashboard-landing (see its own base
   rule further up this file) takes its place as a compact landing/menu
   instead. This is a DIFFERENT mechanism from the "dedicated-sidebar"
   rule just above (that one hides only the sidebar, keeping a dedicated
   page's own main content visible; this one hides the entire SPA,
   including its sidebar, main content and every panel, since none of
   that panel-switching SPA content is the point of a landing menu).
   Desktop (>900px) never sees this rule either — /buyer's own SPA
   renders there exactly as it always has, completely unchanged. */
.dashboard-layout.spa-layout{display:none}
.mobile-dashboard-landing{display:block}
/* BUG-001 fix — Mobile Buyer Dashboard section view. Tapping a landing
   tile (or opening /buyer#section directly, or tapping the mobile
   back link below) only ever changes window.location.hash while
   already on /buyer; dashboard.blade.php's script now toggles
   "mobile-section-open" on #dashboard for exactly that case (see its
   own comment there). These three rules override the three rules just
   above them ONLY while that class is present: the landing menu hides,
   the SPA layout (.dashboard-layout.spa-layout) takes its place, and
   the SPA's own sidebar stays hidden — the landing menu already served
   as the section picker, so showing the sidebar too would duplicate
   it; this reuses the exact same sidebar-hidden/back-link-shown pattern
   .sidebar.dedicated-sidebar/.dashboard-mobile-back already use above
   for a dedicated Buyer page. Desktop (>900px) never sees
   "mobile-section-open" applied (the script only ever adds it under
   the same <=900px check every other mobile-only behavior in this file
   already uses), so none of this affects desktop in any way. */
#dashboard.mobile-section-open .mobile-dashboard-landing{display:none}
#dashboard.mobile-section-open .dashboard-layout.spa-layout{display:block}
#dashboard.mobile-section-open .dashboard-layout.spa-layout .sidebar{display:none}
.profile-grid,.gateway-grid,.steps{grid-template-columns:1fr}
/* Tablet: still the same five logical columns (Product | In Stock |
   Price per pc | Price | Buy) as a real grid, just narrower — nothing
   is dropped or merged, only compacted. */
.group-header,.product-row{grid-template-columns:40px 1fr 90px 98px 82px 74px;gap:6px}
.group-header{padding:11px 10px}
.group-header-col{font-size:10px}
.product-row{padding:12px 10px;font-size:12px}
.product-cell-label{display:block}
.stock-qty{font-size:12px}
.pp-label{font-size:11px}
}
@media(max-width:600px){
/* Mobile Header Compactness Fix — the top row (Logo | Wallet |
   Notification | Profile) must stay together on one line: previously
   the header's default 16px gap plus full desktop-sized Wallet/
   Notification/Profile controls next to the (very wide, ~6.7:1)
   AccountHab wordmark added up to more than a narrow phone's width, so
   flex-wrap split nav-actions onto its own line below the logo, then
   Search below that — three rows, unnecessarily tall. Tightening the
   header's own gap plus every top-row control's size here (and
   .logo-img further down, after its 760px rule so this correctly wins
   at ≤600px) keeps Logo + Wallet + Notification + Profile comfortably
   under even a 320px viewport, so only Search still drops to its own
   row below — back to two rows, and a shorter header overall.
   flex-shrink:0 on .logo/.nav-actions stops the browser from squeezing
   or distorting them instead of honoring these sizes. */
.header{height:auto;padding:10px 12px;flex-wrap:wrap;gap:10px 6px}
.logo,.nav-actions{flex-shrink:0}
/* Mobile Header Compactness Fix — the base .search-wrap rule sets
   flex:0 1 300px (a 300px flex-basis, only shrinking below that if the
   row is too narrow to fit it). width:100% alone doesn't override a
   flex-basis, so above ~324px viewport the search row already had
   enough space and rendered at a fixed 300px instead of filling the
   row — pre-existing, unrelated to the 3-row wrap, but worth fixing
   here since Search is meant to "use the available width efficiently."
   flex-basis:100% makes the intended full-width behavior actually
   apply at every mobile width, not just the very narrowest ones. */
.search-wrap{order:3;width:100%;flex-basis:100%;margin:0}.container{padding:0 12px;margin:15px auto}
/* Mobile Search Icon Redesign — the second header row (.search-wrap,
   sized/positioned by the rule just above) is now collapsed by default
   at mobile widths instead of always shown, and expands in place when
   #navSearchToggle is tapped (see api.js initMobileSearchToggle(),
   which toggles the .mobile-search-open class below). max-height +
   opacity (rather than display:none) gives the "subtle open/close
   animation" the task asks for, and overflow:hidden keeps the
   collapsed row from adding any height or a stray focus target.
   Nothing about .search-wrap's own width/order/margin above is
   changed — this only adds the collapsed/expanded states on top of it. */
.search-wrap{max-height:0;opacity:0;overflow:hidden;transition:max-height .25s ease,opacity .2s ease}
.search-wrap.mobile-search-open{max-height:56px;opacity:1;margin-top:8px}
/* The toggle button (a .header-icon-btn, so it already matches the
   Notification bell's 32x32 mobile size/border/hover) is shown only at
   this width; .search-close-btn (the small X at the right edge of the
   expanded input) is likewise mobile-only and only actually visible
   once .search-wrap is expanded, so it's never a stray tab stop while
   collapsed. */
.header-icon-btn.header-search-toggle{display:inline-flex}
.search-wrap.mobile-search-open .search-close-btn{display:flex;position:absolute;right:6px;top:50%;transform:translateY(-50%);align-items:center;justify-content:center;width:26px;height:26px;border:0;border-radius:50%;background:transparent;color:#9aa1ac;cursor:pointer;padding:0}
.search-wrap.mobile-search-open .search-close-btn:hover{background:var(--blue-50);color:var(--blue-800)}
.search-wrap.mobile-search-open .search-close-btn svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}
.search-wrap.mobile-search-open .search{padding-right:34px}
.nav-actions{gap:4px}
/* Mobile Top Navigation Links — tighter sizing at true phone widths
   (320-430px) so Marketplace/About/Sell on AccountHab sit comfortably on
   one line, using the horizontal-scroll fallback above only in extreme
   cases rather than as the normal look. */
.mobile-subnav{gap:4px;padding:7px 12px}
.mobile-subnav-link{padding:5px 7px;font-size:12px}
.mobile-subnav-cta{padding:6px 10px;font-size:11.5px}
/* Professional Header Redesign — compact Wallet Balance for phone
   widths (smaller than desktop, icon + amount only, per the mobile
   Header requirements). Lives in this existing mobile block, next to
   the .header rule above it, rather than a new media query. Tightened
   one notch further by the Mobile Header Compactness Fix (padding/
   gap/font/icon) so it fits the one-row top layout above. */
.header-wallet-chip{padding:2px 6px;gap:3px;font-size:10.5px}
.header-wallet-chip svg{width:11px;height:11px}
.header-wallet-label{display:none}
/* Mobile Header Compactness Fix — Notification button and Profile chip
   shrink to match the Wallet chip's new compact size. The chevron (a
   desktop-only "there's a menu here" hint) is hidden rather than
   shrunk further — it added width without being tappable on its own,
   since the whole chip already opens the Buyer Dashboard. */
.header-icon-btn{width:32px;height:32px}
.header-icon-btn svg{width:15px;height:15px}
.header-user-chip{padding:4px}
.header-user-avatar{width:24px;height:24px;font-size:11px}
.header-user-chevron{display:none}
.page-header-row{align-items:flex-start}.page-breadcrumb{order:3;width:100%}
/* Mobile: reflow to a single readable column per product instead of a
   cramped 6-up grid — icon on the left spanning the stacked info.
   Nothing is removed: title, subtitle, exact stock, sold count,
   "Price per pc", and price all still appear, just stacked instead of
   side-by-side, and the page never scrolls horizontally. */
.group-header{grid-template-columns:1fr;padding:11px 12px}
.group-header-name{grid-column:1}
.group-header-col{display:none}
.product-cell-label{display:none}
/* Compact Mobile Product Card — stock/sold/"Price per pc" now form one
   left-hand column and price/Buy form one right-hand column, sharing the
   same two grid rows below the title, instead of each stacking on its
   own full-width row underneath the last. This is a pure grid-area
   reassignment: the exact same five cells (.cell-logo/.cell-title/
   .cell-stock/.cell-pplabel/.cell-price/.buy-btn) already produced by
   productRow() in this file are only repositioned here — nothing added,
   removed, or restructured in the HTML/JS, and the desktop/tablet grids
   above this media query are untouched. Tighter padding/row-gap and a
   smaller logo remove the leftover vertical whitespace the old 4-row
   stack had; the title area still spans both right-hand columns so a
   long title can wrap to 2 lines without being squeezed by the price/Buy
   column, and price/Buy stay right-aligned so they're never crowded by
   or overlapping the title/stock text. */
.product-row{
  display:grid;
  grid-template-columns:34px 1fr auto;
  grid-template-areas:
    "logo title   title"
    "logo stock   price"
    "logo pplabel buy";
  row-gap:2px;column-gap:8px;
  padding:10px 10px;
}
.product-row .cell-logo{grid-area:logo;align-self:start}
.product-row .cell-title{grid-area:title}
.product-row .cell-stock{grid-area:stock;line-height:1.25}
.product-row .cell-pplabel{grid-area:pplabel}
.product-row .cell-price{grid-area:price;text-align:right;justify-self:end;align-self:start;min-width:0}
.product-row .cell-price .product-price-value{white-space:nowrap}
.product-row .buy-btn{grid-area:buy;justify-self:end;align-self:center;margin-top:0;flex:0 0 auto}
.buy-btn{height:30px;padding:0 12px;font-size:11.5px}
.product-logo{width:34px;height:34px;font-size:15px}
.product-title{font-size:12px;margin-bottom:2px}.purchase-box{padding:0 12px 15px}.info-row,.total-row{grid-template-columns:125px 1fr}.purchase-btn{margin-top:50px}
}

/* Buyer UI/UX Audit — Critical #1 fix: the fixed Live Chat widget
   (#ahLiveChatWidget, public/css/live-chat.css) is loaded on every Buyer
   page and sits at right:20px/bottom:20px around a 56px circular button
   (right:14px/bottom:14px at <=480px) — a ~76px (70px on small phones)
   fixed footprint in the bottom-right corner of the viewport. Reserving
   a matching strip of empty space at the bottom of the shared page
   wrapper (.container — confirmed the single outer wrapper on every
   Buyer page, never reused for smaller boxes) keeps the last row of
   any product/table list (Marketplace "Buy", Transaction History
   "Next", etc.) from ever landing underneath it, without touching the
   widget itself, .container's width/horizontal padding, or any other
   rule. Longhand padding-bottom only, and deliberately placed here —
   after both existing .container rules above (the unconditional one
   and the <=600px one, which resets padding via shorthand and would
   otherwise wipe this out) — so it wins at every width without a new
   media query: 88px clears the widest (76px) footprint with a small
   buffer and isn't excessive next to the existing 20-24px page margins. */
.container{padding-bottom:88px}

.logo-img{height:42px;width:auto;display:block;object-fit:contain}
@media(max-width:760px){.logo-img{height:37px}}
/* Mobile Header Compactness Fix — a further, narrower override. The
   AccountHab wordmark is very wide relative to its height (~6.7:1), so
   even the 37px size above is still too wide to sit on the same row as
   the Wallet/Notification/Profile controls at phone widths. clamp()
   scales it smoothly across the 320–600px range instead of jumping
   between fixed sizes; declared after the 760px rule above so it wins
   at ≤600px (both match there — source order decides between two
   equal-specificity rules on the same selector). */
@media(max-width:600px){.logo-img{height:clamp(19px,6vw,27px)}}

/* Mobile Search Icon Redesign — narrow-phone follow-up. Adding the new
   Search toggle button to row 1 (Logo, Wallet, Search, Notification,
   Profile — see the header-search-toggle rules above) fits comfortably
   at 375px and up, but at 320-360px the five controls together are a
   few pixels too wide for one row (the logo's own width scales with
   viewport width too — clamp(19px,6vw,27px) — so this isn't only the
   narrowest width), which would otherwise wrap Wallet/Notification/
   Profile onto a second line. This block only trims the logo and a
   few control sizes/paddings a little further, scoped to <=360px so
   375-430px (already comfortable, confirmed by measurement) is
   untouched — and deliberately never touches the shared, bare
   `.header{...}` rule itself (see MarketplaceCategoriesVisualRefinementTest's
   CSS-safety regression guard, which pins that selector's total count
   in this file); every rule below is scoped to its own class instead. */
@media(max-width:360px){
.logo-img{height:17px}
.header-search-toggle,.nav-actions .header-icon-btn{width:28px;height:28px}
.header-search-toggle svg,.nav-actions .header-icon-btn svg{width:13px;height:13px}
.nav-actions{gap:3px}
.header-wallet-chip{padding:2px 4px}
.header-user-chip{padding:3px}
}

/* ===== Loading / API-state helpers (new, additive — not part of the original design) ===== */
/* Role-aware header nav actions (Task 7) — a small flex row of
   .dashboard-link items, rendered by AccountHabAPI.renderNav(). */
.nav-actions{display:flex;align-items:center;gap:14px}
.guard-box{max-width:420px;margin:80px auto;text-align:center;background:var(--white);border:1px solid var(--border);border-radius:10px;padding:30px;box-shadow:var(--shadow-md)}
.guard-box h2{color:var(--blue-900);margin-top:0}
.guard-box a{display:inline-block;margin-top:12px;background:var(--blue-700);color:#fff;border-radius:6px;padding:10px 18px;font-weight:700}

/* Order detail modal (Orders + Checkout Foundation) — same tokens/shadow
   as .guard-box above, just as an overlay instead of a page-centered box,
   so it matches the existing visual language rather than introducing a
   new one. */
.order-overlay{position:fixed;inset:0;background:rgba(9,20,40,.45);display:none;align-items:flex-start;justify-content:center;padding:40px 16px;z-index:50;overflow:auto}
.order-overlay.show{display:flex}
.order-modal{background:var(--white);border-radius:10px;max-width:560px;width:100%;padding:24px;box-shadow:var(--shadow-md)}
.order-modal-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}
.order-modal-close{border:0;background:none;font-size:22px;cursor:pointer;color:#888;line-height:1}

/* Horizontal Scrollbar fix (Buyer Order Details modal) — the Product Name
   popup (#rrHistoryProductNameOverlay) can now be opened from a Product
   title INSIDE the Order Details modal, which is itself an .order-overlay
   already showing. Every .order-overlay shares the same z-index:50, so
   without this override the two tie and DOM order decides the winner —
   #orderDetailOverlay is declared later in dashboard.blade.php than
   #rrHistoryProductNameOverlay, so it would paint on top and make the
   popup invisible/unclickable (confirmed in real-browser testing before
   this rule was added). This popup is only ever meant to sit on top of
   whatever page or modal opened it, so it gets its own, higher z-index
   rather than relying on DOM order — safe because it is the only element
   with this id, so this cannot change the stacking of anything else. */
#rrHistoryProductNameOverlay{z-index:60}

/* Buyer Notifications inbox (Task 12) — reuses .panel/.empty/.secondary-btn/
   .status tokens already established above rather than introducing a new
   visual language. */
.notif-item{display:flex;gap:12px;align-items:flex-start;padding:14px 4px;border-bottom:1px solid var(--border-soft)}
.notif-item:last-child{border-bottom:0}
.notif-item.unread{background:var(--blue-50)}
.notif-dot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;margin-top:6px;background:var(--blue-500)}
.notif-item.unread .notif-dot{background:var(--blue-700)}
.notif-body{flex:1;min-width:0}
.notif-title{font-weight:700;font-size:14px;overflow-wrap:anywhere}
.notif-message{font-size:13px;color:var(--text-muted);margin-top:3px;overflow-wrap:anywhere}
.notif-meta{font-size:11px;color:#999;margin-top:5px}
.notif-item-actions{flex:0 0 auto}

/* Task 14 — per-file download list (Order Detail modal's #odFiles, and
   the extra rows the Download Orders table grows per file-based order).
   Reuses .order-details' border/row language rather than a new one. */
.file-list{margin-top:16px;border:1px solid var(--border);border-radius:8px;overflow:hidden}
.file-list-title{padding:9px 13px;font-size:12px;font-weight:700;color:var(--text-muted);background:var(--blue-50);border-bottom:1px solid var(--border-soft)}
/* Reference-design Download Orders card layout — replaces the earlier
   table-based Download Orders markup (from the original responsive-layout
   fix) with a rounded card per order and a distinct "Files Delivered" panel,
   per the attached reference image. The three wrap/width/flex fixes that
   table-based layout needed (documented in the git history for this
   section) are superseded here: .doc-files-panel's own max-width now
   bounds the files column instead of an nth-child(7) table-cell
   selector, and .file-row/.file-row-name/.file-row-meta (still a single
   shared component reused by the Order Detail overlay and Refund &
   Replacement History — see fileRowHtml()'s own docblock) keep the same
   white-space:normal/overflow-wrap:anywhere overrides so long filenames
   still wrap safely, table cell or not. */
.downloads-order-list{display:flex;flex-direction:column;gap:14px}
.downloads-empty{text-align:center;color:#888;padding:35px;background:#fff;border:1px solid var(--border-soft);border-radius:8px}
.download-order-card{display:flex;flex-wrap:wrap;background:#fff;border:1px solid var(--border-soft);border-radius:10px;box-shadow:0 1px 2px rgba(16,24,40,.06);overflow:hidden}
.doc-info{flex:1 1 300px;min-width:260px;padding:16px 18px;display:flex;flex-direction:column;gap:8px}
.doc-info-top{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.doc-order-num{font-weight:700;font-size:13px;color:var(--blue-900)}
.doc-badges{display:flex;gap:6px;flex-wrap:wrap}
.doc-badge{font-size:10.5px;font-weight:700;padding:3px 9px;border-radius:999px;white-space:nowrap}
.doc-badge-paid,.doc-badge-ready{background:#e8f8ee;color:var(--success)}
.doc-badge-na{background:#fdeceb;color:#b42318}
.doc-badge-pending{background:#fff6e6;color:#a15c00}
.doc-product{min-width:0}
.doc-meta-row{display:flex;flex-wrap:wrap;gap:14px;font-size:12px;color:var(--text-muted)}
.doc-order-action{margin-top:4px}
.doc-files-panel{flex:1 1 300px;min-width:260px;max-width:420px;background:#f8fafc;border-left:1px solid var(--border-soft);display:flex;flex-direction:column}
.doc-files-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;font-size:12px;font-weight:700;color:var(--text);border-bottom:1px solid var(--border-soft)}
.doc-files-header svg{width:12px;height:12px;fill:#9aa1ac;flex:0 0 auto}
.doc-files-list{padding:2px 6px}
@media(max-width:760px){
.download-order-card{flex-direction:column}
/* flex-basis:300px on .doc-info/.doc-files-panel is a WIDTH hint for the
   side-by-side row layout above — once flex-direction switches to
   column, the same flex-basis is read as a HEIGHT hint instead, forcing
   each panel to a tall minimum height it doesn't need and leaving a
   large blank gap before the next one starts. flex-basis:auto here lets
   each panel size to its own content height when stacked. */
.doc-info,.doc-files-panel{flex-basis:auto;min-width:0}
.doc-files-panel{max-width:none;border-left:0;border-top:1px solid var(--border-soft)}
}
.file-row{display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:10px 13px;border-bottom:1px solid var(--border-soft);font-size:13px}
.file-row:last-child{border-bottom:0}
.file-row-icon{width:26px;height:26px;border-radius:6px;background:#eef1f5;display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.file-row-icon svg{width:14px;height:14px;fill:#5b6473}
.file-row-download-btn{display:inline-flex;align-items:center;gap:6px}
.file-row-download-btn svg{width:13px;height:13px;fill:currentColor}
/* Download Orders — Copy action beside the existing Download button
   (Order Contents .txt row). .file-row-actions groups the two buttons so
   they sit side by side without disturbing .file-row's own flex/column
   layout above; see the <=600px override further down for how they stay
   usable instead of overflowing a narrow phone. */
.file-row-actions{display:flex;gap:8px;flex:0 0 auto}
.file-row-copy-btn{display:inline-flex;align-items:center;gap:6px}
.file-row-copy-btn svg{width:13px;height:13px;fill:currentColor}
.file-row-info{flex:1 1 220px;min-width:0}
.file-row-name{font-weight:600;white-space:normal;overflow-wrap:anywhere}
/* UI simplification — the meta line now holds only the file size (the
   full MIME type and the per-file Product Title, both redundant with
   other UI already shown, were removed; see fileRowHtml()'s own
   docblock in dashboard.blade.php). A short file-extension badge next
   to the filename replaces the old MIME type text; kept as an inline
   pill (not its own stacked line like .file-row-replacement-badge)
   since it's short enough to sit beside the name without risking the
   column-overflow bug this row already had fixed once. */
.file-row-type-badge{display:inline-block;margin-left:6px;background:var(--blue-50);color:var(--text-muted);border-radius:4px;padding:1px 6px;font-size:10px;font-weight:700;vertical-align:middle;white-space:nowrap}
.file-row-meta{font-size:11px;color:var(--text-muted);margin-top:2px;white-space:normal;overflow-wrap:anywhere}
.file-row .secondary-btn{height:32px;padding:0 12px;white-space:nowrap;flex-shrink:0}
.file-row-unavailable{font-size:12px;color:#b42318;font-weight:700}
.downloads-file-list{margin-top:8px;padding-top:8px;border-top:1px dashed var(--border-soft)}
.downloads-file-list .file-row{padding:6px 0;border-bottom:0;font-size:12px}
/* Narrow screens — stack the file info above a full-width Download
   button (same "own row, full tap target" pattern already used for the
   Marketplace product row's Buy button in this file's 600px
   breakpoint) rather than letting the row keep squeezing horizontally. */
@media(max-width:600px){
/* flex-wrap:nowrap here is required, not decorative — .file-row's base
   rule sets flex-wrap:wrap for the >600px row layout (so a very long
   inline run can drop to a second line without fully stacking); left
   on at the same time as flex-direction:column here, a flex container
   wraps into additional COLUMNS instead of just growing taller, which
   silently blew .file-row-info/the Download button out to hundreds of
   pixels wide, further right than the row itself — this is what
   actually caused it, confirmed by comparing each element's own
   getBoundingClientRect() in a real headless-browser run. */
.file-row{flex-direction:column;flex-wrap:nowrap;align-items:stretch}
.file-row-info{flex-basis:auto}
.file-row .secondary-btn,.file-row>.file-row-unavailable{align-self:stretch;text-align:center}
/* Download + Copy now share one .file-row-actions row instead of each
   being its own full-width stacked button — split evenly so both stay
   comfortably tappable on a narrow phone without overflowing. */
.file-row-actions{width:100%;gap:8px}
.file-row-actions .secondary-btn{flex:1;min-width:0;padding:0 8px}
/* Professional Mobile UI Refinement — once the row above stacks to
   full width, a button that's still only 32px tall (the desktop-only
   height, sized down to fit several inline buttons in a dense row —
   see .file-row .secondary-btn's own base rule) reads as an unusually
   short, wide pill and falls short of a comfortable tap target. There
   is no longer a horizontal-space reason to keep it shorter than the
   40px height every other .secondary-btn in this app already uses
   (see the base .secondary-btn rule), so this restores that standard
   height for these buttons specifically at this width. */
.file-row .secondary-btn{height:40px;font-size:13px}
/* Order # and its status badges (.doc-info-top, Download Orders card)
   already wrap onto their own line via flex-wrap when they don't fit
   side by side, but at the narrowest phone widths that still leaves
   them sharing a justify-content:space-between row more often than
   not — stacking them (number above, badges below, left-aligned)
   reads clearer once the card is this narrow. */
.doc-info-top{flex-direction:column;align-items:flex-start;gap:7px}
}

/* ===== Phase 4B — Replacement delivery labeling + Buyer feedback
   (additive only; reuses .form-group/.input/.primary-btn/.secondary-btn). ===== */
.file-row-replacement-badge{display:inline-block;margin-top:3px;background:#eef4ff;color:#1d4ed8;border-radius:5px;padding:2px 7px;font-size:10px;font-weight:700}
.rr-feedback-note{font-size:12px;color:var(--text-muted);margin-top:6px}

/* Buyer Replacement History — a dedicated, clearly-labeled summary block
   in the Order Detail modal (separate from the plain #odFiles list and
   from the existing inline refund-only text), plus the "Replacement
   Delivery" file-list group it sits alongside. Deliberately reuses the
   same .file-list/.status/.rr-window-notice visual language already
   established above rather than introducing a new component style. */
.rr-history{margin-top:16px;border:1px solid var(--border);border-radius:8px;overflow:hidden}
.rr-history-title{padding:9px 13px;font-size:12px;font-weight:700;color:var(--text-muted);background:var(--blue-50);border-bottom:1px solid var(--border-soft)}
.rr-history-row{display:grid;grid-template-columns:175px 1fr;gap:8px;padding:8px 13px;font-size:13px;border-bottom:1px solid var(--border-soft)}
.rr-history-row:last-child{border-bottom:0}
.rr-history-row strong{font-weight:700;color:var(--text-muted);font-size:12px}
.rr-history-note{font-size:12px;color:#8a5a00;background:#fff8e6;border-top:1px solid var(--border-soft);padding:9px 13px}
.rr-history-file-list{margin-top:10px;border-color:#c7d7fb}
.rr-history-file-list .file-list-title{background:#eef4ff;color:#1d4ed8}

/* Buyer-Owned Evidence Image Preview — Requirement C/D. Already-submitted
   evidence thumbnails (renderRrEvidenceGallery(), public/js/
   buyer-orders.js), shown inside a .rr-history block (same visual
   language as every other section above) in both the My Orders Order
   Detail modal (#odEvidence) and the Refund & Replacement History Detail
   modal. flex-wrap keeps this responsive/mobile-friendly with no fixed
   height, so it never forces the surrounding modal unreasonably tall. */
.rr-evidence-gallery{display:flex;flex-wrap:wrap;gap:8px;padding:11px 13px}
.rr-evidence-thumb{width:64px;height:64px;object-fit:cover;border-radius:8px;border:1px solid var(--border-soft);cursor:pointer;display:block;background:var(--blue-50);transition:transform .12s ease,box-shadow .12s ease}
.rr-evidence-thumb:hover{transform:translateY(-2px);box-shadow:0 4px 10px rgba(15,23,42,.14)}
.rr-evidence-thumb-loading{width:64px;height:64px;border-radius:8px;border:1px solid var(--border-soft);background:var(--blue-50);display:flex;align-items:center;justify-content:center;color:var(--text-muted);font-size:11px}

/* Buyer-Owned Evidence Image Preview — enlarge-on-click lightbox (see
   buyer.partials.rr-evidence-lightbox). Reuses the shared .order-modal
   shell, only capped narrower/centered since its content is a single
   image + caption rather than a form or a list. */
.rr-evidence-lightbox-modal{max-width:520px;text-align:center}
.rr-evidence-lightbox-img{max-width:100%;max-height:60vh;border-radius:8px;margin:0 auto;display:block}

/* Cumulative Evidence Image Selection fix — Requirement A/B. In-modal,
   not-yet-uploaded preview for each currently-selected evidence image
   (renderRrEvidenceSelection(), public/js/buyer-orders.js), plus its own
   remove control and the "N / 2 images" count. flex-wrap keeps this
   responsive with no fixed height, same reasoning as .rr-evidence-gallery
   above — a Buyer picking 2 small images never makes the Request
   Replacement / Refund modal noticeably taller. */
.rr-evidence-picker{display:flex;flex-wrap:wrap;gap:12px;margin-top:10px}
.rr-evidence-picker-item{position:relative;width:84px}
.rr-evidence-picker-thumb{width:84px;height:84px;object-fit:cover;border-radius:8px;border:1px solid var(--border-soft);display:block;background:var(--blue-50)}
.rr-evidence-picker-remove{position:absolute;top:-8px;right:-8px;width:20px;height:20px;border-radius:50%;border:1px solid var(--border);background:var(--white);color:#a21d1d;font-size:13px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}
.rr-evidence-picker-remove:hover{background:#fff1f1}
.rr-evidence-picker-meta{font-size:10px;color:var(--text-muted);margin-top:3px;max-width:84px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rr-evidence-count{font-size:12px;color:var(--text-muted);margin-top:8px}
@media(max-width:600px){
.rr-evidence-thumb,.rr-evidence-thumb-loading{width:56px;height:56px}
.rr-evidence-picker-item{width:72px}
.rr-evidence-picker-thumb{width:72px;height:72px}
.rr-evidence-picker-meta{max-width:72px}
}

/* Buyer Refund & Replacement History table only — Requested column shows
   date and time stacked on two lines instead of one. white-space:normal
   overrides the shared th,td{white-space:nowrap} rule (line ~123) for
   just these two lines; every other table/column in the app keeps its
   existing single-line behavior. */
.rrh-requested-date{white-space:normal;font-weight:600}
.rrh-requested-time{white-space:normal;margin-top:2px;font-size:11px}

/* Fix Refund/Replacement Request Form — Inventory Method Specific Logic.
   "Affected Product / Delivered Files" picker (#rrFilesGroup, Upload
   Files products only) — reuses the same .file-row proportions/spacing
   already established above for a checkbox-selectable row instead of a
   bare read-only one, plus the same .product-logo-sm/.file-row-type-badge
   components (via productLogoHtml()/fileTypeLabel() in
   dashboard.blade.php) so this list looks consistent with the Files
   Delivered panel it mirrors. Scrollable with a max-height so an order
   with many delivered files never grows the modal itself unreasonably
   tall. */
.rr-files-list{max-height:260px;overflow-y:auto;border:1px solid var(--border-soft);border-radius:8px}
.rr-file-select-row{display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1px solid var(--border-soft);cursor:pointer;font-size:13px}
.rr-file-select-row:last-child{border-bottom:0}
.rr-file-select-row:hover{background:var(--blue-50)}
.rr-file-select-row input[type=checkbox]{width:16px;height:16px;flex:0 0 auto;cursor:pointer}
.rr-file-select-info{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
.rr-file-select-product{font-size:11px;color:var(--text-muted);font-weight:700}
.rr-file-select-filename{font-weight:600;white-space:normal;overflow-wrap:anywhere}
.rr-file-select-meta{font-size:11px;color:var(--text-muted)}
/* Requested Quantity is derived from the checkbox selection in this mode
   (see rrSyncQuantityFromFileSelection() in dashboard.blade.php) rather
   than typed — a subtle "not directly editable" treatment on the same
   .input element, not a different component. */
#rrQuantity[readonly]{background:#f4f6f9;color:var(--text-muted);cursor:not-allowed}
@media(max-width:600px){
.rr-files-list{max-height:220px}
}

/* Buyer Refund & Replacement History table only — Product column: a
   fixed, reasonable width with the name clamped to two lines and an
   ellipsis, so a long Product name can never stretch the table or force
   a horizontal scrollbar. A real <button> (keyboard-focusable/
   activatable), styled as plain table text — NOT a hyperlink (var(--text),
   the same dark color the rest of the table uses, no underline even on
   the ellipsis, since text-decoration:none applies to the whole box) —
   with a subtle background highlight on hover/focus so it still reads as
   clickable; clicking/activating it opens the full-name popup (see
   rrHistoryProductNameOverlay in resources/views/buyer/dashboard.blade.php
   — unchanged). white-space:normal overrides the shared
   th,td{white-space:nowrap} rule for just this element, matching
   -webkit-line-clamp's own wrapping requirement. Also used, verbatim, by
   the Buyer Order Details modal's Product column (Horizontal Scrollbar
   fix) — the same reuse Download Orders already made. overflow-wrap:
   anywhere + word-break:break-word are a defensive addition (Horizontal
   Scrollbar fix) so even a single very long unbroken "word" (no spaces
   for the browser's normal line-breaking to use) still wraps inside the
   200px/140px cap instead of forcing this box — and the table/modal
   around it — wider than intended. */
.rrh-product-trunc{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;white-space:normal;overflow-wrap:anywhere;word-break:break-word;max-width:200px;background:none;border:0;padding:0;margin:0;font:inherit;text-align:left;color:var(--text);text-decoration:none;cursor:pointer;border-radius:3px;transition:background-color .12s ease}
.rrh-product-trunc:hover,.rrh-product-trunc:focus-visible{background:var(--blue-50)}
.rrh-product-trunc:focus-visible{outline:2px solid var(--blue-500);outline-offset:2px}
@media(max-width:600px){.rrh-product-trunc{max-width:140px}}
/* Professional Mobile UI Refinement — .rrh-product-trunc's 200px/140px
   caps exist for the Refund & Replacement History TABLE's narrow
   Product column; the Download Orders card gives .doc-product/.doc-info
   far more width to work with (especially once the card stacks full-
   width — see the ≤760px/≤600px rules above), so clamping the same
   product title there to the table's width wastes that space and can
   truncate titles that would otherwise fit. This is a higher-
   specificity override scoped to the card only — the base rule and its
   own 140px mobile clamp stay exactly as they are for the RR History
   table. */
.download-order-card .rrh-product-trunc{max-width:none;-webkit-line-clamp:3}

/* Product Logo in a Product column/row — Download Orders, the Order
   Detail overlay's items table, and Refund & Replacement History all use
   this same small container beside the Product Title (productLogoHtml()
   in dashboard.blade.php). .product-logo/.product-logo img themselves
   (size, border, ◈ fallback, object-fit) are the exact same rule the
   Marketplace grid's product-row already defines above — reused as-is,
   not duplicated; .product-logo-sm only overrides the size down from the
   grid's 40px to something that fits a data-dense table row without
   growing it taller than the existing Download Orders layout allows. */
.product-logo-sm{width:28px;height:28px;font-size:13px;border-radius:5px;flex:0 0 auto}
.rrh-product-with-logo{display:flex;align-items:center;gap:8px;min-width:0}

/* Buyer header responsive overflow fix (901-1220px) — root cause: the
   right-hand header controls (.search-wrap base width:300px,
   .nav-actions base gap:14px, .header-wallet-chip/.header-user-chip
   base padding) had NO narrowing anywhere between the <=900px block
   above and full desktop, while .nav (Marketplace/About/Sell on
   AccountHab) stayed full-width there too — together these overflowed
   the header and caused page-level horizontal scroll from ~901px up
   to ~1211px. Deliberately placed at the very end of the file, not
   next to the @media(max-width:1220px) block that narrows .nav above
   (same 1220px cutoff — chosen because .nav only reaches its own
   narrow, non-overflowing width once max-width:1220 widens that
   pre-existing block far enough to still apply here) — .search-wrap,
   .nav-actions and .header-wallet-chip/.header-user-chip each already
   have their own unconditional (non-media) base rule earlier in this
   file (e.g. .nav-actions{gap:14px} in the "Role-aware header nav
   actions" section above), and since a plain rule and a media-scoped
   rule of equal specificity resolve by source order alone, a fix
   placed earlier (like the .nav block above) would just lose to those
   later base rules and never apply. Appending here — after every other
   rule for these same selectors — is the minimum change that actually
   wins the cascade, without editing or reordering any existing rule.
   min-width:901px keeps this scoped strictly above the existing
   <=900px block so that block's own (untouched) mobile behavior is
   unaffected. Nothing is removed: the wallet icon+amount, the
   notification bell, and the user avatar all stay visible and
   clickable — only the "Wallet:" text label and the user's name/role
   text are hidden, the exact same technique this file already uses at
   <=600px (.header-wallet-label) and <=900px (.header-user-meta). */
@media(min-width:901px) and (max-width:1220px){
  .logo-img{height:34px}
  .nav-link{gap:3px}
  .nav-link-icon{width:13px;height:13px}
  .nav-cta{padding:8px 10px}
  .nav-cta-icon{width:13px;height:13px}
  .search-wrap{width:170px;flex:0 1 170px}
  .nav-actions{gap:6px}
  .header-wallet-chip{padding:6px 8px}
  .header-wallet-label{display:none}
  .header-user-meta{display:none}
  .header-user-chip{padding:5px 6px 5px 5px}
  .header-user-chevron{display:none}
  .header-icon-btn{width:34px;height:34px}
  .header-icon-btn svg{width:16px;height:16px}
}
/* Transaction History pagination — restyle ONLY the two Prev/Next
   buttons on the Buyer Dashboard's Transaction History panel
   (#txPagination, added to that one .pagination div in
   dashboard.blade.php) to reuse the existing .secondary-btn button
   language instead of the generic ".pagination button" look. That
   base rule (border:1px solid #ddd;background:#fff;padding:7px
   12px;border-radius:5px;font-size:12px, above) is still needed as-is
   for the four OTHER dashboard sections sharing the plain .pagination
   class (Orders/Downloads/Refund & Replacement History/Notifications
   — all left untouched), so it can't be edited directly. It also
   can't just be out-cascaded by adding .secondary-btn to these two
   buttons and relying on source order: ".pagination button" (a class
   + a type selector) is MORE specific than ".secondary-btn" (a single
   class) regardless of which rule comes later in the file — the exact
   cascade trap already hit once in this file (see the header-overflow
   fix above). #txPagination + the button type selector together
   outweigh it, so this rule is placed right here for clarity, not
   because placement matters this time.
   .secondary-btn itself has no :disabled state anywhere in this file
   (Prev/Next are disabled at the start/end of the list), so one is
   added here too, reusing the same opacity:.4;cursor:not-allowed
   language already established by .buy-btn:disabled — scoped to
   #txPagination only so no other, unrelated .secondary-btn instance
   (e.g. the Sign Out popup's Cancel button) is affected. */
#txPagination.pagination{gap:10px}
#txPagination.pagination button.secondary-btn{height:40px;border:1px solid var(--border);background:var(--white);color:var(--text);border-radius:7px;padding:0 16px;font-size:13px;font-weight:700;cursor:pointer}
#txPagination.pagination button.secondary-btn:hover:not(:disabled){background:var(--blue-50);border-color:var(--blue-500);color:var(--blue-800);transform:translateY(-1px)}
#txPagination.pagination button.secondary-btn:disabled{opacity:.4;cursor:not-allowed}

/* Login Page — Centered Card Simplification. Every selector below is
   scoped to classes only used on resources/views/auth/login.blade.php
   (.login-*) or the #loginPage ID+class combo; none of it edits
   .container/.auth-box/.primary-btn/.input/etc., so register/
   seller-register/verify-email (which also use .auth-box) stay
   unaffected. The page used to be a three-column WELCOME | CARD |
   ILLUSTRATION "Premium Redesign" layout; the left welcome/branding
   column and right decorative illustration markup have both been
   removed from login.blade.php per explicit request, so every rule
   that only ever styled THAT removed markup (.login-illustration*,
   .login-intro/.login-eyebrow/.login-headline*/.login-subcopy/
   .login-feature*) has been removed here too, rather than left as dead
   CSS. What remains: .login-shell/.login-decor/.login-decor-blob* (the
   soft light-blue background — explicitly kept) and .login-shell-inner/
   .login-card-col, now simplified to just center the single remaining
   card. #loginPage.login-card's own width/padding/radius/shadow and the
   card-interior polish (title/inputs/button/etc.) are unchanged from
   the prior pass — this is a layout simplification, not a card
   redesign. */
.login-shell{position:relative;overflow:hidden;padding:32px 20px 56px}
.login-decor{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.login-decor-blob{position:absolute;border-radius:50%}
.login-decor-blob--1{width:520px;height:520px;top:-200px;left:-180px;background:radial-gradient(circle at 30% 30%,rgba(59,130,246,.16),rgba(59,130,246,0) 70%)}
.login-decor-blob--2{width:420px;height:420px;bottom:-180px;right:-160px;background:radial-gradient(circle at 60% 40%,rgba(23,105,224,.12),rgba(23,105,224,0) 70%)}
.login-decor-blob--3{width:260px;height:260px;top:38%;left:55%;background:radial-gradient(circle,rgba(59,130,246,.10),rgba(59,130,246,0) 70%)}

.login-shell-inner{position:relative;z-index:1;max-width:1180px;margin:0 auto}
.login-card-col{width:100%;display:flex;justify-content:center}
#loginPage.login-card{width:100%;max-width:420px;margin:0;box-shadow:0 20px 50px rgba(24,55,100,.14)}

@media(min-width:901px){
  .login-shell{padding:64px 32px}

  /* Card polish — ID+class selectors so every declaration wins over
     the shared .auth-box/.input/.primary-btn/.form-group label/
     .remember-me/.auth-footer rules by scoping, never by editing those
     shared rules (register/seller-register/verify-email all use them
     too and stay completely untouched). Same values as the prior
     "Premium Redesign" pass — kept exactly, per "keep the current
     improved input/button styling." */
  #loginPage.login-card{max-width:460px;padding:36px;border-radius:16px;box-shadow:0 24px 60px rgba(24,55,100,.16)}
  #loginPage.login-card .auth-title{font-size:27px}
  #loginPage.login-card .auth-subtitle{font-size:14px;margin-bottom:24px}
  #loginPage.login-card .form-group{margin-bottom:16px}
  #loginPage.login-card .form-group label{font-size:13.5px}
  #loginPage.login-card .input{height:46px;border-radius:9px;border-color:var(--border)}
  #loginPage.login-card .input:focus{border-color:var(--blue-500);box-shadow:0 0 0 3px rgba(23,105,224,.09)}
  #loginPage.login-card .input-icon-group .input{padding-left:42px}
  #loginPage.login-card .input-icon{width:17px;height:17px;left:14px}
  #loginPage.login-card .remember-me{font-size:13.5px;margin-bottom:18px}
  #loginPage.login-card .primary-btn{height:48px;font-size:15px;box-shadow:0 10px 24px rgba(23,105,224,.26)}
  #loginPage.login-card .auth-footer{margin-top:20px;font-size:13.5px}
}

/* Login Page Mobile Height Fix — tightens spacing/sizing for the SAME
   .login-* classes and ID-scoped #loginPage.login-card descendants —
   never the shared .auth-box/.form-group/.auth-subtitle/.remember-me/
   .auth-footer rules themselves — so register/seller-register/
   verify-email (which also use .auth-box/.form-group) are unaffected.
   The decor blobs were never actually a height contributor (already
   clipped by .login-shell{overflow:hidden}); they're only shrunk here
   for a subtler mobile look. Desktop (>=901px) is untouched — this
   query's upper bound (900px) is the exact complement of the
   @media(min-width:901px) block above. The illustration/welcome-intro
   overrides that used to live here were removed along with their now-
   deleted markup. */
@media(max-width:900px){
  .login-shell{padding:20px 16px 28px}

  .login-decor-blob--1{width:300px;height:300px;top:-130px;left:-110px}
  .login-decor-blob--2{width:240px;height:240px;bottom:-110px;right:-90px}
  .login-decor-blob--3{width:160px;height:160px}

  /* ID+class selector, exactly like the existing #loginPage.login-card
     rule above — wins over the shared .auth-box{padding:30px} without
     editing that shared rule, and the descendant selectors below are
     scoped the same way, so none of this reaches any other auth page. */
  #loginPage.login-card{padding:22px 18px}
  #loginPage.login-card .auth-title{margin-bottom:4px}
  #loginPage.login-card .auth-subtitle{margin-bottom:14px}
  #loginPage.login-card .form-group{margin-bottom:11px}
  #loginPage.login-card .remember-me{margin-bottom:12px}
  #loginPage.login-card .auth-footer{margin-top:12px}
}

/* Register Page Premium Redesign — see resources/views/auth/
   register.blade.php's own comments for the full rationale. Every
   selector below is new, scoped to .register-* classes or the
   #registerPage/#registerOtpSection ID+class combos (mirroring the
   exact #loginPage.login-card pattern above), so nothing here touches
   the shared .auth-box/.form-group/.input/.primary-btn/.secondary-btn/
   .seller-cta-card rules that login/seller-register/verify-email also
   depend on — none of those pages, and none of Marketplace/Buyer
   Dashboard/Product Detail, reference any .register-* class, so this
   block cannot affect them either.

   Unlike Login's own first pass (which needed a follow-up task to
   compact an initially too-tall mobile layout), this is written
   compact-by-default: the base (mobile, unqualified) rules below hold
   the FINAL mobile sizing directly, and @media(min-width:901px) — the
   same cutover width Login and the header's own nav-collapse already
   use — only opts INTO the larger desktop spacing. The one decorative
   element (a small corner badge on the registration card) is
   position:absolute relative to the card itself at every breakpoint,
   so — unlike Login's original in-flow illustration — it can never add
   document height, mobile or desktop. */
.register-shell{position:relative;overflow:hidden;padding:20px 16px 28px}
.register-decor{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.register-decor-blob{position:absolute;border-radius:50%}
.register-decor-blob--1{width:300px;height:300px;top:-130px;left:-110px;background:radial-gradient(circle at 30% 30%,rgba(59,130,246,.16),rgba(59,130,246,0) 70%)}
.register-decor-blob--2{width:240px;height:240px;bottom:-110px;right:-90px;background:radial-gradient(circle at 60% 40%,rgba(23,105,224,.12),rgba(23,105,224,0) 70%)}

.register-shell-inner{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;max-width:1180px;margin:0 auto}

/* ID+class selector, exactly like #loginPage.login-card above — wins
   over the shared .auth-box{padding:30px} without editing that shared
   rule. Covers both the registration card and the same-page OTP card,
   which now stack in the same column (registration form on top, the
   OTP card revealed directly beneath it once registration succeeds —
   see register.blade.php's showOtpSection()) rather than swapping in
   the same slot, so both share one consistent card size and width. A
   single centered card (480–560px range) rather than Login's two-
   column shell, since Register only needs one focused step at a time. */
#registerPage.register-card,#registerOtpSection.register-card{position:relative;width:100%;max-width:520px;margin:0;padding:22px 18px;box-shadow:0 20px 50px rgba(24,55,100,.14)}
/* Gap between the registration card and the OTP card once both are
   visible at once (Register Page OTP Below-Form Fix). Irrelevant while
   #registerOtpSection still carries .hidden (display:none takes it out
   of flow), so this only ever applies once the OTP card is revealed. */
#registerPage.register-card + #registerOtpSection.register-card{margin-top:20px}

#registerPage.register-card .auth-title,#registerOtpSection.register-card .auth-title{margin-bottom:4px}
#registerPage.register-card .auth-subtitle,#registerOtpSection.register-card .auth-subtitle{margin-bottom:14px}
#registerPage.register-card .form-group,#registerOtpSection.register-card .form-group{margin-bottom:11px}
#registerPage.register-card .auth-footer{margin-top:12px}
#registerPage .seller-cta-card{margin-top:11px;padding:12px 14px}

/* Decorative only — see the aria-hidden markup comment in
   register.blade.php. Absolutely positioned in the card's own top-right
   corner, so it never participates in document flow. Reuses the exact
   person icon already used for the Name field, plus a small "+" chip,
   for visual consistency with the app's existing single-<path> SVG
   icon convention (no new illustration style introduced). */
.register-card-illustration{position:absolute;top:14px;right:14px;pointer-events:none}
.register-illustration-panel{position:relative;width:44px;height:44px;border-radius:14px;background:linear-gradient(135deg,rgba(59,130,246,.16),rgba(23,105,224,.28));display:flex;align-items:center;justify-content:center}
.register-illustration-badge{width:52%;height:52%;fill:var(--blue-700)}
.register-illustration-chip{position:absolute;bottom:-6px;left:-6px;width:20px;height:20px;border-radius:7px;background:var(--blue-700);box-shadow:0 4px 10px rgba(24,55,100,.18);display:flex;align-items:center;justify-content:center}
.register-illustration-chip svg{width:11px;height:11px;fill:var(--white)}

/* Keeps the card title clear of the corner badge above, without
   touching the shared .auth-title rule other auth pages use. */
#registerPage.register-card .register-card-title{padding-right:56px}

@media(min-width:901px){
  .register-shell{padding:56px 32px 84px}

  /* Desktop Visual Scale Polish (Task P) — raises the card ceiling from
     520px to 580px and scales typography/spacing/illustration to match,
     all still inside this same 901px+ block, so 320–414px mobile is
     completely untouched (it never reads these declarations). */
  #registerPage.register-card,#registerOtpSection.register-card{padding:34px 36px;max-width:580px}
  #registerPage.register-card + #registerOtpSection.register-card{margin-top:30px}
  #registerPage.register-card .auth-title,#registerOtpSection.register-card .auth-title{margin-bottom:8px;font-size:31px}
  #registerPage.register-card .auth-subtitle,#registerOtpSection.register-card .auth-subtitle{margin-bottom:24px;font-size:15px}
  #registerPage.register-card .form-group,#registerOtpSection.register-card .form-group{margin-bottom:16px}
  #registerPage.register-card .form-group label,#registerOtpSection.register-card .form-group label{font-size:13.5px}
  #registerPage.register-card .auth-footer,#registerOtpSection.register-card .auth-footer{margin-top:20px;font-size:14px}
  #registerPage .seller-cta-card{margin-top:16px;padding:18px 20px;font-size:14px}
  #registerPage .seller-cta-card a{font-size:15px}

  .register-card-illustration{top:22px;right:22px}
  .register-illustration-panel{width:72px;height:72px;border-radius:20px}
  .register-illustration-chip{width:28px;height:28px;border-radius:9px;bottom:-8px;left:-8px}
  .register-illustration-chip svg{width:14px;height:14px}
  #registerPage.register-card .register-card-title{padding-right:88px}
}
