/* bk-marketplace.css — Bookku cross-tenant marketplace (Phase 1 UAT)
   Frontend lane, mra-marketplace-phase1.

   DESIGN.md sections implemented:
     §1 / §2.2  — cool-tinted white canvas (--bk-surface-0 ≈ #F7F9FC), NOT pure #FFF / warm-white
     §2.1       — trust-blue brand axis via --brand-primary; all accents cascade
     §2.3 / §2.7— ink hierarchy + contrast floors (price/name on ink, muted meta ≥4.5:1)
     §2.4       — semantic soft fills for the trust chip (success-soft / neutral)
     §3.1 / §3.2— editorial pairing (Fraunces display on hero title, Plus Jakarta body)
     §3.4 / §3.6— tabular price digits, ฿ prefix (via --price-font, mirrors storefront)
     §4.5       — button states (hover / focus-visible / active), 44px touch
     §6.1       — three-tier brand-mixed elevation (--bk-elev-*)
     §6.4       — semantic z-index ladder (--z-sticky for the sticky search bar)
     §8.5       — intrinsic responsive grid repeat(auto-fill, minmax()) — mobile-first
     §1 ban     — no side-stripe borders, no 1px-border+heavy-shadow pairing, radius ≤18px
     §4.4       — auth-modal dialog motion (zoom-in-95 + fade, spring easing; transform/opacity only)
     §6.4       — z-index ladder for the modal (--z-modal-backdrop 1200 / --z-modal 1300)
     §4.14      — modal is fixed-position (never absolute-in-overflow) — overlay clipping ban
     §8.2       — 44×44 touch targets on modal close + logout + OTP controls
     §8.3       — reduced-motion block (collapses the modal zoom + all page motion)
     §11.2 note — APEX chrome stays Bookku-blue (the §11.2 tenant-cascade rule governs
                  CUSTOMER auth inside a tenant shop.html, NOT this cross-tenant apex)

   This is a STANDALONE page (backend serves it at GET /marketplace). It re-uses
   the storefront card visual language (.prod-card: full-bleed rounded .img +
   .meta with .name + .prod-price-row pill-left/price-right) so it reads native,
   but ships its own scoped tokens rather than pulling the 8k-line template-coupled
   bk-shop.css. Tokens are copied verbatim from bk-shop.css :root so hues match. */

/* ── Marketplace v2 (Wave B, 2026-07-02) — cream/cognac scoped palette ──────
   This file is now the SOURCE OF TRUTH for marketplace hues (it no longer
   mirrors bk-shop.css trust-blue). Ported VERBATIM from the pk-approved mock
   (docs/active/mocks/grid.html:22-69). Marketplace-scoped divergence from
   DESIGN.md — a deliberate warm-luxury atmosphere (MARKETPLACE_V2_DESIGN
   §PK DECISIONS / §invariants). Back-compat aliases below keep the 900 legacy
   downstream lines working while sections are re-skinned. */
:root {
  /* ── canvas + surfaces — §2.2 inversion preserved: surface-1/2 LIGHTER than canvas ── */
  --mkt-canvas:        #F5F0E6;
  /* neutral mixes in SRGB — oklch drifts near-neutrals pink in Chrome/Safari<16.4.
     saturated derivations (cognac/green/amber) stay oklch. */
  --mkt-surface-1:     color-mix(in srgb, #FFFFFF 45%, var(--mkt-canvas));
  --mkt-surface-2:     color-mix(in srgb, #FFFFFF 72%, var(--mkt-canvas));
  --mkt-surface-inset: color-mix(in srgb, var(--mkt-ink) 5%, var(--mkt-canvas));
  /* ── ink — espresso ladder ── */
  --mkt-ink:           #221A14;
  --mkt-ink-secondary: #3B2B20;
  --mkt-ink-muted:     #6E5A49;
  --mkt-line:          color-mix(in srgb, var(--mkt-ink) 14%, var(--mkt-canvas));
  --mkt-line-soft:     color-mix(in srgb, var(--mkt-ink) 8%,  var(--mkt-canvas));
  /* ── single action accent — cognac (blue retired on this surface) ── */
  --mkt-accent:        #8A5A2B;
  --mkt-accent-ink:    #FFFFFF;
  --mkt-accent-hover:  color-mix(in oklch, var(--mkt-accent) 88%, black);
  --mkt-accent-active: color-mix(in oklch, var(--mkt-accent) 78%, black);
  --mkt-accent-soft:   color-mix(in srgb, var(--mkt-accent) 10%, var(--mkt-canvas));
  --mkt-accent-ring:   color-mix(in oklch, var(--mkt-accent) 45%, transparent);
  /* ── verified — mapped 1:1 from DESIGN.md §2.4, NEVER re-hued ── */
  --bk-success:        #15803D;
  --mkt-success-soft:  color-mix(in srgb, var(--bk-success) 8%, var(--mkt-canvas));
  --mkt-success-deep:  color-mix(in oklch, var(--bk-success) 72%, var(--mkt-ink));
  /* ── featured (paid placement) — amber, tuned to cream; ≠ verified green ── */
  --mkt-featured:      #8F6400;
  --mkt-featured-soft: color-mix(in srgb, var(--mkt-featured) 12%, var(--mkt-canvas));
  /* ── sale/promo (Wave A 2026-07-04) — a restrained red tuned to the cream
       canvas, distinct from cognac accent + amber featured; ≥4.5:1 on canvas.
       Used ONLY for a discounted card's promo price (struck original stays in
       muted ink). Never applied to a masked/contact figure. ── */
  --mkt-sale:          #B42318;
  /* ── radius — mapped 1:1 §4.0 ── */
  --bk-radius:12px; --bk-radius-sm:6px; --bk-radius-md:10px;
  --bk-radius-lg:12px; --bk-radius-xl:18px; --bk-radius-pill:999px;
  /* ── elevation — §6.1 pattern, tinted with the surface accent (cognac) ── */
  --mkt-elev-card:
    0 1px 2px 0  color-mix(in oklch, var(--mkt-accent) 7%, transparent),
    0 4px 14px 0 color-mix(in oklch, var(--mkt-accent) 9%, transparent);
  --mkt-elev-float:
    0 2px 6px 0   color-mix(in oklch, var(--mkt-accent) 9%,  transparent),
    0 8px 24px 0  color-mix(in oklch, var(--mkt-accent) 12%, transparent),
    0 24px 48px 0 color-mix(in oklch, var(--mkt-accent) 7%,  transparent);
  /* ── motion — mapped 1:1 §4.4 ── */
  --bk-ease-spring:cubic-bezier(.34,1.56,.64,1);
  --bk-ease-standard:cubic-bezier(.2,0,0,1);
  --bk-dur-enter:200ms; --bk-dur-exit:140ms;
  /* ── z ladder — §6.4. KEEP --z-dropdown 1200 for the filter listbox (custom mkDD). ── */
  --z-sticky:1100; --z-dropdown:1200; --z-float:1300;
  /* ── type — §3.1 luxury template. Cormorant Garamond display face. ── */
  --font-display:'Cormorant Garamond','Sarabun',Georgia,serif;
  /* Thai display face — §3.1 CRITICAL: Cormorant has NO Thai glyphs, so Thai
     display text (e.g. the Wave C1 hero headline) MUST NOT be set in Cormorant.
     Sarabun/Noto Sans Thai carry the Thai display type instead. */
  --font-thai-display:'Sarabun','Noto Sans Thai',system-ui,-apple-system,sans-serif;
  --font-body:'Plus Jakarta Sans','Noto Sans Thai',system-ui,-apple-system,sans-serif;
  --price-font: var(--font-body);   /* price uses tabular Plus Jakarta, NOT Bebas (see §3) */
  --container-w:1360px;

  /* ── back-compat aliases (legacy downstream selectors still reference these;
       renamed opportunistically as each section is re-skinned) ── */
  --brand-primary:       var(--mkt-accent);
  --brand-primary-ink:   var(--mkt-accent-ink);
  --brand-primary-hover: var(--mkt-accent-hover);
  --brand-primary-active:var(--mkt-accent-active);
  --brand-primary-soft:  var(--mkt-accent-soft);
  --brand-primary-tint:  var(--mkt-accent-soft);
  --brand-primary-ring:  var(--mkt-accent-ring);
  --accent:              var(--mkt-accent);
  --bk-surface-0:        var(--mkt-canvas);
  --bk-surface-1:        var(--mkt-surface-1);
  --bk-surface-2:        var(--mkt-surface-2);
  --bk-surface-inset:    var(--mkt-surface-inset);
  --bk-ink:              var(--mkt-ink);
  --bk-ink-muted:        var(--mkt-ink-muted);
  --bk-ink-subtle:       var(--mkt-ink-muted);
  --text:                var(--mkt-ink);
  --text-mute:           var(--mkt-ink-muted);
  --border:              var(--mkt-line);
  --bk-success-soft:     var(--mkt-success-soft);
  --bk-elev-base:        0 1px 0 0 color-mix(in oklch, var(--mkt-accent) 4%, transparent);
  /* Legacy elevation names → the cognac --mkt-elev-* values above. Five
     selectors (.mk-dd-list / .mk-shop-strip / .mk-modal / .mk-pdp-main /
     .mk-pdp-shopcard) still consume these; without the alias their box-shadow
     computed to `none` (Wave B regression fix). */
  --bk-elev-card:        var(--mkt-elev-card);
  --bk-elev-float:       var(--mkt-elev-float);
  --display-font:        var(--font-display);
  --body-font:           var(--font-body);
  --card-radius:         var(--bk-radius-md);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bk-surface-0);
  color: var(--text);
  font-family: var(--body-font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { font-family: var(--display-font); }
/* §3.3 — Thai NEVER gets negative tracking. !important is the §3.3-prescribed
   form (Wave-1 2026-07-07 fix): without it, later same-specificity display
   rules (e.g. .mk-pdp-name's -0.01em) beat this by source order and silently
   tracked Thai product names negative. Latin-only lines opt back in via an
   explicit lang="en" (which un-matches :lang(th)). */
:lang(th) { letter-spacing: 0 !important; }

.mk-wrap { max-width: var(--container-w); margin: 0 auto; padding: 0 16px; }

/* ── Marketplace v2 (Wave B) — global grammar ported from the mock ────────── */
.mk-ic { width: 20px; height: 20px; stroke-width: 2; flex: none; }
/* display type — Cormorant; Thai display falls to Sarabun (§3.3 no negative
   tracking on Thai). English display gets tight tracking via [lang="en"]. */
.mk-display { font-family: var(--font-display); font-weight: 500; letter-spacing: 0; text-wrap: balance; overflow-wrap: anywhere; }
[lang="en"].mk-display, .mk-display [lang="en"] { letter-spacing: -0.02em; }
.price { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }
:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: 2px; border-radius: var(--bk-radius-sm); }

/* ── Topbar ─────────────────────────────────────────────────────── */
/* ── Topbar (v2.1 NAV RESTRUCTURE) — slim + sticky on both platforms ──
   Wordmark left · loupe / เปิดร้าน / profile right. Sticky above the (also
   sticky) filter bar; both share the --z-sticky ladder (§6.4) with the topbar
   winning by source order. Solid surface + hairline base shadow (§6.1). */
.mk-topbar {
  position: sticky; top: 0; z-index: calc(var(--z-sticky) + 1);
  background: var(--bk-surface-2);
  box-shadow: var(--bk-elev-base);
  border-bottom: 1px solid var(--mkt-line-soft);
}
.mk-topbar-inner {
  max-width: var(--container-w); margin: 0 auto; padding: 8px 16px;
  display: flex; align-items: center; gap: 12px;
}
.mk-topbar-spacer { flex: 1 1 auto; }
.mk-brand {
  display: inline-flex; align-items: baseline; gap: 8px;
  font-family: var(--display-font); font-weight: 600;
  font-size: 20px; letter-spacing: -0.01em; color: var(--text);
  text-decoration: none;
}
.mk-brand .mk-brand-dot { color: var(--brand-primary); }

/* topbar nav cluster (v2.1) — loupe · เปิดร้าน · profile slot */
.mk-topnav { display: inline-flex; align-items: center; gap: 4px; }
/* §8.2 — every affordance ≥44px */
.mk-topnav-ic {
  display: grid; place-items: center; width: 44px; height: 44px; flex: none;
  border: 0; background: transparent; border-radius: var(--bk-radius-md);
  color: var(--mkt-ink-secondary); cursor: pointer;
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard),
              color var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-topnav-ic .mk-ic { width: 21px; height: 21px; }
.mk-topnav-ic:hover { background: var(--mkt-surface-inset); color: var(--mkt-ink); }
.mk-topnav-ic:active { transform: translateY(1px); }
.mk-topnav-ic:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: -2px; }
/* relocated seller CTA — restrained text link (RealReal "Sell With Us"). */
.mk-topnav-sell {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 12px; border-radius: var(--bk-radius-md);
  font-family: var(--body-font); font-size: 14px; font-weight: 600;
  color: var(--mkt-ink-secondary); text-decoration: none; white-space: nowrap;
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard),
              color var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-topnav-sell .mk-ic { width: 18px; height: 18px; color: var(--mkt-accent); flex: none; }
.mk-topnav-sell:hover { background: var(--mkt-accent-soft); color: var(--mkt-accent); }
.mk-topnav-sell:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: -2px; }
/* the label text hides on very narrow phones — the store glyph carries it. */
@media (max-width: 460px) {
  .mk-topnav-sell span { display: none; }
  .mk-topnav-sell { padding: 0; width: 44px; justify-content: center; }
}

/* ── Hero (Wave C1 — "Editorial depth", Option B pk-chosen 2026-07-04) ──────
   Generous asymmetric cream whitespace (more top than bottom); ONE focal
   element — the Thai headline. The eyebrow is REMOVED (DESIGN.md §3.5 eyebrow
   discipline). Editorial luxury comes from measure + whitespace + a single
   cognac accent keyword — NOT from setting Thai in Cormorant (§3.1 critical:
   Cormorant has no Thai glyphs). An optional Latin italic kicker (Cormorant is
   Latin-safe) sits quietly above. */
.mk-hero {
  padding: 40px 0 8px;
  /* Wave C1 (DESIGN.md §1): softer, OFF-CENTRE single-color cognac wash at ~4%
     (was a centred 7% bleed). One low-opacity single-stop radial, no multi-stop
     SaaS gradient — the wash reads as depth, not paint. */
  background:
    radial-gradient(120% 100% at 20% 0%,
      color-mix(in srgb, var(--mkt-accent) 4%, transparent),
      transparent 62%);
}
/* D2 hero (mock-matched) — editorial kicker + Thai h1 + quiet sub, left-aligned
   with asymmetric cream whitespace. §3.2 display scale, §3.5 sentence-case +
   trailing period, §3.1 Thai in Sarabun (never Cormorant). */
.mk-hero { padding: clamp(34px, 7vh, 60px) 0 clamp(18px, 3.5vh, 28px); }
.mk-hero-copy { max-width: 34ch; }
/* the ONE surviving eyebrow — Cormorant italic (Latin-only → §3.1 safe). */
.mk-hero-kick {
  margin: 0;
  font-family: var(--font-display); font-style: italic; font-weight: 500;
  font-size: clamp(16px, 4.6vw, 20px); letter-spacing: .01em;
  color: var(--mkt-accent);
}
.mk-hero-h1 {
  margin: 2px 0 0;
  font-family: var(--font-thai-display); font-weight: 700;
  font-size: clamp(26px, 6.6vw, 40px); line-height: 1.16; letter-spacing: 0;
  color: var(--mkt-ink); text-wrap: balance;
}
/* the ONE cognac accent phrase — the single restrained emphasis (§3.1). */
.mk-hero-word { color: var(--mkt-accent); }
.mk-hero-sub {
  margin: 8px 0 0;
  color: var(--mkt-ink-secondary);
  font-size: clamp(14px, 3.6vw, 16px);
  max-width: 52ch; text-wrap: pretty;
}

/* ── Search overlay (v2.1) — opened by the topbar loupe. Slim field in a
   lightweight top sheet (NOT a hero bar). Drives the same #mk-search-input. */
.mk-search-overlay {
  position: fixed; inset: 0; z-index: var(--z-float);
  background: color-mix(in srgb, var(--mkt-ink) 32%, transparent);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  display: flex; justify-content: center; align-items: flex-start;
  padding: clamp(16px, 8vh, 96px) 16px 16px;
  animation: mk-overlay-in var(--bk-dur-enter) var(--bk-ease-standard);
}
.mk-search-overlay[hidden] { display: none; }
@keyframes mk-overlay-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .mk-search-overlay { animation: none; } }
.mk-search-sheet {
  width: 100%; max-width: 640px;
  background: var(--mkt-surface-2);
  border: 1px solid var(--mkt-line-soft);
  border-radius: var(--bk-radius-xl);
  box-shadow: var(--mkt-elev-float);
  padding: 14px;
}

/* ── Unverified-shop gating (2026-07-03) — on-marketplace contact sheet ──────
   The buy/contact CTA of an UNVERIFIED (storefront-less) shop opens this bottom
   sheet on the marketplace surface (no storefront deep-link → no 404). Cream/
   cognac tokens; §4.4 bottom-sheet slide-up; §8.2 44px tap targets; §11.0 sprite
   icons. Mirrors the storefront openContactSheet chrome. */
.mk-contact-overlay {
  position: fixed; inset: 0; z-index: var(--z-float, 9000);
  background: color-mix(in srgb, var(--mkt-ink) 42%, transparent);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  display: flex; justify-content: center; align-items: flex-end;
  animation: mk-overlay-in var(--bk-dur-enter) var(--bk-ease-standard);
}
.mk-contact-sheet {
  width: 100%; max-width: 480px;
  background: var(--mkt-surface-2);
  border: 1px solid var(--mkt-line-soft);
  border-radius: var(--bk-radius-xl) var(--bk-radius-xl) 0 0;
  box-shadow: var(--mkt-elev-float);
  padding: 18px 18px calc(18px + env(safe-area-inset-bottom, 0px));
  max-height: 84vh; overflow-y: auto;
  animation: mk-sheet-up var(--bk-dur-enter) var(--bk-ease-spring);
}
@keyframes mk-sheet-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) {
  .mk-contact-overlay, .mk-contact-sheet { animation: none; }
}
.mk-contact-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; margin-bottom: 14px;
}
.mk-contact-title {
  font-family: var(--display-font, var(--body-font));
  font-size: 17px; font-weight: 700; color: var(--mkt-ink); letter-spacing: -0.01em;
}
.mk-contact-sub { font-size: 12.5px; color: var(--mkt-ink-muted); margin-top: 3px; }
.mk-contact-x {
  flex: 0 0 auto; width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--mkt-ink-muted);
  border-radius: var(--bk-radius-pill); cursor: pointer;
}
.mk-contact-x:hover { background: var(--mkt-surface-inset); color: var(--mkt-ink); }
.mk-contact-x svg { width: 18px; height: 18px; }
.mk-contact-body { display: flex; flex-direction: column; gap: 8px; }
.mk-contact-row {
  display: flex; align-items: center; gap: 12px;
  min-height: 52px; padding: 12px 14px;
  border: 1px solid var(--mkt-line); border-radius: var(--bk-radius-md);
  background: var(--mkt-surface-1);
  color: var(--mkt-ink); font-size: 14px; font-weight: 600;
  text-decoration: none; transition: background 140ms ease, border-color 140ms ease;
}
.mk-contact-row:hover { background: var(--mkt-accent-soft); border-color: var(--mkt-accent-ring); }
.mk-contact-ic { width: 22px; height: 22px; color: var(--mkt-accent); flex: 0 0 auto; }
.mk-contact-empty {
  padding: 20px; text-align: center; font-size: 13px; color: var(--mkt-ink-muted);
}
.mk-contact-copy {
  width: 100%; margin-top: 14px; min-height: 44px;
  background: var(--mkt-surface-inset); color: var(--mkt-ink);
  border: 1px solid var(--mkt-line);
}
.mk-contact-copy:hover { background: var(--mkt-accent-soft); }
/* Seller-header contact button reuses .mk-shop-visit chrome but as a <button>. */
.mk-shop-contact { cursor: pointer; font: inherit; }
/* ── Search box (drives ?q) ─────────────────────────────────────── */
.mk-search {
  display: flex; gap: 8px; align-items: stretch;
  width: 100%;
}
.mk-search-field {
  position: relative; flex: 1 1 auto; min-width: 0;
}
.mk-search-field svg {
  position: absolute; left: 16px; top: 50%; transform: translateY(-50%);
  width: 18px; height: 18px; color: var(--text-mute); pointer-events: none;
}
.mk-search input {
  width: 100%; min-height: 50px;
  padding: 10px 14px 10px 44px;
  font-family: var(--body-font); font-size: 16px; color: var(--text);
  background: var(--mkt-surface-inset);
  border: 1.5px solid var(--border);
  border-radius: 999px;
  transition: border-color 160ms ease, box-shadow 160ms ease;
}
.mk-search input::placeholder { color: var(--bk-ink-subtle); }
.mk-search input:hover { border-color: var(--text-mute); }
.mk-search input:focus-visible {
  outline: none; border-color: var(--mkt-accent);
  box-shadow: 0 0 0 3px var(--mkt-accent-ring);
}
.mk-search-close {
  display: grid; place-items: center; width: 50px; height: 50px; flex: none;
  border: 1px solid var(--mkt-line); background: var(--mkt-surface-1);
  border-radius: 50%; color: var(--mkt-ink-secondary); cursor: pointer;
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-search-close .mk-ic { width: 18px; height: 18px; }
.mk-search-close:hover { background: var(--mkt-surface-inset); }
.mk-search-close:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: 2px; }

.mk-footer-seller { margin: 0 0 10px; font-size: 13px; color: var(--text-mute); }
.mk-footer-seller a {
  color: var(--brand-primary); font-weight: 600; text-decoration: none;
}
.mk-footer-seller a:hover { text-decoration: underline; }

/* ── Buttons (§4.5) ─────────────────────────────────────────────── */
.mk-btn {
  min-height: 44px; padding: 10px 18px;
  border-radius: 999px; border: 1.5px solid transparent;
  font-family: var(--body-font); font-weight: 600; font-size: 15px;
  cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  transition: transform 160ms ease, background-color 160ms ease,
              border-color 160ms ease, box-shadow 160ms ease;
}
.mk-btn-primary { background: var(--brand-primary); color: var(--brand-primary-ink); }
.mk-btn-primary:hover  { background: var(--brand-primary-hover); }
.mk-btn-primary:active { background: var(--brand-primary-active); transform: translateY(1px); }
.mk-btn-ghost {
  background: var(--bk-surface-2); color: var(--text);
  border-color: var(--border);
}
.mk-btn-ghost:hover { border-color: var(--text-mute); }
.mk-btn:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }

/* ── Filter / sort bar (sticky) — Wave B cream skin (mock grid.html:219-243) ──
   v2.1: the topbar is NOW sticky, so the filter bar sticks BELOW it (offset by
   --mk-topbar-h, ~60px) instead of at top:0 — otherwise the two would overlap.
   Solid cream (no blur) with a soft hairline; the shop select + (disabled)
   verified toggle join sort/brand/cat. */
:root { --mk-topbar-h: 61px; }
.mk-filters {
  position: sticky; top: var(--mk-topbar-h); z-index: var(--z-sticky);
  background: var(--mkt-canvas);
  border-bottom: 1px solid var(--mkt-line-soft);
  margin-top: 12px;
}
.mk-filters-inner {
  max-width: var(--container-w); margin: 0 auto; padding: 12px 24px;
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
}
@media (max-width: 760px) { .mk-filters-inner { padding: 10px 16px; } }
.mk-select-wrap { position: relative; display: inline-flex; }
/* FIX 2 — the display:inline-flex above overrides the UA [hidden] rule, so the
   shop-filter wrap (grid-only) needs an explicit hide on the shop/pdp view. */
.mk-select-wrap[hidden] { display: none; }
.mk-select {
  -webkit-appearance: none; appearance: none;
  min-height: 44px; padding: 0 34px 0 16px;
  display: inline-flex; align-items: center;
  font-family: var(--body-font); font-size: 14px; font-weight: 500; color: var(--mkt-ink-secondary);
  background: var(--mkt-surface-2);
  border: 1px solid var(--mkt-line); border-radius: var(--bk-radius-md);
  cursor: pointer;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--mkt-ink-muted) 50%),
    linear-gradient(135deg, var(--mkt-ink-muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) center, calc(100% - 13px) center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard),
              border-color var(--bk-dur-exit) var(--bk-ease-standard),
              transform var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-select:hover { background: var(--mkt-surface-1); border-color: var(--mkt-ink-muted); }
.mk-select:active { transform: translateY(1px); }
.mk-select:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: 2px; }
/* ── Wave B fix 1 (2026-07-02) — custom filter dropdown ─────────────────
   The native <select> option popup rendered over the pill text (pk report).
   bk-marketplace.js enhances each pill into a button+listbox; the native
   select stays hidden as the state holder. Styling contract:
   §4.5 pill button (the button REUSES .mk-select so the pill look is
   byte-identical) · §6.4 --z-dropdown layer · §8.2 ≥44px option rows ·
   §8.3 reduced-motion-safe reveal · §4.14 panel overlays, nothing clips it
   (.mk-filters has no overflow) · §2.3 ink hierarchy / §2.5 brand accent. */
.mk-select-wrap.mk-dd-on > select { display: none; }   /* custom control took over */
.mk-dd-btn { text-align: left; }
.mk-dd-btn[aria-expanded="true"] { border-color: var(--brand-primary); }
.mk-dd-btn.is-filtering {                 /* an applied filter is visible at a glance */
  border-color: var(--brand-primary);
  background-color: color-mix(in oklch, var(--brand-primary) 8%, var(--bk-surface-2));
}
.mk-dd-list {
  position: absolute; top: calc(100% + 6px); left: 0;
  z-index: var(--z-dropdown);
  min-width: 100%; width: max-content; max-width: min(320px, 88vw);
  max-height: min(340px, 60vh); overflow-y: auto;
  margin: 0; padding: 6px; list-style: none;
  background: var(--bk-surface-2);
  border: 1.5px solid var(--border); border-radius: 14px;
  box-shadow: var(--bk-elev-float);
  animation: mk-dd-in 140ms ease;
}
@keyframes mk-dd-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {           /* §8.3 */
  .mk-dd-list { animation: none; }
}
.mk-dd-list:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }
.mk-dd-option {
  display: flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 8px 14px;               /* §8.2 touch target */
  border-radius: 9px;
  font-size: 14px; font-weight: 500; color: var(--text);
  cursor: pointer; white-space: nowrap;
}
.mk-dd-option.is-active {                            /* keyboard/hover highlight */
  background: color-mix(in oklch, var(--brand-primary) 8%, transparent);
}
.mk-dd-option[aria-selected="true"] {
  font-weight: 600; color: var(--brand-primary);
}
.mk-dd-option[aria-selected="true"]::before {
  content: "✓"; font-weight: 700; margin-right: 2px;
}
.mk-dd-option[aria-selected="false"]::before {
  content: ""; width: 12px;                          /* align labels under the check */
}

.mk-price-fields { display: inline-flex; align-items: center; gap: 6px; }
.mk-price-fields input {
  width: 96px; min-height: 44px;
  padding: 8px 12px; font-family: var(--body-font); font-size: 14px; color: var(--mkt-ink);
  background: var(--mkt-surface-inset);
  border: 1px solid var(--mkt-line); border-radius: var(--bk-radius-md);
  font-variant-numeric: tabular-nums;
}
.mk-price-fields input:focus-visible {
  outline: none; border-color: var(--mkt-accent);
  box-shadow: 0 0 0 3px var(--mkt-accent-ring);
}
.mk-price-fields .mk-dash { color: var(--mkt-ink-muted); }
.mk-filters .mk-spacer { flex: 1 1 auto; }
.mk-result-count { font-size: 13px; color: var(--mkt-ink-muted); font-variant-numeric: tabular-nums; }

/* ── Verified-only toggle (Wave C Piece 1, 2026-07-03) — mock .mk-ftoggle
   (grid.html:244-268). NOW LIVE: the backend threads verified_only through the
   shared _catalog_filter_clauses (grid + all facet counts), so a click filters
   server-side to green-badge (marketplace_badge='green') shops. Through Wave B
   this shipped disabled + data-wave="c" + aria-disabled + a "เร็วๆ นี้" chip
   (no backend param); those are gone now. The [disabled]/[aria-disabled]/.mk-soon
   rules below are kept but inert (no element carries them anymore). */
.mk-ftoggle {
  display: inline-flex; align-items: center; gap: 10px; flex: none;
  min-height: 44px; padding: 0 16px 0 12px; margin-left: auto; cursor: pointer;
  border: 1px solid var(--mkt-line); border-radius: var(--bk-radius-md);
  background: var(--mkt-surface-2);
  font-size: 14px; font-weight: 500; color: var(--mkt-ink-secondary);
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard),
              border-color var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-ftoggle .mk-ic { width: 18px; height: 18px; color: var(--mkt-ink-muted); transition: color var(--bk-dur-exit) var(--bk-ease-standard); }
.mk-ftoggle[disabled], .mk-ftoggle[aria-disabled="true"] { cursor: not-allowed; opacity: .72; }
.mk-ftoggle .mk-soon {
  font-size: 10.5px; font-weight: 600; letter-spacing: .02em;
  color: var(--mkt-ink-muted); background: var(--mkt-surface-inset);
  border: 1px solid var(--mkt-line-soft); border-radius: var(--bk-radius-sm);
  padding: 1px 7px;
}
.mk-switch {
  width: 40px; height: 22px; border-radius: var(--bk-radius-pill);
  background: color-mix(in oklch, var(--mkt-ink) 22%, var(--mkt-canvas));
  position: relative; flex: none;
  transition: background-color var(--bk-dur-enter) var(--bk-ease-standard);
}
.mk-switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgb(34 26 20/.25);
  transition: transform var(--bk-dur-enter) var(--bk-ease-spring);
}
/* aria-pressed="true" green-on styles carried from the mock (LIVE, Wave C Piece 1). */
.mk-ftoggle[aria-pressed="true"] { border-color: color-mix(in oklch, var(--bk-success) 40%, var(--mkt-line)); background: var(--mkt-success-soft); }
.mk-ftoggle[aria-pressed="true"] .mk-switch { background: var(--bk-success); }
.mk-ftoggle[aria-pressed="true"] .mk-switch::after { transform: translateX(18px); }
.mk-ftoggle[aria-pressed="true"] .mk-ic { color: var(--bk-success); }
.mk-ftoggle[aria-pressed="true"] span { color: var(--mkt-success-deep); }
/* ── Mobile filter bar (v2.1, issue #3) — compact horizontal-scroll pill row ──
   The old layout stacked every control full-width vertically (clunky). v2.1
   collapses them into ONE horizontally-scrolling row of pills (sort · brand ·
   category · ร้านค้า · price · verified) that overflows off-screen-right instead
   of pushing the grid down. All wiring is untouched — this is layout-only; the
   mkDD-enhanced selects, the shop filter (onFilterChanged), and the disabled
   verified toggle all keep their exact DOM + handlers. Desktop bar unchanged. */
/* v2.1 FIX (2026-07-03): the earlier horizontal-scroll approach put
   `overflow-x:auto` + `mask-image` on .mk-filters-inner — but that element is
   the positioning ANCESTOR of the mkDD `.mk-dd-list` panels (position:absolute
   inside a .mk-select-wrap child), so the overflow/mask established a clip
   context that clipped every dropdown to the ~64px pill row (only the first
   option showed = filtering broken). The bk-marketplace.css contract literally
   requires ".mk-filters has no overflow". Fix: NO overflow/clip on the ancestor
   — the compact pills simply WRAP to two rows. Dropdowns open unclipped; all
   wiring untouched. This is still far more compact than the old full-width
   vertical stack (pills size to content). Desktop bar unchanged. */
@media (max-width: 760px) {
  .mk-filters-inner {
    flex-wrap: wrap; align-items: center; gap: 8px;
    /* explicitly NO overflow / NO mask here — see comment above. */
  }
  /* compact the pills so two rows fit cleanly under the sticky bar. */
  .mk-select { min-height: 40px; padding: 0 30px 0 12px; font-size: 13px; }
  .mk-price-fields { gap: 4px; }
  .mk-price-fields input { min-height: 40px; width: 84px; font-size: 13px; }
  /* the flexible spacer collapses so the pills pack tight; the result count
     drops to its own full-width line at the end of the wrap. */
  .mk-filters .mk-spacer { display: none; }
  .mk-result-count { flex-basis: 100%; order: 99; margin-top: 2px; }
  .mk-ftoggle { min-height: 40px; margin-left: 0; gap: 8px; }
}

/* ════ Featured shelf (Wave B, FORK B) — คัดพิเศษประจำวัน 2×2 infinite carousel.
   Static 16-item shelf (4 pages × 2×2) hand-authored in marketplace.html,
   driven by the ported JS carousel + per-card rotator. Ported VERBATIM from
   the mock (grid.html:137-216). The amber "แนะนำ" tag (--mkt-featured) is
   visually + textually distinct from the green verified shield (invariant). ══ */
.mk-shelf {
  margin: 26px auto 8px; max-width: var(--container-w);
  background: var(--mkt-surface-1);
  border: 1px solid var(--mkt-line-soft);
  border-radius: var(--bk-radius-xl);
  box-shadow: var(--mkt-elev-card);
  padding: 24px 24px 22px;
}
.mk-shelf[hidden] { display: none; }
/* v2.1 (issue #5): the head is now ONLY the eyebrow "Special for you." (italic
   Cormorant) + a ">" affordance — the Thai h2 is gone.
   v2.1 FIX (2026-07-03): .mk-shelf-head is a flex ROW containing the head LINK
   (.mk-shelf-title, wrapping just the eyebrow + ">") and, as a SIBLING (not a
   child of the <a>), the .mk-shelf-ctrl arrow group — so an arrow click pages
   the carousel instead of following the head link. */
.mk-shelf-head {
  display: flex; align-items: center; gap: 8px; margin-bottom: 10px;
}
.mk-shelf-title {
  display: inline-flex; align-items: center; gap: 8px;
  text-decoration: none; color: inherit; border-radius: var(--bk-radius-sm);
}
.mk-shelf-title:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: 4px; }
.mk-shelf-head h2 { font-size: clamp(23px, 2.5vw, 30px); line-height: 1.2; margin: 0; }
.mk-shelf-eyebrow {
  font-family: var(--font-display); font-style: italic; font-weight: 500;
  font-size: clamp(22px, 2.6vw, 30px); line-height: 1.15;
  color: var(--mkt-ink); letter-spacing: .01em;
}
/* the ">" affordance next to the eyebrow (mock cue that the shelf links onward) */
.mk-shelf-more {
  display: inline-grid; place-items: center; width: 26px; height: 26px; flex: none;
  color: var(--mkt-accent);
  transition: transform var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-shelf-more .mk-ic { width: 18px; height: 18px; }
.mk-shelf-title:hover .mk-shelf-more { transform: translateX(3px); }
.mk-shelf-ctrl { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.mk-shelf-arrow {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  display: grid; place-items: center; color: var(--mkt-ink-secondary);
  background: var(--mkt-surface-2); border: 1px solid var(--mkt-line);
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard),
              border-color var(--bk-dur-exit) var(--bk-ease-standard),
              transform var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-shelf-arrow:hover { background: var(--mkt-surface-1); border-color: var(--mkt-ink-muted); }
.mk-shelf-arrow:active { transform: translateY(1px); }
.mk-shelf-arrow .mk-ic { width: 18px; height: 18px; }
/* viewport clips the sliding track; each "page" = one 2×2 block. FULL shelf
   width (Wave B defect-2 fix): the 2×2 page spans the whole shelf so each
   .mk-feat is ~half the shelf (large 2-up editorial cards, no dead right-hand
   gutter) — matches the approved grid-desktop-top.png intent. */
.mk-carousel { position: relative; overflow: hidden; margin-top: 14px; }
.mk-track { display: flex; will-change: transform; transition: transform 480ms var(--bk-ease-standard); touch-action: pan-y; }
.mk-track.no-anim { transition: none; }
.mk-page {
  flex: 0 0 100%; min-width: 100%;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 20px;
  padding: 2px 2px 4px;
}
.mk-carousel-dots { display: flex; justify-content: center; gap: 7px; margin-top: 14px; }
.mk-cdot {
  width: 7px; height: 7px; border-radius: 50%; flex: none; padding: 0; border: 0;
  background: color-mix(in oklch, var(--mkt-ink) 22%, var(--mkt-canvas));
  transition: background-color 260ms var(--bk-ease-standard), transform 260ms var(--bk-ease-standard);
}
.mk-cdot.is-on { background: var(--mkt-accent); transform: scale(1.15); }
/* featured card = SAME grammar/size as a grid card, plus amber แนะนำ tag + crossfade. */
.mk-feat {
  position: relative;
  background: var(--mkt-surface-1);
  border: 1px solid var(--mkt-line-soft);
  border-radius: var(--bk-radius-lg);
  /* FIX 3 (2026-07-04) — clip any residual overshoot so a long 7-digit price row
     can never spill past the rounded card edge (the media already rounds via its
     own overflow:hidden; the body content stays inside this box). */
  overflow: hidden;
  box-shadow: var(--mkt-elev-card);
  transition: transform var(--bk-dur-enter) var(--bk-ease-standard),
              box-shadow var(--bk-dur-enter) var(--bk-ease-standard);
}
.mk-feat:hover { transform: translateY(-3px); box-shadow: var(--mkt-elev-float); }
.mk-feat-media {
  /* Wave B defect-2: full-width shelf makes each card ~half the shelf (~560px);
     a 5/4 landscape media keeps the large 2-up cards from becoming absurdly
     tall (a 4:5 portrait at 560px would be ~700px tall). */
  position: relative; display: block; aspect-ratio: 5/4; overflow: hidden;
  border-radius: var(--bk-radius-lg) var(--bk-radius-lg) 0 0;
  background: var(--mkt-surface-inset);
}
.mk-feat-media img { width: 100%; height: 100%; object-fit: cover; }
/* crossfade stack — swaps SKU/image every 6s. */
.rot-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 700ms var(--bk-ease-standard); }
.rot-img.is-on { opacity: 1; }
.mk-media-tone { position: absolute; inset: 0; pointer-events: none; background: var(--mkt-canvas); mix-blend-mode: multiply; opacity: .16; }
.mk-media-shade { position: absolute; inset: 0; pointer-events: none; background: linear-gradient(to top, rgb(34 26 20/.28), transparent 30%); }
.mk-feat-tag {
  position: absolute; top: 9px; left: 9px; z-index: 2;
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--mkt-featured); color: #fff;
  font-size: 11px; font-weight: 600; letter-spacing: .03em;
  border-radius: var(--bk-radius-sm); padding: 3px 9px;
  box-shadow: 0 1px 3px rgb(34 26 20/.22);
}
.mk-feat-tag .mk-ic { width: 11px; height: 11px; fill: currentColor; stroke: none; }
.rot-dots { position: absolute; right: 9px; bottom: 9px; display: flex; gap: 5px; z-index: 2; }
.rot-dot { width: 5px; height: 5px; border-radius: 50%; background: #F5F0E6; opacity: .5; transition: opacity 300ms var(--bk-ease-standard); box-shadow: 0 0 2px rgb(34 26 20/.4); }
.rot-dot.is-on { opacity: 1; }
/* Wave B defect-2 — larger 2-up cards: scale the body type up on desktop
   (mobile overrides below keep it compact). */
.mk-feat-body { padding: 15px 18px 18px; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.mk-feat-brand { font-family: var(--font-display); font-size: 26px; font-weight: 600; line-height: 1.15; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mk-feat-name { font-size: 13.5px; color: var(--mkt-ink-secondary); line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mk-shop-row { display: flex; align-items: center; gap: 5px; font-size: 12.5px; color: var(--mkt-ink-muted); margin-top: 6px; min-width: 0; }
.mk-shop-row .mk-ic { width: 17px; height: 17px; color: var(--bk-success); flex: none; }
.mk-shop-row .mk-shop-glyph { width: 15px; height: 15px; color: var(--mkt-ink-muted); opacity: .75; flex: none; }
.mk-shop-row b { font-weight: 600; color: var(--mkt-ink-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Wave A (2026-07-04): featured foot mirrors the grid card — left group (contact
   pill or spacer) + price cluster pinned bottom-right via space-between. */
.mk-feat-foot { display: flex; align-items: flex-end; justify-content: space-between; gap: 6px; margin-top: 8px; }
.mk-feat-foot .mk-foot-left { display: flex; align-items: flex-end; flex-wrap: wrap; gap: 4px; min-width: 0; flex: 0 1 auto; }
/* FIX 3 (2026-07-04) — the price cluster (struck original + promo) must be allowed
   to SHRINK and, if it still cannot fit on one line, WRAP the struck original above
   the promo — rather than the old `flex:0 0 auto` nowrap that clipped the original's
   leading digits on a 7-digit ฿1,450,000 at 375px. */
.mk-feat-price-cluster { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: flex-end; gap: 4px 6px; min-width: 0; flex: 0 1 auto; }
.mk-feat-price { flex: 0 1 auto; min-width: 0; }
.mk-feat-price-cluster .mk-price-original { font-size: 13px; }
@media (max-width: 760px) { .mk-feat-price-cluster .mk-price-original { font-size: 11px; } }
.mk-feat-price {
  display: inline-flex; align-items: baseline; gap: 8px;
  font-size: 19px; font-weight: 600; text-align: right;
  font-variant-numeric: tabular-nums;
}
.mk-feat-price.mk-price-ask { font-weight: 600; color: var(--mkt-ink-secondary); font-size: 15px; }
/* v2.1 — masked featured price carries the SAME quiet "ติดต่อร้าน" pill as the
   grid card (Piece M), so '฿Nxx,xxx' + hint never run together.
   FIX 2 (2026-07-04) — Wave A moved this pill out of .mk-feat-price and into
   .mk-feat-foot > .mk-foot-left, so the old `.mk-feat-price .mk-contact-hint`
   scope stopped matching → the pill rendered as 16px dark body text wrapping to
   3 lines. Match it in BOTH the legacy and the new location. */
.mk-feat-price .mk-contact-hint,
.mk-feat-foot .mk-contact-hint {
  flex: 0 1 auto; min-width: 0;
  font-size: 11px; font-weight: 500; letter-spacing: 0.01em; line-height: 1.5;
  padding: 2px 8px; border-radius: var(--bk-radius-sm);
  color: var(--mkt-ink-muted);
  background: var(--mkt-surface-inset);
  border: 1px solid var(--mkt-line-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Wave R0 item 5 (2026-07-08) — featured rail RESIZE, desktop ≥1024: ONE row
   of 4 per page (was 2×2 with ~560px landscape heroes → a ~1,400px shelf).
   Portrait 4/5 media + compact type bring the shelf to ~560px so the grid is
   reachable without a scroll marathon. Layout-only: still 4 items per JS page
   — the carousel's arrows/dots/pages are untouched. (Placed AFTER the base
   .mk-feat-* rules: same specificity, so source order is load-bearing.) */
@media (min-width: 1024px) {
  .mk-page { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px 16px; }
  .mk-feat-media { aspect-ratio: 4/5; }
  .mk-feat-body { padding: 12px 14px 14px; }
  .mk-feat-brand { font-size: 19px; }
  .mk-feat-name { font-size: 12.5px; }
  .mk-feat-price { font-size: 16px; }
}
@media (max-width: 760px) {
  .mk-shelf { padding: 16px 14px 16px; border-radius: var(--bk-radius-lg); margin-left: 16px; margin-right: 16px; }
  .mk-shelf-head h2 { font-size: 22px; }
  /* Wave R0 item 5 (2026-07-08) — mobile: ONE horizontal row per page (was a
     tall 2×2). Same 4 items per JS page; the page itself lays out as a
     scroll-snapping column flow (~166px cards) the buyer swipes through
     natively — no JS pagination change. touch-action on the track widens from
     pan-y to pan-x+pan-y here so the browser owns the in-page horizontal pan
     (the carousel's own drag wiring stands down on ≤760px viewports — the
     SAME media query as this block; review FIX 1 in bk-marketplace.js). */
  .mk-track { touch-action: pan-x pan-y; }
  .mk-page {
    grid-template-columns: none; grid-auto-flow: column;
    grid-auto-columns: 166px; gap: 10px;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    padding: 2px 2px 8px;
    /* Review FIX 1 P3 (§9.4 restraint) — the snap row is a swipe surface,
       not a scroll pane: hide its scrollbar (snap points + the carousel dots
       already signal position). */
    scrollbar-width: none;
  }
  .mk-page::-webkit-scrollbar { display: none; }
  .mk-page .mk-feat { scroll-snap-align: start; }
  .mk-feat-media { aspect-ratio: 4/5; }
  .mk-feat-body { padding: 9px 10px 11px; gap: 2px; }
  .mk-feat-brand { font-size: 15px; }
  .mk-feat-name { font-size: 11px; }
  .mk-shop-row { font-size: 11px; margin-top: 4px; }
  .mk-shop-row .mk-ic { width: 15px; height: 15px; }
  .mk-shop-row .mk-shop-glyph { width: 14px; height: 14px; }
  .mk-feat-price { font-size: 14px; }
  .mk-feat-price.mk-price-ask { font-size: 12.5px; }
  /* FIX 3 (2026-07-04) — 7-digit luxury prices (฿1,290,000 struck ฿1,450,000)
     overflow the narrow 2-up featured card. Mirror the grid .mk-card-foot: stack
     the foot to a column so the price cluster gets the FULL card width instead of
     competing with the left pill for the same row. Price stays right-aligned. */
  .mk-feat-foot { flex-direction: column; align-items: stretch; gap: 4px; }
  .mk-feat-foot .mk-foot-left { flex: 0 0 auto; }
  .mk-feat-price-cluster { align-self: flex-end; flex-wrap: wrap; justify-content: flex-end; }
}

/* Wave R0 item 4 (2026-07-08): the float stack (seller-invite popup + docked
   "ขายกับ Bookku" pill + the dead hidden AI FAB) is DELETED — seller CTAs go
   4→2. The surviving seller entries are the topnav "เปิดร้าน" link + the
   footer seller line; their styles live with the topbar/footer sections. */

/* ════ Mobile floating-pill tab bar (<1024) — espresso frosted glass.
   v2.1 (issue #4): 4 tabs, and collapse-to-icon on scroll DOWN (labels fade,
   pill shortens; icons + ≥44px targets survive) — expand on scroll UP. The
   bk-floating-nav shrink-on-scroll pattern (DESIGN.md §4.15 / §1290), adapted
   to the marketplace's espresso glass. bk-marketplace.js toggles .is-compact. */
.mk-tabbar {
  --tab-espresso: color-mix(in oklch, var(--mkt-ink) 92%, black);
  --tab-gold:     #C89A5B;   /* cognac-gold, legible on espresso */
  display: none; position: fixed;
  left: clamp(12px, 4vw, 16px); right: clamp(12px, 4vw, 16px);
  bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
  z-index: var(--z-float);
  max-width: 520px; margin: 0 auto;
  align-items: stretch; gap: 2px; padding: 6px;
  border-radius: var(--bk-radius-pill);
  background: color-mix(in oklch, var(--tab-espresso) 58%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  box-shadow:
    inset 0 0 0 1px rgb(245 240 230/.14),
    0 1px 2px 0  rgb(20 14 9/.24),
    0 10px 28px 0 rgb(20 14 9/.26),
    0 20px 44px 0 rgb(20 14 9/.16);
  /* animate only padding + transform for the compact shrink (§8.3-safe). */
  transition: padding 180ms var(--bk-ease-standard), transform 180ms var(--bk-ease-standard);
  will-change: transform;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .mk-tabbar { background: color-mix(in oklch, var(--tab-espresso) 90%, transparent); }
}
.mk-tab {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: 52px; padding: 6px 4px; border-radius: calc(var(--bk-radius-md) + 2px);
  border: 0; background: transparent; font-family: inherit; cursor: pointer;
  font-size: 10.5px; font-weight: 600; letter-spacing: .01em; line-height: 1.1;
  color: color-mix(in oklch, #F7F2E9 74%, transparent); text-decoration: none;
  text-shadow: 0 1px 2px rgb(20 14 9/.35);
  -webkit-tap-highlight-color: transparent;
  transition: color 160ms var(--bk-ease-standard), background-color 160ms var(--bk-ease-standard);
}
.mk-tab .mk-ic { width: 22px; height: 22px; flex: none; }
/* label collapses on scroll-down (opacity/max-height only — no layout thrash). */
.mk-tab span {
  display: block; overflow: hidden; opacity: 1; max-height: 1.4em;
  transition: opacity 140ms var(--bk-ease-standard), max-height 180ms var(--bk-ease-standard);
}
.mk-tab.is-active { color: var(--tab-gold); }
.mk-tab.is-active span { font-weight: 700; }
.mk-tab:active { background: color-mix(in oklch, #F5F0E6 12%, transparent); }
.mk-tab:focus-visible { outline: 2px solid var(--tab-gold); outline-offset: -2px; border-radius: var(--bk-radius-pill); }

/* compact (scroll-down) — labels hide, pill shortens; icons + ≥44px stay (§8.2). */
.mk-tabbar.is-compact { padding: 4px; transform: translateY(2px); }
.mk-tabbar.is-compact .mk-tab { min-height: 44px; padding: 4px; }
.mk-tabbar.is-compact .mk-tab span { opacity: 0; max-height: 0; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {   /* §8.3 — no shrink glide */
  .mk-tabbar, .mk-tab, .mk-tab span { transition: none; }
  .mk-tabbar.is-compact { transform: none; }
}

/* desktop ≥1024: NO bottom bar (top bar covers it); <1024 shows it. */
@media (max-width: 1023px) {
  .mk-tabbar { display: flex; }
  /* clear the floating tab bar (Wave R0 item 4: the seller float stack that
     used to share this clearance is deleted; the bar itself still needs it). */
  body { padding-bottom: calc(88px + env(safe-area-inset-bottom, 0px)); }
}

/* ── Toast (Wave A 2026-07-04) — non-blocking snackbar for the "saved items"
   coming-soon tap. Bottom-centered, above the mobile tab bar, auto-dismisses. ── */
.mk-toast {
  position: fixed; left: 50%; bottom: 32px; transform: translate(-50%, 12px);
  z-index: calc(var(--z-float) + 2);
  max-width: min(88vw, 360px);
  padding: 11px 18px; border-radius: var(--bk-radius-pill);
  background: var(--mkt-ink); color: var(--mkt-canvas);
  font-family: var(--body-font); font-size: 14px; font-weight: 500; line-height: 1.4;
  text-align: center; box-shadow: var(--mkt-elev-float);
  opacity: 0; pointer-events: none;
  transition: opacity var(--bk-dur-enter) var(--bk-ease-standard),
              transform var(--bk-dur-enter) var(--bk-ease-standard);
}
.mk-toast.is-on { opacity: 1; transform: translate(-50%, 0); }
@media (max-width: 1023px) { .mk-toast { bottom: calc(env(safe-area-inset-bottom, 0px) + 92px); } }
@media (prefers-reduced-motion: reduce) { .mk-toast { transition: opacity var(--bk-dur-enter) linear; } }

/* ── Grid — 4-up desktop / 2-up mobile (D1-REV approved: 2-up on phone).
   Fixed column count (not intrinsic auto-fill) so the card rhythm matches the
   approved mock. */
.prod-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px 16px;
  padding: 8px 0 64px;
}
@media (max-width: 760px) {
  .prod-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 12px; }
}

/* ── Product card (Wave B) — re-skinned to the mock's .mk-card visual grammar
   (grid.html:280-324), re-targeted onto the REAL .prod-card two-anchor
   structure. The structural hooks (.prod-card / .prod-card-link / .mk-shop-link
   / .prod-price-row / .price / .mk-contact-hint) are KEPT — the SPA click
   router, _reqGen fence + Return Rail depend on them.
   .mk-card-media→.img · .mk-card-body→.meta. Card is a bordered cream tile
   with brand-tinted (cognac) elevation, image zoom on hover, brand-first
   display face, single-line name + shop, condition chip + price in the foot. */
.prod-card {
  position: relative;
  display: flex; flex-direction: column;
  background: var(--mkt-surface-1);
  border: 1px solid var(--mkt-line-soft);        /* hairline border on cream */
  border-radius: var(--bk-radius-md);
  box-shadow: var(--mkt-elev-card);
  overflow: hidden;
  color: inherit; text-decoration: none;
  container-type: inline-size;   /* meta text scales with card width (cqi) */
  transition: transform var(--bk-dur-enter) var(--bk-ease-standard),
              box-shadow var(--bk-dur-enter) var(--bk-ease-standard),
              border-color var(--bk-dur-enter) var(--bk-ease-standard);
}
.prod-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--mkt-elev-float);
  border-color: var(--mkt-line);
}
.prod-card-link {
  display: block; color: inherit; text-decoration: none;
}
.prod-card-link::after {          /* stretched product hit-area (whole card) */
  content: ""; position: absolute; inset: 0; z-index: 1;
}
.prod-card-link:focus-visible::after {
  outline: 3px solid var(--mkt-accent-ring); outline-offset: -2px;
  border-radius: var(--bk-radius-md);
}
.prod-card .img {
  position: relative; display: block;
  aspect-ratio: 1 / 1;            /* square-ish, fills width (mock .mk-card-media) */
  overflow: hidden;
  background: var(--mkt-surface-inset);
}
.prod-card .img img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 600ms var(--bk-ease-standard);
}
.prod-card:hover .img img { transform: scale(1.035); }
.prod-card .img .mk-noimg {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  color: var(--mkt-ink-muted);
}
.prod-card .img .mk-noimg svg { width: 34%; height: 34%; opacity: 0.5; }
/* image tone/shade overlays (mock .mk-media-tone/.mk-media-shade), optional. */
.prod-card .mk-media-tone { position: absolute; inset: 0; pointer-events: none; background: var(--mkt-canvas); mix-blend-mode: multiply; opacity: .16; }
.prod-card .mk-media-shade { position: absolute; inset: 0; pointer-events: none; background: linear-gradient(to top, rgb(34 26 20/.28), transparent 30%); }

/* Trust badge (legacy overlay chip) — retained ONLY for the seller-page
   header inline chip (.mk-badge-inline); on cards the verified mark is now the
   green SHIELD beside the shop name (badgeHtml renders .mk-shop-verified). */
.mk-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.01em;
  padding: 4px 9px; border-radius: var(--bk-radius-sm);
  line-height: 1.3;
}
.mk-badge svg { width: 12px; height: 12px; flex: 0 0 auto; }
.mk-badge-green { background: var(--mkt-success-soft); color: var(--mkt-success-deep); }
.mk-badge-gray  { background: var(--mkt-surface-inset); color: var(--mkt-ink-muted); }
/* Journey Phase 2 — the SAME trust chip in normal flow (seller-page header /
   compact bar). One renderer (badgeHtml), two placements. */
.mk-badge.mk-badge-inline {
  position: static; pointer-events: auto;
  box-shadow: none;
  font-size: 12px; padding: 5px 10px;
  max-width: none;
}

/* ── Seller page (Journey Phase 2, 2026-07-02) — DESIGN.md §2.1 apex chrome,
   §4.2-adjacent header strip, §8.2 targets, §6.4 z-ladder ─────────────────
   Header strip above the standard grid: parent-only crumb, monogram avatar,
   shop name (display face), trust chip + product count, and a small
   "เยี่ยมชมหน้าร้านเต็ม ↗" storefront exit. Collapses to the fixed compact
   bar on mobile scroll (body.mk-compact-on, IO-toggled). */
.mk-shop-header {
  padding: 18px 0 4px;
  background:
    radial-gradient(120% 90% at 50% -10%,
      color-mix(in oklch, var(--brand-primary) 8%, transparent),
      transparent 60%);
}
.mk-shop-header[hidden] { display: none; }
.mk-shop-crumb { font-size: 14px; margin-bottom: 10px; }
.mk-shop-crumb a {
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 4px 10px 4px 0;   /* §8.2 tap row */
  color: var(--text-mute); font-weight: 600; text-decoration: none;
  transition: color 140ms ease;
}
.mk-shop-crumb a:hover { color: var(--brand-primary); }
.mk-shop-crumb a:focus-visible {
  outline: 3px solid var(--brand-primary-ring); outline-offset: 2px;
  border-radius: 8px;
}
.mk-shop-strip {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px;
  background: var(--bk-surface-1);
  border: 1px solid var(--border);
  border-radius: 18px;                 /* §4.0 xl ceiling */
  box-shadow: var(--bk-elev-card);
}
.mk-shop-avatar {
  width: 52px; height: 52px; flex: 0 0 auto;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand-primary-soft); color: var(--brand-primary);
  font-family: var(--display-font); font-weight: 600; font-size: 22px;
}
.mk-shop-id { flex: 1 1 auto; min-width: 0; }
.mk-shop-name {
  margin: 0 0 4px; font-weight: 500;
  font-size: clamp(20px, 5vw, 28px); line-height: 1.15;
  letter-spacing: -0.01em; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mk-shop-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
}
.mk-shop-count { font-size: 13px; color: var(--text-mute); font-variant-numeric: tabular-nums; }
.mk-shop-visit {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 4px;
  min-height: 44px; padding: 8px 14px;          /* §8.2 */
  border-radius: 999px; border: 1.5px solid var(--border);
  background: var(--bk-surface-2);
  font-size: 13px; font-weight: 600; color: var(--text-mute);
  text-decoration: none; white-space: nowrap;
  transition: color 140ms ease, border-color 140ms ease;
}
.mk-shop-visit:hover { color: var(--brand-primary); border-color: var(--brand-primary); }
.mk-shop-visit:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }

/* ── Seller-header branding (Lite arc, 2026-07-10) ──────────────────────────
   Shop logo, socials row and copy-link pill. The logo REPLACES the monogram
   .mk-shop-avatar (same 52px circle) rather than restyling it — .mk-shop-avatar
   is shared with the PDP shop-card (.mk-pdp-shopcard sizes it 44px), which is
   out of scope here. Marketplace cream/cognac surface tokens; §8.2 44px tap
   targets on every social link; §11.0 sprite icons (self-coloured via
   currentColor, so only `color` + box size are set here). */
.mk-shop-logo {
  width: 52px; height: 52px; flex: 0 0 auto;
  display: block;
  border-radius: 50%;
  object-fit: cover;                    /* non-square uploads crop, never squash */
  background: var(--brand-primary-soft);/* placeholder tint while the image loads */
  border: 1px solid var(--border);      /* hairline keeps white logos off a white surface */
}
.mk-shop-socials {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 2px;
  margin-top: 2px;
  margin-left: -10px;                   /* optical align: cancel the tap-box padding */
}
.mk-shop-social {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;            /* §8.2 — full 44×44 tap box */
  border-radius: 50%;
  color: var(--text-mute);
  text-decoration: none;
  transition: color 140ms ease, background-color 140ms ease;
}
.mk-shop-social:hover { color: var(--brand-primary); background-color: var(--brand-primary-soft); }
.mk-shop-social:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }
.mk-shop-social-ic { width: 20px; height: 20px; flex: 0 0 auto; }

/* Copy-link pill reuses .mk-shop-visit chrome as a <button> (same idiom as
   .mk-shop-contact). font-FAMILY only — a `font:` shorthand here would reset the
   13px/600 that .mk-shop-visit sets later in this file. */
.mk-shop-copy { cursor: pointer; font-family: inherit; }

/* Narrow screens: drop the two action pills onto their own row rather than let
   flexbox crush the shop name. .mk-shop-id ships min-width:0, so without a floor
   here the name would ellipsis away to nothing before the line ever broke —
   the min-width IS what forces the wrap; flex-wrap alone would not. The h1 keeps
   its own overflow/ellipsis, so a long name still truncates inside that floor. */
@media (max-width: 560px) {
  .mk-shop-strip { flex-wrap: wrap; }
  .mk-shop-id { min-width: 60%; }
  .mk-shop-visit { flex: 1 1 auto; justify-content: center; }
}

/* Mobile sticky compact bar — fixed at top while body.mk-compact-on (the full
   strip has scrolled out); the sticky filter bar shifts down beneath it so
   both stay usable. Mobile-only; desktop keeps the full header (it's short).
   transform/opacity only (§4.4 motion rule), reduced-motion covered by the
   global §8.3 block below. */
.mk-shop-compact {
  position: fixed; top: 0; left: 0; right: 0;
  z-index: calc(var(--z-sticky) + 1);
  display: none;
  align-items: center; gap: 8px;
  min-height: 48px; padding: 6px 12px;
  background: var(--bk-surface-2);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--bk-elev-base);
  transform: translateY(-100%);
  transition: transform 200ms cubic-bezier(0.2, 0, 0, 1);
}
.mk-shop-compact[hidden] { display: none; }
.mk-compact-back {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: 0 0 auto;   /* §8.2 */
  border-radius: 999px;
  color: var(--text); font-size: 22px; font-weight: 600;
  text-decoration: none;
  transition: background-color 140ms ease;
}
.mk-compact-back:hover { background: var(--bk-surface-inset); }
.mk-compact-back:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }
.mk-compact-name {
  flex: 1 1 auto; min-width: 0;
  font-weight: 600; font-size: 15px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 767px) {
  .mk-shop-compact:not([hidden]) { display: flex; }
  body.mk-compact-on .mk-shop-compact:not([hidden]) { transform: translateY(0); }
  body.mk-compact-on .mk-filters { top: 56px; }   /* slide under the compact bar */
}
@media (max-width: 639px) {
  /* Narrow phones: let the visit link wrap under the identity row. */
  .mk-shop-strip { flex-wrap: wrap; padding: 12px 14px; gap: 10px 12px; }
}

/* Empty/missing-state CTA can be a link (seller-page "ไปหน้าตลาด Bookku"). */
.mk-state a.mk-btn { text-decoration: none; }

/* card body (mock .mk-card-body) — flex column, brand-first display face. */
.prod-card .meta {
  padding: 9px 11px 11px;
  display: flex; flex-direction: column; gap: 2px; flex: 1;
}
/* brand — Cormorant display line, single line ellipsis (mock .mk-card-brand). */
.prod-card .mk-card-brand {
  font-family: var(--font-display);
  font-size: clamp(13.5px, 8cqi, 17px); font-weight: 600;
  line-height: 1.15; letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* name — single line, ellipsis (mock .mk-card-name; was 2-line clamp before). */
.prod-card .name {
  font-size: clamp(10.5px, 6cqi, 12px); color: var(--mkt-ink-secondary);
  line-height: 1.4; font-weight: 400; margin: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* shop line (mock .mk-card-shop) — verified shield OR store glyph + shop name.
   v2.1 (issue #1): the shop is a QUIET attribution line, clearly subordinate to
   the product identity (brand + name). Smaller + muted ink (≥4.5:1 on cream),
   regular weight, a hair more separation from the name above. The green verified
   shield stays inline when badge==='green'. */
.prod-card .mk-shop {
  display: flex; align-items: center; gap: 4px;
  font-size: clamp(9px, 4.4cqi, 10.5px); font-weight: 400;
  color: var(--mkt-ink-muted);
  margin-top: 5px; min-width: 0;
}
.prod-card .mk-shop .mk-shop-name {
  /* issue #1 ROOT CAUSE: the seller-page title rule `.mk-shop-name`
     (font-size: clamp(20px,5vw,28px), display face) was leaking onto the CARD
     shop span (same class), so the shop rendered LARGE and competed with the
     product. Force it back to the quiet attribution size + body font here. */
  font-family: var(--font-body);
  font-size: inherit; font-weight: 400; letter-spacing: 0; line-height: 1.3;
  margin: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--mkt-ink-muted);
}
.prod-card .mk-shop .mk-shop-glyph { width: 12px; height: 12px; flex: none; color: var(--mkt-ink-muted); opacity: .7; }
.prod-card .mk-shop .mk-ic-verified { width: 13px; height: 13px; flex: none; color: var(--bk-success); }
@media (max-width: 760px) {
  .prod-card .mk-shop .mk-shop-glyph,
  .prod-card .mk-shop .mk-ic-verified { width: 11px; height: 11px; }
}
/* Journey Phase 2 (2c) — the shop line stays a DISTINCT seller-page tap target
   (≥44px via padding + compensating negative margins), lifted above the
   stretched product link, reading as a link on hover/focus (cognac ink). */
a.mk-shop-link {
  position: relative; z-index: 2;
  min-height: 44px; padding: 12px 6px 12px 0;
  margin: -10px 0 -12px;
  text-decoration: none;
  transition: color 140ms ease;
}
a.mk-shop-link:hover, a.mk-shop-link:focus-visible {
  color: var(--mkt-accent); text-decoration: none;
}
a.mk-shop-link:hover .mk-shop-name,
a.mk-shop-link:focus-visible .mk-shop-name { text-decoration: underline; }
a.mk-shop-link:focus-visible {
  outline: 3px solid var(--mkt-accent-ring);
  outline-offset: -2px; border-radius: var(--bk-radius-sm);
}
/* bottom row (mock .mk-card-foot) — D2 (pk ruling 2026-07-08): condition grade
   is OFF the card (PDP only), so the foot has no left group. It is simply the
   price cluster pinned bottom-RIGHT — no wrap-to-column, no spacer. */
.prod-card .mk-card-foot {
  display: flex; align-items: flex-end; justify-content: flex-end;
  gap: 6px; margin-top: auto; padding-top: 8px; min-width: 0;
}
@media (max-width: 760px) { .prod-card .mk-card-foot { padding-top: 6px; } }
/* condition-grade chip (mock .mk-chip-cond) — quiet frosted micro-pill.
   Card no longer renders it; kept for the PDP twin (.mk-pdp-meta .mk-cond). */
.mk-cond {
  flex: none;
  font-size: clamp(9px, 4.4cqi, 10.5px); font-weight: 500; letter-spacing: 0.01em;
  line-height: 1.5;
  padding: 2px 7px; border-radius: var(--bk-radius-sm);
  color: var(--mkt-ink-secondary);
  background: var(--mkt-surface-inset);
  border: 1px solid var(--mkt-line-soft);
}
@media (max-width: 760px) { .mk-cond { font-size: 9px; padding: 1px 5px; } }
.prod-card .prod-price-row {
  display: flex; align-items: baseline; justify-content: flex-end;
  gap: 4px 6px; min-width: 0; flex: 0 1 auto;
}
/* FIX 3 (2026-07-04) — on a narrow 3-up grid card at 375px a 7-digit promo pair
   (฿1,450,000 struck + ฿1,290,000) cannot fit on ONE line; allow the row to wrap
   so the struck original drops onto its own line ABOVE the promo price instead of
   clipping its leading digits. Individual figures keep white-space:nowrap so no
   single number ever breaks mid-digit. */
@media (max-width: 760px) { .prod-card .prod-price-row { align-self: flex-end; flex-wrap: wrap; } }
.prod-card .prod-price-row .price {
  margin: 0; font-weight: 600;
  font-family: var(--price-font);
  font-size: clamp(11px, 7cqi, 14.5px);
  color: var(--mkt-ink);
  font-variant-numeric: tabular-nums;   /* §3.4 tabular */
  text-align: right; white-space: nowrap; flex: 0 0 auto;
}
/* Promo (Wave A 2026-07-04): struck ORIGINAL list price in muted gray, shown
   BEFORE the (red) promo price. Never rendered for masked/contact cards. */
.mk-price-original {
  font-family: var(--price-font);
  font-size: clamp(10px, 6cqi, 12px);
  color: var(--mkt-ink-muted);
  text-decoration: line-through;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; flex: 0 0 auto;
}
/* the discounted (effective) price rendered in the sale red. */
.price.mk-price-promo, .mk-feat-price.mk-price-promo { color: var(--mkt-sale); }
/* "สอบถามราคา" (contact-only, price-less) — the mock's .mk-price-ask look. */
.prod-card .prod-price-row .price.mk-price-ask {
  font-weight: 600; color: var(--mkt-ink-secondary);
  font-size: clamp(11px, 6cqi, 12.5px);
}
/* D2 masked price (§2.4 accent = action, §3.6 currency): a neutral '฿52x,xxx'
   figure preceded by a COMPACT cognac chat glyph that folds the "ติดต่อร้าน"
   affordance into the price cluster (replaces the old wide left pill). The glyph
   is decorative (aria-hidden); an .mk-sr label carries the meaning for AT.
   Canon: a masked card only ever emits the masked STRING — never an exact figure. */
.prod-card .prod-price-row .price.mk-card-price.is-masked {
  display: inline-flex; align-items: center; gap: 3px;
  color: var(--mkt-ink-secondary);
}
.prod-card .mk-ask-ic { width: 12px; height: 12px; flex: none; color: var(--mkt-accent); }
@media (max-width: 760px) { .prod-card .mk-ask-ic { width: 11px; height: 11px; } }
/* visually-hidden text for screen readers (the masked figure alone is ambiguous
   to a screen reader — restore the "ปกปิดราคา · ติดต่อร้าน" meaning). */
.mk-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* Piece M — retained for the PDP price-row twin (.mk-pdp-price-row) only; the
   card no longer emits .mk-contact-hint (masking folds into the price glyph). */
.prod-card .mk-contact-hint {
  flex: 0 1 auto; min-width: 0;
  font-size: clamp(9px, 4.4cqi, 10.5px); font-weight: 500;
  letter-spacing: 0.01em; line-height: 1.5;
  padding: 2px 7px; border-radius: var(--bk-radius-sm);
  color: var(--mkt-ink-muted);
  background: var(--mkt-surface-inset);
  border: 1px solid var(--mkt-line-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── States: loading skeleton / empty / error ──────────────────── */
.bk-skel {
  border-radius: 18px;
  background:
    linear-gradient(100deg,
      color-mix(in oklch, var(--brand-primary) 5%, var(--bk-surface-inset)) 30%,
      color-mix(in oklch, var(--brand-primary) 10%, var(--bk-surface-inset)) 50%,
      color-mix(in oklch, var(--brand-primary) 5%, var(--bk-surface-inset)) 70%);
  background-size: 200% 100%;
  animation: mk-shimmer 1.3s linear infinite;
}
.bk-skel-prod { aspect-ratio: 1 / 1; }
@keyframes mk-shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .bk-skel { animation: none; } }

.mk-state {
  grid-column: 1 / -1;
  text-align: center; padding: 48px 16px;
  color: var(--text-mute);
}
.mk-state svg { width: 64px; height: 64px; color: var(--bk-ink-subtle); margin-bottom: 12px; }
.mk-state h2 {
  margin: 0 0 6px; font-family: var(--display-font);
  font-weight: 500; font-size: 22px; color: var(--text);
}
.mk-state p { margin: 0 0 16px; font-size: 14px; }

/* Busy-retry spinner for the 429/503 auto-retry state (bk-marketplace.js
   renderBusy). Brand-token colours only — no raw hex (§2.5 / §9.4). Decorative
   (aria-hidden); the .mk-state text carries the message, so under reduced motion
   the ring simply stops — content stays fully readable (§8.3 / §8.6). */
.mk-spin {
  display: inline-block;
  width: 40px; height: 40px;
  margin-bottom: 12px;
  border-radius: 50%;
  border: 3px solid var(--brand-primary-soft);
  border-top-color: var(--brand-primary);
  animation: mk-spin 0.8s linear infinite;
}
@keyframes mk-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .mk-spin { animation: none; } }

/* ── Pagination ────────────────────────────────────────────────── */
.mk-more { text-align: center; padding: 16px 0 40px; }
.mk-more[hidden] { display: none; }

/* ── Footer ────────────────────────────────────────────────────── */
.mk-footer {
  margin-top: 24px; padding: 28px 16px 40px;
  border-top: 1px solid var(--border);
  color: var(--text-mute); font-size: 13px; text-align: center;
}
.mk-footer .mk-disclaimer { max-width: 60ch; margin: 8px auto 0; text-wrap: pretty; }
.mk-footer-links {
  margin: 12px auto 0; display: flex; gap: 8px 14px;
  align-items: center; justify-content: center; flex-wrap: wrap;
}
.mk-footer-links a {
  color: var(--text-mute); text-decoration: none;
  border-bottom: 1px solid transparent; transition: color 160ms ease, border-color 160ms ease;
}
.mk-footer-links a:hover { color: var(--brand-primary); border-bottom-color: var(--brand-primary-ring); }
.mk-footer-links .mk-dot { color: var(--bk-ink-subtle); }

/* ── Account chip in the topbar (logged-out button / logged-in identity) ──
   Bookku-blue chrome is intentional: the marketplace is the APEX cross-tenant
   surface (--brand-primary = trust-blue, see :root note above / DESIGN.md §2.1).
   §11.2's tenant-cascade "no Bookku-blue" rule governs CUSTOMER auth INSIDE a
   tenant shop.html — it does NOT apply to this apex chrome. */
.mk-account { display: inline-flex; align-items: center; gap: 8px; }
.mk-account-btn {                       /* logged-OUT: "เข้าสู่ระบบ / สมัคร" */
  min-height: 40px; padding: 8px 16px;
  border-radius: 999px; border: 1.5px solid transparent;
  background: var(--brand-primary); color: var(--brand-primary-ink);
  font-family: var(--body-font); font-weight: 600; font-size: 14px;
  cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px;
  transition: transform 160ms ease, background-color 160ms ease;
}
.mk-account-btn svg { width: 16px; height: 16px; }
.mk-account-btn:hover  { background: var(--brand-primary-hover); }
.mk-account-btn:active { background: var(--brand-primary-active); transform: translateY(1px); }
.mk-account-btn:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }
/* v2.1 NAV — logged-out profile is a QUIET icon-only button in the slim top nav
   (not the loud filled brand pill). §8.2 44px, §11.0 SVG glyph. */
.mk-account-btn.mk-account-icon {
  width: 44px; height: 44px; min-height: 0; padding: 0;
  justify-content: center; gap: 0;
  background: transparent; color: var(--mkt-ink-secondary);
  border-radius: var(--bk-radius-md);
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard),
              color var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-account-btn.mk-account-icon .mk-ic { width: 22px; height: 22px; }
.mk-account-btn.mk-account-icon:hover { background: var(--mkt-surface-inset); color: var(--mkt-ink); }
.mk-account-btn.mk-account-icon:active { background: var(--mkt-surface-inset); transform: translateY(1px); }
.mk-account-btn.mk-account-icon:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: -2px; }

/* Wave-1 (2026-07-07): the logged-IN identity pill (.mk-account-id) + the
   standalone .mk-logout-btn are GONE — replaced by one 44px icon trigger
   (reusing .mk-account-icon above) + the account MENU below. The monogram
   avatar survives as the menu header's identity mark. */
.mk-account-avatar {
  width: 26px; height: 26px; flex: 0 0 auto;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand-primary); color: var(--brand-primary-ink);
  font-weight: 700; font-size: 12px;
}
/* Signed-in trigger — a tiny presence dot distinguishes it from the visually
   identical signed-out icon (§11.0 pure-CSS, no second glyph). */
.mk-account-btn.mk-account-icon.is-authed { position: relative; }
.mk-account-btn.mk-account-icon.is-authed::after {
  content: ''; position: absolute; top: 8px; right: 8px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--bk-success);
  border: 2px solid var(--bk-surface-2);
}

/* ── Wave-1 (2026-07-07) — ACCOUNT MENU ─────────────────────────────────────
   Mobile ≤760px: a bottom sheet REUSING the .mk-contact-overlay/.mk-contact-
   sheet chrome (§4.4 slide-up — transform/opacity only; §8.2 44px rows).
   Desktop ≥761px: the .mk-acct-pop overrides turn the same markup into an
   anchored popover under the trigger (--z-dropdown per the §6.4 ladder). */
.mk-acct-sheet { padding: 10px 10px calc(12px + env(safe-area-inset-bottom, 0px)); }
.mk-acct-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px 12px;
  border-bottom: 1px solid var(--mkt-line-soft); margin-bottom: 6px;
}
.mk-acct-head .mk-account-avatar { width: 32px; height: 32px; font-size: 13px; }
.mk-acct-name {
  min-width: 0; font-size: 14.5px; font-weight: 700; color: var(--mkt-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mk-acct-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 44px; padding: 10px 12px;        /* §8.2 44px rows */
  border: 0; border-radius: var(--bk-radius-md);
  background: transparent; color: var(--mkt-ink);
  font-family: var(--font-body); font-size: 14.5px; font-weight: 600;
  text-align: left; text-decoration: none; cursor: pointer;
}
.mk-acct-item:hover { background: var(--mkt-accent-soft); }
.mk-acct-item:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: -2px; }
.mk-acct-count {
  margin-left: auto; min-width: 22px; padding: 1px 7px;
  border-radius: var(--bk-radius-pill);
  background: var(--mkt-accent-soft); color: var(--mkt-accent);
  font-size: 12px; font-weight: 700; text-align: center;
  font-variant-numeric: tabular-nums;          /* §3.4 — live saved count */
}
.mk-acct-sep { height: 1px; margin: 6px 4px; background: var(--mkt-line-soft); }
/* ออกจากระบบ — LAST row, quiet danger tint (--mkt-sale, the surface's only red). */
.mk-acct-logout { color: var(--mkt-sale); }
.mk-acct-logout:hover { background: color-mix(in srgb, var(--mkt-sale) 8%, var(--mkt-canvas)); }
@media (min-width: 761px) {
  /* Desktop popover: transparent full-viewport click-catcher at --z-dropdown
     (§6.4); the panel is fixed under the trigger (inline top/right from JS),
     zoom+fade in — transform/opacity only (§4.4). */
  .mk-acct-pop {
    display: block;
    background: transparent;
    -webkit-backdrop-filter: none; backdrop-filter: none;
    z-index: var(--z-dropdown);
    animation: none;
  }
  .mk-acct-pop .mk-acct-sheet {
    position: fixed; width: 264px; max-width: calc(100vw - 16px);
    max-height: calc(100dvh - 72px);
    border-radius: 14px; border: 1px solid var(--mkt-line-soft);
    padding: 8px;
    transform-origin: top right;
    animation: mk-acct-pop-in var(--bk-dur-enter) var(--bk-ease-spring);
  }
  .mk-acct-pop .mk-acct-head { padding-top: 8px; }
}
@keyframes mk-acct-pop-in {
  from { opacity: 0; transform: scale(0.95); }
  to   { opacity: 1; transform: scale(1); }
}

/* ── Auth modal (§4.4 dialog motion · §6.4 z-index ladder · §4.14 overlay) ──
   Native <dialog>-style centered modal (fixed-position, NOT absolute-in-overflow
   — §4.14 clipping ban). Backdrop = --z-modal-backdrop, card = --z-modal. */
.mk-modal-backdrop {
  position: fixed; inset: 0; z-index: 1200;      /* --z-modal-backdrop (§6.4) */
  background: color-mix(in oklch, var(--bk-ink) 55%, transparent);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
  animation: mk-fade-in var(--mk-dur-enter, 200ms) linear;
}
.mk-modal-backdrop[hidden] { display: none; }
.mk-modal {
  position: relative; z-index: 1300;              /* --z-modal (§6.4) */
  width: 100%; max-width: 420px;
  max-height: calc(100dvh - 32px); overflow-y: auto;
  background: var(--bk-surface-2);
  border-radius: 18px;                            /* §5 dialog radius ceiling */
  box-shadow: var(--bk-elev-float);               /* §6.1 brand-mixed float */
  padding: 24px 24px 22px;
  /* §4.4 zoom-in + fade, spring easing; transform/opacity only. */
  animation: mk-zoom-in var(--mk-dur-enter, 200ms) cubic-bezier(0.34, 1.56, 0.64, 1),
             mk-fade-in var(--mk-dur-enter, 200ms) linear;
}
@keyframes mk-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes mk-zoom-in { from { transform: scale(0.95); } to { transform: scale(1); } }

.mk-modal-close {
  position: absolute; top: 12px; right: 12px;
  width: 44px; height: 44px;                      /* §8.2 touch target */
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--text-mute);
  border-radius: 999px; cursor: pointer;
  transition: background-color 160ms ease, color 160ms ease;
}
.mk-modal-close:hover { background: var(--bk-surface-inset); color: var(--text); }
.mk-modal-close:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }
.mk-modal-close svg { width: 20px; height: 20px; }

.mk-modal h2 {
  margin: 0 4px 4px 0; padding-right: 28px;
  font-family: var(--display-font); font-weight: 500;
  font-size: 24px; letter-spacing: -0.01em; color: var(--text);
}
.mk-modal-sub { margin: 0 0 18px; font-size: 14px; color: var(--text-mute); }

/* Social auth buttons (Google / LINE) — full-width provider buttons */
.mk-oauth { display: flex; flex-direction: column; gap: 10px; }
.mk-oauth-btn {
  min-height: 48px; padding: 10px 16px;
  border-radius: 12px; border: 1.5px solid var(--border);
  background: var(--bk-surface-2); color: var(--text);
  font-family: var(--body-font); font-weight: 600; font-size: 15px;
  cursor: pointer; text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  transition: border-color 160ms ease, background-color 160ms ease, transform 160ms ease;
}
/* FIX 9 (2026-07-04 Wave C) — the `.mk-oauth-btn { display: inline-flex }` author
   rule beats the UA `[hidden]{display:none}`, so a hidden OAuth button (e.g. the
   pk-requested "hide Google" #mk-auth-google[hidden]) still paints. Restore the
   hide explicitly (mirrors .mk-shelf[hidden] above). `.mk-oauth-btn[hidden]` (0,1,1)
   outranks `.mk-oauth-btn` (0,1,0) on specificity, so it wins regardless of order. */
.mk-oauth-btn[hidden] { display: none; }
.mk-oauth-btn:hover  { border-color: var(--text-mute); }
.mk-oauth-btn:active { transform: translateY(1px); }
.mk-oauth-btn:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }
.mk-oauth-btn svg, .mk-oauth-btn img { width: 20px; height: 20px; flex: 0 0 auto; }
.mk-oauth-line { background: #06C755; color: #FFF; border-color: #06C755; }
.mk-oauth-line:hover { background: #05b34c; border-color: #05b34c; }

/* Divider between social + phone */
.mk-or {
  display: flex; align-items: center; gap: 12px;
  margin: 16px 0; color: var(--bk-ink-subtle); font-size: 12px;
}
.mk-or::before, .mk-or::after {
  content: ""; flex: 1 1 auto; height: 1px; background: var(--border);
}

/* Phone-OTP form */
.mk-field { margin: 0 0 12px; }
.mk-label { display: block; margin: 0 0 6px; font-size: 13px; font-weight: 600; color: var(--text); }
.mk-input {
  width: 100%; min-height: 48px;
  padding: 10px 14px;
  font-family: var(--body-font); font-size: 16px; color: var(--text);
  background: var(--bk-surface-2);
  border: 1.5px solid var(--border); border-radius: 12px;
  transition: border-color 160ms ease, box-shadow 160ms ease;
}
.mk-input::placeholder { color: var(--bk-ink-subtle); }
.mk-input:hover { border-color: var(--text-mute); }
.mk-input:focus-visible {
  outline: none; border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px var(--brand-primary-ring);
}
/* 2026-07-07 review fix — FUNCTIONAL tracking must survive the :lang(th)
   { letter-spacing: 0 !important } kill-switch at the top of this sheet (§3.3
   targets typographic tracking, not OTP digit separation; the inputs inherit
   lang="th" from <html>). Same specificity as :lang(th) (0,1,0), both
   !important → this later rule wins by source order. Audit of the marketplace
   surfaces found exactly TWO reliant elements: this auth-modal code input and
   marketplace-profile.html's #gate .otp-input (restored below — that page
   loads this sheet, and its own non-!important 8px rule loses to the
   kill-switch). Every other tracked element is cosmetic: Latin lines opt back
   in via lang="en"; Thai lines are MEANT to be untracked per §3.3. */
.mk-input-code { letter-spacing: 0.35em !important; font-variant-numeric: tabular-nums; text-align: center; }
#gate .otp-input { letter-spacing: 8px !important; }

.mk-btn-block { width: 100%; margin-top: 4px; }
.mk-btn[disabled], .mk-oauth-btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }

/* Inline hint / error under the OTP form */
.mk-hint { margin: 8px 0 0; font-size: 13px; color: var(--text-mute); }
.mk-error { margin: 8px 0 0; font-size: 13px; color: #B91C1C; }
.mk-error[hidden], .mk-hint[hidden] { display: none; }

/* "back to phone / resend" secondary link */
.mk-linkbtn {
  background: none; border: none; padding: 4px 2px; margin: 0;
  font-family: var(--body-font); font-size: 13px; font-weight: 600;
  color: var(--brand-primary); cursor: pointer; text-decoration: underline;
}
.mk-linkbtn:disabled { color: var(--text-mute); cursor: default; text-decoration: none; }
.mk-linkbtn:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; border-radius: 4px; }

/* Consent line (PDPA §1) — inline disclosure with a checkbox (not pre-ticked) */
.mk-consent {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 16px 0 4px; padding: 12px;
  background: var(--brand-primary-tint);
  border: 1px solid var(--border); border-radius: 12px;
  font-size: 12.5px; line-height: 1.55; color: var(--text-mute);
}
.mk-consent input[type="checkbox"] {
  flex: 0 0 auto; width: 20px; height: 20px; margin: 1px 0 0;
  accent-color: var(--brand-primary); cursor: pointer;
}
.mk-consent label { cursor: pointer; }
.mk-consent a { color: var(--brand-primary); font-weight: 600; text-decoration: underline; }

.mk-stage[hidden] { display: none; }

/* ── PDPA / legal pages (marketplace-privacy.html · marketplace-terms.html) ── */
.mk-legal {
  max-width: 760px; margin: 0 auto; padding: 32px 20px 64px;
}
.mk-legal .mk-legal-back {
  display: inline-flex; align-items: center; gap: 6px;
  margin-bottom: 20px; font-size: 14px; font-weight: 600;
  color: var(--brand-primary); text-decoration: none;
}
.mk-legal .mk-legal-back:hover { text-decoration: underline; }
.mk-legal .mk-legal-back svg { width: 16px; height: 16px; }
.mk-legal h1 {
  margin: 0 0 4px; font-weight: 500;
  font-size: clamp(26px, 6vw, 34px); line-height: 1.2; letter-spacing: -0.01em;
  color: var(--text);
}
.mk-legal .mk-legal-meta { margin: 0 0 28px; font-size: 13px; color: var(--text-mute); }
.mk-legal h2 {
  margin: 30px 0 8px; font-weight: 500;
  font-size: clamp(18px, 4.4vw, 22px); letter-spacing: -0.01em; color: var(--text);
}
.mk-legal p { margin: 0 0 12px; font-size: 15.5px; line-height: 1.7; color: var(--text); text-wrap: pretty; }
.mk-legal ul { margin: 0 0 12px; padding-left: 22px; }
.mk-legal li { margin: 0 0 8px; font-size: 15.5px; line-height: 1.7; color: var(--text); }
.mk-legal a { color: var(--brand-primary); font-weight: 600; }
.mk-legal .mk-legal-lead {
  padding: 14px 16px; margin: 0 0 24px;
  background: var(--brand-primary-tint); border: 1px solid var(--border);
  border-radius: 14px; font-size: 15px; color: var(--text-mute);
}
/* Visible placeholder token (e.g. {dpo_email}) — pk fills before launch (§ PDPA notes) */
.mk-token {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.92em; padding: 1px 6px; border-radius: 6px;
  background: color-mix(in oklch, var(--brand-primary) 10%, white);
  color: var(--brand-primary-active); white-space: nowrap;
}

/* ══ Journey Phase 3 (2026-07-02) — marketplace-native PDP ═══════════════
   /marketplace/p/<slug>?shop=<tid> inside the Bookku-blue apex shell
   (§2.1 brand axis · §2.2 cool-white canvas). Mobile-first single column
   (gallery → name/condition → price → CTA above the fold → merchant-of-
   record → shop card → description); two columns from 860px (§8.1). While
   the pdp owns the surface, body.mk-pdp-on hides the grid + filter bar —
   the footer (trust disclaimer) stays on every view. */
body.mk-pdp-on .mk-filters,
body.mk-pdp-on #mk-main { display: none; }

.mk-pdp-wrap { padding: 12px 16px 40px; }   /* pk 2026-07-11: restore the 16px side gutter (was 0 → edge-to-edge PDP) */
.mk-pdp-crumb { margin: 4px 0 10px; }        /* reuses .mk-shop-crumb type */

.mk-pdp-grid { display: grid; grid-template-columns: 1fr; gap: 18px; }
@media (min-width: 860px) {                   /* §8.1 desktop split */
  .mk-pdp-grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 32px; }
}

/* Gallery — full-bleed 1:1 cover like the cards (§4.2 media slot); resting
   card surface + soft elevation (§6.1 tier 1, radius ≤18px per the §1 ban). */
.mk-pdp-main {
  position: relative;                /* Wave-1 — anchors .mk-pdp-actions overlay */
  aspect-ratio: 1 / 1; overflow: hidden;
  border-radius: 18px; border: 1px solid var(--border);
  background: var(--bk-surface-1);
  box-shadow: var(--bk-elev-card);
  display: flex; align-items: center; justify-content: center;
}
/* Wave-1 (2026-07-07) — PDP gallery overlay actions: share + save, pinned
   top-right of the main image. Both are FULL 44px visual targets here (§8.2 —
   room allows; no hit-pad math needed) with the tier-1 card shadow (§6.1). */
.mk-pdp-actions {
  position: absolute; top: 12px; right: 12px; z-index: 3;
  display: flex; gap: 8px;
}
.mk-pdp-actions .mk-heart {
  /* relative, NOT static (2026-07-07 review fix). The global .mk-heart::before
     hit-pad is position:absolute — under a static button it anchored to the
     .mk-pdp-actions row and overlaid BOTH buttons, so every tap on the share
     button hit the heart instead (share was dead). relative keeps the flex-row
     layout, re-anchors the pad to the button itself (44px visual + 4px pad),
     and top/right:auto neutralize the base rule's card-pin offsets (which
     would otherwise apply as relative offsets). */
  position: relative; top: auto; right: auto;
  width: 44px; height: 44px;
  box-shadow: var(--mkt-elev-card);
}
.mk-pdp-actions .mk-heart .mk-heart-ic { width: 22px; height: 22px; }
.mk-pdp-share {
  width: 44px; height: 44px; padding: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--bk-radius-pill);
  border: 1px solid var(--mkt-line-soft);
  background: color-mix(in srgb, var(--mkt-surface-2) 82%, transparent);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  color: var(--mkt-accent); cursor: pointer;
  box-shadow: var(--mkt-elev-card);
  transition: transform var(--bk-dur-enter) var(--bk-ease-standard),
              border-color var(--bk-dur-enter) var(--bk-ease-standard);
}
.mk-pdp-share:hover { border-color: var(--mkt-accent); transform: translateY(-1px); }
.mk-pdp-share:focus-visible { outline: 2px solid var(--mkt-accent-ring); outline-offset: 2px; }
.mk-pdp-share .mk-ic { width: 20px; height: 20px; }
.mk-pdp-main img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mk-pdp-main .mk-noimg { width: 44%; height: 44%; color: var(--bk-ink-subtle); }
.mk-pdp-main .mk-noimg svg { width: 100%; height: 100%; }
/* pk 2026-07-11 — gallery prev/next arrows over the main image (multi-image
   products). Vertically centered on the L/R edges; mobile advances by swipe too. */
.mk-pdp-navbtn {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 40px; height: 40px; padding: 0; border-radius: var(--bk-radius-pill);
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--mkt-line-soft);
  background: color-mix(in srgb, var(--mkt-surface-2) 82%, transparent);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  color: var(--mkt-ink-secondary); cursor: pointer; box-shadow: var(--mkt-elev-card);
  transition: transform var(--bk-dur-enter) var(--bk-ease-standard),
              border-color var(--bk-dur-enter) var(--bk-ease-standard),
              color var(--bk-dur-enter) var(--bk-ease-standard);
}
.mk-pdp-navbtn:hover { border-color: var(--mkt-accent); color: var(--mkt-accent); }
.mk-pdp-navbtn:focus-visible { outline: 2px solid var(--mkt-accent-ring); outline-offset: 2px; }
.mk-pdp-navprev { left: 10px; }
.mk-pdp-navnext { right: 10px; }
.mk-pdp-navbtn .mk-ic { width: 18px; height: 18px; }
@media (prefers-reduced-motion: reduce) { .mk-pdp-navbtn { transition: none; } }
@media (max-width: 767px) { .mk-pdp-navbtn { width: 34px; height: 34px; } }
/* pk 2026-07-11 — the share sheet must sit ABOVE the mobile bottom tab bar
   (z-index 1300) so its copy-link button isn't covered; + clear the home-safe
   area at the sheet bottom. */
.mk-share-overlay { z-index: 1400; }
.mk-share-overlay .mk-contact-sheet { padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
.mk-pdp-thumbs { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.mk-pdp-thumb {
  width: 64px; height: 64px; padding: 0;      /* ≥44px tap target (§8.2) */
  border-radius: 12px; overflow: hidden; cursor: pointer;
  border: 2px solid var(--border); background: var(--bk-surface-1);
}
.mk-pdp-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mk-pdp-thumb.is-active { border-color: var(--brand-primary); }
.mk-pdp-thumb:focus-visible { outline: 3px solid var(--brand-primary-ring); outline-offset: 2px; }

/* Identity block — ink hierarchy per §2.3; taxonomy line stays muted meta. */
/* Wave-1 (2026-07-07) — brand eyebrow ABOVE the h1. Latin-only caps line
   (lang="en" in the JS — §3.3: positive tracking never touches Thai), quiet
   muted-cognac ink, ~13px. The brand LEFT the meta line so it never doubles. */
.mk-pdp-brand {
  margin: 0 0 4px;
  font-family: var(--font-body);
  font-size: 13px; font-weight: 600;
  letter-spacing: 0.02em;                     /* §3.3 caption-size positive tracking */
  text-transform: uppercase;
  color: var(--mkt-accent);                   /* muted cognac ink (§2.3 hierarchy) */
}
.mk-pdp-name {
  margin: 0 0 6px; font-weight: 700;
  font-size: clamp(20px, 5vw, 26px); line-height: 1.25;
  letter-spacing: -0.01em; color: var(--text);
}
.mk-pdp-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; }
.mk-pdp-meta .mk-cond { margin: 0; }
.mk-pdp-tax { font-size: 12.5px; color: var(--text-mute); }

/* Price — tabular ฿ digits (§3.4/§3.6, --price-font mirrors the cards);
   masked items reuse the card's contact-hint chip grammar (Piece M). */
.mk-pdp-price-row { display: flex; align-items: center; gap: 10px; margin: 12px 0 0; }
.mk-pdp-price {
  font-family: var(--price-font); font-weight: 700;
  font-size: clamp(24px, 6vw, 32px); color: var(--text);
  font-variant-numeric: tabular-nums;
}
.mk-pdp-price-row .mk-contact-hint {          /* pdp twin of the card chip */
  font-size: 11px; font-weight: 600; letter-spacing: 0.02em;
  padding: 3px 10px; border-radius: 999px;
  color: var(--bk-ink-muted);                  /* §2.3 muted ink ≥4.5:1 (§2.7) */
  background: color-mix(in oklch, var(--bk-ink-muted) 8%, white);
  border: 1px solid var(--border);
}

/* THE CTA (amendment #1) — the page's ONE primary action (§4.5 button
   states via .mk-btn-primary; §8.2 comfortable 52px target). Above the fold
   on the 375px reference viewport (§8.4). */
.mk-pdp-cta {
  display: flex; width: 100%; min-height: 52px;
  margin: 14px 0 0; font-size: 16.5px;
  text-decoration: none;
}
/* Expectation microcopy + merchant-of-record disclosure (amendment #9) —
   small but visible muted meta (§2.3; ≥4.5:1 per §2.7), never footer-tucked. */
.mk-pdp-micro { margin: 8px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--text-mute); }
.mk-pdp-mor {
  margin: 10px 0 0; font-size: 12.5px; font-weight: 600; color: var(--text-mute);
  padding: 6px 10px; border-radius: 10px;
  background: var(--brand-primary-tint); border: 1px solid var(--border);
  width: fit-content;
}

/* Shop card — seller identity BEFORE any click-out (§4.2 card grammar,
   §6.1 tier 1; monogram avatar + trust chip reuse the seller-page pieces). */
.mk-pdp-shopcard {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 0 0; padding: 12px 14px;
  background: var(--bk-surface-1); border: 1px solid var(--border);
  border-radius: 14px; box-shadow: var(--bk-elev-card);
}
.mk-pdp-shopcard .mk-shop-avatar { width: 44px; height: 44px; font-size: 18px; }
.mk-pdp-shopcard-id { flex: 1 1 auto; min-width: 0; }
.mk-pdp-shopname {
  font-weight: 600; font-size: 15px; color: var(--text);
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
}
.mk-pdp-shoplinks { display: flex; flex-wrap: wrap; gap: 2px 16px; margin-top: 2px; }
.mk-pdp-shoplinks a {
  display: inline-flex; align-items: center; gap: 3px;
  min-height: 44px; padding: 6px 0;            /* §8.2 row-height targets */
  margin: -8px 0;
  font-size: 13px; font-weight: 600; color: var(--brand-primary);
  text-decoration: none;
}
.mk-pdp-shoplinks a:hover, .mk-pdp-shoplinks a:focus-visible { text-decoration: underline; }
.mk-pdp-shoplinks a:focus-visible {
  outline: 3px solid var(--brand-primary-ring); outline-offset: -2px; border-radius: 8px;
}

/* Description — readable measure (§3.7) + preserved line breaks. */
.mk-pdp-desc { margin: 22px 0 0; }
.mk-pdp-desc h2 { margin: 0 0 8px; font-size: 15px; font-weight: 700; color: var(--text); }
.mk-pdp-desc p {
  margin: 0; max-width: 65ch;
  font-size: 14.5px; line-height: 1.75; color: var(--text);
  white-space: pre-line; overflow-wrap: anywhere;
}

/* ── Wave-1 (2026-07-07) — PDP spec sheet: "ข้อมูลสินค้า" ─────────────────
   §4.11 definition-list/table grammar: hairline-separated 2-col label/value
   rows on a resting card surface; values carry tabular figures (§3.4). */
.mk-pdp-spec { margin: 22px 0 0; }
.mk-pdp-spec h2 { margin: 0 0 8px; font-size: 15px; font-weight: 700; color: var(--text); }
.mk-spec {
  margin: 0;
  border: 1px solid var(--mkt-line-soft); border-radius: 14px;
  background: var(--mkt-surface-1);
  overflow: hidden;
}
.mk-spec-row {
  display: grid; grid-template-columns: minmax(110px, 38%) 1fr;
  gap: 4px 12px; padding: 9px 14px;
}
.mk-spec-row + .mk-spec-row { border-top: 1px solid var(--mkt-line-soft); }
.mk-spec dt { margin: 0; font-size: 13px; font-weight: 500; color: var(--mkt-ink-muted); }
.mk-spec dd {
  margin: 0; font-size: 13.5px; font-weight: 600; color: var(--mkt-ink);
  font-variant-numeric: tabular-nums;          /* §3.4 — numeric values align */
  overflow-wrap: anywhere;
}

/* Wave-1 — "อุปกรณ์ที่มี" line (d.authenticity): quiet secondary-ink meta. */
.mk-pdp-includes { margin: 10px 0 0; font-size: 13px; color: var(--mkt-ink-secondary); }

/* Wave-1 — seller highlight callout (d.highlight_description): a QUIET gold
   rule in the page's luxury idiom (--mkt-featured on its soft tint) above the
   description — §2.3 secondary ink, never a loud banner. */
.mk-pdp-highlight {
  margin: 22px 0 0; padding: 10px 14px;
  max-width: 65ch;                             /* §3.7 measure */
  border-left: 2px solid var(--mkt-featured);
  background: var(--mkt-featured-soft);
  border-radius: 0 10px 10px 0;
  font-size: 14px; line-height: 1.7; color: var(--mkt-ink-secondary);
  white-space: pre-line; overflow-wrap: anywhere;
}

/* Wave-1 — §4.3 empty-state stub when the seller wrote no description: icon
   in a soft rounded square (radius 14, accent-soft tint) + muted copy. */
.mk-pdp-desc-empty {
  display: flex; align-items: center; gap: 12px;
  padding: 14px; border-radius: 14px;
  background: var(--mkt-surface-1); border: 1px dashed var(--mkt-line);
  color: var(--mkt-ink-muted);
}
.mk-pdp-desc-empty p { margin: 0; font-size: 13.5px; line-height: 1.6; }
.mk-pdp-desc-empty-ic {
  flex: 0 0 auto; width: 44px; height: 44px; border-radius: 14px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--mkt-accent-soft); color: var(--mkt-ink-muted);
}
.mk-pdp-desc-empty-ic svg { width: 22px; height: 22px; }

/* ── Wave-1 — "สินค้าอื่นจากร้านนี้" related rail ──────────────────────────
   Full-width below the PDP grid: header row (h2 + ดูทั้งหมด → seller page),
   then a horizontal-scroll rail of the SAME .prod-card grammar the grid uses.
   Fixed card width via grid-auto-columns; snap for touch. */
.mk-pdp-related { margin: 28px 0 0; }
.mk-rel-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin: 0 0 10px;
}
.mk-rel-head h2 { margin: 0; font-size: 17px; font-weight: 700; color: var(--text); }
.mk-rel-more {
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 4px 0;            /* §8.2 row-height target */
  font-size: 13.5px; font-weight: 600; color: var(--mkt-accent);
  text-decoration: none; white-space: nowrap;
}
.mk-rel-more:hover, .mk-rel-more:focus-visible { text-decoration: underline; }
.mk-rel-rail {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: clamp(150px, 38vw, 200px);
  gap: 12px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  scrollbar-width: none;                 /* pk 2026-07-11: hide the gray scrollbar */
  padding: 4px 2px 12px;
}
.mk-rel-rail::-webkit-scrollbar { display: none; }
.mk-rel-rail .prod-card { scroll-snap-align: start; }
/* pk 2026-07-11 — edge-overlay prev/next arrows (reuse .mk-rail-arrow chrome).
   Desktop only; mobile scrolls by touch-swipe. */
.mk-rel-railwrap { position: relative; }
.mk-rel-arrow { position: absolute; top: 50%; transform: translateY(-50%); z-index: 3; box-shadow: var(--mkt-elev-card); }
.mk-rel-arrow[data-rail-prev] { left: -6px; }
.mk-rel-arrow[data-rail-next] { right: -6px; }
@media (max-width: 1023px) { .mk-rel-arrow { display: none; } }

/* Loading skeleton — reuses the §8.3-safe .bk-skel shimmer. */
.mk-pdp-skel-img { aspect-ratio: 1 / 1; }
.mk-pdp-skel-line { height: 22px; margin: 0 0 12px; border-radius: 8px; }
.mk-pdp-skel-cta { height: 52px; margin-top: 18px; border-radius: 14px; }

/* ── Operator-owned promo banners (Wave C3, 2026-07-04) ──────────────────
   Marketplace-wide TOP (below hero) + BOTTOM (before footer) banners the
   operator manages. "Not too big" (pk) — a slim editorial strip, NOT a hero.
   Cream canvas (§2.2 --mkt-canvas), dimensional card shadow (§6 / --mkt-elev-card),
   cognac hairline (§2.2 --mkt-line). Constrained to the .mk-wrap measure so it
   lines up with the hero + shelf + grid. The image scales responsively; a mobile
   crop (image_url_mobile) swaps in via <picture>. Fail-open: JS leaves the
   [hidden] section empty when there are no banners, so nothing paints. */
.mk-promo { padding: 0; }
.mk-promo[hidden] { display: none; }
.mk-promo .mk-wrap { padding-top: 0; padding-bottom: 0; }
.mk-promo-top    { margin: clamp(8px, 2vh, 20px) 0 clamp(4px, 1.5vh, 12px); }
.mk-promo-bottom { margin: clamp(20px, 4vh, 40px) 0 clamp(8px, 2vh, 16px); }
/* One or more stacked banners inside a placement (sort_order asc). */
.mk-promo__list { display: flex; flex-direction: column; gap: 12px; }
/* The banner card — a link (or a bare figure when no link_url). Clipped rounded
   card so the image corners follow the radius; §4.14 no absolute-in-overflow. */
.mk-promo__item {
  display: block;
  position: relative;
  border-radius: var(--bk-radius-lg, 16px);
  overflow: hidden;
  background: var(--mkt-surface-1);
  border: 1px solid var(--mkt-line-soft);
  box-shadow: var(--mkt-elev-card);
  text-decoration: none;
  line-height: 0;                 /* kill inline-image descender gap */
}
a.mk-promo__item { cursor: pointer; transition: box-shadow var(--bk-dur-enter, .18s) var(--bk-ease-standard, ease), transform var(--bk-dur-enter, .18s) var(--bk-ease-standard, ease); }
a.mk-promo__item:hover { box-shadow: var(--mkt-elev-float); transform: translateY(-1px); }
a.mk-promo__item:focus-visible { outline: 2px solid var(--mkt-accent); outline-offset: 2px; }
.mk-promo__img {
  display: block; width: 100%; height: auto;
  object-fit: cover;
}
/* "Not too big" height caps (§3.2). Top a touch taller than bottom; images with
   an intrinsic ratio are capped so a tall asset can't blow the strip up. */
.mk-promo-top    .mk-promo__img { max-height: 120px; }
.mk-promo-bottom .mk-promo__img { max-height: 100px; }
@media (max-width: 640px) {
  .mk-promo-top    .mk-promo__img { max-height: 96px; }
  .mk-promo-bottom .mk-promo__img { max-height: 84px; }
}
/* Optional caption overlay when a headline/subtext is supplied — a soft
   bottom-anchored ink scrim so text stays legible over any image (§2.7 contrast).
   Kept OUT of overflow-clipped absolute traps by living inside the clipped card. */
.mk-promo__cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 10px 16px;
  line-height: 1.25;
  color: #fff;
  background: linear-gradient(to top,
    color-mix(in srgb, var(--mkt-ink) 62%, transparent), transparent);
}
.mk-promo__head { font-family: var(--font-display); font-style: italic; font-weight: 500; font-size: clamp(15px, 2.4vw, 20px); }
.mk-promo__sub  { font-size: clamp(12px, 1.8vw, 14px); opacity: .92; }

/* ── "เปิดร้านฟรี" house promo — Direction A editorial card (2026-07-11, pk).
   Reuses the .mk-promo__item card chrome (rounded cream surface + hairline +
   hover lift); overrides line-height:0 (that was for images) and lays out a
   left cognac rule → kicker/headline stack → underlined-link CTA. Cream/cognac
   DESIGN.md §1.5; Cormorant kicker (Latin) + Sarabun Thai head (§3.1 — Thai is
   NEVER set in Cormorant). §8.2 the whole card is the 44px+ tap target. */
.mk-sellcta {
  display: flex; align-items: center;
  gap: clamp(16px, 2.6%, 34px);
  padding: clamp(16px, 2.2vw, 24px) clamp(20px, 4%, 60px);
  line-height: normal;                 /* undo .mk-promo__item line-height:0 */
  min-height: 80px;
}
.mk-sellcta__rule {
  flex: 0 0 auto; width: 2px; align-self: stretch;
  margin: clamp(10px, 1.6vw, 18px) 0;  /* inset the rule from the card edges */
  background: var(--mkt-accent); opacity: .55; border-radius: 2px;
}
.mk-sellcta__body { flex: 1 1 auto; min-width: 0; }
.mk-sellcta__kick {
  display: block;
  font-family: var(--font-display); font-style: italic; font-weight: 500;
  font-size: clamp(13px, 1.6vw, 18px); line-height: 1.3;
  color: var(--mkt-accent); letter-spacing: .01em;
}
.mk-sellcta__head {
  display: block;
  margin-top: 6px;                     /* pk fix: clear the kicker so Thai tone
                                          marks (ไม้เอก/โท) never touch it */
  font-family: var(--font-thai-display); font-weight: 700;
  font-size: clamp(19px, 3.2vw, 34px); line-height: 1.18;
  letter-spacing: -.005em; color: var(--mkt-ink);
}
.mk-sellcta__dot { color: var(--mkt-accent); }
.mk-sellcta__cta {
  flex: 0 0 auto;
  font-family: var(--font-thai-display); font-weight: 600;
  font-size: clamp(13px, 1.6vw, 18px); color: var(--mkt-accent);
  border-bottom: 1.5px solid var(--mkt-accent); padding-bottom: 3px;
  white-space: nowrap;
  transition: color var(--bk-dur-exit, .15s) var(--bk-ease-standard, ease),
              border-color var(--bk-dur-exit, .15s) var(--bk-ease-standard, ease);
}
.mk-sellcta__arrow { display: inline-block; transition: transform var(--bk-dur-exit, .15s) var(--bk-ease-standard, ease); }
a.mk-sellcta:hover .mk-sellcta__cta { color: var(--mkt-accent-hover); border-color: var(--mkt-accent-hover); }
a.mk-sellcta:hover .mk-sellcta__arrow { transform: translateX(3px); }
/* Mobile: the CTA drops under the copy so the headline keeps its size. */
@media (max-width: 560px) {
  .mk-sellcta { flex-wrap: wrap; gap: 10px 16px; padding: 16px; min-height: 0; }
  .mk-sellcta__rule { display: none; }
  .mk-sellcta__cta { flex-basis: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  a.mk-sellcta:hover .mk-sellcta__arrow { transform: none; }
}

/* ── §8.3 reduced-motion — collapse all animation/motion (paste block) ── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── Wave C2 (2026-07-04) — SAVE / HEART control on product cards ─────────────
   A subtle, cream/cognac save button pinned top-right of the card image. It is a
   REAL <button> (keyboard reachable, aria-pressed reflects state). Sits ABOVE the
   stretched .prod-card-link::after hit-area (z-index) so the tap toggles save and
   never triggers the card navigation. Empty = hollow cognac outline heart; saved =
   filled cognac. §8.2 44px EFFECTIVE tap target: 36px visual + the §8.7.2
   ::before hit-pad below (Wave-1 2026-07-07 — the old comment claimed 44px
   while the button was a bare 36px). */
.mk-heart {
  position: absolute; top: 8px; right: 8px; z-index: 3;
  width: 36px; height: 36px; padding: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--bk-radius-pill);
  border: 1px solid var(--mkt-line-soft);
  background: color-mix(in srgb, var(--mkt-surface-2) 82%, transparent);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  color: var(--mkt-accent); cursor: pointer;
  box-shadow: 0 1px 3px 0 color-mix(in oklch, var(--mkt-accent) 12%, transparent);
  transition: transform var(--bk-dur-enter) var(--bk-ease-standard),
              background var(--bk-dur-enter) var(--bk-ease-standard),
              border-color var(--bk-dur-enter) var(--bk-ease-standard);
}
/* §8.7.2 hit-pad — extends the HIT target 4px per side without growing the
   36px visual: 36 + 4×2 = 44px effective (§8.2). .mk-heart is already
   position:absolute, so the pad positions against the button itself. */
.mk-heart::before {
  content: ''; position: absolute; inset: -4px;
  background: transparent;
}
.mk-heart:hover { border-color: var(--mkt-accent); transform: translateY(-1px); }
.mk-heart:focus-visible {
  outline: 2px solid var(--mkt-accent-ring); outline-offset: 2px;
}
.mk-heart-ic {
  width: 19px; height: 19px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linejoin: round; stroke-linecap: round;
  transition: fill var(--bk-dur-enter) var(--bk-ease-standard);
}
/* Saved: filled cognac heart + a warm tinted chip. */
.mk-heart.is-saved { color: var(--mkt-accent); border-color: var(--mkt-accent); }
.mk-heart.is-saved .mk-heart-ic { fill: currentColor; }
/* A tiny pop when toggled on (reduced-motion users skip it via the global block). */
@media (prefers-reduced-motion: no-preference) {
  .mk-heart.is-saved .mk-heart-ic { animation: mk-heart-pop 260ms var(--bk-ease-standard); }
}
@keyframes mk-heart-pop {
  0% { transform: scale(0.7); } 55% { transform: scale(1.18); } 100% { transform: scale(1); }
}
/* Featured card: same control, nudged in from the larger media's rounded corner. */
.mk-feat .mk-heart { top: 10px; right: 10px; z-index: 3; }

/* ══ Wave R3 (2026-07-08) — buyer retention ═══════════════════════════════
   "ดูล่าสุด" rail · contact-sheet report + buyer-guide · PDP guide link ·
   how-to-buy page steps. Additive; no motion of its own (§8.3-safe). */

/* "ดูล่าสุด" recently-viewed rail — GRID-ONLY (renderChrome toggles [hidden]),
   ABOVE the grid. Same horizontal-scroll grammar + card shell as the PDP
   related rail (.mk-rel-rail); its head reuses .mk-rel-head. */
.mk-recent { margin: 4px 0 22px; }
.mk-recent[hidden] { display: none; }
.mk-recent .mk-rel-head { margin: 0 0 10px; }
.mk-recent-rail {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: clamp(150px, 42vw, 190px);
  gap: 12px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  padding: 4px 2px 10px;
}
.mk-recent-rail .prod-card { scroll-snap-align: start; }

/* Contact-sheet foot — the buyer-guide link + the quiet "รายงานสินค้านี้"
   control, below the "คัดลอกลิงก์สินค้า" button. */
.mk-contact-foot {
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--mkt-line-soft);
  display: flex; flex-direction: column; gap: 8px; align-items: center;
}
.mk-contact-howto {
  min-height: 44px; display: inline-flex; align-items: center;   /* §8.2 */
  font-size: 13.5px; font-weight: 600; color: var(--mkt-accent);
  text-decoration: none; text-align: center;
}
.mk-contact-howto:hover, .mk-contact-howto:focus-visible { text-decoration: underline; }
.mk-contact-report-wrap {
  width: 100%; display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.mk-contact-report {
  min-height: 44px; padding: 0 12px;                             /* §8.2 tap target */
  background: none; border: none; cursor: pointer; font: inherit;
  font-size: 13px; font-weight: 600; color: var(--mkt-ink-muted);
  text-decoration: underline; text-underline-offset: 3px;
}
.mk-contact-report:hover:not(:disabled) { color: var(--mkt-ink); }
.mk-contact-report:disabled {
  color: var(--mkt-ink-muted); cursor: default; text-decoration: none; opacity: .8;
}
.mk-report-panel { width: 100%; display: flex; flex-direction: column; gap: 8px; }
.mk-report-panel[hidden] { display: none; }
.mk-report-label { font-size: 13px; font-weight: 600; color: var(--mkt-ink); }
.mk-report-input {
  width: 100%; box-sizing: border-box; padding: 10px 12px;
  border: 1px solid var(--mkt-line); border-radius: var(--bk-radius-md);
  background: var(--mkt-surface-1); color: var(--mkt-ink);
  font: inherit; font-size: 14px; line-height: 1.5; resize: vertical; min-height: 72px;
}
.mk-report-input:focus-visible { outline: 2px solid var(--mkt-accent); outline-offset: 1px; }
.mk-report-send { width: 100%; min-height: 44px; }               /* §8.2 */
.mk-report-msg { margin: 0; font-size: 12.5px; color: var(--bk-danger, #b42318); }

/* PDP buyer-guide link, directly under the CTA/micro (item 18). */
.mk-pdp-howto { margin: 4px 0 0; font-size: 13px; }
.mk-pdp-howto a { color: var(--mkt-accent); font-weight: 600; text-decoration: none; }
.mk-pdp-howto a:hover, .mk-pdp-howto a:focus-visible { text-decoration: underline; }

/* how-to-buy page — numbered step cards (reuses the .mk-legal chrome). */
.mk-legal ol.mk-howto-steps {
  margin: 0 0 24px; padding: 0; list-style: none; counter-reset: howto;
}
.mk-legal ol.mk-howto-steps > li {
  position: relative; margin: 0 0 10px; padding: 14px 16px 14px 58px;
  border: 1px solid var(--border); border-radius: 14px;
  font-size: 15px; line-height: 1.6; color: var(--text); text-wrap: pretty;
  counter-increment: howto;
}
.mk-legal ol.mk-howto-steps > li::before {
  content: counter(howto);
  position: absolute; left: 14px; top: 14px;
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--brand-primary); color: #fff;
  font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums;
}
.mk-legal .mk-howto-step-t {
  display: block; margin-bottom: 2px; font-weight: 700; color: var(--text);
}

/* ══════════════════════════════════════════════════════════════════════════
   D2 MARKETPLACE REDESIGN (2026-07-08) — chip row · rails · filter bottom-sheet
   · how-to strip · desktop inline search. Cream/cognac tokens (§2.2/§2.4),
   §3.6 currency already on .price, §4.4 sheet motion, §8.1/§8.2/§8.5 responsive.
   Appended last so these component rules win the cascade over legacy skins.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Category chip row (§8.5 horizontal scroll; counts HIDDEN per pk) ── */
.mk-cats { max-width: var(--container-w); margin: 14px auto 0; }
.mk-cats[hidden] { display: none; }
.mk-cats-in {
  display: flex; gap: 9px; overflow-x: auto; scrollbar-width: none;
  scroll-snap-type: x proximity; padding: 2px 16px 6px;
}
.mk-cats-in::-webkit-scrollbar { display: none; }
.mk-cat {
  scroll-snap-align: start; flex: none; min-height: 44px; padding: 0 16px;
  display: inline-flex; align-items: center;
  border-radius: var(--bk-radius-pill);
  background: var(--mkt-surface-2); border: 1px solid var(--mkt-line);
  font-size: 14px; font-weight: 500; color: var(--mkt-ink-secondary);
  white-space: nowrap; cursor: pointer;
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard),
              border-color var(--bk-dur-exit) var(--bk-ease-standard),
              color var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-cat:hover { border-color: var(--mkt-ink-muted); background: var(--mkt-surface-1); }
.mk-cat:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: 2px; }
.mk-cat.is-on { background: var(--mkt-accent); border-color: var(--mkt-accent); color: var(--mkt-accent-ink); }
/* skeleton chips while facets load */
.mk-cat-skel { width: 88px; color: transparent; pointer-events: none;
  background: var(--mkt-surface-inset); border-color: var(--mkt-line-soft); }
@media (min-width: 1024px) { .mk-cats-in { padding-left: 24px; padding-right: 24px; } }

/* ── Rails (featured "คัดพิเศษ" + "มาใหม่") — §8.5 scroll-snap track of cards ── */
.mk-rail { max-width: var(--container-w); margin: 30px auto 0; padding: 0 16px; }
.mk-rail[hidden] { display: none; }
.mk-rail-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.mk-rail-title { display: inline-flex; align-items: center; gap: 8px; color: inherit; text-decoration: none; }
.mk-rail-title:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: 2px; border-radius: var(--bk-radius-sm); }
.mk-rail-eyebrow { font-family: var(--font-thai-display); font-weight: 700; font-size: clamp(19px, 5vw, 24px); color: var(--mkt-ink); letter-spacing: 0; }
.mk-rail-more { display: inline-grid; place-items: center; width: 26px; height: 26px; color: var(--mkt-accent); flex: none; }
.mk-rail-more .mk-ic { width: 18px; height: 18px; }
.mk-rail-ctrl { margin-left: auto; display: none; gap: 6px; }
.mk-rail-arrow {
  width: 44px; height: 44px; border-radius: 50%; flex: none; cursor: pointer;
  display: grid; place-items: center; color: var(--mkt-ink-secondary);
  background: var(--mkt-surface-2); border: 1px solid var(--mkt-line);
  transition: background-color var(--bk-dur-exit) var(--bk-ease-standard),
              border-color var(--bk-dur-exit) var(--bk-ease-standard),
              transform var(--bk-dur-exit) var(--bk-ease-standard), opacity .15s;
}
.mk-rail-arrow:hover { background: var(--mkt-surface-1); border-color: var(--mkt-ink-muted); }
.mk-rail-arrow:active { transform: translateY(1px); }
.mk-rail-arrow[disabled] { opacity: .38; cursor: default; }
.mk-rail-arrow .mk-ic { width: 18px; height: 18px; }
.mk-rail-track {
  display: grid; grid-auto-flow: column; grid-auto-columns: 158px; gap: 12px;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity;
  scrollbar-width: none; padding: 2px 2px 8px;
}
.mk-rail-track::-webkit-scrollbar { display: none; }
.mk-rail-track > .prod-card, .mk-rail-track > .bk-skel { scroll-snap-align: start; }
@media (min-width: 768px) { .mk-rail-track { grid-auto-columns: 190px; } }
@media (min-width: 1024px) {
  .mk-rail { padding-left: 24px; padding-right: 24px; }
  .mk-rail-ctrl { display: flex; }
  .mk-rail-track { grid-auto-columns: 224px; }
}

/* ── "ร้านค้า" shops rail (2026-07-11) — compact avatar cards (narrower than the
   product cards), so the track uses its own column width. DESIGN.md §1.5 cream/
   cognac surface tokens; §8.2 44px+ tap target (whole card ≥120px tall). */
.mk-shops-track { grid-auto-columns: 116px; }
.mk-shops-track > .mk-shop-card { scroll-snap-align: start; }
@media (min-width: 768px) { .mk-shops-track { grid-auto-columns: 128px; } }
@media (min-width: 1024px) { .mk-shops-track { grid-auto-columns: 132px; } }
.mk-shop-card {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 6px; padding: 14px 8px; min-height: 44px;
  border-radius: var(--bk-radius-md, 14px);
  background: var(--mkt-surface-1); border: 1px solid var(--mkt-line);
  color: inherit; text-decoration: none;
  transition: border-color var(--bk-dur-exit) var(--bk-ease-standard),
              transform var(--bk-dur-exit) var(--bk-ease-standard),
              box-shadow var(--bk-dur-exit) var(--bk-ease-standard);
}
.mk-shop-card:hover { border-color: var(--mkt-accent); transform: translateY(-2px); }
.mk-shop-card:focus-visible { outline: 3px solid var(--mkt-accent-ring); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .mk-shop-card:hover { transform: none; } }
/* Round avatar — 64px circle, favicon/logo cover-cropped or the monogram. Reuses
   .mk-shop-logo / .mk-shop-avatar visuals; only the box size is overridden. */
.mk-shop-card-av { width: 64px; height: 64px; font-size: 26px; }
.mk-shop-card-name {
  font-weight: 600; font-size: 13px; line-height: 1.25; color: var(--mkt-ink);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mk-shop-card-meta { display: inline-flex; }
/* Compact verified chip inside the card (the inline badge is sized for the
   seller header; shrink it for the avatar card). */
.mk-shop-card .mk-badge-inline { font-size: 10px; padding: 2px 6px; gap: 3px; }
.mk-shop-card-count {
  font-size: 12px; color: var(--mkt-ink-muted); font-variant-numeric: tabular-nums;
}

/* ── Filter: desktop single inline row / mobile "ตัวกรอง" bottom-sheet (§4.4) ──
   The mkDD custom dropdown is enhanced on DESKTOP only (its absolutely-positioned
   listbox would be clipped by the sheet's overflow); the mobile sheet uses the
   NATIVE <select> OS picker (not clipped by CSS overflow). */
.mk-filter-trigger, .mk-filter-backdrop { display: none; }
.mk-sheet-grip, .mk-filters-sheet-head, .mk-filters-sheet-foot { display: none; }
.mk-filters-panel {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  flex: 1 1 auto; min-width: 0;
}
@media (max-width: 1023px) {
  .mk-filters-inner { flex-wrap: nowrap; }
  .mk-filter-trigger {
    display: inline-flex; align-items: center; gap: 8px; flex: none;
    min-height: 44px; padding: 0 16px; border-radius: var(--bk-radius-md);
    background: var(--mkt-surface-2); border: 1px solid var(--mkt-line);
    font-size: 14px; font-weight: 600; color: var(--mkt-ink-secondary); cursor: pointer;
  }
  .mk-filter-trigger .mk-ic { width: 17px; height: 17px; color: var(--mkt-ink-muted); }
  .mk-filter-dot {
    display: inline-grid; place-items: center; min-width: 18px; height: 18px;
    padding: 0 5px; border-radius: 99px; background: var(--mkt-accent);
    color: #fff; font-size: 11px; font-weight: 700;
  }
  .mk-filter-dot[hidden] { display: none; }
  /* the panel becomes a viewport-anchored slide-up sheet (§4.4). */
  .mk-filters-panel {
    /* above the floating tab bar (also --z-float) so the sheet footer isn't
       obscured; the backdrop (one below) still covers the tab bar. */
    position: fixed; left: 0; right: 0; bottom: 0; z-index: calc(var(--z-float, 9000) + 11);
    flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 12px;
    max-height: 86vh; overflow-y: auto;
    background: var(--mkt-surface-2); border: 1px solid var(--mkt-line-soft);
    border-radius: var(--bk-radius-xl) var(--bk-radius-xl) 0 0;
    box-shadow: var(--mkt-elev-float);
    padding: 8px 18px calc(18px + env(safe-area-inset-bottom, 0px));
    transform: translateY(100%); visibility: hidden;
    transition: transform var(--bk-dur-enter) var(--bk-ease-spring),
                visibility 0s linear var(--bk-dur-enter);
  }
  /* lift the sticky bar's whole stacking context above the floating tab bar
     (--z-float) while the sheet is open — otherwise the panel/backdrop, being
     descendants of the sticky .mk-filters (z:--z-sticky), are trapped below it. */
  .mk-filters.sheet-open { z-index: calc(var(--z-float, 9000) + 12); }
  .mk-filters.sheet-open .mk-filters-panel {
    transform: translateY(0); visibility: visible;
    transition: transform var(--bk-dur-enter) var(--bk-ease-spring);
  }
  .mk-filters.sheet-open .mk-filter-backdrop {
    display: block; position: fixed; inset: 0; z-index: calc(var(--z-float, 9000) + 10);
    background: color-mix(in srgb, var(--mkt-ink) 42%, transparent);
    -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  }
  .mk-sheet-grip { display: block; width: 38px; height: 4px; border-radius: 99px; background: var(--mkt-line); margin: 8px auto 4px; }
  .mk-filters-sheet-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 2px 0 10px; border-bottom: 1px solid var(--mkt-line-soft);
  }
  .mk-filters-sheet-title { font-family: var(--font-thai-display); font-weight: 700; font-size: 17px; color: var(--mkt-ink); }
  .mk-sheet-x { width: 44px; height: 44px; display: grid; place-items: center; border: 0; background: none; color: var(--mkt-ink-muted); border-radius: 50%; cursor: pointer; }
  .mk-sheet-x:hover { background: var(--mkt-surface-inset); color: var(--mkt-ink); }
  .mk-sheet-x .mk-ic { width: 18px; height: 18px; }
  .mk-filters-sheet-foot {
    display: flex; gap: 10px; padding-top: 12px; margin-top: 2px;
    border-top: 1px solid var(--mkt-line-soft);
    position: sticky; bottom: 0; background: var(--mkt-surface-2);
  }
  .mk-filters-sheet-foot .mk-btn { flex: 1 1 auto; min-height: 48px; }
  /* controls stack full-width in the sheet */
  .mk-filters-panel .mk-select-wrap,
  .mk-filters-panel .mk-select,
  .mk-filters-panel .mk-price-fields,
  .mk-filters-panel .mk-ftoggle { width: 100%; }
  .mk-filters-panel .mk-price-fields input { width: auto; flex: 1 1 auto; }
  .mk-filters-panel .mk-ftoggle { justify-content: space-between; margin-left: 0; }
  .mk-filters-panel .mk-spacer { display: none; }
  /* Review fix (D2): if a select was mkDD-enhanced at a WIDER load (e.g. a tablet
     in landscape ≥1024) and the viewport later drops below 1024, fall back to the
     NATIVE <select> OS picker inside the sheet — the mkDD listbox is
     position:absolute and would be clipped by the sheet's overflow. Show the
     native control + hide the custom button/list; the native 'change' still
     routes through onFilterChanged. */
  .mk-filters-panel .mk-select-wrap.mk-dd-on > select { display: inline-flex; width: 100%; }
  .mk-filters-panel .mk-select-wrap.mk-dd-on > .mk-dd-btn,
  .mk-filters-panel .mk-select-wrap.mk-dd-on > .mk-dd-list { display: none; }
  @media (prefers-reduced-motion: reduce) { .mk-filters-panel { transition: none; } }
}

/* ── How-to-buy strip (§4.3 rounded-square tinted step media) ── */
.mk-how { max-width: var(--container-w); margin: 40px auto 0; padding: 0 16px; }
.mk-how[hidden] { display: none; }
.mk-how-card { background: var(--mkt-surface-1); border: 1px solid var(--mkt-line-soft); border-radius: var(--bk-radius-xl); box-shadow: var(--mkt-elev-card); padding: 24px 20px; }
.mk-how-head { margin-bottom: 4px; }
.mk-how-title { font-family: var(--font-thai-display); font-weight: 700; font-size: clamp(19px, 4.6vw, 23px); color: var(--mkt-ink); margin: 0; }
.mk-how-steps { display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 16px; }
.mk-step { display: flex; gap: 13px; align-items: flex-start; }
.mk-step-media { flex: none; width: 52px; height: 52px; border-radius: 14px; display: grid; place-items: center; background: var(--mkt-accent-soft); color: var(--mkt-accent); position: relative; }
.mk-step-media .mk-ic { width: 24px; height: 24px; }
.mk-step-num { position: absolute; top: -6px; right: -6px; width: 22px; height: 22px; border-radius: 50%; background: var(--mkt-accent); color: #fff; font-size: 12px; font-weight: 700; display: grid; place-items: center; font-variant-numeric: tabular-nums; box-shadow: var(--mkt-elev-card); }
.mk-step-copy h3 { font-family: var(--font-thai-display); font-weight: 700; font-size: 15px; color: var(--mkt-ink); letter-spacing: 0; margin: 0; }
.mk-step-copy p { font-size: 13px; color: var(--mkt-ink-secondary); margin: 2px 0 0; line-height: 1.5; }
.mk-hl { color: var(--mkt-accent); font-weight: 700; }
.mk-how-disclaim { display: flex; gap: 10px; align-items: flex-start; margin-top: 20px; padding: 13px 15px; border-radius: var(--bk-radius-md); background: var(--mkt-success-soft); border: 1px solid color-mix(in oklch, var(--bk-success) 22%, var(--mkt-line-soft)); }
.mk-how-disclaim .mk-ic { width: 20px; height: 20px; flex: none; color: var(--bk-success); margin-top: 1px; }
.mk-how-disclaim p { font-size: 12.5px; color: var(--mkt-ink-secondary); line-height: 1.55; margin: 0; }
.mk-how-disclaim strong { color: var(--mkt-success-deep); }
@media (min-width: 768px) { .mk-how-steps { grid-template-columns: repeat(2, 1fr); gap: 18px 22px; } }
@media (min-width: 1024px) {
  .mk-how { padding-left: 24px; padding-right: 24px; }
  .mk-how-steps { grid-template-columns: repeat(4, 1fr); }
  .mk-how-card { padding: 30px 28px; }
}

/* ── Desktop inline search (≥1200) — mobile keeps the loupe→overlay ── */
.mk-topbar-search { display: none; }
@media (min-width: 1200px) {
  .mk-topbar-search {
    display: inline-flex; align-items: center; gap: 10px;
    flex: 1 1 auto; max-width: 520px; margin: 0 10px;
    height: 44px; padding: 0 16px;
    background: var(--mkt-surface-inset); border: 1.5px solid var(--mkt-line-soft);
    border-radius: var(--bk-radius-pill); color: var(--mkt-ink-muted);
    transition: border-color .16s var(--bk-ease-standard), box-shadow .16s var(--bk-ease-standard);
  }
  .mk-topbar-search:focus-within { border-color: var(--mkt-accent); box-shadow: 0 0 0 3px var(--mkt-accent-ring); }
  .mk-topbar-search .mk-ic { width: 18px; height: 18px; flex: none; }
  .mk-topbar-search input { border: 0; background: none; outline: none; font: inherit; width: 100%; color: var(--mkt-ink); }
  .mk-topbar-search input::placeholder { color: var(--mkt-ink-muted); }
  .mk-topnav-loupe { display: none; }
}
