/* =========================================================================
   MARKETPLACE DESIGN SYSTEM
   Tokens -> Base -> Components -> Utilities -> Motion -> Print
   Brand: Blue (trust + action) - Yellow (highlight + opportunity)
   Type : Lexend Deca (variable, self-hosted)
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. FONT
   Lexend Deca, self-hosted. It is a variable font, so one woff2 per subset
   covers every weight the design uses (400/500/600/700/800) — 76KB for the
   whole family rather than ten static files, and no third-party request on
   page load.

   The stack still falls through to a metrically similar geometric-humanist
   set, so a blocked or failed font never reflows the layout.
   ------------------------------------------------------------------------- */
@font-face {
  font-family: 'Lexend Deca';
  src: url('../fonts/LexendDeca-latin.woff2') format('woff2-variations'),
       url('../fonts/LexendDeca-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Lexend Deca';
  src: url('../fonts/LexendDeca-latin-ext.woff2') format('woff2-variations'),
       url('../fonts/LexendDeca-latin-ext.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
                 U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
                 U+2C60-2C7F, U+A720-A7FF;
}

/* -------------------------------------------------------------------------
   2. DESIGN TOKENS
   ------------------------------------------------------------------------- */
:root {
  /* --- typography --------------------------------------------------------
     Every value here is a Customizer default. The theme prints an inline
     :root override in wp_head, so changing a font or a colour never needs a
     rebuild and never touches this file.
     ------------------------------------------------------------------------ */
  --font-body:    'Lexend Deca', Inter, system-ui, -apple-system, 'Segoe UI',
                  Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-heading: var(--font-body);
  --fs-base:      15px;
  --fw-heading:   700;
  --ls-heading:   -.015em;

  /* --- brand ------------------------------------------------------------ */
  --c-blue:        #2563EB;
  --c-blue-dark:   #1D4ED8;
  --c-blue-soft:   #EFF6FF;
  --c-blue-line:   #DBEAFE;
  --c-blue-ring:   rgba(37, 99, 235, .22);
  --c-yellow:      #FACC15;
  --c-yellow-soft: #FEF9C3;
  --c-yellow-line: #FDE68A;
  --c-yellow-deep: #A16207;

  /* --- neutrals (SaaS slate scale) -------------------------------------- */
  --c-surface:     #FFFFFF;
  --c-page:        #F8FAFC;
  --c-subtle:      #F1F5F9;
  --c-text:        #111827;
  --c-text-2:      #475569;
  --c-muted:       #64748B;
  --c-border:      #E2E8F0;
  --c-border-soft: #F1F5F9;

  /* --- footer ----------------------------------------------------------- */
  --c-footer:      #181A20;
  --c-footer-2:    #1F222A;
  --c-footer-text: #94A3B8;
  --c-footer-line: rgba(255, 255, 255, .08);

  /* --- semantic --------------------------------------------------------- */
  --c-ok:   #16A34A;
  --c-warn: #F59E0B;
  --c-bad:  #DC2626;

  /* --- radius (tighter, more product-like) ------------------------------ */
  --r-xs: 4px;
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-2xl: 20px;
  --r-pill: 999px;

  /* --- elevation (soft, never heavy) ------------------------------------ */
  --sh-xs:   0 1px 2px rgba(15, 23, 42, .05);
  --sh-card: 0 1px 2px rgba(15, 23, 42, .04), 0 1px 3px rgba(15, 23, 42, .05);
  --sh-lift: 0 6px 20px -6px rgba(15, 23, 42, .10), 0 2px 6px rgba(15, 23, 42, .04);
  --sh-pop:  0 12px 36px -8px rgba(15, 23, 42, .16), 0 2px 8px rgba(15, 23, 42, .05);

  /* --- spacing scale ---------------------------------------------------- */
  --s-1:  4px;  --s-2:  8px;  --s-3: 12px; --s-4: 16px; --s-5: 20px;
  --s-6: 24px;  --s-8: 32px;  --s-10: 40px; --s-12: 48px; --s-16: 64px;
  --s-20: 80px; --s-24: 96px;

  /* --- layout ----------------------------------------------------------- */
  --gutter: clamp(16px, 3.5vw, 28px);
  --shell:  1320px;
  --sidebar-w: 300px;

  /* --- control sizing --------------------------------------------------- */
  --h-control: 44px;
  --h-search:  50px;

  /* --- motion ----------------------------------------------------------- */
  --t-fast: 150ms;
  --t-base: 220ms;
  --t-slow: 360ms;
  --ease:   cubic-bezier(.4, 0, .2, 1);

  /* --- sticky offsets ---------------------------------------------------
     main.js measures the real header and writes --header-h back on load,
     resize and whenever the header compacts. These are first-paint defaults:
     row 1 (88px) + nav row (46px) + category row (48px) on desktop, row 1 +
     search row on mobile. */
  --header-h: 182px;
  --mobilenav-h: 62px;
}

/* -------------------------------------------------------------------------
   3. BASE
   ------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (max-width: 1023px) { :root { --header-h: 198px; } }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  /* `clip`, never `hidden`.

     The header's mega-menu panels are absolutely positioned and hidden with
     `visibility`, so a closed panel under a category near the right edge still
     occupies layout and pushed the document about 190px wider than the
     viewport — every page scrolled sideways on a desktop. `clip` stops that
     without creating a scroll container, which is what `hidden` would do, and
     a scroll container here would break the sticky header and the sticky
     filter panel. Panels that open are nudged back inside the shell by
     main.js, so nothing that should be seen is ever clipped. */
  overflow-x: clip;
  background: var(--c-page);
  color: var(--c-text);
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: 1.55;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5 {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: var(--fw-heading, 700);
  letter-spacing: var(--ls-heading, -.015em);
  color: var(--c-text);
}
p { margin: 0; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
ul, ol { margin: 0; padding: 0; list-style: none; }
table { border-collapse: collapse; width: 100%; }
svg { flex: none; }

/* fluid type scale */
.t-hero    { font-size: clamp(2.1rem, 4.6vw, 3.6rem); line-height: 1.06; font-weight: 800; letter-spacing: -.03em; }
.t-h1      { font-size: clamp(1.75rem, 3.4vw, 2.6rem); line-height: 1.12; font-weight: 700; letter-spacing: -.025em; }
.t-h2      { font-size: clamp(1.35rem, 2.4vw, 1.85rem); line-height: 1.2;  font-weight: 700; letter-spacing: -.02em; }
.t-h3      { font-size: clamp(1.1rem, 1.6vw, 1.3rem);  line-height: 1.3;  font-weight: 600; }
.t-lead    { font-size: clamp(1rem, 1.4vw, 1.125rem); color: var(--c-text-2); line-height: 1.6; }
.t-meta    { font-size: 12.5px; color: var(--c-muted); }
.t-eyebrow { font-size: 12px; font-weight: 600; letter-spacing: .09em; text-transform: uppercase; color: var(--c-blue); }

/* -------------------------------------------------------------------------
   4. ACCESSIBILITY
   ------------------------------------------------------------------------- */
:focus { outline: none; }

/*
 * The focus ring, and the one thing it must NOT be drawn on.
 *
 * `tabindex="-1"` means an element is reachable by script and not by the
 * keyboard, which is how WooCommerce scrolls to a notice — cart.js sets that
 * attribute and calls `.focus()`. Chrome then matches `:focus-visible` and a
 * blue box was drawn around "Cart updated." for a mouse user who had not
 * focused anything. Nothing that cannot be tabbed to needs a tab indicator.
 *
 * `:where()` IS LOAD-BEARING. It contributes nothing to specificity, so this
 * stays at (0,1,0) — and components that draw their own focus treatment can go
 * on switching this one off with `outline: none` at (0,1,1). Written as a plain
 * `:not()` it became (0,2,0), beat every one of those, and the header search
 * drew its own ring on the wrapper AND this outline on the input inside it.
 */
:focus-visible:where( :not( [tabindex="-1"] ) ),
.focusable:focus-visible {
  outline: 2px solid var(--c-blue);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/*
 * `[hidden]` WINS. base.css sets this first at specificity 0,1,0, and any class
 * in this file that sets `display` is also 0,1,0 and simply came later — which
 * is how a `hidden` typing indicator stayed on screen for good. The three
 * `!important` lines further down this file were this same bug, found one
 * selector at a time; this is the rule they were standing in for.
 *
 * `until-found` is exempt: the browser reveals that itself when a find-in-page
 * match is inside it.
 */
[hidden]:not( [hidden="until-found"] ) { display: none !important; }
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--c-blue); color: #fff; padding: 10px 16px;
  border-radius: var(--r-md); font-weight: 600; transition: top var(--t-fast) var(--ease);
}
.skip-link:focus { top: 12px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* -------------------------------------------------------------------------
   5. LAYOUT
   ------------------------------------------------------------------------- */
.shell { width: 100%; max-width: var(--shell); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: clamp(40px, 6vw, 72px); }
.section-tight { padding-block: clamp(28px, 4vw, 48px); }
.section-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; margin-bottom: 22px; flex-wrap: wrap; }
.rule { height: 1px; background: var(--c-border); border: 0; margin: 0; }

/* -------------------------------------------------------------------------
   6. BUTTONS
   ------------------------------------------------------------------------- */
.btn {
  --btn-bg: transparent; --btn-fg: var(--c-text); --btn-bd: transparent;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 44px; padding: 0 18px;
  background: var(--btn-bg); color: var(--btn-fg);
  border: 1px solid var(--btn-bd); border-radius: var(--r-md);
  font-size: 14.5px; font-weight: 600; white-space: nowrap; cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }

.btn-primary   { --btn-bg: var(--c-blue); --btn-fg: #fff; --btn-bd: var(--c-blue); }
.btn-primary:hover { --btn-bg: var(--c-blue-dark); --btn-bd: var(--c-blue-dark); box-shadow: 0 6px 16px -6px var(--c-blue-ring); }

.btn-secondary { --btn-bg: #fff; --btn-fg: var(--c-blue); --btn-bd: var(--c-blue); }
.btn-secondary:hover { --btn-bg: var(--c-blue-soft); --btn-fg: var(--c-blue-dark); --btn-bd: var(--c-blue-dark); }

.btn-ghost     { --btn-bg: #fff; --btn-fg: var(--c-text); --btn-bd: var(--c-border); }
.btn-ghost:hover { --btn-bg: var(--c-page); --btn-bd: #cbd5e1; }

.btn-quiet     { --btn-bg: transparent; --btn-fg: var(--c-text-2); --btn-bd: transparent; }
.btn-quiet:hover { --btn-bg: var(--c-border-soft); --btn-fg: var(--c-text); }

.btn-highlight { --btn-bg: var(--c-yellow); --btn-fg: #1F2937; --btn-bd: var(--c-yellow); }
.btn-highlight:hover { --btn-bg: #EAB308; --btn-bd: #EAB308; box-shadow: 0 6px 16px -6px rgba(234,179,8,.5); }

.btn-danger    { --btn-bg: #fff; --btn-fg: var(--c-bad); --btn-bd: #FECACA; }
.btn-danger:hover { --btn-bg: #FEF2F2; --btn-bd: var(--c-bad); }

.btn-whatsapp  { --btn-bg: #fff; --btn-fg: #128C7E; --btn-bd: #A7E5D8; }
.btn-whatsapp:hover { --btn-bg: #F0FDF9; --btn-bd: #128C7E; }

.btn-sm  { height: 36px; padding: 0 13px; font-size: 13.5px; border-radius: var(--r-sm); }
.btn-lg  { height: 52px; padding: 0 26px; font-size: 16px; }
.btn-block { width: 100%; }
.btn-icon { width: 44px; padding: 0; }
.btn-icon.btn-sm { width: 36px; }

/* -------------------------------------------------------------------------
   7. FORM CONTROLS
   ------------------------------------------------------------------------- */
.field { display: block; }
.label {
  display: block; font-size: 13px; font-weight: 600; color: var(--c-text);
  margin-bottom: 6px;
}
.label .req { color: var(--c-bad); }
.help { font-size: 12.5px; color: var(--c-muted); margin-top: 6px; }
.err  { font-size: 12.5px; color: var(--c-bad); margin-top: 6px; display: none; align-items: center; gap: 5px; }
.field.is-invalid .err { display: flex; }
.field.is-invalid .input,
.field.is-invalid .select,
.field.is-invalid .textarea { border-color: var(--c-bad); background: #FFFBFB; }

.input, .select, .textarea {
  width: 100%; background: #fff; color: var(--c-text);
  border: 1px solid var(--c-border); border-radius: var(--r-md);
  padding: 0 14px; height: 46px; font-size: 15px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.textarea { height: auto; padding: 12px 14px; min-height: 120px; resize: vertical; line-height: 1.6; }
.input::-moz-placeholder, .textarea::-moz-placeholder { color: #9CA3AF; }
.input::placeholder, .textarea::placeholder { color: #9CA3AF; }
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--c-blue); box-shadow: 0 0 0 3px var(--c-blue-ring); outline: none;
}
.select {
  -moz-appearance: none;
       appearance: none; -webkit-appearance: none; padding-right: 38px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%234B5563' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center;
}
.input-group { position: relative; }
.input-group .input { padding-left: 42px; }
.input-group > .ig-icon {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  color: var(--c-muted); pointer-events: none;
}

/* checkbox + radio */
.check { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; font-size: 14px; color: var(--c-text-2); }
.check input { accent-color: var(--c-blue); width: 17px; height: 17px; margin: 2px 0 0; flex: none; cursor: pointer; }
.check:hover { color: var(--c-text); }

/* switch */
.switch { position: relative; display: inline-flex; align-items: center; gap: 10px; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  width: 42px; height: 24px; border-radius: var(--r-pill); background: #CBD5E1;
  transition: background var(--t-fast) var(--ease); flex: none; position: relative;
}
.switch .track::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
  background: #fff; border-radius: 50%; box-shadow: 0 1px 3px rgba(0,0,0,.2);
  transition: transform var(--t-base) var(--ease);
}
.switch input:checked + .track { background: var(--c-blue); }
.switch input:checked + .track::after { transform: translateX(18px); }
.switch input:focus-visible + .track { box-shadow: 0 0 0 3px var(--c-blue-ring); }

/* segmented control */
.segment { display: inline-flex; background: var(--c-border-soft); border-radius: var(--r-md); padding: 4px; gap: 2px; }
.segment button {
  border: 0; background: transparent; border-radius: var(--r-sm); padding: 7px 14px;
  font-size: 13.5px; font-weight: 600; color: var(--c-text-2); cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.segment button[aria-selected="true"] { background: #fff; color: var(--c-blue); box-shadow: var(--sh-card); }

/* -------------------------------------------------------------------------
   8. CARDS
   ------------------------------------------------------------------------- */
.card {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--r-lg); box-shadow: var(--sh-xs);
}
.card-pad { padding: clamp(16px, 2vw, 22px); }
.card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 16px 20px; border-bottom: 1px solid var(--c-border);
}
.card-head h2, .card-head h3 { font-size: 15.5px; font-weight: 600; letter-spacing: 0; }

/* --- Product card ------------------------------------------------------- */
.p-card {
  position: relative; display: flex; flex-direction: column; height: 100%;
  background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-lg);
  box-shadow: var(--sh-card); overflow: hidden;
  transition: box-shadow var(--t-base) var(--ease), border-color var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.p-card:hover { box-shadow: var(--sh-lift); border-color: #D6DEE9; transform: translateY(-2px); }
.p-card:focus-within { border-color: var(--c-blue); box-shadow: 0 0 0 3px var(--c-blue-ring); }
.p-card--featured { border-color: #FDE68A; }
.p-card--featured::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--c-yellow), #FDE68A); z-index: 2;
}

.p-media { position: relative; aspect-ratio: 4 / 3; background: var(--c-border-soft); overflow: hidden; }
.p-media img {
  width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover;
  transition: transform var(--t-slow) var(--ease), opacity var(--t-base) var(--ease);
}
.p-card:hover .p-media img { transform: scale(1.035); }
.p-badges { position: absolute; top: 10px; left: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; z-index: 2; }
.p-sold {
  position: absolute; inset: 0; display: grid; place-items: center; z-index: 3;
  background: rgba(17,24,39,.55);
}
.p-sold span {
  background: #fff; color: var(--c-text); font-weight: 700; font-size: 13px;
  letter-spacing: .1em; padding: 7px 16px; border-radius: var(--r-pill);
}
.p-body { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 7px; flex: 1; }
.p-title {
  font-size: 15px; font-weight: 600; line-height: 1.35; color: var(--c-text);
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: 2.7em; transition: color var(--t-fast) var(--ease);
}
.p-card a.p-link::after { content: ''; position: absolute; inset: 0; z-index: 1; }
.p-card:hover .p-title { color: var(--c-blue); }
.p-price { font-size: 18px; font-weight: 700; letter-spacing: -.02em; color: var(--c-text); }
/* Listing prices share the CVList blue #0068EB: cards, detail page, variation and
   grouped prices, search suggestions and the cart's unit price. Colour only. */
.p-card .p-price,
.p-detail-price,
.mk-product form.cart .single_variation .price,
.mk-product .woocommerce-grouped-product-list-item__price,
.suggest-item[data-product] .sub,
.cart-line-price:not(.cart-line-price--sub) .cart-line-price__value { color: #0068EB; }
.p-price .was { font-size: 13px; font-weight: 500; color: var(--c-muted); text-decoration: line-through; margin-left: 7px; }
.p-price .off { font-size: 12px; font-weight: 600; color: var(--c-ok); margin-left: 7px; }
.p-seller { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--c-text-2); min-width: 0; }
.p-seller .name { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-meta { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--c-muted); margin-top: auto; padding-top: 2px; flex-wrap: wrap; }
.p-meta .dot { width: 3px; height: 3px; border-radius: 50%; background: #CBD5E1; flex: none; }

/* favourite */
.fav {
  position: absolute; top: 8px; right: 8px; z-index: 4;
  width: 38px; height: 38px; display: grid; place-items: center;
  background: rgba(255,255,255,.94); border: 1px solid var(--c-border);
  border-radius: 50%; color: var(--c-text-2); cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.fav:hover { color: var(--c-blue); border-color: var(--c-blue); transform: scale(1.06); }
.fav[aria-pressed="true"] { color: var(--c-blue); border-color: var(--c-blue); background: var(--c-blue-soft); }
.fav[aria-pressed="true"] svg { fill: currentColor; }
.fav.is-pop { animation: favPop var(--t-base) var(--ease); }

/* The Wishlist button in the purchase column. Same behaviour as `.fav` — both
   carry `data-fav` — and a different component: `.fav` is the round heart in a
   corner and is `position: absolute`, so it cannot be worn by a button in a
   flow. Only the pressed state is shared, and the two have to stay in step. */
.fav-btn[aria-pressed="true"] {
  color: var(--c-blue);
  border-color: var(--c-blue);
  background: var(--c-blue-soft);
}

.fav-btn[aria-pressed="true"] svg { fill: currentColor; }
.fav-btn.is-pop { animation: favPop var(--t-base) var(--ease); }

/* The gallery's heart. The prototype overrides `.fav` inline to 42px at a 12px
   inset, which is a modifier's job. */
.fav--gallery { top: 12px; right: 12px; width: 42px; height: 42px; }
@keyframes favPop { 0% { transform: scale(1); } 45% { transform: scale(1.24); } 100% { transform: scale(1); } }

/* list layout variant used on search page */
.p-card--row { flex-direction: row; }
.p-card--row .p-media { aspect-ratio: auto; width: 230px; flex: none; }
.p-card--row .p-body { padding: 16px 18px; }
.p-card--row .p-title { -webkit-line-clamp: 1; line-clamp: 1; min-height: 0; font-size: 16px; }
@media (max-width: 640px) { .p-card--row { flex-direction: column; } .p-card--row .p-media { width: 100%; aspect-ratio: 4/3; } }

/* -------------------------------------------------------------------------
   9. BADGES
   ------------------------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-sm);
  font-size: 11.5px; font-weight: 600; letter-spacing: .02em; line-height: 1.5;
  border: 1px solid transparent; white-space: nowrap;
}
.badge svg { width: 12px; height: 12px; }
.badge-featured { background: var(--c-yellow); color: #422006; border-color: #EAB308; }
.badge-boosted  { background: var(--c-yellow-soft); color: var(--c-yellow-deep); border-color: #FDE68A; }
.badge-new      { background: var(--c-blue-soft); color: var(--c-blue-dark); border-color: #BFDBFE; }
.badge-verified { background: #ECFDF5; color: #047857; border-color: #A7F3D0; }
.badge-business { background: #1F2937; color: #fff; border-color: #1F2937; }
.badge-start    { background: var(--c-blue); color: #fff; border-color: var(--c-blue); }
.badge-premium  { background: #6D28D9; color: #fff; border-color: #6D28D9; }
.badge-free     { background: var(--c-border-soft); color: var(--c-text-2); border-color: var(--c-border); }
.badge-neutral  { background: var(--c-border-soft); color: var(--c-text-2); border-color: var(--c-border); }
.badge-pending  { background: #FFFBEB; color: #B45309; border-color: #FDE68A; }
.badge-approved { background: #ECFDF5; color: #047857; border-color: #A7F3D0; }
.badge-rejected { background: #FEF2F2; color: #B91C1C; border-color: #FECACA; }
.badge-draft    { background: var(--c-border-soft); color: var(--c-muted); border-color: var(--c-border); }
.badge-paused   { background: #F5F3FF; color: #5B21B6; border-color: #DDD6FE; }
.badge-sold     { background: #111827; color: #fff; border-color: #111827; }
.badge-expired  { background: #FEF2F2; color: #991B1B; border-color: #FECACA; }
.badge-dot::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* rating */
.stars { display: inline-flex; align-items: center; gap: 2px; color: var(--c-yellow); }
.stars svg { width: 14px; height: 14px; fill: currentColor; }
.stars .empty { color: #E2E8F0; }
.rating { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 600; color: var(--c-text); }
.rating .count { font-weight: 400; color: var(--c-muted); }

/* avatar */
.avatar {
  display: inline-grid; place-items: center; flex: none;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--c-blue-soft); color: var(--c-blue-dark);
  font-weight: 600; font-size: 14px; overflow: hidden; border: 1px solid var(--c-border);
}
.avatar img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; }
.avatar-sm { width: 30px; height: 30px; font-size: 12px; }
.avatar-lg { width: 64px; height: 64px; font-size: 20px; }
.avatar-xl { width: 96px; height: 96px; font-size: 28px; border-width: 3px; border-color: #fff; box-shadow: var(--sh-card); }

/* -------------------------------------------------------------------------
   10. CHIPS / PILLS / SCROLLERS
   ------------------------------------------------------------------------- */
.chip {
  display: inline-flex; align-items: center; gap: 7px;
  height: 36px; padding: 0 14px; border-radius: var(--r-pill);
  background: #fff; border: 1px solid var(--c-border); color: var(--c-text-2);
  font-size: 13.5px; font-weight: 500; cursor: pointer; white-space: nowrap;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.chip:hover { border-color: var(--c-blue); color: var(--c-blue); background: var(--c-blue-soft); }
.chip[aria-pressed="true"], .chip.is-active {
  background: var(--c-blue-soft); border-color: var(--c-blue); color: var(--c-blue-dark); font-weight: 600;
}
.chip-remove { display: inline-grid; place-items: center; opacity: .6; }
.chip-remove:hover { opacity: 1; }

.scroll-x {
  display: flex; gap: 10px; max-width: 100%; min-width: 0;
  overflow-x: auto; overflow-y: hidden; padding-bottom: 4px;
  overscroll-behavior-x: contain; scrollbar-width: thin; scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.scroll-x > * { scroll-snap-align: start; }
.scroll-x::-webkit-scrollbar { height: 6px; }
.scroll-x::-webkit-scrollbar-thumb { background: #D9E0EA; border-radius: 3px; }
.no-scrollbar::-webkit-scrollbar { display: none; }
.no-scrollbar { scrollbar-width: none; }
.cat-chip-rail {
  cursor: grab; -webkit-user-select: none; -moz-user-select: none; user-select: none;
  scrollbar-color: #CBD5E1 transparent;
}
.cat-chip-rail:active { cursor: grabbing; }
.cat-chip-rail .chip { flex: 0 0 auto; }
.cat-chip-wrap { position: relative; min-width: 0; }
.cat-chip-wrap::before,
.cat-chip-wrap::after {
  content: ''; position: absolute; top: 0; bottom: 8px; z-index: 1; width: 54px;
  pointer-events: none; opacity: 0; transition: opacity var(--t-fast) var(--ease);
}
.cat-chip-wrap::before {
  left: 0; background: linear-gradient(90deg, var(--c-page) 35%, rgba(248,250,252,0));
}
.cat-chip-wrap::after {
  right: 0; background: linear-gradient(270deg, var(--c-page) 35%, rgba(248,250,252,0));
}
.cat-chip-wrap.has-left::before,
.cat-chip-wrap.has-right::after { opacity: 1; }
.cat-chip-arrow {
  position: absolute; top: 50%; z-index: 2; width: 34px; height: 34px;
  display: inline-grid; place-items: center; border-radius: var(--r-pill);
  border: 1px solid var(--c-border); background: #fff; color: var(--c-text-2);
  box-shadow: var(--sh-card); cursor: pointer;
  transform: translateY(calc(-50% - 4px));
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.cat-chip-arrow:hover { background: var(--c-blue-soft); border-color: var(--c-blue); color: var(--c-blue); box-shadow: var(--sh-lift); }
.cat-chip-arrow[hidden] { display: none; }
.cat-chip-arrow--left { left: -17px; }
.cat-chip-arrow--right { right: -17px; }

/* -------------------------------------------------------------------------
   11. HEADER / NAVIGATION
   ------------------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 60;
  background: #fff; border-bottom: 1px solid var(--c-border);
  transition: box-shadow var(--t-base) var(--ease), border-color var(--t-base) var(--ease);
}
.site-header.is-stuck { box-shadow: 0 2px 12px -4px rgba(17,24,39,.14); border-color: transparent; }
.header-bar { border-top: 1px solid var(--c-border-soft); }

.logo { display: inline-flex; align-items: center; gap: 9px; font-weight: 700; font-size: 18px; letter-spacing: -.03em; flex: none; }
.logo-mark {
  width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center;
  background: var(--c-blue); color: #fff; font-weight: 800; font-size: 16px; position: relative;
}
.logo-mark::after {
  content: ''; position: absolute; right: -3px; bottom: -3px; width: 12px; height: 12px;
  background: var(--c-yellow); border-radius: 4px; border: 2px solid #fff;
}
.logo-text .accent { color: var(--c-blue); }

.header-search { flex: 1; min-width: 0; max-width: 640px; position: relative; }
.header-search .input { height: 44px; background: var(--c-page); }
.header-search .input:focus { background: #fff; }

.icon-link {
  position: relative; display: inline-grid; place-items: center;
  width: 42px; height: 42px; border-radius: var(--r-md); color: var(--c-text-2);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.icon-link:hover { background: var(--c-blue-soft); color: var(--c-blue); }
.icon-link .count {
  position: absolute; top: 3px; right: 3px; min-width: 18px; height: 18px; padding: 0 4px;
  display: grid; place-items: center; border-radius: var(--r-pill);
  background: var(--c-blue); color: #fff; font-size: 10.5px; font-weight: 700; border: 2px solid #fff;
}
.icon-link .count[data-count="0"] { display: none; }

.nav-link {
  display: inline-flex; align-items: center; gap: 6px; height: 38px; padding: 0 12px;
  border-radius: var(--r-md); font-size: 14px; font-weight: 500; color: var(--c-text-2);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.nav-link:hover { background: var(--c-border-soft); color: var(--c-text); }
.nav-link[aria-current="page"] { color: var(--c-blue); font-weight: 600; }

/* dropdown */
.dropdown { position: relative; }
.dropdown-panel {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 70; min-width: 250px;
  background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-lg);
  box-shadow: var(--sh-pop); padding: 6px; opacity: 0; visibility: hidden;
  transform: translateY(-6px);
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease), visibility var(--t-fast);
}
.dropdown-panel.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
.dropdown-panel.align-left { right: auto; left: 0; }
.dd-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 11px; border-radius: var(--r-sm); font-size: 14px; color: var(--c-text-2);
  background: none; border: 0; cursor: pointer; text-align: left;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.dd-item:hover, .dd-item:focus-visible { background: var(--c-blue-soft); color: var(--c-blue-dark); }
.dd-item[aria-current="page"] { color: var(--c-blue); font-weight: 600; }
.dd-sep { height: 1px; background: var(--c-border); margin: 6px 4px; }
.dd-label { padding: 8px 11px 4px; font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--c-muted); }

/* search suggestions */
.suggest {
  position: absolute; top: calc(100% + 8px); left: 0; right: 0; z-index: 75;
  background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-lg);
  box-shadow: var(--sh-pop); padding: 8px; max-height: 66vh; overflow: auto; display: none;
}
.suggest.is-open { display: block; }
.suggest-item {
  display: flex; align-items: center; gap: 11px; width: 100%; padding: 9px 11px;
  border: 0; background: none; border-radius: var(--r-sm); cursor: pointer;
  font-size: 14px; color: var(--c-text); text-align: left;
}
.suggest-item:hover, .suggest-item.is-cursor { background: var(--c-blue-soft); }
.suggest-item .sub { margin-left: auto; font-size: 12px; color: var(--c-muted); flex: none; }
.suggest-item mark { background: transparent; color: var(--c-blue); font-weight: 600; }
.suggest-item .thumb-xs { width: 34px; height: 34px; border-radius: var(--r-sm); -o-object-fit: cover; object-fit: cover; flex: none; border: 1px solid var(--c-border); }

/* mobile bottom nav */
.mobile-nav {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 65;
  display: grid; grid-template-columns: repeat(5, 1fr);
  background: #fff; border-top: 1px solid var(--c-border);
  padding-bottom: env(safe-area-inset-bottom);
}
.mobile-nav a {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  height: var(--mobilenav-h); font-size: 10.5px; font-weight: 500; color: var(--c-muted); position: relative;
}
.mobile-nav a[aria-current="page"] { color: var(--c-blue); font-weight: 600; }
.mobile-nav .sell-fab {
  background: var(--c-blue); color: #fff; width: 46px; height: 46px; border-radius: 14px;
  display: grid; place-items: center; margin-top: -18px; box-shadow: 0 6px 16px -4px var(--c-blue-ring);
  border: 3px solid #fff;
}
.mobile-nav .mn-badge {
  position: absolute; top: 8px; right: calc(50% - 20px); min-width: 16px; height: 16px; padding: 0 4px;
  background: var(--c-blue); color: #fff; font-size: 9.5px; font-weight: 700;
  border-radius: var(--r-pill); display: grid; place-items: center; border: 2px solid #fff;
}
.mobile-nav .mn-badge[data-count="0"] { display: none; }
.has-mobile-nav { padding-bottom: calc(var(--mobilenav-h) + env(safe-area-inset-bottom)); }
@media (min-width: 1024px) { .mobile-nav { display: none; } .has-mobile-nav { padding-bottom: 0; } }

/* off-canvas drawer */
.drawer-backdrop {
  position: fixed; inset: 0; z-index: 90; background: rgba(17,24,39,.45);
  opacity: 0; visibility: hidden; transition: opacity var(--t-base) var(--ease), visibility var(--t-base);
}
.drawer-backdrop.is-open { opacity: 1; visibility: visible; }
.drawer {
  position: fixed; z-index: 95; background: #fff; display: flex; flex-direction: column;
  transition: transform var(--t-slow) var(--ease); box-shadow: var(--sh-pop);
}
.drawer-left  { inset: 0 auto 0 0; width: min(340px, 86vw); transform: translateX(-102%); }
.drawer-right { inset: 0 0 0 auto; width: min(400px, 92vw); transform: translateX(102%); }
.drawer-bottom { inset: auto 0 0 0; max-height: 88vh; border-radius: var(--r-xl) var(--r-xl) 0 0; transform: translateY(102%); }
.drawer.is-open { transform: none; }
.drawer-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 18px; border-bottom: 1px solid var(--c-border); flex: none; }
.drawer-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 16px 18px; }
.drawer-foot { flex: none; padding: 14px 18px; border-top: 1px solid var(--c-border); display: flex; gap: 10px; padding-bottom: calc(14px + env(safe-area-inset-bottom)); }

/* -------------------------------------------------------------------------
   12. MODAL
   ------------------------------------------------------------------------- */
.modal-root { position: fixed; inset: 0; z-index: 100; display: none; }
.modal-root.is-open { display: block; }
.modal-backdrop { position: fixed; inset: 0; background: rgba(17,24,39,.5); opacity: 0; transition: opacity var(--t-base) var(--ease); }
.modal-root.is-open .modal-backdrop { opacity: 1; }
.modal-wrap { position: absolute; inset: 0; display: grid; place-items: center; padding: 20px; overflow: auto; }
.modal {
  position: relative; width: min(560px, 100%); background: #fff;
  border-radius: var(--r-xl); box-shadow: var(--sh-pop); max-height: calc(100vh - 40px);
  display: flex; flex-direction: column; opacity: 0; transform: translateY(10px) scale(.98);
  transition: opacity var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.modal-root.is-open .modal { opacity: 1; transform: none; }
.modal-lg { width: min(880px, 100%); }
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 20px 22px 14px; }
.modal-body { padding: 0 22px 20px; overflow-y: auto; }
.modal-foot { padding: 16px 22px; border-top: 1px solid var(--c-border); display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
@media (max-width: 560px) {
  .modal-wrap { place-items: end center; padding: 0; }
  .modal { border-radius: var(--r-xl) var(--r-xl) 0 0; max-height: 92vh; }
  .modal-foot .btn { flex: 1; }
}

/* -------------------------------------------------------------------------
   13. TOASTS
   ------------------------------------------------------------------------- */
.toast-stack {
  position: fixed; z-index: 120; right: 20px; bottom: 20px;
  display: flex; flex-direction: column; gap: 10px; width: min(400px, calc(100vw - 40px));
  pointer-events: none;
}
@media (max-width: 640px) { .toast-stack { right: 12px; left: 12px; bottom: calc(var(--mobilenav-h) + 12px); width: auto; } }
.toast {
  pointer-events: auto; display: flex; align-items: flex-start; gap: 11px;
  background: #111827; color: #fff; border-radius: var(--r-md); padding: 13px 15px;
  box-shadow: var(--sh-pop); font-size: 14px; font-weight: 500;
  animation: toastIn var(--t-base) var(--ease);
}
.toast.is-out { animation: toastOut var(--t-base) var(--ease) forwards; }
.toast .t-ico { flex: none; margin-top: 1px; }

/* The message and its action, as ONE flex item. They used to be two, each with
   `margin-left: auto`, which is what pushed the close button off the edge. */
.toast .t-body {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 7px;
}

/* `anywhere`, not `break-word`: these messages quote an email address, which is
   one unbreakable word wider than the toast. */
.toast .t-msg { line-height: 1.5; overflow-wrap: anywhere; }

.toast .t-action {
  flex: none; background: none; border: 0; padding: 0;
  font: inherit; font-weight: 600; color: #93C5FD;
  cursor: pointer; text-align: left;
}
.toast .t-action:hover,
.toast .t-action:focus-visible { color: #BFDBFE; text-decoration: underline; }
.toast--ok  .t-ico { color: #4ADE80; }
.toast--bad .t-ico { color: #FCA5A5; }
.toast--info .t-ico { color: #93C5FD; }
.toast .t-close { margin-left: auto; opacity: .6; background: none; border: 0; cursor: pointer; color: inherit; padding: 0; }
.toast .t-close:hover { opacity: 1; }
@keyframes toastIn  { from { opacity: 0; transform: translateY(12px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes toastOut { to { opacity: 0; transform: translateY(8px) scale(.98); } }

/* -------------------------------------------------------------------------
   14. SKELETON / EMPTY / ERROR STATES
   ------------------------------------------------------------------------- */
.skel { background: #EEF1F5; border-radius: var(--r-sm); position: relative; overflow: hidden; }
.skel::after {
  content: ''; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.75), transparent);
  animation: shimmer 1.25s infinite;
}
@keyframes shimmer { 100% { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .skel::after { animation: none; } }
.skel-line { height: 12px; }
.skel-title { height: 16px; width: 75%; }
.skel-media { aspect-ratio: 4/3; border-radius: 0; }

.state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: clamp(36px, 6vw, 64px) 24px; gap: 8px;
}
.state-icon {
  width: 68px; height: 68px; border-radius: var(--r-xl); display: grid; place-items: center;
  background: var(--c-blue-soft); color: var(--c-blue); margin-bottom: 8px;
}
.state-icon--warn { background: #FFFBEB; color: #B45309; }
.state-icon--bad  { background: #FEF2F2; color: var(--c-bad); }
.state-icon--gold { background: var(--c-yellow-soft); color: var(--c-yellow-deep); }
.state h3 { font-size: 18px; font-weight: 700; }
.state p { color: var(--c-text-2); max-width: 440px; font-size: 14.5px; }
.state .state-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 14px; }

/* -------------------------------------------------------------------------
   15. TABLES -> responsive stacked cards
   ------------------------------------------------------------------------- */
.table-wrap { overflow-x: auto; }
.table { width: 100%; font-size: 14px; }
.table thead th {
  text-align: left; font-size: 11.5px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--c-muted); padding: 11px 14px;
  border-bottom: 1px solid var(--c-border); background: var(--c-page); white-space: nowrap;
}
.table tbody td { padding: 14px; border-bottom: 1px solid var(--c-border-soft); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background var(--t-fast) var(--ease); }
.table tbody tr:hover { background: var(--c-page); }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }

@media (max-width: 900px) {
  .table.stack thead { display: none; }
  .table.stack, .table.stack tbody, .table.stack tr, .table.stack td { display: block; width: 100%; }
  .table.stack tr {
    border: 1px solid var(--c-border); border-radius: var(--r-md);
    margin-bottom: 12px; padding: 6px 2px; background: #fff;
  }
  .table.stack tr:hover { background: #fff; }
  .table.stack tbody td { border: 0; padding: 8px 14px; display: flex; align-items: center; justify-content: space-between; gap: 14px; }
  .table.stack tbody td::before {
    content: attr(data-th); font-size: 11.5px; font-weight: 600; letter-spacing: .06em;
    text-transform: uppercase; color: var(--c-muted); flex: none;
  }
  .table.stack tbody td.cell-main { display: block; }
  .table.stack tbody td.cell-main::before { display: none; }
  .table.stack .num { text-align: right; }
}

/* -------------------------------------------------------------------------
   16. DASHBOARD SHELL
   ------------------------------------------------------------------------- */
.dash { display: grid; grid-template-columns: 248px minmax(0, 1fr); align-items: start; }
@media (max-width: 1023px) { .dash { grid-template-columns: minmax(0, 1fr); } }

.dash-side {
  position: sticky; top: calc(var(--header-h) + var(--wpsticky)); align-self: start;
  height: calc(100vh - var(--header-h) - var(--wpsticky)); overflow-y: auto;
  border-right: 1px solid var(--c-border); background: #fff; padding: 20px 14px;
}
@media (max-width: 1023px) { .dash-side { display: none; } }
.dash-main { padding: clamp(18px, 3vw, 30px) var(--gutter) 60px; min-width: 0; background: var(--c-page); min-height: calc(100vh - var(--header-h) - var(--wpsticky)); }
@media (max-width: 1023px) { .dash-main { min-height: 0; } }

.side-link {
  display: flex; align-items: center; gap: 11px; padding: 10px 12px; border-radius: var(--r-md);
  font-size: 14px; font-weight: 500; color: var(--c-text-2); margin-bottom: 2px;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.side-link:hover { background: var(--c-border-soft); color: var(--c-text); }
.side-link[aria-current="page"] { background: var(--c-blue-soft); color: var(--c-blue-dark); font-weight: 600; }
.side-link .trail { margin-left: auto; display: inline-flex; align-items: center; }
.side-label { padding: 16px 12px 6px; font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--c-muted); }

/* metric card */
.metric { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-lg); padding: 18px; box-shadow: var(--sh-card); }
.metric .m-label { font-size: 11.5px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--c-muted); }
.metric .m-value { font-size: clamp(24px, 3vw, 30px); font-weight: 700; letter-spacing: -.03em; margin-top: 6px; font-variant-numeric: tabular-nums; }
.metric .m-delta { display: inline-flex; align-items: center; gap: 4px; font-size: 12.5px; font-weight: 600; margin-top: 6px; }
.m-delta.up   { color: var(--c-ok); }
.m-delta.down { color: var(--c-bad); }
.m-delta.flat { color: var(--c-muted); }
.metric .m-ico { width: 38px; height: 38px; border-radius: var(--r-md); display: grid; place-items: center; background: var(--c-blue-soft); color: var(--c-blue); }
.metric--gold .m-ico { background: var(--c-yellow-soft); color: var(--c-yellow-deep); }

/* locked feature overlay */
.locked { position: relative; }
.locked > .locked-inner { filter: blur(3px); opacity: .45; pointer-events: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; }
.locked-veil {
  position: absolute; inset: 0; z-index: 5; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center; gap: 8px; padding: 24px;
  background: rgba(255,255,255,.74); border-radius: var(--r-lg);
}

/* -------------------------------------------------------------------------
   17. CHARTS (lightweight inline SVG, no library)
   ------------------------------------------------------------------------- */
.chart { width: 100%; height: 100%; display: block; overflow: visible; }
.chart .grid-line { stroke: var(--c-border); stroke-width: 1; }
.chart .axis-label { font-size: 10.5px; fill: var(--c-muted); font-weight: 500; }
.chart .line { fill: none; stroke: var(--c-blue); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.chart .bar { fill: var(--c-blue); transition: fill var(--t-fast) var(--ease); }
.chart .bar:hover { fill: var(--c-blue-dark); }
.chart .bar-gold { fill: var(--c-yellow); }
.chart .point { fill: #fff; stroke: var(--c-blue); stroke-width: 2.5; }
.spark { display: block; width: 100%; height: 42px; }

/* -------------------------------------------------------------------------
   18. STEPPER + UPLOADER (create listing)
   ------------------------------------------------------------------------- */
.stepper { display: flex; align-items: center; gap: 4px; overflow-x: auto; padding-bottom: 4px; }
.step { display: flex; align-items: center; gap: 9px; padding: 6px 4px; flex: none; }
.step-dot {
  width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  background: #fff; border: 1.5px solid var(--c-border); color: var(--c-muted);
  font-size: 12.5px; font-weight: 700; flex: none;
  transition: background var(--t-base) var(--ease), border-color var(--t-base) var(--ease), color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease);
}
.step-name { font-size: 13px; font-weight: 500; color: var(--c-muted); white-space: nowrap; }
.step.is-active .step-dot { background: var(--c-blue); border-color: var(--c-blue); color: #fff; box-shadow: 0 0 0 4px var(--c-blue-soft); }
.step.is-active .step-name { color: var(--c-blue-dark); font-weight: 600; }
.step.is-done .step-dot { background: var(--c-blue-soft); border-color: var(--c-blue); color: var(--c-blue); }
.step.is-done .step-name { color: var(--c-text-2); }
.step-bar { width: 22px; height: 2px; background: var(--c-border); flex: none; border-radius: 1px; transition: background var(--t-base) var(--ease); }
.step-bar.is-done { background: var(--c-blue); }
.progress-track { height: 5px; background: var(--c-border); border-radius: 3px; overflow: hidden; }
.progress-fill { height: 100%; background: var(--c-blue); border-radius: 3px; transition: width var(--t-slow) var(--ease); }

.dropzone {
  border: 1.5px dashed var(--c-border); border-radius: var(--r-lg); background: var(--c-page);
  padding: 28px 20px; text-align: center; cursor: pointer; width: 100%;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.dropzone:hover, .dropzone.is-over { border-color: var(--c-blue); background: var(--c-blue-soft); }
.thumb {
  position: relative; aspect-ratio: 1; border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--c-border); background: var(--c-border-soft);
}
.thumb img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; }
.thumb .thumb-x {
  position: absolute; top: 5px; right: 5px; width: 26px; height: 26px; border-radius: 50%;
  background: rgba(17,24,39,.72); color: #fff; display: grid; place-items: center; border: 0; cursor: pointer;
}
.thumb .thumb-x:hover { background: var(--c-bad); }
.thumb .cover-tag {
  position: absolute; bottom: 5px; left: 5px; background: var(--c-blue); color: #fff;
  font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: var(--r-sm); letter-spacing: .04em;
}

/* -------------------------------------------------------------------------
   19. MESSAGING
   ------------------------------------------------------------------------- */
.chat-shell {
  display: grid; grid-template-columns: 330px minmax(0, 1fr);
  height: calc(100vh - var(--header-h)); background: #fff;
  min-width: 0; overflow: hidden;
  border-inline: 1px solid var(--c-border);
}
/* The bottom navigation is present below 1024px, so the chat surface has to
   give up that height there — not only at the two-pane breakpoint. */
@media (max-width: 1023px) {
  .chat-shell { height: calc(100vh - var(--header-h) - var(--mobilenav-h)); }
}
@media (max-width: 900px) {
  .chat-shell { grid-template-columns: minmax(0, 1fr); border-inline: 0; }
  .chat-shell[data-view="list"] .chat-thread { display: none; }
  .chat-shell[data-view="thread"] .chat-list { display: none; }
}
.chat-list { border-right: 1px solid var(--c-border); display: flex; flex-direction: column; min-height: 0; }
.chat-list-scroll { overflow-y: auto; flex: 1; overscroll-behavior: contain; }
.conv {
  display: flex; gap: 11px; padding: 13px 15px; border-bottom: 1px solid var(--c-border-soft);
  cursor: pointer; width: 100%; text-align: left; background: none; border-left: 3px solid transparent;
  border-right: 0; border-top: 0;
  transition: background var(--t-fast) var(--ease);
}
.conv:hover { background: var(--c-page); }
.conv[aria-selected="true"] { background: var(--c-blue-soft); border-left-color: var(--c-blue); }
.conv .conv-body { min-width: 0; flex: 1; }
.conv .conv-top { display: flex; align-items: baseline; gap: 8px; }
.conv .conv-name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conv .conv-time { margin-left: auto; font-size: 11.5px; color: var(--c-muted); flex: none; }
.conv .conv-product { font-size: 12px; color: var(--c-blue-dark); background: var(--c-blue-soft); border-radius: var(--r-sm); padding: 1px 6px; display: inline-block; margin: 3px 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conv .conv-last { font-size: 13px; color: var(--c-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conv .conv-unread {
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--r-pill); background: var(--c-blue);
  color: #fff; font-size: 11px; font-weight: 700; display: grid; place-items: center; align-self: center; flex: none;
}
.chat-thread { display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--c-page); overflow: hidden; }
.chat-context {
  flex: none; background: #fff; border-bottom: 1px solid var(--c-border); padding: 10px 16px;
  display: flex; align-items: center; gap: 12px;
}
.chat-context img { width: 46px; height: 46px; border-radius: var(--r-sm); -o-object-fit: cover; object-fit: cover; flex: none; border: 1px solid var(--c-border); }
.chat-scroll { flex: 1; overflow-y: auto; padding: 20px 16px; display: flex; flex-direction: column; gap: 10px; overscroll-behavior: contain; }
.bubble {
  max-width: min(74%, 520px); padding: 10px 14px; border-radius: 16px; font-size: 14.5px; line-height: 1.5;
  overflow-wrap: anywhere; box-shadow: var(--sh-card);
}
.bubble a { color: var(--c-blue); text-decoration: underline; text-underline-offset: 2px; }
.bubble .b-time { display: block; font-size: 11px; margin-top: 4px; opacity: .65; }
.bubble--in  { align-self: flex-start; background: #fff; border: 1px solid var(--c-border); border-bottom-left-radius: 5px; }
.bubble--out { align-self: flex-end; background: var(--c-blue); color: #fff; border-bottom-right-radius: 5px; }
.bubble--out a { color: #fff; }
.chat-day { align-self: center; font-size: 11.5px; color: var(--c-muted); background: #fff; border: 1px solid var(--c-border); padding: 3px 12px; border-radius: var(--r-pill); }
.chat-compose { flex: none; background: #fff; border-top: 1px solid var(--c-border); padding: 12px 16px; }
/* One field, not two controls side by side: the FORM carries the border and the
   focus ring, the textarea is transparent inside it, and the send button sits
   within the same frame on the right. Bottom-aligned so the button stays beside
   the last line as the box grows rather than drifting to the middle of it. */
.chat-compose form {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  background: #fff;
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  padding: 6px 6px 6px 14px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.chat-compose form:focus-within { border-color: var(--c-blue); box-shadow: 0 0 0 3px rgba( 37, 99, 235, .12 ); }
.chat-compose .compose-field { flex: 1; min-width: 0; }
/* The base .textarea is a 120px-tall block control; inside the composer it is a
   single line that grows to 120px, so every one of those properties is reset
   rather than overridden piecemeal from the template. */
.chat-compose .textarea {
  width: 100%;
  min-height: 0;
  height: 40px;
  max-height: 120px;
  padding: 9px 0;
  border: 0;
  background: transparent;
  border-radius: 0;
  resize: none;
  line-height: 1.5;
  overflow-y: auto;
}
.chat-compose .textarea:focus { border: 0; box-shadow: none; outline: 0; }
.chat-compose .compose-send { flex: none; width: 38px; height: 38px; padding: 0; border-radius: var(--r-md); }
.chat-notice { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--c-muted); margin-top: 8px; }

/* -------------------------------------------------------------------------
   20. PRODUCT DETAIL
   ------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
   The frame is on the container, and the image area fills it.

   `.gallery-main > img` used to carry the sizing, and matched NOTHING:
   WooCommerce nests its image as
   `.woocommerce-product-gallery > .woocommerce-product-gallery__wrapper >
   .woocommerce-product-gallery__image > a > img`, so the frame sat empty at
   4:3 with a natural-size image in its top-left corner.

   The frame stays on `.gallery-main` because `.p-badges` is positioned against
   it, and because a single-image product has nothing below the frame anyway.
   For a multi-image product flexslider adds a thumbnail strip INSIDE this
   element, which `overflow: hidden` would clip — so the frame's height is the
   image area's, not the container's, and the strip is allowed to sit below it.
   ------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
   The listing detail grid.

   Declared here rather than as `lg:grid-cols-[…]` in the template, because a
   Tailwind arbitrary value only exists if a build has seen that exact string —
   and a build cannot run here. See the note in content-single-product.php.

   minmax(0,…) rather than a bare fr on both tracks: without it a long word or
   a wide table in either column can push the track past its share, which is
   the whole reason the utility version needed `min-w-0` on its children.
   ------------------------------------------------------------------------- */
/* The purchase column's own type scale, from page-product.js — the title and
   price are set larger here than anywhere the card components appear. */
.p-detail-title { font-size: clamp(1.25rem, 2.2vw, 1.6rem); }

.p-detail-price {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
  font-size: clamp(26px, 4vw, 34px);
  font-weight: 800;
  letter-spacing: -.035em;
}

/* The sale figures stay at reading size beside a 34px price rather than
   scaling with it. */
.p-detail-price .was { font-size: 16px; margin-left: 0; }
.p-detail-price .off { font-size: 13px; margin-left: 0; }

.p-detail-meta { margin: 12px 0 0; padding: 0; list-style: none; }

.p-detail-grid { display: grid; gap: 24px; }

@media (min-width: 1024px) {
  .p-detail-grid { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); gap: 32px; }

  /*
   * The summary column — badges, title, price, seller, actions — is FIRST in
   * the source, so the page's `h1` comes before the "Details", "Description"
   * and "Seller reviews" headings. The note in content-single-product.php says
   * why that matters.
   *
   * These two rules put it back on the right at desktop width, so the designed
   * two-column layout is exactly what it was: gallery left, summary right. They
   * are the only thing standing between the accessible source order and the
   * intended visual one, which is why they are stated explicitly rather than
   * left to a `row-reverse` a later edit could quietly drop.
   *
   * Below 1024px the grid is one column and follows the source, which is the
   * order a phone should have had all along: title and price before the
   * specification table and the description.
   */
  .p-detail-grid > :first-child { order: 2; }

  .p-detail-grid > :nth-child(2) { order: 1; }
}

/* -------------------------------------------------------------------------
   CHECKOUT
   The prototype's structure: three numbered cards down the left, one sticky
   order summary on the right. `page-checkout.js` is the reference.

   Almost none of this existed. `woocommerce-checkout-review-order-table`,
   `shop_table`, `order-total`, `wc_payment_methods` and `place-order` had not
   one rule between them, so the whole right-hand column and the payment
   method list rendered as bare browser defaults inside designed cards.
   ------------------------------------------------------------------------- */

/* The two columns. In marketplace.css rather than as `lg:grid-cols-[…]`
   because a Tailwind arbitrary value only exists once a build has seen that
   exact string, and the prototype's `minmax(0,1fr)_380px` has never been
   built. See the note in content-single-product.php. */
.checkout-grid { display: grid; gap: 24px; }

@media (min-width: 1024px) {
  .checkout-grid { grid-template-columns: minmax(0, 1fr) 380px; }
}

/* WooCommerce prints its own "Billing details" / "Ship to a different
   address?" headings inside these wrappers, and the numbered card head above
   them already says what the card is — so two headings stacked. Hidden rather
   than removed by overriding form-billing.php and form-shipping.php, which
   would mean carrying 140 lines of WooCommerce's field and registration logic
   in this theme to delete one line from each.

   The shipping one is a LABEL for the ship-to-different-address checkbox, so
   only its `h3` role is dropped — the checkbox inside it has to stay. */
.woocommerce-billing-fields > h3,
.woocommerce-additional-fields > h3 { display: none; }

.woocommerce-shipping-fields > h3#ship-to-different-address {
  margin: 0 0 14px;
  font-size: inherit;
  font-weight: 400;
}

/* -------------------------------------------------------------------------
   The order summary card
   ------------------------------------------------------------------------- */

/* The item list scrolls rather than growing the card past the viewport, so
   the total and the payment step stay reachable on a long order. */
.co-items {
  margin: 0;
  padding: 6px 0;
  list-style: none;
  max-height: 320px;
  overflow-y: auto;
}

.co-item {
  display: flex;
  gap: 11px;
  align-items: center;
  padding: 10px 20px;
}

.co-item-thumb { position: relative; flex: none; }

.co-item-thumb img {
  display: block;
  width: 48px;
  height: 48px;
  border-radius: 8px;
  -o-object-fit: cover;
     object-fit: cover;
  border: 1px solid var(--c-border);
}

/* The quantity, as a badge on the thumbnail. Its white ring keeps it legible
   against any photo. */
.co-item-qty {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 10px;
  background: var(--c-blue);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: grid;
  place-items: center;
  border: 2px solid #fff;
}

.co-item-body { min-width: 0; flex: 1; }

.co-item-name {
  display: block;
  font-size: 13.5px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.co-item-total { flex: none; font-weight: 600; font-size: 14px; }

/* The card clips its own scrolling list against its rounded corners — without
   this the list's first and last rows square off the card's top and bottom. */
.co-summary { overflow: hidden; }

.co-totals { border-top: 1px solid var(--c-border); }

/* A cart fee is a totals row like any other and needs nothing of its own. The
   class is kept because it is WooCommerce's and plugins target it. */
.co-totals-table .fee th { color: var(--c-muted); }

/* A table, because the helpers and hooks that fill this region print `<tr>`
   rows — see the note in review-order.php. Styled to read as the design's
   label/value rows rather than as a table. */
.co-totals-table { width: 100%; border-collapse: collapse; }

.co-totals-table th,
.co-totals-table td {
  padding: 5px 0;
  border: 0;
  vertical-align: baseline;
}

.co-totals-table th {
  text-align: left;
  font-weight: 400;
  font-size: 13px;
  color: var(--c-muted);
}

.co-totals-table td { text-align: right; font-weight: 600; }

/* Free delivery is good news, so it reads as such. */
.co-totals-table .woocommerce-free-shipping-label,
.co-totals-table .free-shipping td { color: var(--c-ok); }

/* The grand total, set large and separated by the design's rule. */
.co-totals-table .order-total th,
.co-totals-table .order-total td {
  border-top: 1px solid var(--c-border-soft);
  padding-top: 13px;
}

.co-totals-table .order-total th { color: var(--c-text); font-weight: 600; font-size: 14.5px; }

.co-totals-table .order-total td {
  font-weight: 800;
  font-size: 22px;
  letter-spacing: -.03em;
}

.co-total-note { margin-top: 3px; text-align: right; }

/* Shipping choices arrive as WooCommerce's own list inside a cell. */
.co-totals-table #shipping_method {
  margin: 0;
  padding: 0;
  list-style: none;
  font-weight: 400;
  font-size: 13px;
}

.co-totals-table #shipping_method li { padding: 2px 0; }
.co-totals-table #shipping_method label { cursor: pointer; }

.co-totals-table .woocommerce-shipping-destination { font-weight: 400; font-size: 12px; color: var(--c-muted); }

/* -------------------------------------------------------------------------
   Payment methods, as the design's selectable cards
   WooCommerce renders `<ul class="wc_payment_methods"><li><input radio>
   <label>…`, and the template is not overridden — the terms checkbox, the
   nonce and the submit button live in it together, and separating them to
   match the prototype's column would orphan the hooks gateways use. So this
   is styling only.
   ------------------------------------------------------------------------- */
.wc_payment_methods { margin: 0; padding: 0; list-style: none; display: grid; gap: 12px; }

.wc_payment_methods > li.wc_payment_method {
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: #fff;
  padding: 14px;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
  /* The whole card selects the method — see assets/js/checkout.js, which
     forwards a click on the card to the radio. The cursor has to say so across
     the whole card, not only over the label. */
  cursor: pointer;
}

/* The gateway's own panel keeps normal cursors: it holds its fields and links,
   and the card handler deliberately leaves clicks inside it alone. */
.wc_payment_methods > li.wc_payment_method .payment_box,
.wc_payment_methods > li.wc_payment_method .payment_box * { cursor: auto; }

.wc_payment_methods > li.wc_payment_method .payment_box a,
.wc_payment_methods > li.wc_payment_method .payment_box button { cursor: pointer; }

/* Keyboard focus has to be as visible as the hover state, because the radio
   itself is the tab stop and it sits inside a card that now looks clickable. */
.wc_payment_methods > li.wc_payment_method:focus-within {
  border-color: var(--c-blue);
  box-shadow: 0 0 0 3px var(--c-blue-soft);
}

.wc_payment_methods > li.wc_payment_method:hover { border-color: var(--c-blue); }

/* The chosen method, marked by WooCommerce on the input rather than the row —
   so the row is reached from it. */
.wc_payment_methods > li.wc_payment_method:has( input:checked ) {
  border-color: var(--c-blue);
  background: var(--c-blue-soft);
}

.wc_payment_methods > li.wc_payment_method > label {
  display: flex;
  align-items: center;
  gap: 12px;
  font-weight: 600;
  font-size: 14.5px;
  cursor: pointer;
  margin: 0;
}

.wc_payment_methods > li.wc_payment_method > input[type="radio"] {
  accent-color: var(--c-blue);
  width: 18px;
  height: 18px;
  flex: none;
  margin: 0 0 0 2px;
}

/* A gateway's own icon, which is an <img> it supplies. */
.wc_payment_methods > li.wc_payment_method > label img {
  max-height: 24px;
  width: auto;
  margin-left: auto;
}

/* A gateway's description and fields, revealed under the row it belongs to. */
.wc_payment_methods .payment_box {
  margin: 12px 0 0;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--c-page);
  border: 1px solid var(--c-border-soft);
  font-size: 13px;
  color: var(--c-text-2);
}

.wc_payment_methods .payment_box p:last-child { margin-bottom: 0; }

/* No gateway configured. WooCommerce prints a notice in a bare <li>, which
   would otherwise wear the card border above and look like a choice. */
.wc_payment_methods > li:not( .wc_payment_method ) {
  border: 0;
  padding: 0;
  background: none;
}

/* -------------------------------------------------------------------------
   Terms, and the submit button
   ------------------------------------------------------------------------- */
.woocommerce-checkout-payment .place-order { margin: 16px 0 0; padding: 0; }

.woocommerce-checkout-payment .woocommerce-terms-and-conditions-wrapper { margin-bottom: 14px; }

.woocommerce-checkout-payment .form-row.place-order label.checkbox,
.woocommerce-checkout-payment .validate-required label.checkbox {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: 13.5px;
  cursor: pointer;
}

/* `#place_order` is WooCommerce's id and cannot be given `.btn` from a
   template, so `.btn-primary.btn-lg.btn-block`'s appearance is written onto
   it. Keep it in step with those. */
#place_order {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 48px;
  padding: 0 22px;
  border: 1px solid var(--c-blue);
  border-radius: var(--r-md);
  background: var(--c-blue);
  color: #fff;
  font-size: 15.5px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}

#place_order:hover { background: var(--c-blue-dark); border-color: var(--c-blue-dark); }
#place_order:disabled { opacity: .55; cursor: default; }

/* The no-JavaScript "Update totals" fallback, which must stay reachable. */
.woocommerce-checkout-payment noscript { display: block; margin-bottom: 12px; font-size: 13px; }

.gallery-main { position: relative; }

/* The framed image area. `.flex-viewport` is flexslider's own wrapper and
   only exists once its JS has run; the gallery wrapper is what is there
   before that and on a single-image product. Both are framed so the box does
   not change shape when the slider initialises. */
.gallery-main .flex-viewport,
.gallery-main .woocommerce-product-gallery__wrapper {
  aspect-ratio: 4/3;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--c-border-soft);
  border: 1px solid var(--c-border);
  margin: 0;
}

/* Once flexslider wraps it, the inner wrapper is the moving track and must not
   be framed a second time. */
.gallery-main .flex-viewport .woocommerce-product-gallery__wrapper {
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
  background: none;
  overflow: visible;
  height: 100%;
}

.gallery-main .woocommerce-product-gallery__image,
.gallery-main .woocommerce-product-gallery__image > a { display: block; height: 100%; }

.gallery-main .woocommerce-product-gallery__image img,
.gallery-main > img {
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
     object-fit: cover;
  cursor: zoom-in;
  transition: opacity var(--t-base) var(--ease);
}

/* WooCommerce prints `opacity: 0` inline and its own script restores it after
   the slider initialises. If that script does not run — a JS error anywhere
   earlier on the page will do it — the gallery is invisible with no clue why.
   `!important` because the 0 is an inline style and nothing else can beat it. */
.no-js .gallery-main .woocommerce-product-gallery { opacity: 1 !important; }

/* WooCommerce's full-screen trigger, hidden.
   Two reasons, and either alone would be enough: the design has no such
   control, and it is injected at the gallery's top-right — exactly where the
   wishlist heart now sits, so the two overlapped. Nothing is lost, because
   clicking the image opens the same lightbox: WooCommerce binds PhotoSwipe to
   the anchor around it, not to this button. */
.gallery-main .woocommerce-product-gallery__trigger { display: none; }

/* flexslider's thumbnail strip, given the design's `.gthumb` language. It is
   a plain <ol> until this styles it. */
.gallery-main .flex-control-thumbs {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}

.gallery-main .flex-control-thumbs li { margin: 0; }

.gallery-main .flex-control-thumbs img {
  width: 100%;
  aspect-ratio: 1;
  -o-object-fit: cover;
     object-fit: cover;
  border-radius: var(--r-sm);
  border: 2px solid transparent;
  background: var(--c-border-soft);
  cursor: pointer;
  opacity: .7;
  transition: opacity var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}

.gallery-main .flex-control-thumbs img:hover { opacity: 1; }

/* flexslider marks the current thumbnail with `.flex-active`. */
.gallery-main .flex-control-thumbs img.flex-active {
  opacity: 1;
  border-color: var(--c-blue);
}

/* flexslider's prev/next arrows, drawn as the design's `.gnav` overlay
   controls — the prototype has a pair on the gallery, so they are kept rather
   than hidden. Its markup is an <ul> of <li><a> with the label as text.

   A single-image product gets no arrows: flexslider adds `.flex-disabled` to
   both ends, and two dead controls over one photo is worse than none. */
.gallery-main .flex-direction-nav { margin: 0; padding: 0; list-style: none; }

.gallery-main .flex-direction-nav a {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255,255,255,.94);
  border: 1px solid var(--c-border);
  color: var(--c-text);
  font-size: 0;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}

.gallery-main .flex-direction-nav a:hover { background: #fff; box-shadow: var(--sh-card); }

.gallery-main .flex-direction-nav .flex-prev { left: 12px; }
.gallery-main .flex-direction-nav .flex-next { right: 12px; }

/* The chevrons. Drawn rather than iconised because this markup is
   WooCommerce's and carries nowhere to put an SVG. */
.gallery-main .flex-direction-nav a::after {
  font-size: 17px;
  line-height: 1;
  font-family: inherit;
}

.gallery-main .flex-direction-nav .flex-prev::after { content: "\2039"; }
.gallery-main .flex-direction-nav .flex-next::after { content: "\203A"; }

/* Both ends disabled means one image, so there is nothing to move between. */
.gallery-main .flex-direction-nav a.flex-disabled { display: none; }

/* -------------------------------------------------------------------------
   SELLER REVIEWS
   The prototype's summary: the average set large with its stars beside a
   five-row bar chart, then the reviews themselves.
   ------------------------------------------------------------------------- */
.review-summary {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--c-border-soft);
}

/* The score column: number, stars, count — kept together so the chart beside
   it cannot pull them apart when the row wraps. */
.review-score { flex: none; }

/* The single line the review form prints when it cannot be used — "You cannot
   review your own listing", or an invitation to sign in. It sits at the foot of
   the reviews card instead of in a card of its own, so the rule is what
   separates it from the moderation note above it. */
.review-blocker { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--c-border); }

/* The seller's own detail rows on the listing form: a name and a value side by
   side, the value given the wider half because "Space grey, 256GB" is longer
   than "Colour". Stacked below 640px, where two inputs on a line leave neither
   readable. */
/* A listing that is not live, in place of the price and Add to cart. Only its
   seller and a moderator ever see it, and it replaces what used to be an empty
   price line above an empty meta list. */
.listing-state {
  display: grid; gap: 8px; justify-items: start;
  margin: 4px 0 2px; padding: 14px;
  border: 1px solid var(--c-border); border-left: 3px solid var(--c-blue);
  border-radius: var(--r-md); background: var(--c-blue-soft);
}
.listing-state-head { display: flex; align-items: center; gap: 8px; color: var(--c-blue-dark); }
.listing-state-head strong { font-size: 14.5px; }
.listing-state-body { margin: 0; line-height: 1.55; }

/* -------------------------------------------------------------------------
   THE LISTING FORM'S MEDIA PICKER
   Square frames because a listing card crops to a square, so what the seller
   arranges here is what a buyer will see. The cover badge and the two controls
   sit on the image rather than under it: five photographs with a row of labels
   under each becomes a list, not a gallery.
   ------------------------------------------------------------------------- */
/* The suggestion panel's section label, when it carries an action. `dd-label`
   is a plain caption everywhere else, so the row variant is what makes room
   for Clear rather than changing the caption itself. */
.dd-label--row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

.dd-clear {
  border: 0; background: none; padding: 0; cursor: pointer;
  font: inherit; font-weight: 600; text-transform: none; letter-spacing: 0;
  color: var(--c-blue);
}
.dd-clear:hover { text-decoration: underline; }

.media-thumbs { display: flex; gap: 10px; flex-wrap: wrap; }
.media-thumbs:not(:empty) { margin-bottom: 10px; }

.media-thumb {
  position: relative; width: 92px; height: 92px; flex: none;
  border: 1px solid var(--c-border); border-radius: var(--r-md);
  overflow: hidden; background: var(--c-subtle);
}
.media-thumb img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; display: block; }
.media-thumb.is-featured { border-color: var(--c-blue); box-shadow: 0 0 0 2px var(--c-blue-ring); }

.media-thumb-badge,
.media-thumb-cover {
  position: absolute; left: 4px; bottom: 4px;
  padding: 2px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 600; line-height: 1.6;
}
.media-thumb-badge { background: var(--c-blue); color: #fff; }

.media-thumb-cover {
  border: 0; cursor: pointer;
  background: rgba(17, 24, 39, .74); color: #fff;
  opacity: 0; transition: opacity var(--t-fast) var(--ease);
}
.media-thumb:hover .media-thumb-cover,
.media-thumb-cover:focus-visible { opacity: 1; }

.media-thumb-remove {
  position: absolute; top: 4px; right: 4px;
  width: 22px; height: 22px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 999px; cursor: pointer;
  background: rgba(17, 24, 39, .74); color: #fff;
  font-size: 15px; line-height: 1;
}
.media-thumb-remove:hover { background: var(--c-bad); }

/* The whole picker while a file is in flight, and while one is over it. */
[data-media-picker].is-uploading { opacity: .65; pointer-events: none; }
[data-media-picker].is-dragging {
  outline: 2px dashed var(--c-blue); outline-offset: 4px; border-radius: var(--r-md);
}

.detail-rows { display: grid; gap: 10px; }
.detail-row { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 10px; }

/* The button that reveals the spare rows. It is `hidden` in the markup and
   only shown by listing-form.js — with no script every row is already on the
   page, and a button offering to reveal what is already visible is worse than
   no button. */
.detail-add { margin-top: 10px; gap: 6px; }

/* The category's own fields ("Vehicles details": Make, Model, Year…), printed
   by MarketFlow Core's Listing_Attribute_Fields with bare `<label>`, `<input>`
   and `<select>` and only its own mf-* classes. Styled here to match the rest of
   the form rather than by adding theme classes to the plugin's markup. */
.mf-attributes:not(:has(.mf-attr-group:not([hidden]))) { display: none; }
.mf-attr-group {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px 20px;
  margin: 0; padding: 20px; min-width: 0;
  border: 1px solid var(--c-border); border-radius: var(--r-lg); background: var(--c-subtle);
}
/* `display: grid` would otherwise override the attribute listing-form.js sets. */
.mf-attr-group[hidden] { display: none; }
@media (min-width: 640px) {
  .mf-attr-group { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Floated, so the legend leaves the border and becomes the card's heading — a
   grid item spanning both columns. */
.mf-attr-group > legend {
  float: left; width: 100%; grid-column: 1 / -1; padding: 0;
  font-size: 15px; font-weight: 700; color: var(--c-text);
}
.mf-field-attr { margin: 0; min-width: 0; }
.mf-field-attr > label {
  display: block; margin-bottom: 6px;
  font-size: 12.5px; font-weight: 600; color: var(--c-text-2);
}
.mf-field-attr > input,
.mf-field-attr > select {
  width: 100%; background: #fff; color: var(--c-text);
  border: 1px solid var(--c-border); border-radius: var(--r-md);
  padding: 0 14px; height: 46px; font-size: 15px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.mf-field-attr > select:not([multiple]) {
  appearance: none; -webkit-appearance: none; padding-right: 38px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%234B5563' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center;
}
.mf-field-attr > select[multiple] { height: auto; padding: 8px 10px; }
.mf-field-attr > input:focus,
.mf-field-attr > select:focus {
  border-color: var(--c-blue); box-shadow: 0 0 0 3px var(--c-blue-ring); outline: none;
}
/* Model waits for a Make: say so, rather than looking like a broken box. */
.mf-field-attr > select:disabled { background-color: var(--c-subtle); color: var(--c-muted); cursor: not-allowed; }

/* The Location box takes a `<datalist>`, and Chrome draws a picker arrow inside
   any input that has one — which makes a text field look like a select. The
   attribute stays, because it is what offers the places already in use with no
   script and no API key; only the arrow goes. Two names for one control: Safari
   and older Chrome called it the list button. */
input[data-mf-places]::-webkit-calendar-picker-indicator,
input[data-mf-places]::-webkit-list-button {
  display: none !important;
  opacity: 0;
  -webkit-appearance: none;
          appearance: none;
}
@media (max-width: 640px) { .detail-row { grid-template-columns: minmax(0, 1fr); gap: 8px; } }
.review-blocker p { margin: 0; }

.review-score-num {
  font-size: 38px;
  font-weight: 800;
  letter-spacing: -.04em;
  line-height: 1;
}

/* The chart takes the rest of the row, and drops under the score rather than
   squeezing to nothing on a narrow column. */
.review-bars { flex: 1; min-width: 200px; }

.rating-bars { display: grid; gap: 6px; }

.rating-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}

.rating-bar-star { width: 26px; color: var(--c-muted); flex: none; }

.rating-bar-track {
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: var(--c-border-soft);
  overflow: hidden;
}

.rating-bar-fill {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--c-yellow);
}

.rating-bar-pct {
  width: 34px;
  flex: none;
  text-align: right;
  color: var(--c-muted);
  font-variant-numeric: tabular-nums;
}

/* Which listing a review was left on. */
.review-on { display: inline-block; margin-top: 6px; }

/* -------------------------------------------------------------------------
   A GROUPED PRODUCT
   WooCommerce renders its children as `table.woocommerce-grouped-product-list`
   — a quantity, a label and a price per row. The simple-product grid above was
   forcing the whole table into column one and the button into column two
   beside it, which stacked the rows on top of each other and clipped the
   button's own label.
   ------------------------------------------------------------------------- */
.mk-product form.cart.grouped_form { grid-template-columns: minmax(0, 1fr); }

.mk-product .woocommerce-grouped-product-list {
  width: 100%;
  border-collapse: collapse;
  margin: 0;
}

/* Each row becomes a grid so the cells can be REORDERED — WooCommerce prints
   them quantity-first and the design puts the quantity last, and a table cell
   cannot be moved any other way. `display: contents` on the row would hand the
   cells to the table's own layout again, so the row itself is the grid. */
.mk-product .woocommerce-grouped-product-list-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--c-border-soft);
}

.mk-product .woocommerce-grouped-product-list-item:last-child { border-bottom: 0; }

.mk-product .woocommerce-grouped-product-list-item > td {
  padding: 10px 0;
  border: 0;
  vertical-align: middle;
}

/* Name, price, then the stepper. */
.mk-product .woocommerce-grouped-product-list-item__label { order: 1; }
.mk-product .woocommerce-grouped-product-list-item__price { order: 2; }
.mk-product .woocommerce-grouped-product-list-item__quantity { order: 3; white-space: nowrap; }

/* The row's own head cells, if a theme or plugin adds them, follow the name. */
.mk-product .woocommerce-grouped-product-list-item > th { order: 1; padding: 10px 0; border: 0; }

@media (max-width: 480px) {
  /* Two lines on a narrow column: name over price and stepper. */
  .mk-product .woocommerce-grouped-product-list-item {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .mk-product .woocommerce-grouped-product-list-item__label { grid-column: 1 / -1; }
}

.mk-product .woocommerce-grouped-product-list-item__label { font-size: 14.5px; }
.mk-product .woocommerce-grouped-product-list-item__label label { margin: 0; font-weight: 500; }
.mk-product .woocommerce-grouped-product-list-item__label a { color: inherit; }
.mk-product .woocommerce-grouped-product-list-item__label a:hover { color: var(--c-blue); }

.mk-product .woocommerce-grouped-product-list-item__price {
  text-align: right;
  font-weight: 600;
  white-space: nowrap;
}

.mk-product .woocommerce-grouped-product-list-item__price del { color: var(--c-muted); font-weight: 500; margin-right: 6px; }
.mk-product .woocommerce-grouped-product-list-item__price ins { text-decoration: none; }

/* A child that cannot be bought says so instead of showing a stepper. */
.mk-product .woocommerce-grouped-product-list-item .stock { font-size: 12.5px; }

/* The one button, under the whole table. */
.mk-product form.cart.grouped_form .single_add_to_cart_button { margin-top: 14px; }

/* -------------------------------------------------------------------------
   WOOCOMMERCE'S REVIEW FORM
   Shown for a product that is NOT a MarketFlow listing — a plain shop product
   keeps WooCommerce's own reviews, because a rating there belongs to the
   product and not to a seller. It had no styling whatsoever, so it arrived as
   a run of bare text and five unlabelled star links.
   ------------------------------------------------------------------------- */
#reviews .woocommerce-Reviews-title { font-size: 17px; font-weight: 700; margin-bottom: 10px; }
#reviews .woocommerce-noreviews { color: var(--c-muted); font-size: 14px; }

#reviews .comment-reply-title {
  display: block;
  font-size: 15px;
  font-weight: 600;
  margin: 18px 0 12px;
}

#reviews .comment-form { display: grid; gap: 14px; }
#reviews .comment-form p { margin: 0; }

#reviews .comment-form label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: var(--c-text-2);
  margin-bottom: 6px;
}

#reviews .comment-form input[type="text"],
#reviews .comment-form input[type="email"],
#reviews .comment-form textarea {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: #fff;
  color: var(--c-text);
  font-size: 14.5px;
  font-family: inherit;
}

#reviews .comment-form textarea { min-height: 120px; resize: vertical; }

#reviews .comment-form input:focus,
#reviews .comment-form textarea:focus {
  outline: 2px solid var(--c-blue);
  outline-offset: -1px;
  border-color: var(--c-blue);
}

/* The rating. WooCommerce ships five links whose text is "1 of 5 stars" and
   so on, with a star font behind them — and the font is in the stylesheet this
   theme dequeues, so the words showed instead. Drawn as five characters, with
   the words kept for screen readers. */
#reviews .comment-form-rating { display: grid; gap: 6px; }

/* `p.stars` holds a `<span>` which holds the five links, and it was the SPAN
   that needed to be the row — styling the paragraph left five block-level
   anchors stacked one per line down the form. */
#reviews .stars { margin: 0; line-height: 1; }

#reviews .stars > span {
  display: inline-flex;
  gap: 4px;
  font-size: 0;
}

#reviews .stars a {
  position: relative;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  text-decoration: none;
  color: var(--c-border);
  transition: color var(--t-fast) var(--ease);
}

#reviews .stars a::before {
  content: "\2605";
  font-size: 22px;
  line-height: 1;
}

#reviews .stars a:hover,
#reviews .stars.selected a.active,
#reviews .stars.selected a:not( .active ) { color: var(--c-yellow-deep); }

/* Once a rating is chosen WooCommerce marks the run up to it; the ones past it
   go back to grey. */
#reviews .stars.selected a.active ~ a { color: var(--c-border); }

#reviews .comment-form-cookies-consent { display: flex; gap: 8px; align-items: flex-start; }
#reviews .comment-form-cookies-consent label { margin: 0; font-size: 13px; }

/* The submit button, given `.btn.btn-primary`'s appearance. */
#reviews .comment-form .submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  height: 42px;
  padding: 0 20px;
  border: 1px solid var(--c-blue);
  border-radius: var(--r-md);
  background: var(--c-blue);
  color: #fff;
  font-size: 14.5px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}

#reviews .comment-form .submit:hover { background: var(--c-blue-dark); border-color: var(--c-blue-dark); }

/* An existing review's own layout. */
#reviews .commentlist { margin: 0; padding: 0; list-style: none; display: grid; gap: 14px; }

#reviews .commentlist .review {
  padding: 14px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
}

#reviews .commentlist .review .meta { font-size: 13px; color: var(--c-muted); margin-bottom: 6px; }
#reviews .commentlist .review .description p:last-child { margin-bottom: 0; }
#reviews .commentlist .review img.avatar { width: 36px; height: 36px; border-radius: 50%; float: left; margin-right: 10px; }

/* -------------------------------------------------------------------------
   THE SIDEBAR ADVERT
   Under the home page's category list. No fixed height: the image sets it, so
   a 300x250 and a 300x600 both sit correctly and neither is letterboxed.
   ------------------------------------------------------------------------- */
.sidebar-ad { margin-top: 16px; position: relative; }

.sidebar-ad-img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-lg);
  border: 1px solid var(--c-border);
}

/* The disclosure, over the image's corner rather than below it — the design
   has no room for a caption line in this column. */
.sidebar-ad-tag {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 2px 7px;
  border-radius: var(--r-sm);
  background: rgba(17,24,39,.7);
  color: #fff;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
}

/* -------------------------------------------------------------------------
   THE ADD-TO-CART FORM
   WooCommerce's own `form.cart`, which had NO styling in this theme at all —
   so the design's primary action on a listing page rendered as a browser
   default button next to a bare number field.

   The template calls woocommerce_template_single_add_to_cart() on purpose, so
   variations, stock, tax display and every gateway's hooks keep working. That
   means the markup is WooCommerce's and the styling has to come to it.
   ------------------------------------------------------------------------- */
.mk-product form.cart { display: grid; gap: 10px; margin: 0; }

/* Quantity beside the button on one row, the button taking the rest — for a
   SIMPLE product, whose form holds only those two.

   `:not(.variations_form)` matters. A variable product's form starts with a
   `<table class="variations">`, which landed in column one and squeezed the
   quantity and the button into column two beside the selects. Its layout is
   below. */
/* Simple products only. A VARIABLE form starts with `table.variations` and a
   GROUPED form is a table of children — both carry `.quantity`, so both were
   caught by this and had their layout crushed into two columns. Each has its
   own rules further down. */
.mk-product form.cart:not( .variations_form ):not( .grouped_form ):has( .quantity ) {
  grid-template-columns: auto 1fr;
  align-items: center;
}

/* -------------------------------------------------------------------------
   A variable product: the attribute selects, then quantity + button
   ------------------------------------------------------------------------- */

/* WooCommerce ships the selects as a table with a `presentation` role, so it
   is not a table to anyone — which means it can be laid out as the pairs it
   actually is. */
.mk-product form.cart .variations {
  display: grid;
  gap: 10px;
  width: 100%;
  margin: 0;
  border: 0;
}

.mk-product form.cart .variations tbody,
.mk-product form.cart .variations tr {
  display: contents;
}

.mk-product form.cart .variations th.label,
.mk-product form.cart .variations td.value {
  display: block;
  padding: 0;
  border: 0;
  text-align: left;
}

.mk-product form.cart .variations th.label {
  font-size: 13px;
  font-weight: 500;
  color: var(--c-text-2);
  margin-bottom: 4px;
}

.mk-product form.cart .variations th.label label { margin: 0; cursor: pointer; }

/* The select, given the design system's own field appearance — WooCommerce
   supplies no class of ours to hook. */
.mk-product form.cart .variations select {
  width: 100%;
  height: 44px;
  padding: 0 34px 0 12px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background-color: #fff;
  color: var(--c-text);
  font-size: 14.5px;
  font-family: inherit;
  cursor: pointer;
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  /* The chevron, drawn rather than iconised: this is WooCommerce's markup and
     carries nowhere to put an SVG. */
  background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748B' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E" );
  background-repeat: no-repeat;
  background-position: right 12px center;
}

.mk-product form.cart .variations select:focus {
  outline: 2px solid var(--c-blue);
  outline-offset: -1px;
  border-color: var(--c-blue);
}

/* "Clear" sits under the last select rather than beside it, where it was
   colliding with the chevron. */
.mk-product form.cart .reset_variations {
  display: inline-block;
  margin-top: 6px;
  font-size: 12.5px;
  color: var(--c-muted);
}

.mk-product form.cart .reset_variations:hover { color: var(--c-blue); }

/* The price and stock line WooCommerce injects once a variation is chosen. */
.mk-product form.cart .single_variation { margin-bottom: 4px; }
.mk-product form.cart .single_variation .price { font-size: 20px; font-weight: 700; }

/* Quantity and button, on their own row under the selects. */
.mk-product form.cart .woocommerce-variation-add-to-cart {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: center;
}

/* Until a variation is chosen WooCommerce disables the button and leaves it in
   place, which is right — the row should not jump when it becomes usable. */
.mk-product form.cart .woocommerce-variation-add-to-cart-disabled .single_add_to_cart_button {
  opacity: .55;
  cursor: default;
}

.mk-product form.cart .quantity {
  display: flex;
  align-items: center;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  overflow: hidden;
}

.mk-product form.cart .quantity input {
  width: 66px;
  height: 46px;
  border: 0;
  text-align: center;
  padding: 0;
  border-radius: 0;
  font-size: 15px;
  background: #fff;
  color: var(--c-text);
}

.mk-product form.cart .quantity input:focus { outline: 2px solid var(--c-blue); outline-offset: -2px; }

/* The button, given `.btn.btn-primary.btn-lg.btn-block`'s appearance — which
   is what the prototype uses for "Buy now". Written out rather than shared
   with `.btn` because the class is WooCommerce's and cannot be changed from a
   template. Keep it in step with `.btn-primary`. */
.mk-product form.cart .single_add_to_cart_button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 46px;
  padding: 0 20px;
  border: 1px solid var(--c-blue);
  border-radius: var(--r-md);
  background: var(--c-blue);
  color: #fff;
  font-size: 15px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}

.mk-product form.cart .single_add_to_cart_button:hover {
  background: var(--c-blue-dark);
  border-color: var(--c-blue-dark);
}

.mk-product form.cart .single_add_to_cart_button:disabled {
  opacity: .55;
  cursor: default;
}

/* A grouped or external product has no quantity field, so the button is the
   whole row. */
.mk-product form.cart .single_add_to_cart_button.disabled { grid-column: 1 / -1; }

/* Stock and variation copy, which arrive as WooCommerce's own paragraphs. */
.mk-product .stock { font-size: 13px; margin: 0; }
.mk-product .stock.in-stock { color: var(--c-ok); }
.mk-product .stock.out-of-stock { color: var(--c-bad); }
.gallery-thumbs { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-top: 10px; }
.gthumb {
  aspect-ratio: 1; border-radius: var(--r-sm); overflow: hidden; border: 2px solid transparent;
  background: var(--c-border-soft); cursor: pointer; padding: 0;
  transition: border-color var(--t-fast) var(--ease);
}
.gthumb img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; }
.gthumb[aria-current="true"] { border-color: var(--c-blue); }
.gnav {
  position: absolute; top: 50%; transform: translateY(-50%); width: 38px; height: 38px; z-index: 2;
  border-radius: 50%; background: rgba(255,255,255,.94); border: 1px solid var(--c-border);
  display: grid; place-items: center; cursor: pointer; color: var(--c-text);
  transition: background var(--t-fast) var(--ease);
}
.gnav:hover { background: #fff; box-shadow: var(--sh-card); }
.gnav-prev { left: 12px; } .gnav-next { right: 12px; }
.lightbox { position: fixed; inset: 0; z-index: 110; background: rgba(17,24,39,.94); display: none; place-items: center; padding: 24px; }
.lightbox.is-open { display: grid; }
.lightbox img { max-width: 100%; max-height: 86vh; -o-object-fit: contain; object-fit: contain; border-radius: var(--r-md); }

.spec-row { display: flex; justify-content: space-between; gap: 20px; padding: 11px 0; border-bottom: 1px solid var(--c-border-soft); font-size: 14px; }
.spec-row:last-child { border-bottom: 0; }
.spec-row dt { color: var(--c-muted); }
.spec-row dd { margin: 0; font-weight: 500; text-align: right; }

/*
 * Sticky only where there is a second column to scroll beside. Below 1024px
 * every layout that uses this class (product, cart, checkout, order pages) is
 * one column, and a sticky block there pins under the header while the rest of
 * the page scrolls OVER it - on the product page the gallery slid across the
 * price and the Contact seller button.
 */
@media (min-width: 1024px) {
  .sticky-side { position: sticky; top: calc(var(--header-h) + var(--wpsticky) + 16px); }
}
.mobile-cta-bar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 64; background: #fff;
  border-top: 1px solid var(--c-border); padding: 10px var(--gutter);
  padding-bottom: calc(10px + env(safe-area-inset-bottom));
  display: flex; gap: 10px; align-items: center; box-shadow: 0 -4px 16px -6px rgba(17,24,39,.12);
}
/* Sits directly above the bottom navigation, never on top of it. */
.has-mobile-nav .mobile-cta-bar { bottom: calc(var(--mobilenav-h) + env(safe-area-inset-bottom)); padding-bottom: 10px; }
.has-mobile-nav.has-cta-bar { padding-bottom: calc(var(--mobilenav-h) + 76px + env(safe-area-inset-bottom)); }
@media (min-width: 1024px) {
  .mobile-cta-bar { display: none; }
  .has-mobile-nav.has-cta-bar { padding-bottom: 0; }
}

/* -------------------------------------------------------------------------
   21. FILTERS + PRICING
   ------------------------------------------------------------------------- */
.filter-group { border-bottom: 1px solid var(--c-border); padding: 2px 0; }
.filter-group:last-child { border-bottom: 0; }

/* The category's own filters. A label sits above its control rather than beside
   it, because "Home, Furniture & Garden" beside a select leaves the select
   about forty pixels wide in a 264px sidebar. `fieldset` carries no default
   styling of its own here — the range below is one control conceptually, and
   the legend is its label. */
.filter-label {
  display: block; padding: 13px 2px 6px;
  font-size: 14px; font-weight: 600; color: var(--c-text);
}
fieldset.filter-group { border: 0; border-bottom: 1px solid var(--c-border); margin: 0; padding: 2px 0; }
fieldset.filter-group:last-child { border-bottom: 0; }

/* Min and max on one line with the dash between them, the way the price range
   above already reads. */
.filter-range { display: flex; align-items: center; gap: 8px; }
.filter-range input { min-width: 0; flex: 1; }
.filter-range span { color: var(--c-muted); flex: none; }

/* -------------------------------------------------------------------------
   THE FILTER PANEL

   One question per row: label on the left, control on the right. Eleven
   filters in a narrow rail are only readable when the labels form a column the
   eye can run down — stacked label-over-control, the same eleven became
   twenty-two lines of equal weight and the panel read as a list of words.

   The label column is a fixed width rather than `auto`, so the controls line
   up with each other regardless of how long "Transmission" is next to "Year",
   and it is `minmax(0, …)` at both ends so neither column can be forced wider
   than the rail by its content.

   Everything here is blue: the headings, the labels, the control borders. The
   panel is the one piece of chrome on a results page that is entirely the
   visitor's to operate, and the approved design separates it from the results
   by colour rather than by a heavier box.
   ------------------------------------------------------------------------- */
.filter-panel {
  /* One step darker than --c-blue, for text that has to hold at 14px against
     white without shouting the way the button's blue does. */
  --filter-ink: #1E3A8A;
  --filter-line: #C7DBF8;

  display: grid; gap: 0;
}

.filter-row {
  display: grid;
  /* One column. The label sits above its control and the control takes the
     full width of the panel.

     Side by side, the label column had to be sized for "Transmission" and the
     control got whatever was left — which in a 300px rail is a select too
     narrow for its own longest option, and a Min–Max pair squeezed into half a
     panel. Stacking gives every control the same full width, and the labels
     still form the column the eye runs down. */
  grid-template-columns: minmax(0, 1fr);
  gap: 5px;
  /* No rules between rows. Ten hairlines down a narrow panel read as a table
     of unrelated facts; the spacing alone separates one question from the
     next, and it leaves the eye free for the controls. */
  padding: 8px 0;
}

.filter-row > .filter-label {
  display: block; padding: 0;
  font-size: 14px; font-weight: 600; line-height: 1.3;
  color: var(--filter-ink);
  overflow-wrap: normal;
}

.filter-row .select,
.filter-row .input {
  width: 100%; min-width: 0;
  height: 44px; padding-inline: 12px; font-size: 14.5px;
  border-color: var(--filter-line);
}

.filter-row .select { padding-right: 34px; background-position: right 11px center; }

/* Min and Max share the row evenly, and neither may win: `flex: 1 1 0` with a
   zero basis is what keeps them the same width when one holds four digits and
   the other holds none. */
.filter-range { gap: 10px; }
.filter-range input { flex: 1 1 0; }
.filter-range span { color: var(--filter-ink); font-weight: 600; }

/* A checkbox group is a list, not a control: the options run across the full
   width under their label and wrap as a list does. */
.filter-checks { display: flex; flex-wrap: wrap; gap: 9px 18px; padding-block: 2px; }
.filter-checks .check { font-size: 14px; color: var(--filter-ink); gap: 8px; }
.filter-checks .check input { width: 16px; height: 16px; margin-top: 1px; }

/* "On sale only" and the widget area have no label of their own. */
.filter-row-plain > .check { color: var(--filter-ink); font-size: 14px; }

/* The submit and the escape hatch. One rule above them is the panel's only
   divider, because this is the one place the page stops asking questions and
   starts acting on the answers. */
.filter-actions {
  display: grid; gap: 8px;
  margin-top: 10px; padding-top: 14px;
  border-top: 1px solid var(--filter-line);
}

.filter-actions .btn-primary { height: 46px; font-size: 15px; }

/* "Clear filters" is not a second submit — it throws work away — so it is
   quieter than the button above it while still obviously a control. */
.filter-clear {
  display: flex; align-items: center; justify-content: center;
  height: 42px; border-radius: var(--r-md);
  background: var(--c-blue-soft); color: var(--c-blue-dark);
  font-size: 14.5px; font-weight: 600; text-decoration: none;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.filter-clear:hover { background: var(--c-blue-line); color: var(--filter-ink); }

/* The mobile sheet renders the same form on a full-width surface, where the
   rows have room to breathe a little more. */
@media (max-width: 1023px) {
  .filter-row { padding: 10px 0; }
}
.filter-toggle {
  display: flex; align-items: center; justify-content: space-between; width: 100%; gap: 10px;
  padding: 13px 2px; background: none; border: 0; cursor: pointer;
  font-size: 14px; font-weight: 600; color: var(--c-text); text-align: left;
}
.filter-toggle .chev { transition: transform var(--t-base) var(--ease); color: var(--c-muted); }
.filter-toggle[aria-expanded="false"] .chev { transform: rotate(-90deg); }
.filter-panel { padding-bottom: 14px; display: grid; gap: 9px; }
.filter-toggle[aria-expanded="false"] + .filter-panel { display: none; }
.filter-count { font-size: 12px; color: var(--c-muted); margin-left: auto; }

.plan { position: relative; display: flex; flex-direction: column; }
.plan--featured { border-color: var(--c-yellow); box-shadow: 0 10px 30px -12px rgba(234,179,8,.4); }
.plan-flag {
  position: absolute; top: -13px; left: 50%; transform: translateX(-50%);
  background: var(--c-yellow); color: #422006; font-size: 11.5px; font-weight: 700;
  padding: 4px 14px; border-radius: var(--r-pill); letter-spacing: .05em; white-space: nowrap;
}
.plan-price { font-size: 34px; font-weight: 800; letter-spacing: -.035em; }
.plan-list li { display: flex; gap: 10px; align-items: flex-start; font-size: 14px; color: var(--c-text-2); padding: 6px 0; }
.plan-list li svg { flex: none; margin-top: 3px; color: var(--c-ok); }
.plan-list li.off { color: #9CA3AF; }
.plan-list li.off svg { color: #CBD5E1; }

/* -------------------------------------------------------------------------
   22. MISC BLOCKS
   ------------------------------------------------------------------------- */
.banner-promo {
  position: relative; overflow: hidden; border-radius: var(--r-xl);
  background: linear-gradient(105deg, #1D4ED8 0%, #2563EB 55%, #3B82F6 100%);
  color: #fff;
}
.banner-promo::after {
  content: ''; position: absolute; right: -60px; top: -60px; width: 320px; height: 320px;
  background: radial-gradient(circle, rgba(250,204,21,.28), transparent 68%); pointer-events: none;
}
.banner-gold { background: linear-gradient(105deg, #FEF9C3 0%, #FEF3C7 100%); color: var(--c-text); border: 1px solid #FDE68A; }

/* The trail's own spacing, so the gallery below it is not crowded. */
.breadcrumb-nav { margin-bottom: 16px; }

.breadcrumb { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--c-muted); flex-wrap: wrap; margin: 0; padding: 0; list-style: none; }
.breadcrumb a:hover { color: var(--c-blue); }
.breadcrumb li[aria-current] { color: var(--c-text); font-weight: 500; }

.cat-tile {
  display: flex; flex-direction: column; align-items: center; gap: 9px; text-align: center;
  padding: 18px 10px; background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-lg);
  transition: border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.cat-tile:hover { border-color: var(--c-blue); box-shadow: var(--sh-lift); transform: translateY(-2px); }
.cat-tile .cat-ico {
  width: 48px; height: 48px; border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--c-blue-soft); color: var(--c-blue);
  transition: background var(--t-base) var(--ease), color var(--t-base) var(--ease);
}
.cat-tile:hover .cat-ico { background: var(--c-blue); color: #fff; }
.cat-tile .cat-name { font-size: 13.5px; font-weight: 600; line-height: 1.3; }

.step-num {
  font-size: 40px; font-weight: 800; letter-spacing: -.04em; color: #DBEAFE;
  line-height: 1; margin-bottom: 6px;
}
.step-num--gold { color: #FDE68A; }

.trust-item { display: flex; gap: 13px; align-items: flex-start; }
.trust-item .t-ico {
  width: 40px; height: 40px; border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--c-blue-soft); color: var(--c-blue); flex: none;
}

.site-footer { background: #fff; border-top: 1px solid var(--c-border); }
.footer-link { font-size: 14px; color: var(--c-text-2); transition: color var(--t-fast) var(--ease); display: inline-block; padding: 4px 0; }
.footer-link:hover { color: var(--c-blue); }

.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--c-border); overflow-x: auto; }
.tab {
  padding: 12px 16px; font-size: 14px; font-weight: 500; color: var(--c-text-2);
  border: 0; border-bottom: 2px solid transparent; background: none; cursor: pointer; white-space: nowrap;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.tab:hover { color: var(--c-text); }
.tab[aria-selected="true"] { color: var(--c-blue); border-bottom-color: var(--c-blue); font-weight: 600; }

.divider-text { display: flex; align-items: center; gap: 14px; color: var(--c-muted); font-size: 13px; }
.divider-text::before, .divider-text::after { content: ''; flex: 1; height: 1px; background: var(--c-border); }

.link-blue { color: var(--c-blue); font-weight: 500; }
.link-blue:hover { color: var(--c-blue-dark); text-decoration: underline; text-underline-offset: 2px; }

/* product grids */
.grid-products { display: grid; gap: clamp(12px, 1.6vw, 20px); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 640px)  { .grid-products { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .grid-products { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 1400px) { .grid-products { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.grid-products.cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 1024px) { .grid-products.cols-4 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .grid-products.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* A results grid sits beside a 264px filter card, so it has roughly 970px to
   work with rather than the full band. Three across is what the approved
   layout draws and what leaves a card wide enough to read. Two across on a
   phone, like every other listing grid on the site: one across made each card
   taller than the screen, so a visitor saw a single listing at a time.

   Declared after the shared rules and matching on two classes, so it beats
   them without !important and without touching the grids anywhere else. */
.grid-products.grid-results { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 640px)  { .grid-products.grid-results { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .grid-products.grid-results { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.grid-products.is-list { grid-template-columns: minmax(0, 1fr) !important; }

/* -------------------------------------------------------------------------
   23. MOTION
   ------------------------------------------------------------------------- */
.reveal { opacity: 0; transform: translateY(16px); }
.no-js .reveal, .motion-off .reveal { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1 !important; transform: none !important; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* -------------------------------------------------------------------------
   24. PRINT
   ------------------------------------------------------------------------- */
@media print {
  .site-header, .site-footer, .mobile-nav, .mobile-cta-bar, .toast-stack, .dash-side { display: none !important; }
  body { background: #fff; }
  .card, .p-card { box-shadow: none; }
}

/* messaging: back button only exists below the chat two-pane breakpoint */
.chat-back { display: inline-grid; }
@media (min-width: 901px) { .chat-back { display: none; } }

/* =========================================================================
   25. MARKETPLACE SHELL — header, sidebar, banner, quick categories, footer
   Added for the reference home layout. Everything here is a shared
   component: one definition, reused by every page through Components.mount().
   ========================================================================= */

/* -------------------------------------------------------------------------
   25.1 HEADER — two rows on desktop, collapses to one on scroll
   ------------------------------------------------------------------------- */
/* Row heights are their own tokens on purpose. --header-h is an OUTPUT of
   this component (measured by main.js for sticky offsets elsewhere); reading
   it back here would make the header resize itself on every measurement. */
.site-header { --hdr-nav-h: 46px; --hdr-top-h: 88px; --hdr-top-h-compact: 64px; }

.hdr-top {
  display: flex; align-items: center; gap: clamp(12px, 1.8vw, 22px);
  height: var(--hdr-top-h);
  transition: height var(--t-base) var(--ease);
}
.site-header.is-stuck .hdr-top { height: var(--hdr-top-h-compact); }

.hdr-nav {
  border-top: 1px solid var(--c-border-soft);
  height: var(--hdr-nav-h);
  display: flex; align-items: center; gap: 2px;
  transition: height var(--t-base) var(--ease), opacity var(--t-fast) var(--ease), border-color var(--t-base) var(--ease);
}
/* Compact mode: the secondary nav row folds away, search stays reachable.
   Clipping is applied only while collapsed — a permanent overflow:hidden here
   also clips the "Pages" dropdown panel down to the 46px row. */
.site-header.is-stuck .hdr-nav {
  height: 0; opacity: 0; border-color: transparent;
  overflow: hidden; visibility: hidden; pointer-events: none;
}
@media (max-width: 1023px) { .hdr-nav { display: none; } }

.logo-mark {
  width: 36px; height: 36px; border-radius: var(--r-md);
  display: grid; place-items: center; position: relative; flex: none;
  background: var(--c-blue); color: #fff; font-weight: 800; font-size: 17px;
  letter-spacing: -.02em;
}
.logo-mark::after {
  content: ''; position: absolute; right: -3px; bottom: -3px;
  width: 12px; height: 12px; background: var(--c-yellow);
  border-radius: 3px; border: 2px solid #fff;
}

/* Search wrapper — widened when the header runs edge to edge. */
.hdr-search { flex: 1; min-width: 0; max-width: 720px; position: relative; }
.site-header.is-fluid .hdr-search { max-width: 860px; }

/* Full-bleed header for pages whose content already runs edge to edge
   (seller dashboard, account shell, messaging). Without this the header sits
   in a 1320px column while the page beneath it spans the viewport.
   The footer keeps its centred column — its dark band is full-bleed already. */
.site-header.is-fluid .shell { max-width: none; }

/* Language link. GTranslate's `[gt-link]` prints a bare <a><img> <span> and
   styles none of it, so it takes the account button's metrics here to sit in
   row one like the items beside it. Below 640px row one has no room for the
   word: the flag stays, and GTranslate titles the link "English". */
.hdr-lang { flex: none; margin-left: 4px; }
.hdr-lang a {
  display: inline-flex; align-items: center; gap: 8px; height: 42px; padding: 0 8px;
  border-radius: var(--r-md); font-size: 14px; font-weight: 500; color: var(--c-text-2);
  white-space: nowrap;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.hdr-lang a:hover { background: var(--c-border-soft); color: var(--c-text); }
.hdr-lang img { width: 22px; height: auto; border-radius: 2px; }
.hdr-lang span { display: none; }
@media (min-width: 640px) { .hdr-lang span { display: inline; } }

/* -------------------------------------------------------------------------
   25.1b CATEGORY ROW — navigation level three, and its dropdowns
   ------------------------------------------------------------------------- */
/* Level three survives the compacting that folds level two away: on a long
   results page the search and the categories are the two controls still worth
   having, which is what the approved header specifies. */
.site-header { --hdr-cats-h: 48px; }

/* Outside the content column, so the rule above it runs edge to edge; the list
   inside it is a `.shell`, so the categories line up with the logo and the
   search above them. */
.hdr-cats {
  border-top: 1px solid var(--c-border-soft);
  height: var(--hdr-cats-h);
  display: flex; align-items: stretch;
}

.hdr-cats-list {
  display: flex; align-items: stretch; gap: 2px;
  /* `margin-block`, never `margin`. This element also carries `.shell`, whose
     `margin-inline: auto` is what centres the row in the content column — and
     this rule comes later in the stylesheet, so a blanket `margin: 0` here
     silently wiped it out and the categories ran to the viewport edge while
     every other header row stayed in the column. */
  margin-block: 0;
  list-style: none;
  min-width: 0;
}

/* ---- the dropdown itself -------------------------------------------------
   Deliberately NOT full width. It is a `.dropdown-panel`, so it is already
   positioned against its own `<li>` and `align-left` pins it to the category's
   left edge. `width: max-content` lets the content decide, capped so a wide
   category cannot run past the viewport; main.js nudges it back inside the
   shell when a category near the right edge would otherwise overflow. */
.megamenu {
  --mm-cols: 1;
  top: calc(100% - 1px);
  padding: 18px 20px 14px;
  width: -moz-max-content;
  width: max-content;
  max-width: min(720px, calc(100vw - 2 * var(--gutter)));
  border-radius: 0 0 var(--r-lg) var(--r-lg);
  border-top-color: transparent;
}

.megamenu-cols {
  display: grid;
  grid-template-columns: repeat(var(--mm-cols), minmax(150px, 1fr));
  gap: 6px 28px;
}

/* A rule between columns, not around them — the panel already has a border. */
.megamenu-col + .megamenu-col {
  border-left: 1px solid var(--c-border-soft);
  padding-left: 28px; margin-left: -14px;
}

.megamenu-head {
  display: block; margin-bottom: 6px; padding: 2px 0;
  font-size: 13px; font-weight: 700; letter-spacing: .01em;
  color: var(--c-text); text-decoration: none;
}
.megamenu-head:hover { color: var(--c-blue); }

.megamenu-items { margin: 0; padding: 0; list-style: none; }
.megamenu-items a {
  display: block; padding: 5px 8px; margin-left: -8px;
  border-radius: var(--r-sm);
  font-size: 13.5px; color: var(--c-text-2); text-decoration: none;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.megamenu-items a:hover,
.megamenu-items a:focus-visible { background: var(--c-blue-soft); color: var(--c-blue-dark); }

.megamenu-all {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--c-border-soft);
  width: 100%;
  font-size: 13.5px; font-weight: 600; color: var(--c-blue); text-decoration: none;
}
.megamenu-all:hover { color: var(--c-blue-dark); }
.megamenu-all svg { transition: transform var(--t-fast) var(--ease); }
.megamenu-all:hover svg { transform: translateX(3px); }

/* Below the desktop breakpoint the row goes entirely.

   Every category in it is already in the hamburger drawer, listed rather than
   scrolled — so on a phone the row was a second, worse copy of a menu the
   visitor already had: seven items in a horizontal scroller, most of them off
   screen, costing 46px of the first thing anyone sees.

   1023px is not an arbitrary number: the hamburger is `lg:hidden`, so it
   appears at exactly the width this row disappears at. There is never a width
   where neither is present.

   The height variable goes to zero with it, because the sticky offsets and
   main.js's header measurements are both written in terms of it. */
@media (max-width: 1023px) {
  .hdr-cats { display: none; }
  .site-header { --hdr-cats-h: 0px; }
}

.hdr-cat { position: relative; display: flex; align-items: stretch; }

/* The label and the chevron read as one control but are two elements, so the
   category stays a link while the panel stays keyboard-operable. The hover
   tint is painted on the row rather than on either half, or the two would
   light up separately. */
.hdr-cat-link,
.hdr-cat-toggle {
  display: inline-flex; align-items: center;
  border: 0; background: none; cursor: pointer;
  font: inherit; color: var(--c-text-2);
  text-decoration: none; white-space: nowrap;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}

.hdr-cat-link {
  padding: 0 4px 0 12px; font-size: 14.5px; font-weight: 500;
  border-radius: var(--r-sm) 0 0 var(--r-sm);
}
.hdr-cat:not(.dropdown) .hdr-cat-link { padding-right: 12px; border-radius: var(--r-sm); }

.hdr-cat-toggle {
  padding: 0 9px 0 2px; color: var(--c-muted);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}

.hdr-cat-toggle svg { transition: transform var(--t-fast) var(--ease); }
.hdr-cat-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

.hdr-cat:hover .hdr-cat-link,
.hdr-cat:hover .hdr-cat-toggle { background: var(--c-border-soft); color: var(--c-text); }

/* The open tint, in its own rule. An invalid selector voids the whole rule it
   sits in, so keeping `:has()` apart means a browser without it loses the open
   tint and still gets the hover one. It reads the panel rather than a class so
   it covers both routes in: the click handler in ui.js and the hover intent in
   main.js. */
.hdr-cat:has(.dropdown-panel.is-open) .hdr-cat-link,
.hdr-cat:has(.dropdown-panel.is-open) .hdr-cat-toggle { background: var(--c-border-soft); color: var(--c-text); }

.hdr-cat-link:focus-visible,
.hdr-cat-toggle:focus-visible {
  outline: 2px solid var(--c-blue); outline-offset: -2px; border-radius: var(--r-sm);
  color: var(--c-text);
}

/* The section you are in, marked the way the primary nav marks it. */
.hdr-cat-link[aria-current="page"] { color: var(--c-blue); font-weight: 600; }
.hdr-cat-link[aria-current="page"]::after {
  content: ''; position: absolute; left: 12px; right: 12px; bottom: 0;
  height: 2px; background: var(--c-blue); border-radius: 2px 2px 0 0;
}

/* -------------------------------------------------------------------------
   25.2 MARKETPLACE SEARCH — icon / input / category / button
   ------------------------------------------------------------------------- */
.msearch {
  display: flex; align-items: center; width: 100%;
  height: var(--h-search); background: #fff;
  border: 1px solid var(--c-border); border-radius: var(--r-md);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.msearch:hover { border-color: #CBD5E1; }
/* No focus decoration on the search, as asked: no outline and no shadow. The
   trade is real and worth knowing — this was the only visible indication of
   where the keyboard is on this control. */
.msearch:focus-within { border-color: var(--c-border); box-shadow: none; }

.msearch .ms-icon { display: grid; place-items: center; width: 44px; color: var(--c-muted); flex: none; }
.msearch input {
  flex: 1; min-width: 0; height: 100%; border: 0; outline: none; background: transparent;
  font: inherit; font-size: 15px; color: var(--c-text); padding: 0 4px 0 0;
}
.msearch input::-moz-placeholder { color: #94A3B8; }
.msearch input::placeholder { color: #94A3B8; }
.msearch .ms-divide { width: 1px; height: 26px; background: var(--c-border); flex: none; }

.msearch .ms-select {
  position: relative; display: grid; place-items: center; overflow: hidden;
  width: 42px; height: 100%; flex: none; color: var(--c-muted);
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.msearch .ms-select:hover { color: var(--c-text); background: var(--c-subtle); }
.msearch .ms-select.is-active { color: var(--c-blue); }
.msearch .ms-select__icon { pointer-events: none; display: grid; place-items: center; }
.msearch .ms-select__control {
  /* `inset: 0` alone, not also `width/height: 100%` - with both, a <select>
     over-constrained this way was measured at its OWN intrinsic content
     width (the selected option's text) rather than the container's, which
     silently widened its real clickable area past the icon and into
     whichever control sat next to it. `overflow: hidden` on .ms-select
     above is kept as a second, unconditional guard against exactly that -
     the visible hotspot can never exceed the icon's own box either way. */
  position: absolute; inset: 0;
  margin: 0; padding: 0; border: 0; background: none;
  /* Not literally 0: iOS Safari (and some Android WebViews) are documented
     to sometimes exclude a fully opacity:0 element from touch hit-testing -
     a tap lands on whatever is visually underneath instead of this control,
     even though the exact same element responds correctly to a mouse click.
     0.01 keeps it invisible to the eye while keeping it a real, touchable
     target on every browser tested against this pattern. */
  opacity: 0.01; cursor: pointer;
  font: inherit; font-size: 14px;
  -moz-appearance: none;
       appearance: none; -webkit-appearance: none;
}
.msearch .ms-select__control:focus-visible { outline: none; }
.msearch .ms-select:has(.ms-select__control:focus-visible) {
  outline: 2px solid var(--c-blue); outline-offset: -2px; border-radius: var(--r-sm);
  color: var(--c-text);
}

.msearch--sm .ms-select { width: 38px; }

.msearch .ms-btn {
  flex: none; height: calc(100% - 10px); margin-right: 5px; padding: 0 20px;
  border: 0; border-radius: var(--r-sm); cursor: pointer;
  background: var(--c-blue); color: #fff; font-weight: 600; font-size: 14.5px;
  display: inline-flex; align-items: center; gap: 7px;
  transition: background var(--t-fast) var(--ease);
}
.msearch .ms-btn:hover { background: var(--c-blue-dark); }
.msearch .ms-cam {
  flex: none; width: 40px; height: 100%; display: grid; place-items: center;
  border: 0; background: transparent; color: var(--c-muted); cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
.msearch .ms-cam:hover { color: var(--c-blue); }

.msearch--sm { height: 44px; }
.msearch--sm .ms-icon { width: 40px; }
.msearch--sm .ms-btn { padding: 0 14px; }

/* -------------------------------------------------------------------------
   25.3 POST AD CTA
   ------------------------------------------------------------------------- */
.btn-post {
  --btn-bg: var(--c-yellow); --btn-fg: #1F2937; --btn-bd: var(--c-yellow);
  font-weight: 700; box-shadow: 0 1px 2px rgba(202, 138, 4, .28);
}
.btn-post:hover { --btn-bg: #EAB308; --btn-bd: #EAB308; box-shadow: 0 4px 14px -4px rgba(202, 138, 4, .55); }

/* -------------------------------------------------------------------------
   25.4 CATEGORY SIDEBAR
   ------------------------------------------------------------------------- */
.cat-panel {
  background: #fff; border: 1px solid var(--c-border);
  border-radius: var(--r-lg); overflow: hidden;
}
.cat-panel-head {
  display: flex; align-items: center; gap: 9px;
  padding: 13px 16px; border-bottom: 1px solid var(--c-border);
  font-size: 13px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--c-text);
}
.cat-nav { padding: 6px; }
.cat-nav a {
  position: relative; display: flex; align-items: center; gap: 11px;
  padding: 9px 10px; border-radius: var(--r-md);
  font-size: 14px; font-weight: 500; color: var(--c-text-2);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.cat-nav a .ico {
  width: 32px; height: 32px; border-radius: var(--r-sm); flex: none;
  display: grid; place-items: center;
  background: var(--c-subtle); color: var(--c-text-2);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.cat-nav a .label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-nav a .count { font-size: 12px; color: #94A3B8; font-variant-numeric: tabular-nums; flex: none; }
.cat-nav a .chev { color: #CBD5E1; flex: none; transition: transform var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.cat-nav a:hover { background: var(--c-blue-soft); color: var(--c-blue-dark); }
.cat-nav a:hover .ico { background: #fff; color: var(--c-blue); }
.cat-nav a:hover .chev { color: var(--c-blue); transform: translateX(2px); }
.cat-nav a[aria-current="page"] { background: var(--c-blue-soft); color: var(--c-blue-dark); font-weight: 600; }
.cat-nav a[aria-current="page"] .ico { background: var(--c-blue); color: #fff; }
.cat-nav a[aria-current="page"]::before {
  content: ''; position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 3px; border-radius: 2px; background: var(--c-blue);
}
.cat-panel-foot { padding: 10px 16px 14px; border-top: 1px solid var(--c-border-soft); }

/* -------------------------------------------------------------------------
   25.5 PROMOTION BANNER (sidebar + reusable)
   ------------------------------------------------------------------------- */
.promo-card {
  position: relative; overflow: hidden; border-radius: var(--r-lg);
  border: 1px solid var(--c-border); background: #fff; display: block;
  transition: box-shadow var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.promo-card:hover { box-shadow: var(--sh-lift); transform: translateY(-2px); }
.promo-card .promo-media { aspect-ratio: 3 / 2; overflow: hidden; background: var(--c-subtle); }
.promo-card .promo-media img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; transition: transform var(--t-slow) var(--ease); }
.promo-card:hover .promo-media img { transform: scale(1.04); }
.promo-card .promo-body { padding: 14px 16px 16px; }
.promo-card--blue { background: linear-gradient(160deg, #1D4ED8, #2563EB); border-color: #1D4ED8; color: #fff; }
.promo-card--gold { background: linear-gradient(160deg, #FEF9C3, #FEF3C7); border-color: var(--c-yellow-line); }

/* -------------------------------------------------------------------------
   25.6 HERO BANNER CAROUSEL
   ------------------------------------------------------------------------- */
.hcar { position: relative; border-radius: var(--r-xl); overflow: hidden; background: var(--c-subtle); }
.hcar-viewport { overflow: hidden; }
.hcar-track { display: flex; transition: transform var(--t-slow) var(--ease); will-change: transform; }
/* `flex: none` means the slide sizes to its CONTENT, and min-width only sets a
   floor — a slide with a long headline could grow past the viewport and the
   track's transform would then land short on that one slide. `width: 100%`
   pins every slide to exactly one viewport. */
.hcar-slide { min-width: 100%; width: 100%; flex: none; }
@media (prefers-reduced-motion: reduce) { .hcar-track { transition: none; } }

/* An even split: half copy, half photograph.
   It was 1.08 / .92, which left the picture visibly the smaller half. The
   prototype gives the image close to the same width as the words, and at this
   size a photograph needs it — cropped much narrower it stops being a scene
   and becomes a texture. */
.hcar-inner {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  min-height: 300px; height: 100%; align-items: center;
}
@media (max-width: 767px) { .hcar-inner { grid-template-columns: minmax(0, 1fr); min-height: 0; } }
.hcar-copy {
  padding: clamp(24px, 3.4vw, 40px);
  /* room for the dot row pinned to the bottom-left */
  padding-bottom: calc(clamp(24px, 3.4vw, 40px) + 20px);
}
.hcar-media { align-self: stretch; min-height: 220px; position: relative; overflow: hidden; }
.hcar-media img { position: absolute; inset: 0; width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; }
@media (max-width: 767px) { .hcar-media { min-height: 170px; order: -1; } }

.hcar-slide--blue { background: linear-gradient(120deg, #1D4ED8 0%, #2563EB 62%, #3B82F6 100%); color: #fff; }
.hcar-slide--blue .hcar-body { color: #DBEAFE; }
.hcar-slide--gold { background: linear-gradient(120deg, #FEF9C3 0%, #FEF3C7 100%); color: var(--c-text); }
.hcar-slide--gold .hcar-body { color: #57534E; }

.hcar-dots { position: absolute; left: clamp(24px, 3.4vw, 40px); bottom: 18px; display: flex; gap: 7px; z-index: 3; }
.hcar-dots button {
  width: 8px; height: 8px; padding: 0; border: 0; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .45); cursor: pointer;
  transition: width var(--t-base) var(--ease), background var(--t-base) var(--ease);
}
.hcar-dots button[aria-current="true"] { width: 24px; background: #fff; }
.hcar[data-tone="gold"] .hcar-dots button { background: rgba(120, 113, 108, .3); }
.hcar[data-tone="gold"] .hcar-dots button[aria-current="true"] { background: #78716C; }

/* Controls live in the bottom corners: dots left, arrows right. Centring the
   arrows vertically put them straight through the headline. */
.hcar-arrow {
  position: absolute; bottom: 16px; z-index: 3;
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(255, 255, 255, .94); border: 1px solid rgba(15, 23, 42, .10);
  display: grid; place-items: center; cursor: pointer; color: var(--c-text);
  box-shadow: var(--sh-xs);
  transition: background var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.hcar-arrow:hover { background: #fff; transform: translateY(-1px); }
.hcar-prev { right: 60px; }
.hcar-next { right: 16px; }
@media (max-width: 767px) { .hcar-arrow { display: none; } }

/* -------------------------------------------------------------------------
   25.7 QUICK CATEGORY CARDS
   ------------------------------------------------------------------------- */
.qcat {
  display: block; background: #fff; border: 1px solid var(--c-border);
  border-radius: var(--r-lg); overflow: hidden;
  transition: border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.qcat:hover { border-color: var(--c-blue-line); box-shadow: var(--sh-lift); transform: translateY(-2px); }
.qcat-media { aspect-ratio: 4 / 3; overflow: hidden; background: var(--c-subtle); position: relative; }
.qcat-media img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; transition: transform var(--t-slow) var(--ease); }
.qcat:hover .qcat-media img { transform: scale(1.04); }
.qcat-media .qcat-ico {
  position: absolute; left: 10px; top: 10px; width: 30px; height: 30px;
  border-radius: var(--r-sm); display: grid; place-items: center;
  background: rgba(255, 255, 255, .92); color: var(--c-blue);
}
.qcat-body { padding: 10px 12px 13px; text-align: center; }
.qcat-name { font-size: 13.5px; font-weight: 600; line-height: 1.3; color: var(--c-text); transition: color var(--t-fast) var(--ease); }
.qcat:hover .qcat-name { color: var(--c-blue); }
.qcat-count { font-size: 12px; color: var(--c-muted); margin-top: 2px; }

/* ── The category tiles become a rail on a phone ──────────────────────────────
   Seven tiles in a three-column grid is three rows, of which the last holds a
   single tile beside two empty cells — roughly 380px of the first screen spent
   on a menu, pushing the listings below the fold before anyone has scrolled.

   As a rail they cost one row and read as browsable: the third tile is cut off
   at the edge, which is what tells a thumb there is more to the right. It stops
   at 640px because that is where the grid itself becomes four across and the
   seven fit in two tidy rows.

   `.qcat-rail.grid` rather than `.qcat-rail`: the utility layer loads after
   this stylesheet, so a single class cannot outrank Tailwind's own `.grid` and
   `.grid-cols-3`. */
@media (max-width: 639px) {
  .qcat-rail.grid {
    display: flex;
    grid-template-columns: none;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;

    /* Full bleed. The rail runs to both edges of the screen while the section
       around it keeps the page's gutter, so the scroll does not stop short of
       the edge with a stripe of background beside it. The padding puts the
       gutter back inside the scrollable content, and `scroll-padding-inline`
       keeps snapping from eating it — without that the first tile ends up
       flush against the edge the moment anyone scrolls. */
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    padding-bottom: 2px;
    scroll-padding-inline: var(--gutter);
  }

  .qcat-rail.grid::-webkit-scrollbar { display: none; }

  .qcat-rail.grid > .qcat {
    flex: 0 0 clamp(124px, 40vw, 168px);
    scroll-snap-align: start;
  }
}

/* -------------------------------------------------------------------------
   25.8 PRODUCT CARD — premium minimal refinement
   ------------------------------------------------------------------------- */
.p-card { border-radius: var(--r-lg); box-shadow: var(--sh-xs); }
.p-card:hover { box-shadow: var(--sh-lift); border-color: var(--c-blue-line); }
/* Shorter image area for grid cards (same width, same cover crop). The row variant keeps its own sizing. */
.p-card:not(.p-card--row) .p-media { aspect-ratio: 3 / 2; }
.p-cat {
  flex: none; max-width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11.5px; font-weight: 600; line-height: 1; letter-spacing: 0;
  color: var(--c-blue-dark); background: var(--c-blue-soft);
  padding: 3px 9px; border-radius: var(--r-pill);
}
.p-card .p-meta { margin-top: 0; padding-top: 0; }
.p-card .p-meta svg { color: #94A3B8; }
/* Info row: location · condition on the left, category badge on the right. */
.p-info { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: auto; padding-top: 0; min-width: 0; }
.p-info .p-meta { flex: 1 1 auto; min-width: 0; flex-wrap: nowrap; }
.p-info .p-meta > svg { flex: none; }
.p-info .p-meta > span:not(.p-loc) { flex: none; white-space: nowrap; }
.p-info .p-loc { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-info .p-cat { margin-inline-start: auto; }
.p-body { gap: 1px; padding: 7px 14px 8px; }
.p-title { font-size: 14.5px; line-height: 1.25; min-height: 0; }
.p-title .p-cond { font-weight: 500; color: var(--c-muted); }
.p-price { font-size: 17px; line-height: 1.2; }
.p-foot {
  display: flex; align-items: center; gap: 8px; margin-top: auto;
  padding-top: 10px; border-top: 1px solid var(--c-border-soft); min-width: 0;
}

/* -------------------------------------------------------------------------
   25.9 SECTION HEADINGS
   ------------------------------------------------------------------------- */
.sec-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
.sec-title { font-size: clamp(1.05rem, 1.6vw, 1.3rem); font-weight: 700; letter-spacing: -.02em; }
.sec-sub { font-size: 13.5px; color: var(--c-muted); margin-top: 2px; }

/* -------------------------------------------------------------------------
   25.10 FOOTER — dark neutral
   ------------------------------------------------------------------------- */
.site-footer { background: var(--c-footer); color: #E2E8F0; border-top: 0; }
.site-footer h2, .site-footer h3 { color: #fff; }
.footer-heading { font-size: 14.5px; font-weight: 600; color: #fff; margin-bottom: 14px; letter-spacing: -.01em; }
.footer-link {
  font-size: 14px; color: var(--c-footer-text); display: inline-block; padding: 0;
  transition: color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.footer-link:hover { color: #60A5FA; transform: translateX(2px); }
.footer-top { border-bottom: 1px solid var(--c-footer-line); }
.footer-bottom { border-top: 1px solid var(--c-footer-line); }

.footer-news {
  display: flex; gap: 8px; width: 100%; max-width: 460px;
  background: var(--c-footer-2); border: 1px solid var(--c-footer-line);
  border-radius: var(--r-md); padding: 5px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.footer-news:focus-within { border-color: var(--c-blue); box-shadow: 0 0 0 3px var(--c-blue-ring); }
.footer-news input {
  flex: 1; min-width: 0; height: 40px; border: 0; outline: none; background: transparent;
  font: inherit; font-size: 14px; color: #fff; padding: 0 12px;
}
.footer-news input::-moz-placeholder { color: #64748B; }
.footer-news input::placeholder { color: #64748B; }
.footer-news button {
  flex: none; height: 40px; padding: 0 18px; border: 0; border-radius: var(--r-sm);
  background: var(--c-blue); color: #fff; font-weight: 600; font-size: 14px; cursor: pointer;
  transition: background var(--t-fast) var(--ease);
}
.footer-news button:hover { background: var(--c-blue-dark); }

.social-btn {
  width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(255, 255, 255, .06); color: var(--c-footer-text);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.social-btn:hover { background: var(--c-blue); color: #fff; transform: translateY(-2px); }

/* -------------------------------------------------------------------------
   25.11 HOME LAYOUT GRID
   ------------------------------------------------------------------------- */
.mk-layout {
  display: grid; align-items: start;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  gap: clamp(16px, 2vw, 26px);
}

/* The filter panel stacks its labels above its controls, so the rail is sized
   for the widest control rather than for a label plus a control. 300px is what
   gives "Any transmission" and a Min–Max pair room without taking a column off
   the results grid. */
@media (max-width: 1023px) { .mk-layout { grid-template-columns: minmax(0, 1fr); } }
.mk-aside { position: sticky; top: calc(var(--header-h) + var(--wpsticky) + 16px); display: grid; gap: 16px; min-width: 0; }

/* A widget decides its own width unless it is told not to. A block widget with
   an intrinsic minimum — a search form, a table, a long unbroken word — grew
   past the 264px rail and pushed the whole blog page sideways. Grid children
   default to `min-width: auto`, which is what let it: the track is 264px and
   the item was 335px. */
.mk-aside > * { min-width: 0; max-width: 100%; }
.mk-aside img, .mk-aside iframe, .mk-aside table { max-width: 100%; height: auto; }
.mk-aside pre, .mk-aside code { overflow-x: auto; }
@media (max-width: 1023px) { .mk-aside { display: none; } }
/* `minmax(0, 1fr)` rather than an implicit `auto` column.

   An `auto` track's growth limit is max-content, so one wide child sizes the
   track past the container and every sibling stretches with it — the home
   page's category rail is 1100px of tiles, and it took the hero, the section
   headings and the whole column out to that width, giving the page a
   horizontal scrollbar on a phone. A `minmax(0, 1fr)` track cannot exceed the
   container, so a wide child scrolls inside itself, which is what it is for. */
.mk-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(24px, 3vw, 36px);
  min-width: 0;
}

/* The blog puts its posts first in the DOM and its widgets in the narrow
   column, which is the opposite way round from the marketplace archive. The
   reading order stays content-first for anyone using a screen reader or the
   keyboard; only the columns swap. Without this the blog inherited the
   marketplace order and rendered its posts inside the sidebar width. */
.mk-layout--content-first { grid-template-columns: minmax(0, 1fr) var(--sidebar-w); }
@media (max-width: 1023px) { .mk-layout--content-first { grid-template-columns: minmax(0, 1fr); } }

/* Mobile category rail replaces the sidebar below 1100px */
.cat-rail { display: none; }
@media (max-width: 1023px) { .cat-rail { display: flex; } }

/* -------------------------------------------------------------------------
   25.12 LOAD MORE
   ------------------------------------------------------------------------- */
.loadmore { display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 8px; }
.loadmore .lm-meta { font-size: 13px; color: var(--c-muted); }
.loadmore .lm-track { width: min(220px, 60vw); height: 4px; border-radius: 2px; background: var(--c-border); overflow: hidden; }
.loadmore .lm-fill { height: 100%; background: var(--c-blue); border-radius: 2px; transition: width var(--t-slow) var(--ease); }
.btn.is-loading { pointer-events: none; opacity: .75; }
.btn.is-loading .spin { display: inline-flex; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* -------------------------------------------------------------------------
   25.13 ARTICLE / BLOG
   ------------------------------------------------------------------------- */
.post-card {
  display: flex; flex-direction: column; height: 100%; background: #fff;
  border: 1px solid var(--c-border); border-radius: var(--r-lg); overflow: hidden;
  transition: border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.post-card:hover { border-color: var(--c-blue-line); box-shadow: var(--sh-lift); transform: translateY(-2px); }
.post-media { aspect-ratio: 16 / 10; overflow: hidden; background: var(--c-subtle); }
.post-media img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; transition: transform var(--t-slow) var(--ease); }
.post-card:hover .post-media img { transform: scale(1.03); }
.post-body { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.post-title { font-size: 16px; font-weight: 600; line-height: 1.35; letter-spacing: -.01em; transition: color var(--t-fast) var(--ease); }
.post-card:hover .post-title { color: var(--c-blue); }

.prose p { margin-bottom: 16px; font-size: 16px; line-height: 1.75; color: var(--c-text-2); }
.prose h2 { font-size: 1.35rem; font-weight: 700; margin: 28px 0 12px; letter-spacing: -.02em; }
.prose h3 { font-size: 1.1rem; font-weight: 600; margin: 22px 0 10px; }
.prose ul { margin: 0 0 16px; display: grid; gap: 8px; }
.prose ul li { position: relative; padding-left: 22px; font-size: 16px; line-height: 1.7; color: var(--c-text-2); }
.prose ul li::before {
  content: ''; position: absolute; left: 4px; top: 11px; width: 6px; height: 6px;
  border-radius: 50%; background: var(--c-blue);
}
.prose blockquote {
  margin: 0 0 20px; padding: 16px 20px; border-left: 3px solid var(--c-blue);
  background: var(--c-blue-soft); border-radius: 0 var(--r-md) var(--r-md) 0;
  font-size: 16px; color: var(--c-text);
}

/* -------------------------------------------------------------------------
   HEADER ANNOUNCEMENT BAR
   A theme addition rather than a prototype component — the static design has
   no equivalent. Kept low-contrast and thin so it reads as a notice above the
   header instead of competing with it.
   ------------------------------------------------------------------------- */
.hdr-announce {
  background: var(--c-text);
  color: #fff;
  font-size: 13px;
  line-height: 1.4;
  text-align: center;
}
.hdr-announce .shell { padding-block: 8px; }
.hdr-announce a { color: var(--c-yellow); text-decoration: underline; }
.hdr-announce a:hover { text-decoration: none; }

/* A header the site owner has un-stuck, and one that should not shrink. */
.site-header--static { position: static; }
.site-header--no-shrink.is-stuck .hdr-top { height: var(--hdr-top-h); }

/* -------------------------------------------------------------------------
   THIRD-PARTY NEWSLETTER FORM
   When the site supplies its own mailing-list shortcode, its markup is not
   ours and cannot be restyled element by element. These rules do the minimum
   that keeps it legible on the dark footer band: readable text, an input that
   matches the designed field, and a button in the brand colour.
   ------------------------------------------------------------------------- */
.footer-news-embed { color: var(--c-footer-text); font-size: 14px; }

.footer-news-embed label { display: block; margin-bottom: 6px; font-size: 13px; }

.footer-news-embed input[type="email"],
.footer-news-embed input[type="text"] {
  width: 100%;
  height: var(--h-control);
  padding: 0 14px;
  border: 1px solid var(--c-footer-line);
  border-radius: var(--r-md);
  background: var(--c-footer-2);
  color: #fff;
  font: inherit;
}
.footer-news-embed input::-moz-placeholder { color: var(--c-muted); }
.footer-news-embed input::placeholder { color: var(--c-muted); }

.footer-news-embed input:focus-visible {
  outline: 2px solid var(--c-blue);
  outline-offset: 1px;
}

.footer-news-embed button,
.footer-news-embed input[type="submit"] {
  height: var(--h-control);
  margin-top: 8px;
  padding: 0 20px;
  border: 0;
  border-radius: var(--r-md);
  background: var(--c-blue);
  color: var(--c-on-primary, #fff);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.footer-news-embed button:hover,
.footer-news-embed input[type="submit"]:hover { background: var(--c-blue-dark); }

/* -------------------------------------------------------------------------
   STORE COVER
   The banner across the top of a seller's store page. A theme addition: the
   plugin declares `cover` but does not populate it yet, so this renders only
   when a site supplies one through the marketflow_store_data filter.
   ------------------------------------------------------------------------- */
.store-cover {
  aspect-ratio: 4 / 1;
  min-height: 120px;
  max-height: 260px;
  background: linear-gradient(120deg, var(--c-blue-soft), var(--c-subtle));
  overflow: hidden;
}
.store-cover img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; }

/* A form label sitting directly inside .field, which the marketplace forms use
   for every input. Weighted a little above .t-meta so a label reads as a label
   rather than as help text. */
.field > label { display: block; margin-bottom: 6px; font-weight: 600; color: var(--c-text-2); }

/* -------------------------------------------------------------------------
   PAGINATION
   The prototype's archive revealed more results with a button, which cannot
   be linked to or indexed. A server-rendered archive uses numbered pages
   instead, so this is a theme addition — built from existing tokens so it
   follows the Customizer like everything else.
   ------------------------------------------------------------------------- */
.pagination,
.woocommerce-pagination,
.navigation.pagination .nav-links {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: center;
}

.pagination .page-numbers,
.woocommerce-pagination .page-numbers,
.navigation.pagination .page-numbers {
  display: inline-grid;
  place-items: center;
  min-width: 38px;
  height: 38px;
  padding: 0 10px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-text-2);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}

.pagination a.page-numbers:hover,
.woocommerce-pagination a.page-numbers:hover,
.navigation.pagination a.page-numbers:hover {
  background: var(--c-subtle);
  border-color: var(--c-muted);
  color: var(--c-text);
}

.pagination .page-numbers.current,
.woocommerce-pagination .page-numbers.current,
.navigation.pagination .page-numbers.current {
  background: var(--c-blue);
  border-color: var(--c-blue);
  color: var(--c-on-primary, #fff);
}

.pagination .page-numbers.dots,
.woocommerce-pagination .page-numbers.dots {
  border-color: transparent;
  background: none;
}

/* The plugin's marketflow_pagination() (used by the listings shortcode) emits
   <nav class="mf-pagination"><ul class="page-numbers"><li>…</li></ul></nav>,
   so the list needs resetting and the items styling like the buttons above. */
.mf-pagination {
  grid-column: 1 / -1;
  width: 100%;
  margin-top: 28px;
}

.mf-pagination ul.page-numbers {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.mf-pagination li {
  margin: 0;
  padding: 0;
  list-style: none;
}

.mf-pagination li > .page-numbers {
  display: inline-grid;
  place-items: center;
  min-width: 38px;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-text-2);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}

.mf-pagination li > a.page-numbers:hover {
  background: var(--c-subtle);
  border-color: var(--c-muted);
  color: var(--c-text);
}

.mf-pagination li > .page-numbers.current {
  background: var(--c-blue);
  border-color: var(--c-blue);
  color: var(--c-on-primary, #fff);
}

.mf-pagination li > .page-numbers.dots {
  border-color: transparent;
  background: none;
}

/* WordPress wraps its own pagination in a .navigation element that would
   otherwise add a second row of spacing above the buttons. */
.navigation.pagination { display: block; }
.navigation.pagination .screen-reader-text { position: absolute; }

/* -------------------------------------------------------------------------
   WORDPRESS CONTENT
   Preflight strips list markers, table borders and blockquote indents, which
   is right for application chrome and wrong for editor content. They are put
   back inside .prose only, so a post reads normally while the marketplace UI
   keeps its reset.
   ------------------------------------------------------------------------- */
.prose > * + * { margin-top: 1em; }
.prose h1, .prose h2, .prose h3, .prose h4 { margin-top: 1.6em; line-height: 1.25; }
.prose h2 { font-size: 1.4em; }
.prose h3 { font-size: 1.15em; }
.prose p, .prose li { line-height: 1.7; color: var(--c-text-2); }
.prose ul, .prose ol { padding-left: 1.4em; }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }

/*
 * A shortcode can drop an interface inside prose — a listing grid in the
 * middle of an article, say. These undo the article treatment for anything
 * the theme drew, so a card's links are not underlined and a message list is
 * not bulleted.
 */
.prose .mf-messages,
.prose .grid-products,
.prose .chat-shell,
.prose .cat-nav,
.prose .dash-side,
.prose .segment,
.prose .filters { padding-left: 0; }

.prose .mf-messages,
.prose .grid-products ul,
.prose .chat-shell ul,
.prose .dash-side ul { list-style: none; padding-left: 0; }

.prose .btn,
.prose .side-link,
.prose .nav-link,
.prose .dd-item,
.prose .conv,
.prose .p-link,
.prose .segment a,
.prose .footer-link,
.prose .chat-list a,
.prose .page-numbers { text-decoration: none; }
.prose li + li { margin-top: .35em; }
.prose a { color: var(--c-blue); text-decoration: underline; text-underline-offset: 2px; }
.prose img { border-radius: var(--r-lg); }
.prose blockquote {
  padding-left: 1em;
  border-left: 3px solid var(--c-blue-line);
  color: var(--c-muted);
  font-style: italic;
}
.prose code {
  padding: 2px 5px;
  border-radius: var(--r-sm);
  background: var(--c-subtle);
  font-size: .92em;
}
.prose pre { padding: 14px; border-radius: var(--r-lg); background: var(--c-subtle); overflow-x: auto; }
.prose pre code { padding: 0; background: none; }
.prose table { width: 100%; border-collapse: collapse; }
.prose th, .prose td { padding: 8px 10px; border: 1px solid var(--c-border); text-align: left; }
.prose hr { border: 0; border-top: 1px solid var(--c-border); }

/* -------------------------------------------------------------------------
   CATEGORY CARD WITHOUT AN IMAGE
   Most category terms have no thumbnail, and the design assumed one. Without
   it the 4:3 media box collapsed and its absolutely positioned icon fell over
   the label. The fallback below fills the box with the category's own icon on
   a brand tint, so an unillustrated category reads as deliberate.
   ------------------------------------------------------------------------- */
.qcat-media--empty {
  display: grid;
  place-items: center;
  background: linear-gradient(140deg, var(--c-blue-soft), var(--c-subtle));
}
.qcat-media--empty .qcat-glyph { color: var(--c-blue); opacity: .55; }

/* The corner badge is only meaningful over a photograph. */
.qcat-media--empty .qcat-ico { display: none; }

/* -------------------------------------------------------------------------
   HERO SLIDE WITHOUT AN IMAGE
   The slide is a two-column grid with the artwork on the right. With no image
   the second column was simply empty, which read as a broken half-slide. A
   slide with nothing to show becomes one centred column instead.
   ------------------------------------------------------------------------- */
.hcar-inner--solo { grid-template-columns: minmax(0, 1fr); }
.hcar-inner--solo .hcar-copy { max-width: 68ch; }

/* -------------------------------------------------------------------------
   CATEGORY ROW CHEVRON
   Belt and braces over preflight's `svg { display: block }`: the row is a flex
   line, so the trailing chevron is centred explicitly rather than left to sit
   on the text baseline.
   ------------------------------------------------------------------------- */
.cat-nav a .chev { display: inline-flex; align-items: center; margin-left: 2px; }
.cat-nav a .count { margin-left: auto; }

/* -------------------------------------------------------------------------
   FULL-BLEED PAGE
   The account dashboard is laid out edge to edge in the design: the sidebar
   sits against the viewport rather than inside the centred shell. A page that
   asks for it drops the shell's max width, keeping only a small gutter.
   ------------------------------------------------------------------------- */
.shell--flush {
  max-width: none;
  padding-inline: 0;
}

/* The dashboard grid supplies its own padding, so the two do not double up. */
.shell--flush .dash-main { padding: 20px clamp(16px, 3vw, 28px) 56px; }
.shell--flush .dash-side { padding-block: 20px; }

@media (max-width: 1023px) {
  .shell--flush .dash-main { padding-inline: var(--gutter); }
  .shell--flush .dash-side { padding-inline: var(--gutter); }
}

/* -------------------------------------------------------------------------
   CATEGORY CARD TEXT
   The name and the count are spans, and the design system styles them as
   though they were blocks — `.qcat-count` carries a top margin, which an
   inline element ignores. The prototype's sixteen categories were single
   words, so the two ran together on one line and nobody noticed. A real site
   has names like "Apartments for Rent", which collided with the count and
   wrapped into it.

   Stacking them is the correction. The name is clamped to two lines and the
   body given a floor, so a row of cards lines up whatever the names are.
   ------------------------------------------------------------------------- */
.qcat-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 62px;
  justify-content: center;
}

.qcat-name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.qcat-count { display: block; margin-top: 0; }

/* -------------------------------------------------------------------------
   FULL-SCREEN ACCOUNT ENDPOINT
   .chat-shell is already sized as `100vh - header`; it only ever looked wrong
   because it was nested inside the account grid. With the sidebar out of the
   way it needs the page around it to stop adding its own space — and the
   footer to stand down, exactly as messages.html omits it.
   ------------------------------------------------------------------------- */
.mf-full-screen .shell--flush { padding: 0; }
.mf-full-screen .site-footer { display: none; }

/*
 * Everything page.php and WooCommerce put between the shell and the chat is
 * a wrapper with nothing to contribute here. Zeroing them is what makes the
 * screen actually full: otherwise the panes sit inside three nested boxes,
 * each adding a little, and the thread never reaches the bottom of the window.
 */
.mf-full-screen .page-app,
.mf-full-screen .woocommerce,
.mf-full-screen .woocommerce-account .woocommerce,
.mf-full-screen article,
.mf-full-screen .entry-content {
  margin: 0;
  padding: 0;
}

/* The bottom navigation is still there below 1024px, so the shell already
   subtracts it — nothing more to do but keep out of its way. */
.mf-full-screen .mobile-nav { z-index: 40; }

/* -------------------------------------------------------------------------
   PROFILE PHOTO FIELD
   A label wrapping a hidden file input, so the button is the control and the
   browser's own "No file chosen" text never appears.
   ------------------------------------------------------------------------- */
.mf-avatar-field {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.mf-avatar-field .avatar {
  width: 80px;
  height: 80px;
  flex: none;
  font-size: 26px;
}

.mf-avatar-field label.btn { cursor: pointer; }

/* Keyboard focus lands on the input, which is visually hidden — so the ring
   has to be drawn on the label that stands in for it. */
.mf-avatar-field input:focus-visible + span,
.mf-avatar-field label.btn:has( input:focus-visible ) {
  outline: 2px solid var(--c-blue);
  outline-offset: 2px;
}

/* -------------------------------------------------------------------------
   FIELD ERRORS
   The account form names the field that failed rather than dropping a notice
   at the top of the page, so each field needs a place to say so.
   ------------------------------------------------------------------------- */
.field .err {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-top: 6px;
  font-size: 12.5px;
  color: var(--c-bad);
}

.field.is-invalid .select,
.field.is-invalid input,
.field.is-invalid textarea { border-color: var(--c-bad); }

/* -------------------------------------------------------------------------
   SEGMENTED CONTROL — links as well as buttons
   The design system styles `.segment button`, because the prototype filtered
   in JavaScript. Every filter the theme renders is a real link instead, so
   each state has a URL that can be bookmarked, shared and indexed — which
   left them as bare underlined text. The same rules now cover both.
   ------------------------------------------------------------------------- */
.segment a {
  border: 0;
  background: transparent;
  border-radius: var(--r-sm);
  padding: 7px 14px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--c-text-2);
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.segment a[aria-selected="true"],
.segment a[aria-current="page"],
.segment a[aria-current="true"] {
  background: var(--c-surface);
  color: var(--c-blue);
  box-shadow: var(--sh-card);
}

/* -------------------------------------------------------------------------
   LIVE MESSAGING
   The plugin's poller appends `li.mf-message.mf-message-mine|-theirs` with a
   `p.mf-message-meta` inside, and it knows nothing of the design system. So
   those class names are styled here to match `.bubble` exactly — otherwise a
   message that arrived by polling would look nothing like the same message
   after a reload, which is the one place a seam would be obvious.

   The template puts both sets of classes on its own messages, so these rules
   and the .bubble rules describe the same thing from either direction.
   ------------------------------------------------------------------------- */

/* The list is the flex column, not .chat-scroll: the scroller has a single
   child, so aligning bubbles has to happen one level in. */
.mf-messages {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 100%;
  justify-content: flex-end;
}

.mf-message {
  display: flex;
  flex-direction: column;
  max-width: min(74%, 520px);
  padding: 10px 14px;
  border-radius: 16px;
  font-size: 14.5px;
  line-height: 1.5;
  overflow-wrap: anywhere;
  box-shadow: var(--sh-card);
}

.mf-message p { margin: 0; }
.mf-message p + p { margin-top: .5em; }
.mf-message a { color: var(--c-blue); text-decoration: underline; text-underline-offset: 2px; }

.mf-message-theirs {
  align-self: flex-start;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-bottom-left-radius: 5px;
}

.mf-message-mine {
  align-self: flex-end;
  background: var(--c-blue);
  color: var(--c-on-primary, #fff);
  border-bottom-right-radius: 5px;
}
.mf-message-mine a { color: inherit; }

/*
 * The poller emits the meta before the body, and the design puts the time
 * after it. Ordering rather than reordering the DOM keeps the markup matching
 * what the poller appends while the bubble reads the way it was drawn.
 */
.mf-message-meta {
  order: 2;
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-top: 4px;
  font-size: 11px;
  opacity: .65;
}

/*
 * The sender's name is already on the conversation — repeating it in every
 * bubble is noise. It stays in the markup for a screen reader, which has no
 * left-and-right to tell the two sides apart.
 */
.mf-message-sender {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

.mf-message-time { font-variant-numeric: tabular-nums; }

/* A message drawn optimistically, before the server has confirmed it. */
.mf-message.is-pending { opacity: .6; }

/* An unread badge is hidden by the plugin at zero; nothing should override it. */
[data-marketflow-unread][hidden] { display: none !important; }

/* -------------------------------------------------------------------------
   MESSAGING — the theme's two additions
   The design system already carries .chat-shell, .chat-list, .chat-thread and
   the rest. A sticky heading for the list, and the state the right pane shows
   before a conversation is chosen.
   ------------------------------------------------------------------------- */
.chat-thread--empty {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: var(--gutter);
}
.chat-thread--empty .chat-notice { margin-top: 12px; }

@media (max-width: 900px) {
  /* The list is the whole screen here, so an empty right pane says nothing. */
  .chat-shell[data-view="list"] .chat-thread--empty { display: none; }
}

/* -------------------------------------------------------------------------
   BACK OUT OF MESSAGING
   The account sidebar is not rendered on this screen, so the way back to the
   dashboard has to live inside the conversation list — small and quiet, above
   the heading, the way a mail client puts it.
   ------------------------------------------------------------------------- */
.chat-exit {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 10px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--c-muted);
  transition: color var(--t-fast) var(--ease);
}

.chat-exit:hover,
.chat-exit:focus-visible { color: var(--c-blue); }

/* -------------------------------------------------------------------------
   WORDPRESS ADMIN BAR
   The prototype had no admin bar; a logged-in site does. WordPress pushes the
   document down with `html { margin-top }` and, above 783px, pins the bar over
   the viewport — neither of which 100vh knows about. The chat surface is sized
   against the viewport, so for anyone who can see the bar it ran that much too
   tall: a scrollbar on a screen designed not to have one, and the compose box
   below the fold.

   The height it costs is a token so the three chat rules below stay readable,
   and so the sticky header can stop hiding underneath it.
   ------------------------------------------------------------------------- */
:root { --wpbar: 0px; --wpsticky: 0px; }
.admin-bar { --wpbar: 46px; }

@media screen and (min-width: 783px) {
  .admin-bar { --wpbar: 32px; }

  /*
   * What the bar costs a STICKY element, which is not the same number.
   *
   * Above 783px the bar is fixed over the viewport, so anything sticking to the
   * top has to clear it as well as the header. Below 783px the bar is in the
   * document and scrolls away, so reserving room for it would leave a gap —
   * which is why this stays 0 there while `--wpbar` does not.
   */
  .admin-bar { --wpsticky: 32px; }

  /* Sticky at top:0 means sticky underneath the bar. */
  .admin-bar .site-header { top: 32px; }
}

.chat-shell { height: calc(100vh - var(--header-h) - var(--wpbar)); }

@media (max-width: 1023px) {
  .chat-shell { height: calc(100vh - var(--header-h) - var(--mobilenav-h) - var(--wpbar)); }
}

/* -------------------------------------------------------------------------
   SAVED ADDRESSES
   ------------------------------------------------------------------------- */
.mf-address-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

/* Browsers italicise <address>; nothing else on the site is italic. */
.woocommerce-Address address {
  font-style: normal;
  font-size: 14px;
  line-height: 1.65;
  color: var(--c-text-2);
}

.mf-address-empty { margin: 0; }

/* -------------------------------------------------------------------------
   WOOCOMMERCE FORM FIELDS
   Checkout and the address editor draw their own fields, because country and
   state are wired together by WooCommerce's script through the ids and classes
   it emits — reimplementing them in .field markup would look right and break
   every address outside the default country.

   So the markup stays WooCommerce's and is dressed to match .input / .label
   here. It is the same visual contract, applied to `p.form-row > label +
   span.woocommerce-input-wrapper > input.input-text` instead.
   ------------------------------------------------------------------------- */
.woocommerce-address-fields__field-wrapper,
.woocommerce-billing-fields__field-wrapper,
.woocommerce-shipping-fields__field-wrapper,
.woocommerce-additional-fields__field-wrapper {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 16px;
}

/*
 * The additional fields are the exception: ONE column.
 *
 * This wrapper holds the order note and whatever a store adds beside it, and
 * both are things a buyer types a sentence into — WooCommerce gives the note
 * only `notes` and no width class, so in a two-column grid it came out half
 * width beside empty space. Its own heading is hidden below, which is also why
 * the label needs the grid's row gap put back above it.
 */
.woocommerce-additional-fields { margin-top: 14px; }
.woocommerce-additional-fields__field-wrapper { grid-template-columns: minmax(0, 1fr); }

@media (max-width: 640px) {
  .woocommerce-address-fields__field-wrapper,
  .woocommerce-billing-fields__field-wrapper,
  .woocommerce-shipping-fields__field-wrapper,
  .woocommerce-additional-fields__field-wrapper {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* WooCommerce ships these as paragraphs with their own margins, and pairs them
   with -first / -last floats. In a grid the pairing is the grid's job. */
.form-row { margin: 0; min-width: 0; }
.form-row-wide { grid-column: 1 / -1; }

/* City / State / PIN, three across — the trio the prototype's delivery card
   puts on one row. Set from the field's own `class` in
   marketflow_checkout_field_layout(), so the layout travels with the field.
   The wrapper's grid is two columns, so this needs its own. */
.woocommerce-billing-fields__field-wrapper:has( .form-row-third ) {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

.woocommerce-billing-fields__field-wrapper:has( .form-row-third ) .form-row-wide { grid-column: 1 / -1; }
.woocommerce-billing-fields__field-wrapper:has( .form-row-third ) .form-row-first { grid-column: span 3; }
.woocommerce-billing-fields__field-wrapper:has( .form-row-third ) .form-row-last { grid-column: span 3; }
.form-row-third { grid-column: span 2; }

@media (max-width: 640px) {
  .woocommerce-billing-fields__field-wrapper:has( .form-row-third ) {
    grid-template-columns: minmax(0, 1fr);
  }

  .woocommerce-billing-fields__field-wrapper:has( .form-row-third ) .form-row-first,
  .woocommerce-billing-fields__field-wrapper:has( .form-row-third ) .form-row-last,
  .form-row-third { grid-column: 1 / -1; }
}

.form-row > label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--c-text);
  margin-bottom: 6px;
}

.form-row .required {
  color: var(--c-bad);
  text-decoration: none;
  border: 0;
}

.form-row .optional { color: var(--c-muted); font-weight: 500; }

.woocommerce-input-wrapper { display: block; width: 100%; }

.form-row input.input-text,
.form-row textarea.input-text,
.form-row select {
  width: 100%;
  background: #fff;
  color: var(--c-text);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  padding: 0 14px;
  height: 46px;
  font-size: 15px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}

.form-row textarea.input-text {
  height: auto;
  padding: 12px 14px;
  min-height: 110px;
  resize: vertical;
  line-height: 1.6;
}

.form-row input.input-text::-moz-placeholder, .form-row textarea.input-text::-moz-placeholder { color: #9CA3AF; }

.form-row input.input-text::placeholder,
.form-row textarea.input-text::placeholder { color: #9CA3AF; }

.form-row input.input-text:focus,
.form-row textarea.input-text:focus,
.form-row select:focus {
  border-color: var(--c-blue);
  box-shadow: 0 0 0 3px var(--c-blue-ring);
  outline: none;
}

/* The same chevron .select carries, so a plain country box matches the rest. */
.form-row select {
  -moz-appearance: none;
       appearance: none;
  -webkit-appearance: none;
  padding-right: 38px;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%234B5563' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
}

/* WooCommerce validates as you leave a field and puts the verdict on the row. */
.form-row.woocommerce-invalid input.input-text,
.form-row.woocommerce-invalid select { border-color: var(--c-bad); }
.form-row.woocommerce-validated input.input-text { border-color: var(--c-ok); }
.form-row .woocommerce-error { color: var(--c-bad); font-size: 12.5px; margin-top: 6px; display: block; }

/*
 * Country and state become selectWoo (select2) boxes when the script loads, and
 * select2 draws a replacement element rather than styling the original — so the
 * rules above never reach it. These four are the minimum for it to pass as one
 * of ours: the closed box, its text, its arrow, and the open dropdown.
 */
.form-row .select2-container { width: 100% !important; }

.select2-container--default .select2-selection--single {
  height: 46px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: #fff;
}

.select2-container--default .select2-selection--single .select2-selection__rendered {
  line-height: 44px;
  padding-left: 14px;
  color: var(--c-text);
  font-size: 15px;
}

.select2-container--default .select2-selection--single .select2-selection__arrow { height: 44px; right: 8px; }

.select2-container--open .select2-selection--single,
.select2-container--focus .select2-selection--single {
  border-color: var(--c-blue);
  box-shadow: 0 0 0 3px var(--c-blue-ring);
}

.select2-dropdown {
  border-color: var(--c-border);
  border-radius: var(--r-md);
  box-shadow: var(--sh-pop);
  overflow: hidden;
}

.select2-container--default .select2-results__option--highlighted[aria-selected] { background: var(--c-blue); }
.select2-container--default .select2-search--dropdown .select2-search__field {
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  padding: 8px 10px;
}

/* The row of buttons under a form. */
.mf-form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--c-border-soft);
}

/* -------------------------------------------------------------------------
   PASSWORD FIELD
   The prototype had no password toggle — its auth screen was a mock — so this
   is the theme's, built to the same field metrics: the button occupies the
   right inset and the input gives up that much padding, so the text never runs
   underneath it.
   ------------------------------------------------------------------------- */
.pw-field { position: relative; }
.pw-field .input { padding-right: 46px; }

/*
 * Pinned to the INPUT, not to the middle of the field.
 *
 * WooCommerce inserts its strength meter and hint inside `.pw-field`, right
 * after the input, so `top: 50%` centred this button on input-plus-meter the
 * moment somebody typed — it ended up level with the hint text. The input is
 * 46px, so this centres itself in the first 46px and stays there whatever
 * appears below.
 */
.pw-toggle {
  position: absolute;
  top: 0;
  height: 46px;
  right: 6px;
  display: inline-grid;
  place-items: center;
  width: 34px;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--c-muted);
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}

.pw-toggle:hover { color: var(--c-text); background: var(--c-subtle); }

.pw-toggle:focus-visible {
  outline: 2px solid var(--c-blue);
  outline-offset: 1px;
  color: var(--c-text);
}

/* Pressed reads as "the password is currently visible". */
.pw-toggle[aria-pressed="true"] { color: var(--c-blue); }

/*
 * WooCommerce's script adds a show/hide button of its own to every password
 * field. The field already has this one, so the second is a zero-width twin that
 * screen readers still announce ("Mostrar palavra-passe" twice). Removed from
 * the page, and from assistive technology, wherever the theme's button is.
 */
.pw-field .show-password-input { display: none !important; }

/* -------------------------------------------------------------------------
   WOOCOMMERCE'S PASSWORD STRENGTH METER
   Unstyled until now: its stylesheet is one of the three this theme dequeues,
   so "Very weak - Please enter a stronger password." and the hint below it
   arrived as bare text running into the input above them.

   A block under the field, in the tone of the verdict — and the hint is a
   separate, quieter line, because it is advice rather than a result.
   ------------------------------------------------------------------------- */
.woocommerce-password-strength {
  display: block;
  margin-top: 8px;
  padding: 8px 12px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-subtle);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
}

.woocommerce-password-strength.short,
.woocommerce-password-strength.bad {
  border-color: var(--c-bad);
  background: #FEF2F2;
  color: var(--c-bad);
}

.woocommerce-password-strength.good {
  border-color: #B45309;
  background: #FFFBEB;
  color: #B45309;
}

.woocommerce-password-strength.strong {
  border-color: var(--c-ok);
  background: #F0FDF4;
  color: var(--c-ok);
}

/* WooCommerce prints this as a `<small>` sibling. It is the "use upper and
   lower case letters, numbers and symbols" line, and it is long — so it wraps
   like a sentence rather than being clamped. */
.woocommerce-password-hint {
  display: block;
  margin-top: 6px;
  color: var(--c-muted);
  font-size: 12.5px;
  line-height: 1.55;
}


/* -------------------------------------------------------------------------
   LOGO IMAGE
   The Customizer has always written --logo-h, and nothing read it: an uploaded
   logo rendered at its natural size and the height slider did nothing at all.
   These are the rules that were missing.

   Height drives, width follows, so a wordmark keeps its proportions whatever
   the file is. The max-width is a guard against a very wide mark pushing the
   search box out of the header, not a design choice.
   ------------------------------------------------------------------------- */
.logo-img {
  display: block;
  height: var(--logo-h, 40px);
  width: auto;
  max-width: min(220px, 40vw);
  -o-object-fit: contain;
     object-fit: contain;
}

/* The footer sizes on its own token, because a footer mark is usually set
   smaller than the one in the header. */
.logo-img--footer { height: var(--footer-logo-h, 36px); }

/* A smaller header mark on phones, where the logo was taking most of the bar.
   min() rather than a fixed height, so the Customizer slider still decides
   whenever it is set below this cap. */
@media (max-width: 640px) {
  #siteHeader .logo-img { height: min(var(--logo-h, 40px), 36px); }
}

/* The site logo, borrowed by the footer because no footer-specific file was
   uploaded.

   NO colour filter. `brightness(0) invert(1)` was tried here and removed: it
   made the mark legible by destroying it, turning the blue pin and the yellow
   dot white along with the wordmark. A logo that has lost its brand colours is
   not the brand.

   What a borrowed dark logo gets instead is a light plate — the mark itself,
   unaltered, on a small rounded ground so the near-black wordmark has something
   to sit on. It is the honest fallback for a site that has only one logo file.

   The better answer is a real light variant under Customizer > Footer > Footer
   logo, which renders with no treatment at all. This site has one. */
.logo-img--on-dark {
  background: #fff;
  border-radius: var(--r-sm);
  padding: 6px 10px;
  box-sizing: content-box;
}

/* High-DPI: the attachment is served at its natural size and scaled by height,
   so a 2x screen already gets the full pixel data. Nothing to do but stop the
   browser smoothing a downscale into mush. */
.logo-img { image-rendering: auto; }

/* An image logo replaces the letter mark, so the gap it left goes too. */
.logo:has( .logo-img ) { gap: 0; }

/* -------------------------------------------------------------------------
   STORE — the seller's public shop front

   Written as real CSS rather than the prototype's utility classes. Its hero is
   `lg:grid-cols-[auto_minmax(0,1fr)_auto]` and its stats strip is
   `sm:grid-cols-4`; neither is in the compiled Tailwind sheet, because the JIT
   only emits classes it finds in the source it scans. Both would have silently
   produced a single stacked column at every width.
   ------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
   CONTACT
   ------------------------------------------------------------------------- */
/* `align-items: stretch`, not `start`: the form and the details card are two
   halves of one row and were ending at different heights, which left a ragged
   step between them. Stretching makes both cards the height of the taller. */
.mf-contact-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  align-items: stretch;
}

@media (min-width: 1024px) {
  .mf-contact-layout {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
    gap: 32px;
  }
}

/* Both children fill the row they share. */
.mf-contact-layout > * { min-width: 0; }

.mf-contact-aside { height: 100%; }

.mf-contact-aside__title { font-size: 15px; margin-bottom: 14px; }

.mf-contact-channels { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; }

.mf-contact-channel {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  color: inherit;
}

.mf-contact-channel__icon {
  width: 38px;
  height: 38px;
  border-radius: var(--r-md);
  display: grid;
  place-items: center;
  flex: none;
  background: var(--c-blue-soft);
  color: var(--c-blue);
}

.mf-contact-channel__body { min-width: 0; }

.mf-contact-channel__title { display: block; font-weight: 600; font-size: 14px; }

.mf-contact-channel__value {
  display: block;
  font-size: 13.5px;
  color: var(--c-text-2);
  margin-top: 1px;
  word-break: break-word;
}

a.mf-contact-channel:hover .mf-contact-channel__title { color: var(--c-blue); }

/* The map, full width under both columns. A ratio box rather than a fixed
   height, so it keeps its shape at every width and the iframe can never push
   the page sideways. Wider than it is tall, because it now has the whole
   measure — a 4/3 box across 1300px would be a wall. */
.mf-contact-map { overflow: hidden; margin-top: 32px; }

.mf-contact-map__title { padding: 16px 18px 0; margin-bottom: 12px; }

.mf-contact-map__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--c-page);
}

@media (min-width: 640px)  { .mf-contact-map__frame { aspect-ratio: 16 / 9; } }
@media (min-width: 1024px) { .mf-contact-map__frame { aspect-ratio: 21 / 7; } }

.mf-contact-map__frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* -------------------------------------------------------------------------
   SELLER PLANS — the public pricing page
   ------------------------------------------------------------------------- */
.mf-plans-intro { max-width: 62ch; margin-bottom: 26px; }
.mf-plans-intro__text { margin-top: 10px; }
.mf-plans-note { margin-top: 18px; }

.mf-plan-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  height: 100%;
}

.mf-plan-card.is-current { border-color: var(--c-blue); }

.mf-plan-card__action { margin-top: auto; padding-top: 8px; }

/* Launch promotion (3 months free) — pricing page banner, plan cards and the
   promotion summary. The free months are the plans' existing trial; these
   rules only present them. */
.mf-promo-banner {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 16px;
  margin-bottom: 16px; padding: 16px 20px; border-radius: 13px;
  background: #e9f4ff; color: #243c5d; font-size: 15px;
}
.mf-promo-banner strong { color: #1253bb; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; }

.mf-promo-tag {
  align-self: flex-start; padding: 5px 10px; border-radius: 8px;
  background: #e8f8ef; color: #137447; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .02em;
}
.p-price.mf-promo-price { font-size: 30px; color: var(--c-blue); line-height: 1.1; }
.mf-promo-normal { margin: -4px 0 0; font-size: 14px; color: var(--c-muted); }
.mf-promo-normal s { text-decoration-thickness: 1.5px; }
.mf-promo-after {
  margin: 0; padding-bottom: 12px; border-bottom: 1px solid var(--c-border-soft, #e7edf4);
  font-size: 14px; font-weight: 700; color: var(--c-text);
}
.mf-promo-note { margin: 0 0 10px; font-size: 12.5px; color: var(--c-muted); }

.mf-promo-summary__back { margin: 0 0 12px; font-size: 14px; }
.mf-promo-summary .t-lead { margin-top: 6px; }
.mf-promo-strip {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 16px;
  margin-top: 20px; padding: 16px 20px; border: 1px solid #b5e5c8; border-radius: 12px;
  background: #e8f7ef; color: #214333; font-weight: 600;
}
.mf-promo-strip strong { color: #126e42; font-weight: 800; text-transform: uppercase; }
.mf-promo-summary__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; margin-top: 20px; align-items: start; }
@media (min-width: 1024px) {
  .mf-promo-summary__grid { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
}
.mf-promo-item__kicker { margin: 0 0 14px; padding-bottom: 14px; border-bottom: 1px solid var(--c-border-soft, #e4eaf1); font-weight: 700; }
.mf-promo-item__title { margin: 0 0 6px; font-size: 22px; font-weight: 700; }
.mf-promo-rows { display: grid; gap: 14px; margin: 20px 0 0; }
.mf-promo-rows > div { display: grid; grid-template-columns: minmax(0, 220px) minmax(0, 1fr); gap: 10px; align-items: baseline; }
.mf-promo-rows dt { color: var(--c-muted); }
.mf-promo-rows dd { margin: 0; font-weight: 600; color: var(--c-text); }
.mf-promo-rows__normal { color: var(--c-muted) !important; }
.mf-promo-rows__free { font-size: 22px; font-weight: 800 !important; color: var(--c-blue) !important; }
.mf-promo-item__foot { margin: 20px 0 0; padding-top: 14px; border-top: 1px solid var(--c-border-soft, #e4eaf1); font-size: 14px; color: var(--c-text-2, #455a72); }
.mf-promo-order { display: flex; flex-direction: column; gap: 12px; }
.mf-promo-order__title { margin: 0; padding-bottom: 12px; border-bottom: 1px solid var(--c-border-soft, #e3eaf1); font-size: 20px; font-weight: 700; }
.mf-promo-order__row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.mf-promo-order__total { padding-top: 12px; border-top: 1px solid var(--c-border-soft, #e3eaf1); font-size: 18px; font-weight: 700; }
.mf-promo-order__total strong { font-size: 26px; }
.mf-promo-order__date { margin: 0; font-size: 14px; }
.mf-promo-blue { color: var(--c-blue); }
.mf-promo-green { color: #127647; }
.mf-promo-summary__continue {
  margin-top: 20px; padding: 16px 20px; border: 1px solid #f4e0a3; border-radius: 11px;
  background: #fff8e7; color: #53431f; font-size: 14.5px;
}
@media (max-width: 640px) {
  .mf-promo-rows > div { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .p-price.mf-promo-price { font-size: 26px; }
}

.store-hero {
  display: grid;
  gap: 20px;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}

.store-hero__body { min-width: 0; }

/* The action column sits inline on a phone and becomes a rail beside the
   details once there is room for one. */
.store-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.store-hero__actions:empty { display: none; }

@media (min-width: 640px) {
  .store-hero { grid-template-columns: auto minmax(0, 1fr); }

  /* The buttons keep the full width under both columns until the rail exists. */
  .store-hero__actions { grid-column: 1 / -1; }
}

@media (min-width: 1024px) {
  .store-hero { grid-template-columns: auto minmax(0, 1fr) auto; }

  .store-hero__actions {
    grid-column: auto;
    flex-direction: column;
    min-width: 200px;
  }
}

.store-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin: 0;
  padding: 18px clamp(14px, 3vw, 22px) clamp(14px, 3vw, 22px);
  border-top: 1px solid var(--c-border-soft);
}

@media (min-width: 640px) {
  .store-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.store-stats > div { text-align: center; }

.store-stats dd {
  margin: 2px 0 0;
  font-weight: 700;
  font-size: 19px;
  color: var(--c-text);
}

/* -------------------------------------------------------------------------
   CART
   The design system carries .card, .card-head and .card-pad; these are the
   pieces the cart adds on top — the seller strip at the head of each group,
   the stock line, and the right-hand end of a line.
   ------------------------------------------------------------------------- */
.cart-seller {
  display: flex;
  gap: 10px;
  align-items: center;
  min-width: 0;
}

.cart-seller-name {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  font-size: 14px;
}

.cart-verified { color: var(--c-ok); display: inline-flex; }

.cart-stock { margin-top: 2px; color: var(--c-ok); }
.cart-stock.is-low { color: var(--c-warn); }

/* Line total above the quantity control, both hard right. */
.cart-line-end {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  text-align: right;
  min-width: 116px;
}

/* Unit price above the quantity control, line subtotal below it, each with its
   own label — so neither number can be mistaken for the other. */
.cart-line-price {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  line-height: 1.25;
}

.cart-line-price .t-meta { font-size: 11.5px; }

.cart-line-price__value { font-size: 14px; color: var(--c-text-2); }

.cart-line-price--sub .cart-line-price__value {
  font-size: 16px;
  color: var(--c-text);
}

.cart-seller-foot {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  padding: 12px 20px;
  border-top: 1px solid var(--c-border-soft);
}

/* The stepper buttons inside the pill. Square, flush to the input, and
   separated from it by a hairline — the prototype's shape. */
.quantity .qty-step {
  flex: none;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--c-text-2);
}

.quantity .qty-step:hover:not( :disabled ) { background: var(--c-page); color: var(--c-blue); }
.quantity .qty-step:disabled { opacity: .4; cursor: default; }

.quantity .qty-step[data-qty-step="-1"] { border-right: 1px solid var(--c-border); }
.quantity .qty-step[data-qty-step="1"] { border-left: 1px solid var(--c-border); }

/* The browser's own number spinner, removed.
   The field already has its own - and + buttons either side of it, so the
   native stepper is a second, tinier set of the same control sitting inside the
   input — which is what the arrows in the middle of the quantity box were. */
.quantity input[type="number"] {
  -moz-appearance: textfield;
  -webkit-appearance: textfield;
          appearance: textfield;
}

.quantity input[type="number"]::-webkit-outer-spin-button,
.quantity input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* On the listing page the control is taller, to sit level with the 46px
   add-to-cart button beside it. */
.mk-product form.cart .quantity .qty-step { width: 40px; height: 46px; }

/* WooCommerce's quantity control, given the bordered pill the design uses. */
.cart-line-end .quantity {
  display: flex;
  align-items: center;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  overflow: hidden;
}

.cart-line-end .quantity input {
  width: 62px;
  height: 34px;
  border: 0;
  text-align: center;
  padding: 0;
  border-radius: 0;
  font-size: 14px;
  background: #fff;
  color: var(--c-text);
}

.cart-line-end .quantity input:focus { outline: 2px solid var(--c-blue); outline-offset: -2px; }

.cart-totals-list dd { margin: 0; font-weight: 600; }
.cart-totals-list dd .woocommerce-Price-amount { font-weight: 600; }

.cart-grand-total,
.cart-grand-total .woocommerce-Price-amount {
  font-weight: 800;
  font-size: 22px;
  letter-spacing: -.03em;
}

/* WooCommerce renders the checkout button itself; the design wants it full
   width and large, which is what the prototype's markup had inline. */
/* The button now wears `.btn.btn-primary.btn-lg.btn-block` from the theme's own
   override of proceed-to-checkout-button.php, so nothing is needed here beyond
   clearing WooCommerce's `button alt`, which this theme never styled and which
   would otherwise contribute a stray underline. */
.wc-proceed-to-checkout .checkout-button { text-decoration: none; }

/* `button alt` is WooCommerce's and this theme styles neither, so `.alt` needs
   no rule of its own — it is written into proceed-to-checkout-button.php only
   because extensions select `.button.alt`.

   ⚠️ It once carried `background: inherit` here, purely to satisfy the class
   audit. That inherited the card's white and beat `.btn-primary`'s blue, so the
   button rendered as white text on white — an empty outlined box. A class that
   should do nothing must be given NOTHING, not a harmless-looking value. The
   audit's allowlist is the right place for a class the design system does not
   own. */

/* The shipping rows come from WooCommerce as table markup in a list context. */
.cart_totals .shipping th,
.cart_totals .shipping td { display: block; padding: 0; text-align: left; }
.cart_totals .shipping th { font-size: 12.5px; color: var(--c-muted); font-weight: 500; margin-bottom: 4px; }
.cart_totals .woocommerce-shipping-methods { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.cart_totals .woocommerce-shipping-methods label { font-size: 13.5px; }

/* -------------------------------------------------------------------------
   MY LISTINGS TABLE
   ------------------------------------------------------------------------- */
.mf-listing-name {
  font-weight: 500;
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The rejection reason sits under the status badge rather than in a column of
   its own — it is the one cell that carries a sentence. */
.mf-reject-reason {
  display: flex;
  gap: 6px;
  align-items: flex-start;
  margin-top: 6px;
  color: var(--c-bad);
  max-width: 30ch;
}

/* -------------------------------------------------------------------------
   UNREAD COUNT IN A ROW
   The design system styles `.count` only inside `.icon-link`, where it is a
   dot pinned over the icon. In a sidebar row or a dropdown item it is a inline
   pill at the end of the line instead — same colour, different shape, because
   there is no icon to sit on top of.
   ------------------------------------------------------------------------- */
.side-link .count,
.dd-item .count {
  flex: none;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  display: inline-grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: var(--c-blue);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* An active row is already blue-on-blue, so the pill inverts to stay legible. */
.side-link[aria-current="page"] .count {
  background: var(--c-blue-dark);
}

/* -------------------------------------------------------------------------
   NOTIFICATION ROW
   The bell panel's rows. Built on .conv from the conversation list — same
   shape, same avatar, same preview — but tighter, because a dropdown is not
   a screen.
   ------------------------------------------------------------------------- */
.notif {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--c-border-soft);
  transition: background var(--t-fast) var(--ease);
}

.notif:last-of-type { border-bottom: 0; }
.notif:hover { background: var(--c-page); }

.notif-body {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Top-aligned, not baseline: a two-line title beside a one-line timestamp has
   no shared baseline worth aligning to, and `baseline` pushed the time down to
   meet the title's second line. */
.notif-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

/*
 * The title is the message.
 *
 * It used to be one nowrap line with an ellipsis, so "Your listing was
 * approved" arrived as "Your listing was approv…" — clipped by a timestamp
 * that had taken a third of the panel to wrap itself onto two lines. Two lines
 * here, and the clamp only bites on something genuinely long.
 */
.notif-name {
  font-weight: 600;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--c-text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* The timestamp: as wide as its words and not one pixel more. */
.notif-top .t-meta {
  flex: none;
  white-space: nowrap;
  padding-top: 1px;
}

/* Two lines of preview, then clipped — a dropdown row cannot grow. */
.notif-text {
  font-size: 12.5px;
  color: var(--c-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.notif .conv-unread { flex: none; align-self: center; }

/* An unread row. A tint rather than a heavier weight on the title, because
   several rows are unread at once and bolding all of them bolds nothing. */
.notif.is-unread { background: var(--c-blue-soft); }
.notif.is-unread:hover { background: #E4EEFE; }

/* The row is a link, and its text should not turn blue for being one. */
a.notif { text-decoration: none; color: inherit; }

/* The type icon. Squared-off rather than round: these are things that
   happened, not people who did them, and the avatars in the conversation list
   are round — the two lists sit behind adjacent icons in the same header and
   should not be mistakable for each other. */
.notif-ico {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  display: grid;
  place-items: center;
  background: var(--c-blue-soft);
  color: var(--c-blue);
}

/* Only three types are toned, and the tones match .state-icon--* so an
   approval reads the same here as it does on the page it links to. An
   approval and a rejection have to be tellable apart at a glance; colouring
   every row would mean colouring none. */
.notif-ico--ok   { background: #F0FDF4; color: var(--c-ok); }
.notif-ico--bad  { background: #FEF2F2; color: var(--c-bad); }
.notif-ico--warn { background: #FFFBEB; color: #B45309; }

/* The unread marker. A dot, not a count: a notification is one event, so
   there is never a number to print — unlike a conversation, which is why
   .conv-unread is a pill and this is not. */
.notif-dot {
  flex: none;
  align-self: center;
  width: 8px;
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--c-blue);
}

/* The panel's own heading, holding the label and "Mark all read". Sticky, so
   the button stays reachable once the list is long enough to scroll — the
   panel scrolls, not the page. */
.notif-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  background: #fff;
  border-bottom: 1px solid var(--c-border-soft);
}

/* Both are hidden at zero — by the server on render, and by the poller and
   notifications.js afterwards. Nothing should override that. */
[data-marketflow-notifications][hidden],
[data-mf-notifications-read-all][hidden] { display: none !important; }

/* -------------------------------------------------------------------------
   DOT BADGE
   A badge that shows only that there is something, not how much.

   This was the bell, on the reasoning that its dropdown held the unread
   conversations and the message icon sat right beside it, so a number would
   have been the same fact printed twice. That stopped being true in
   MarketFlow Core 0.23.0: the bell is the notification centre now, messages
   belong to the message icon alone, and the two counts are different facts —
   so the bell prints its number.

   Kept because marketflow_unread_badge_markup()'s third argument still offers
   it. The text stays in the element, since the poller writes into it, and is
   clipped away instead.
   ------------------------------------------------------------------------- */
.icon-link .count--dot {
  min-width: 10px;
  width: 10px;
  height: 10px;
  padding: 0;
  top: 6px;
  right: 6px;
  overflow: hidden;
  text-indent: -99em;
  border-width: 2px;
}

/* -------------------------------------------------------------------------
   WOOCOMMERCE NOTICES
   "Added to cart", "Please enter a valid email", "Your account is using a
   temporary password". The theme dequeues WooCommerce's stylesheets, so these
   were arriving as bare bulleted text — the one place on the site with a list
   marker on a sentence.

   Inline alerts, not toasts. A toast is right for something the visitor did
   and can forget (a wishlist tap); these report on a page that has just
   changed, and a checkout error that floats away before it is read is a form
   nobody can complete. So they sit in the flow, above the content they
   concern, and stay there.

   THE MARKUP IS NOT ONE SHAPE, and assuming it was is what broke the first
   version of this. WooCommerce emits either

     <ul class="woocommerce-error"><li>…</li><li>…</li></ul>
     <div class="woocommerce-info"><a class="button">Resend</a> Some text.</div>

   — a list, or a div carrying a bare text node with the action button BEFORE
   it. Styling only the list left the second form as a three-column row reading
   "icon, button, text", with the sentence taking the tone colour because the
   rule that set text colour was scoped to the <li> that did not exist.

   AND IT IS NOT A FLEX ROW, which is what broke the second version. Every
   in-flow child of a flex container becomes a flex item, an inline <a>
   included — so "We emailed you a <a>link</a> to change your password" had the
   word "link" lifted out of the sentence with the row's 12px gap on either
   side of it, and on a narrow column it broke onto a line of its own.

   A sentence has to stay inline. So this is a BLOCK: `flow-root` to contain the
   float, the icon positioned into the padding it already reserved, and the
   button floated to the far end. The list form needs nothing — list items
   stack by themselves.
   ------------------------------------------------------------------------- */
.woocommerce-notices-wrapper:not(:empty) { margin-bottom: 18px; }

.woocommerce-message,
.woocommerce-info,
.woocommerce-error {
  /* `flow-root` rather than `block`: it contains the floated button, so a
     one-line notice keeps its full height. NOT flex — see the note above. */
  display: flow-root;
  position: relative;
  margin: 0 0 12px;
  padding: 14px 16px 14px 46px;
  list-style: none;
  border: 1px solid;
  border-left-width: 3px;
  border-radius: var(--r-md);
  font-size: 14px;
  line-height: 1.55;
  /* The sentence stays readable. Only the icon and the rules carry the tone —
     a whole paragraph in the tone colour reads as a link. */
  color: var(--c-text);
}

.woocommerce-message:last-child,
.woocommerce-info:last-child,
.woocommerce-error:last-child { margin-bottom: 0; }

.woocommerce-message::before,
.woocommerce-info::before,
.woocommerce-error::before {
  content: '';
  position: absolute;
  left: 18px;
  top: 15px;
  width: 18px;
  height: 18px;
  background: currentColor;
}

/*
 * The list form. One row shares the line with the icon; a second and beyond
 * take a full line each, so a validation list stacks instead of forming
 * columns.
 */
.woocommerce-message > li,
.woocommerce-info > li,
.woocommerce-error > li {
  margin: 0;
  list-style: none;
}

.woocommerce-message > li ~ li,
.woocommerce-info > li ~ li,
.woocommerce-error > li ~ li { margin-top: 6px; }

/*
 * WooCommerce's own `.button` — "Resend", or "View cart" after adding
 * something. It is emitted BEFORE the message text, so it is ordered last and
 * pushed to the far end: the sentence is what to read, the action is what to
 * do after reading it.
 */
.woocommerce-message .button,
.woocommerce-info .button,
.woocommerce-error .button {
  float: right;
  margin: 0 0 8px 14px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 14px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: #fff;
  color: var(--c-text);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}

.woocommerce-message .button:hover,
.woocommerce-info .button:hover,
.woocommerce-error .button:hover { border-color: var(--c-blue); color: var(--c-blue); }

/* Below this the sentence and the button each want the full width, and the
   button reads better under the text than squeezed beside it. */
@media (max-width: 560px) {
  .woocommerce-message .button,
  .woocommerce-info .button,
  .woocommerce-error .button {
    margin: 0 0 8px 12px;
  }
}

/* -- tones ---------------------------------------------------------------- */

/* Success — the check from the icon registry, so it matches every other tick
   on the site rather than being a second visual language. */
.woocommerce-message {
  border-color: var(--c-ok);
  background: #F0FDF4;
}

.woocommerce-message::before {
  color: var(--c-ok);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
}

.woocommerce-info {
  border-color: var(--c-blue);
  background: var(--c-blue-soft);
}

.woocommerce-info::before {
  color: var(--c-blue);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11v5'/%3E%3Cpath d='M12 8h.01'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11v5'/%3E%3Cpath d='M12 8h.01'/%3E%3C/svg%3E") center / contain no-repeat;
}

.woocommerce-error {
  border-color: var(--c-bad);
  background: #FEF2F2;
}

.woocommerce-error::before {
  color: var(--c-bad);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.3 3.9 2.6 17a2 2 0 0 0 1.7 3h15.4a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.3 3.9 2.6 17a2 2 0 0 0 1.7 3h15.4a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* A link inside a notice is still a link, and the tone is already carried by
   the border — so it takes the theme's link colour, not the tone's. */
.woocommerce-message a:not(.button),
.woocommerce-info a:not(.button),
.woocommerce-error a:not(.button) {
  color: var(--c-blue-dark);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* -------------------------------------------------------------------------
   CART THUMBNAIL
   The theme dequeues WooCommerce's stylesheets, so a cart image arrived at
   whatever size the attachment happened to be. cart.html sizes it 88 square,
   cropped, with a hairline border.
   ------------------------------------------------------------------------- */
.cart-thumb {
  flex: none;
  display: block;
  width: 88px;
  height: 88px;
}

.cart-thumb img {
  width: 88px;
  height: 88px;
  border-radius: 10px;
  -o-object-fit: cover;
     object-fit: cover;
  border: 1px solid var(--c-border);
  display: block;
}

@media (max-width: 480px) {
  .cart-thumb,
  .cart-thumb img { width: 64px; height: 64px; }
}

/* -------------------------------------------------------------------------
   PLAN COMPARISON TABLE
   ------------------------------------------------------------------------- */
.mf-compare-label {
  text-align: left;
  padding: 12px 14px;
  font-weight: 500;
  font-size: 14px;
  border-bottom: 1px solid var(--c-border-soft);
}

/*
 * A tick or a cross, never an empty cell. The prototype greyed the cross
 * rather than omitting it, which is what makes the row scannable — an empty
 * cell reads as missing data instead of as "no".
 */
.mf-compare-mark {
  display: inline-flex;
  color: #CBD5E1;
}

.mf-compare-mark.is-in { color: var(--c-ok); }

/* -------------------------------------------------------------------------
   PROFILE PHOTO CARD
   One row: avatar, rule, copy, actions hard right. Wraps to a column on a
   narrow screen rather than squeezing, because the two buttons are wide and
   the hint line is long.
   ------------------------------------------------------------------------- */
.mf-photo-card {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2.4vw, 28px);
  padding: clamp(18px, 2.2vw, 26px);
  flex-wrap: wrap;
}

/* The avatar and the camera badge that overlaps it. */
.mf-photo-figure {
  position: relative;
  flex: none;
  display: block;
  cursor: pointer;
  /* The rule the design draws between the photo and the copy. Padding rather
     than a border on the next element, so it disappears with the wrap. */
  padding-right: clamp(16px, 2.4vw, 28px);
  border-right: 1px solid var(--c-border);
}

.mf-photo-badge {
  position: absolute;
  right: calc(clamp(16px, 2.4vw, 28px) - 2px);
  bottom: -2px;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--c-ok);
  color: #fff;
  border: 3px solid #fff;
  box-shadow: var(--sh-xs);
  transition: transform var(--t-fast) var(--ease);
}

.mf-photo-figure:hover .mf-photo-badge { transform: scale(1.06); }

.mf-photo-figure:focus-within .mf-photo-badge,
.mf-photo-card input:focus-visible + .mf-photo-badge {
  outline: 2px solid var(--c-blue);
  outline-offset: 2px;
}

.mf-photo-copy {
  flex: 1;
  min-width: 200px;
}

.mf-photo-lead {
  margin-top: 4px;
  font-size: 15px;
  color: var(--c-text-2);
}

/* Set apart from the lead, because it is reference rather than instruction. */
.mf-photo-hint { margin-top: 10px; }

.mf-photo-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  flex: none;
}

@media (max-width: 720px) {
  .mf-photo-figure {
    padding-right: 0;
    border-right: 0;
  }

  .mf-photo-badge { right: -2px; }
}

/* -------------------------------------------------------------------------
   TONAL BUTTONS
   A tinted face, a matching border and matching text — not the theme's blue.
   For a pair of actions where the outcome, not the brand, is the thing to
   read at a glance: adding a photo against removing one.

   Built on .btn, so height, radius, font and icon spacing all come from there
   and these only supply colour.
   ------------------------------------------------------------------------- */
.btn-soft-ok,
.btn-soft-bad {
  border: 1px solid;
  font-weight: 700;
}

.btn-soft-ok {
  color: var(--c-ok);
  border-color: var(--c-ok);
  background: #F0FDF4;
}

.btn-soft-ok:hover { background: #DCFCE7; }

.btn-soft-bad {
  color: var(--c-bad);
  border-color: var(--c-bad);
  background: #FEF2F2;
}

.btn-soft-bad:hover { background: #FEE2E2; }

/* A label styled as a button is still a label. */
label.btn-soft-ok { cursor: pointer; }

/* -------------------------------------------------------------------------
   ORDER ITEM LINES
   One order row can list several items, so they stack inside the cell rather
   than running together on one line.
   ------------------------------------------------------------------------- */
.mf-order-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 13.5px;
}

.mf-order-line + .mf-order-line { margin-top: 4px; }

/* -------------------------------------------------------------------------
   SIGN-IN SCREEN
   auth.html is a split screen with no site chrome at all: the form on the
   left with its own logo, a brand panel on the right. The header is not
   suppressed for tidiness — a visitor who cannot sign in has nothing to
   navigate to, so a header would only offer them ways to leave.

   Everything page.php and WooCommerce put between the shell and this file is
   a wrapper with nothing to contribute, so those are zeroed the same way the
   messaging screen zeroes them.
   ------------------------------------------------------------------------- */
.mf-auth .site-header,
.mf-auth .site-footer,
.mf-auth .mobile-nav { display: none; }

.mf-auth .shell,
.mf-auth .page-app,
.mf-auth .woocommerce,
.mf-auth article,
.mf-auth .entry-content {
  margin: 0;
  padding: 0;
  max-width: none;
}

/* The bottom padding the mobile nav reserved is not needed with it gone. */
.mf-auth.has-mobile-nav { padding-bottom: 0; }

.mf-auth-split {
  display: grid;
  min-height: 100vh;
  background: #fff;
}

@media (min-width: 1024px) {
  .mf-auth-split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* -- form side ------------------------------------------------------------ */
.mf-auth-form {
  display: flex;
  flex-direction: column;
  padding: clamp(20px, 4vw, 44px);
  background: var(--c-page);
  min-width: 0;
}

/* auto margins push the logo to the top and the footnote to the bottom,
   leaving the panel centred in whatever is left. */
.mf-auth-brand { margin-bottom: auto; }

/* `margin-block: auto` is what actually centres the panel vertically, and it is
   here rather than relying on the footnote because only the sign-in screen has
   one. Lost password, "Choose a new password" and the confirmation each render a
   brand and a panel and nothing else — so `.mf-auth-brand`'s auto bottom margin
   had nothing to push against and drove those panels to the bottom of a
   full-height column. On sign-in the footnote still balances the column and this
   changes nothing. */
.mf-auth-panel {
  width: 100%;
  max-width: 420px;
  margin-inline: auto;
  margin-block: auto;
  padding-block: 32px;
}

.mf-auth-tabs {
  width: 100%;
  margin-bottom: 24px;
}

.mf-auth-title { font-size: clamp(1.6rem, 3vw, 2.1rem); }

.mf-auth-lead {
  margin-top: 6px;
  font-size: 15px;
}

.mf-auth-foot {
  text-align: center;
  margin-top: auto;
}

/* -- brand side ----------------------------------------------------------- */
.mf-auth-brand-side {
  display: none;
  padding: 48px;
  flex-direction: column;
  justify-content: center;
  position: relative;
  overflow: hidden;
  color: #fff;
  /* Derived from the palette rather than fixed hexes, so a site that repaints
     its brand colour repaints this panel with it. */
  background: linear-gradient(160deg, var(--c-blue-dark), var(--c-blue) 55%, var(--c-blue-dark));
}

@media (min-width: 1024px) {
  .mf-auth-brand-side { display: flex; }
}

/* The accent bloom in the top corner. */
.mf-auth-glow {
  position: absolute;
  right: -80px;
  top: -80px;
  width: 380px;
  height: 380px;
  background: radial-gradient(circle, rgba(250, 204, 21, .26), transparent 68%);
  pointer-events: none;
}

.mf-auth-brand-inner {
  position: relative;
  max-width: 440px;
}

.mf-auth-eyebrow { color: var(--c-yellow); }

.mf-auth-headline {
  color: #fff;
  margin-top: 12px;
}

.mf-auth-copy {
  color: var(--c-blue-line);
  margin-top: 14px;
  font-size: 16px;
  line-height: 1.6;
}

.mf-auth-points {
  display: grid;
  gap: 12px;
  margin-top: 28px;
  list-style: none;
  padding: 0;
}

.mf-auth-points li {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 15px;
}

.mf-auth-tick {
  color: var(--c-yellow);
  display: inline-flex;
  flex: none;
}

.mf-auth-stats {
  margin-top: 36px;
  padding-top: 24px;
  border-top: 1px solid rgba(255, 255, 255, .2);
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
}

.mf-auth-stat {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}

.mf-auth-stat-label {
  color: #BFDBFE;
  font-size: 13px;
}

/* -------------------------------------------------------------------------
   SHOP / ARCHIVE — three bands
   The page heading, then the result toolbar, then filters beside results.

   Both of the first two used to live inside the right-hand column, so the
   filter card started level with the page title: "Shop" looked indented by the
   width of the sidebar, and the filters read as part of the page header rather
   than as a control over the results. Full width puts the sidebar level with
   the first row of products, which is what it is filtering.
   ------------------------------------------------------------------------- */
.mk-head {
  padding-bottom: 14px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--c-border);
}

/* -------------------------------------------------------------------------
   CATEGORY RESULTS HEAD — breadcrumb, heading, count, applied filters
   ------------------------------------------------------------------------- */
/* One band above the results, sharing the page's own column so the breadcrumb,
   the heading, the chips, the filter card and the first row of cards all sit on
   the same left edge. */
.mk-page-head { padding-top: clamp(14px, 2vw, 22px); padding-bottom: clamp(14px, 2vw, 20px); }

.mk-page-head .breadcrumb-nav { margin-bottom: 10px; }

.mk-page-title { margin: 0; }

.mk-page-count {
  margin: 6px 0 0;
  font-size: 14.5px;
  color: var(--c-muted);
  font-variant-numeric: tabular-nums;
}

.mk-page-intro { margin-top: 14px; max-width: 72ch; font-size: 14.5px; color: var(--c-text-2); }

/* Applied filters. Each is a link that removes itself, so they read as
   controls rather than as labels — which is why they carry the chip's hover
   and focus treatment rather than a flat badge's. */
.mk-chips {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  /* Space on both sides. The row used to carry a top margin only, which was
     fine under a category heading but put the chips hard against the top of
     the result toolbar on the shop — two rows of small controls reading as
     one. */
  margin-block: 14px 16px;
}

.chip--applied {
  gap: 7px;
  background: var(--c-blue-soft);
  border-color: transparent;
  color: var(--c-blue-dark);
  font-weight: 500;
  text-decoration: none;
}
.chip--applied:hover { border-color: var(--c-blue); background: var(--c-blue-soft); }
.chip--applied:focus-visible { outline: 2px solid var(--c-blue); outline-offset: 2px; }

.mk-chips-clear {
  margin-left: 4px;
  font-size: 13.5px; font-weight: 600;
  color: var(--c-muted); text-decoration: none;
}
.mk-chips-clear:hover { color: var(--c-blue); text-decoration: underline; }

.mk-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 18px;
  padding: 10px 14px;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-card);
}

/* -------------------------------------------------------------------------
   FILTER SIDEBAR
   Sized by its contents. It used to carry a max-height and its own scrollbar,
   with a second sticky header inside that — which on a short filter set drew a
   tall card with an inner scroll area and empty space in it, and clipped the
   last control halfway through.

   There are five filters at most, so nothing needs to scroll. The card is
   sticky as a whole and simply as tall as what is in it.
   ------------------------------------------------------------------------- */
.mk-filters {
  position: sticky;
  top: calc(var(--header-h) + var(--wpsticky) + 16px);
  align-self: start;
}

/* Tinted to match what it contains, and lighter than a result card so the two
   do not compete along the same edge. */
.mk-filters { border-color: #C7DBF8; }

.mk-filters .card-head {
  padding: 18px 16px 6px;
  border-bottom: 0;
}

.mk-filters .card-head h2 {
  font-size: 20px; font-weight: 700; letter-spacing: -.01em;
  color: #1E3A8A;
}

.mk-filters-body { padding: 0 16px 18px; }

/* The rows carry their own spacing (see THE FILTER PANEL above); the card only
 * trims the gap under its heading. */
.mk-filters-body .filter-row:first-child { padding-top: 2px; }

@media (max-width: 1023px) {
  .mk-toolbar { padding: 10px 12px; }
}

/* -------------------------------------------------------------------------
   A SELLER'S OWN SALE

   The seller side of an order — see template-parts/account/sale.php for why
   WooCommerce's customer-facing order page cannot serve this.
   ------------------------------------------------------------------------- */
.mf-sale { display: grid; gap: 16px; }

.mf-sale-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px 24px;
}

.mf-sale-facts > div { min-width: 0; }
.mf-sale-actions { display: grid; gap: 18px; }
.mf-sale-actions .select { max-width: 260px; }
.mf-sale-actions .textarea { min-height: 96px; }
.mf-sale-actions p { margin: 8px 0 0; }
.mf-sale-actions .filter-label { padding: 0 0 6px; }

/* Each action is its own block, with a rule between them so "update the
   status" and "say something to the buyer" do not read as one form. */
.mf-sale-status,
.mf-sale-message { display: block; }
.mf-sale-message { border-top: 1px solid var(--c-border); padding-top: 16px; }
.mf-sale-facts p { margin: 4px 0 0; font-weight: 600; color: var(--c-text); }
.mf-sale-facts p .t-meta { display: block; font-weight: 400; }

/* -------------------------------------------------------------------------
   NOTICES WITHOUT SCRIPT
   The toast fallback, printed in the footer because that is where the decision
   is made. Given the shell every other band has, so it does not read as loose
   text under the page.
   ------------------------------------------------------------------------- */
.mf-noscript-notices {
  max-width: var(--shell);
  margin-inline: auto;
  padding: 18px var(--gutter);
}

/* The sign-in screen hides the footer and the bottom bar, so the toast has the
   whole corner to itself rather than clearing a nav that is not there. */
.mf-auth .toast-stack { bottom: 16px; }

/* -------------------------------------------------------------------------
   READ RECEIPTS
   The plugin sets data-marketflow-receipt and draws nothing; the ticks are the
   theme's. One grey tick sent, two grey delivered, two blue seen — the
   convention every messenger has already taught people to read, so it needs no
   legend.

   The ticks overlap slightly, as they do everywhere else, rather than sitting
   as two separate marks.
   ------------------------------------------------------------------------- */
.mf-receipt {
  display: inline-flex;
  align-items: center;
  margin-left: 3px;
  color: rgba(255, 255, 255, .72);
}

.mf-receipt .tick { display: inline-flex; }
.mf-receipt .tick-2 { margin-left: -7px; }

/* Sent: one tick. The second is not merely faded — it has not happened. */
[data-marketflow-receipt="sent"] .tick-2 { display: none; }

[data-marketflow-receipt="delivered"] .tick { color: rgba(255, 255, 255, .72); }

/*
 * Seen. On the blue outgoing bubble a mid-blue tick would vanish, so this is
 * the pale end of the ramp rather than the brand colour — the same distinction
 * read against a different ground.
 */
[data-marketflow-receipt="seen"] .tick { color: #7DD3FC; }

/*
 * One screen-reader label per state, shown by the attribute. A single label
 * would be written once and then be wrong the moment the poller changed the
 * state under it.
 */
.mf-receipt [data-receipt-label] { display: none; }
[data-marketflow-receipt="sent"] [data-receipt-label="sent"],
[data-marketflow-receipt="delivered"] [data-receipt-label="delivered"],
[data-marketflow-receipt="seen"] [data-receipt-label="seen"] { display: inline; }

/* -------------------------------------------------------------------------
   PRESENCE AND TYPING
   Both are empty sockets the poller fills — they have to be in the markup
   before the first poll or they never get filled at all.
   ------------------------------------------------------------------------- */
.chat-status {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 16px;
  margin-top: 1px;
}

.chat-presence {
  font-size: 12.5px;
  color: var(--c-muted);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* The dot is the signal; the word beside it is confirmation. Grey until the
   poller adds is-online, so an unknown state never reads as present. */
.chat-presence::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #CBD5E1;
  flex: none;
}

.chat-presence.is-online { color: var(--c-ok); }
.chat-presence.is-online::before { background: var(--c-ok); }

/* Block and Delete in the thread header. Quiet by default — they are exits,
   not the point of the screen — and the destructive one only takes its colour
   on hover, so a red button is never sitting there waiting to be misread. */
/* At the far end of the header row: the row is a flex line, so this is all
   it takes to put them opposite the person they apply to. */
.chat-actions { display: flex; align-items: center; gap: 4px; margin-left: auto; flex: none; }

/* "Contact seller": a <details> whose summary is the button. The marker is
   removed because a disclosure triangle inside a button reads as a bug, and the
   button already says what it does. */
.contact-seller summary { list-style: none; cursor: pointer; }
.contact-seller summary::-webkit-details-marker { display: none; }
.contact-seller-toggle { justify-content: center; }
.contact-seller[open] .contact-seller-toggle { margin-bottom: 2px; }
.chat-actions .btn { gap: 6px; }
.chat-action-danger:hover { color: var(--c-bad); }

/* Blocked: the composer is replaced by this rather than disabled, because a
   disabled text box invites somebody to keep clicking it. */
.chat-blocked {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 14px 16px; border-top: 1px solid var(--c-border);
  color: var(--c-muted); font-size: 13.5px; line-height: 1.55;
}
.chat-blocked svg { flex: none; margin-top: 2px; }

.chat-typing {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--c-blue);
  font-style: italic;
}

.chat-typing-dots { display: inline-flex; gap: 3px; }

.chat-typing-dots i {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  animation: mfTyping 1.2s infinite ease-in-out;
}

.chat-typing-dots i:nth-child(2) { animation-delay: .15s; }
.chat-typing-dots i:nth-child(3) { animation-delay: .3s; }

@keyframes mfTyping {
  0%, 60%, 100% { opacity: .25; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-2px); }
}

@media (prefers-reduced-motion: reduce) {
  .chat-typing-dots i { animation: none; opacity: .6; }
}

/* -------------------------------------------------------------------------
   PER-CONVERSATION BADGE
   Rendered at zero and hidden, because the poller fills elements rather than
   creating them: a row that ships without this span can never show a count,
   however many messages arrive while the page is open.
   ------------------------------------------------------------------------- */
.conv-unread[hidden] { display: none !important; }

/* -------------------------------------------------------------------------
   INBOX ROW ACTIONS
   Archive, restore and mark-unread, from MarketFlow Core 0.20.0.

   The buttons are SIBLINGS of the row, not children: the row is an <a> that
   fills the list, and a button inside an anchor is invalid markup that a
   browser resolves by closing the anchor early — which split every row in two.
   So `.conv-row` is a positioned wrapper holding both, and the actions are
   absolutely placed over the row's right edge.

   `.conv` keeps every one of its own rules, because none of them were ever
   written as a child selector of the scroller.
   ------------------------------------------------------------------------- */
.conv-row { position: relative; }

.conv-actions {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--r-pill);
  /* Opaque, because it sits over the row's timestamp and unread badge. */
  background: #fff;
  border: 1px solid var(--c-border);
  box-shadow: var(--sh-card);
}

.conv-action {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: var(--r-pill);
  background: none;
  color: var(--c-muted);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}

.conv-action:hover { background: var(--c-page); color: var(--c-blue); }
.conv-action:disabled { opacity: .5; cursor: default; }

/* Revealed on hover, and on keyboard focus anywhere in the row — without the
   focus-within half these buttons would be reachable by tab and invisible
   while focused, which is worse than not having them. */
@media (hover: hover) {
  .conv-actions {
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t-fast) var(--ease);
  }

  .conv-row:hover .conv-actions,
  .conv-row:focus-within .conv-actions {
    opacity: 1;
    pointer-events: auto;
  }
}

/* On touch there is no hover to reveal them, so they simply stay visible. */

.conv-pager {
  display: flex;
  justify-content: center;
  padding: 14px 12px 18px;
}

/* The poller adds this to a row that has unread messages, so the row itself
   can carry the weight rather than leaning on the badge alone. */
.conv.mf-has-unread .conv-name { font-weight: 700; color: var(--c-text); }
.conv.mf-has-unread .conv-last { color: var(--c-text-2); }

/* -- Plan screen ---------------------------------------------------------- */
/* Four plans, four columns. The grid carried `xl:grid-cols-3` from when there
   were three of them, so Premium wrapped onto a row by itself.

   Written out here rather than as Tailwind utilities because the Tailwind build
   is just-in-time: `xl:grid-cols-4` is not in the compiled sheet, so the class
   would have collapsed the row to one column on desktop. */
.mf-plan-grid { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 640px) {
  .mf-plan-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1280px) {
  .mf-plan-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Equal-height cards, so the CTA rows line up across all four. */
.mf-plan-grid > .card { height: 100%; }

/* The category price selector sits beside the section title. Baseline alignment
   keeps the control on the same line as the heading instead of riding up
   against the section boundary above it, and the bottom margin stops it
   colliding with the cards when the row wraps on a narrow viewport. */
.mf-plan-head { align-items: flex-end; row-gap: 12px; }
.mf-plan-head form { margin-bottom: 2px; }
.mf-plan-head .input { min-width: 200px; }

@media (max-width: 640px) {
  .mf-plan-head { align-items: stretch; }
  .mf-plan-head form { width: 100%; }
  .mf-plan-head .input { flex: 1; min-width: 0; }
}

/* -- Blog ----------------------------------------------------------------- */
.mf-post-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
}

@media (min-width: 640px) {
  .grid.mf-post-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .grid.mf-post-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.mf-post-card { display: flex; flex-direction: column; overflow: hidden; height: 100%; }
.mf-post-card__media { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: var(--c-border-soft); }
.mf-post-card__media img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; display: block; }
.mf-post-card__body { display: flex; flex-direction: column; gap: 8px; flex: 1; }
.mf-post-card__terms { margin: 0; text-transform: uppercase; letter-spacing: .04em; font-size: 11.5px; }
.mf-post-card__title { font-size: 17px; line-height: 1.35; margin: 0; }
.mf-post-card__title a { color: inherit; }
.mf-post-card__excerpt { margin: 0; line-height: 1.6; }
/* Pushed to the bottom so the date line sits level across a row of cards
   whatever length the titles are. */
.mf-post-card__meta { margin: auto 0 0; padding-top: 4px; }

/* Article beside a sticky rail, matching static/js/page-blog-post.js. Written as
   real CSS rather than Tailwind's arbitrary-value grid utility, because the
   Tailwind build is just-in-time and that class is not in the compiled sheet —
   using it would collapse the layout to one column. */
.mf-post-crumbs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.mf-post-title { font-size: clamp(1.7rem, 3.6vw, 2.5rem); max-width: none; margin-bottom: 22px; }

.mf-post-layout { display: grid; gap: 32px; align-items: start; }

@media (min-width: 1024px) {
  .mf-post-layout { grid-template-columns: minmax(0, 1fr) 290px; gap: 40px; }
  .mf-post-title { max-width: calc(100% - 330px); }
}

.mf-post-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 18px; }
/* "More from the blog" — the three-card strip below an article. Real CSS
   rather than `sm:grid-cols-3`, which the compiled Tailwind sheet does carry,
   but the strip also needs its own top rule and spacing. */
/* The seller overview, now a section of the My Account dashboard rather than a
   page of its own. It needs spacing below it, because what follows is the
   account's own two-column grid. */
.mf-seller-overview { display: grid; gap: 20px; margin-bottom: 20px; }

.mf-post-more { margin-top: 48px; }

.mf-post-more__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
}

@media (min-width: 640px) {
  .mf-post-more__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.mf-post__media { margin: 0 0 26px; }
.mf-post__media img {
  width: 100%;
  aspect-ratio: 16 / 9;
  -o-object-fit: cover;
     object-fit: cover;
  border-radius: var(--r-lg);
  border: 1px solid var(--c-border);
  display: block;
}
.mf-post__content { max-width: none; line-height: 1.75; }
.mf-post__content > :first-child { margin-top: 0; }
.mf-post__content > * + * { margin-top: 1.1em; }
.mf-post__content h2 { font-size: 1.35rem; margin-top: 1.8em; }
.mf-post__content h3 { font-size: 1.15rem; margin-top: 1.5em; }
.mf-post__content ul,
.mf-post__content ol { padding-left: 1.3em; }
.mf-post__content li + li { margin-top: .4em; }
.mf-post__content blockquote {
  border-left: 3px solid var(--c-blue);
  padding-left: 16px;
  color: var(--c-text-2);
  font-style: italic;
}
.mf-post__content img { max-width: 100%; height: auto; border-radius: var(--r-md); }
.mf-post__terms {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--c-border);
}

/* Author card, rendered only when a bio exists. */
.mf-post-author { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; margin-top: 32px; }
.mf-post-author__avatar img { width: 56px; height: 56px; border-radius: 50%; display: block; }
.mf-post-author__body { flex: 1; min-width: 200px; }
.mf-post-author__name { font-weight: 600; }
.mf-post-author .t-meta { margin-top: 3px; line-height: 1.55; }

/* -- Keep reading rail ---------------------------------------------------- */
.mf-post-rail__title { font-size: 15px; font-weight: 700; margin-bottom: 12px; }
.mf-post-rail__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.mf-post-rail__list a { display: flex; gap: 11px; align-items: center; color: inherit; }
.mf-post-rail__list img { width: 56px; height: 48px; border-radius: 8px; -o-object-fit: cover; object-fit: cover; flex: none; }
.mf-post-rail__text { min-width: 0; }
.mf-post-rail__text .link-blue { display: block; font-size: 13.5px; font-weight: 500; line-height: 1.35; }

@media (min-width: 1024px) {
  /* Sticky under the header, as the reference has it. */
  .mf-post-rail { position: sticky; top: calc(var(--header-h) + 16px); }
}

/* -- Comments ------------------------------------------------------------- */
/* WordPress prints its own field markup, so the theme's `.input` / `.textarea`
   classes are never applied. These rules match those controls by element
   instead, so the comment form looks like every other form on the site rather
   than a bare browser textarea. */
.mf-post-comments { max-width: 820px; margin: 24px auto 0; }
.mf-post-comments .comments-title,
.mf-post-comments .comment-reply-title { font-size: 17px; font-weight: 700; margin-bottom: 14px; }
.mf-post-comments .comment-list { list-style: none; margin: 0 0 24px; padding: 0; }
.mf-post-comments .comment-list li { padding: 14px 0; border-top: 1px solid var(--c-border-soft); }
.mf-post-comments .comment-form { display: grid; gap: 14px; max-width: 640px; }
.mf-post-comments .comment-form p { margin: 0; }
.mf-post-comments .comment-form label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 6px; }

.mf-post-comments .comment-form input[type="text"],
.mf-post-comments .comment-form input[type="email"],
.mf-post-comments .comment-form input[type="url"],
.mf-post-comments .comment-form textarea {
  width: 100%;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  padding: 10px 12px;
  font: inherit;
  background: #fff;
  color: inherit;
}

.mf-post-comments .comment-form textarea { min-height: 130px; resize: vertical; line-height: 1.6; }

.mf-post-comments .comment-form input:focus,
.mf-post-comments .comment-form textarea:focus {
  outline: 0;
  border-color: var(--c-blue);
  box-shadow: 0 0 0 3px rgba( 37, 99, 235, .12 );
}

.mf-post-comments .comment-form .form-submit { margin: 0; }
.mf-post-comments .comment-form input[type="submit"] {
  background: var(--c-blue);
  color: #fff;
  border: 0;
  border-radius: var(--r-md);
  padding: 11px 20px;
  font-weight: 600;
  cursor: pointer;
}
.mf-post-comments .comment-form input[type="submit"]:hover { filter: brightness( .95 ); }
.mf-post-comments .comment-notes,
.mf-post-comments .logged-in-as { font-size: 13px; color: var(--c-muted); }

.mf-post-nav { display: grid; gap: 12px; margin-top: 28px; }

@media (min-width: 640px) {
  .mf-post-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.mf-post-nav__link { display: flex; flex-direction: column; gap: 4px; color: inherit; }
.mf-post-nav__link--next { text-align: right; }
.mf-post-nav__title { font-weight: 600; }

/* -------------------------------------------------------------------------
   Ported verbatim from the prototype's stylesheet (static/css/marketplace.css,
   section 26) so the WooCommerce order-received endpoint renders the design
   that was drawn, rather than an approximation of it. The tokens it uses —
   --c-ok, --r-xl, --sh-card, --c-blue-soft — are the theme's own, so nothing
   new had to be defined.
   ------------------------------------------------------------------------- */
/* =========================================================================
   26. ORDER RECEIVED — WooCommerce thank-you page
   Page-scoped, all prefixed .oc-. Layout and spacing are done with Tailwind
   utilities in the markup; only the pieces utilities cannot express cleanly
   (the success ring, the divided meta strip, the summary rows and the order
   item media) live here.
   ========================================================================= */
.oc-shell { max-width: 1240px; }

/* --- success hero ------------------------------------------------------ */
.oc-hero {
  background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-xl);
  box-shadow: var(--sh-card); text-align: center;
  padding: clamp(28px, 4vw, 48px) clamp(18px, 3vw, 40px);
}
.oc-hero-icon {
  width: 68px; height: 68px; margin-inline: auto; border-radius: 50%;
  display: grid; place-items: center; color: var(--c-ok);
  background: #ECFDF5; box-shadow: 0 0 0 8px rgba(22, 163, 74, .07);
}
.oc-hero-icon svg { width: 32px; height: 32px; }
.oc-order-line {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 8px 6px 14px;
  border: 1px solid var(--c-border); border-radius: var(--r-pill); background: var(--c-page);
}
.oc-order-no { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }

/* --- copy button -------------------------------------------------------- */
.oc-copy {
  display: inline-flex; align-items: center; gap: 5px; height: 30px; padding: 0 10px;
  border: 1px solid var(--c-border); border-radius: var(--r-pill); background: #fff;
  font-size: 12.5px; font-weight: 600; color: var(--c-text-2); cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.oc-copy:hover { color: var(--c-blue); border-color: var(--c-blue-line); background: var(--c-blue-soft); }
.oc-copy.is-done { color: var(--c-ok); border-color: #A7F3D0; background: #ECFDF5; }
.oc-copy svg { width: 14px; height: 14px; }

/* --- meta strip ---------------------------------------------------------
   Separate blocks rather than one divided strip: the number of blocks comes
   from the order, so any count has to sit correctly at every breakpoint
   without leaving a dead cell. */
.oc-meta {
  display: grid; gap: 12px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 640px)  { .oc-meta { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .oc-meta { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.oc-meta-item {
  background: #fff; padding: 14px 16px; min-width: 0;
  border: 1px solid var(--c-border); border-radius: var(--r-lg); box-shadow: var(--sh-xs);
}
.oc-meta-label {
  display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600;
  letter-spacing: .07em; text-transform: uppercase; color: var(--c-muted);
}
.oc-meta-label svg { width: 14px; height: 14px; color: #94A3B8; }
.oc-meta-value {
  margin-top: 6px; font-size: 14.5px; font-weight: 600; color: var(--c-text);
  line-height: 1.4; overflow-wrap: anywhere;
}
.oc-meta-value.num { font-variant-numeric: tabular-nums; }
/* A long value (an email) reads badly in a half-width block on a phone. */
@media (max-width: 639px) { .oc-meta-item--wide { grid-column: 1 / -1; } }

/* --- order item --------------------------------------------------------- */
.oc-item-media {
  width: 64px; height: 64px; flex: none; border-radius: var(--r-md); overflow: hidden;
  background: var(--c-subtle); border: 1px solid var(--c-border);
}
.oc-item-media img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; }
.oc-item-media--empty { display: grid; place-items: center; color: #94A3B8; }
.oc-item-name { font-size: 14.5px; font-weight: 600; line-height: 1.35; }
.oc-item-name:hover { color: var(--c-blue); }

/* --- summary rows ------------------------------------------------------- */
.oc-sum-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 9px 0; font-size: 14px; color: var(--c-text-2);
}
.oc-sum-row .val { font-weight: 600; color: var(--c-text); font-variant-numeric: tabular-nums; }
.oc-sum-row.is-free .val { color: var(--c-ok); }
.oc-sum-row.is-discount .val { color: var(--c-ok); }
.oc-sum-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  margin-top: 6px; padding-top: 14px; border-top: 1px solid var(--c-border);
}
.oc-sum-total .lbl { font-size: 14.5px; font-weight: 600; }
.oc-sum-total .val {
  font-size: clamp(20px, 2.6vw, 24px); font-weight: 800; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}

/* --- address / info cards ----------------------------------------------- */
.oc-address { font-style: normal; font-size: 14px; color: var(--c-text-2); line-height: 1.65; }
.oc-address .oc-name { font-size: 14.5px; font-weight: 600; color: var(--c-text); }
.oc-contact-row { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--c-text-2); }
.oc-contact-row svg { width: 15px; height: 15px; color: #94A3B8; }
.oc-contact-row a:hover { color: var(--c-blue); }

/* --- note panel --------------------------------------------------------- */
.oc-note {
  display: flex; gap: 12px; padding: 16px 18px; border-radius: var(--r-lg);
  background: var(--c-blue-soft); border: 1px solid var(--c-blue-line);
}
.oc-note svg { color: var(--c-blue); flex: none; margin-top: 2px; }

/* --- trust strip -------------------------------------------------------- */
.oc-trust {
  display: flex; gap: 12px; align-items: flex-start; padding: 14px 18px;
  border: 1px solid var(--c-border); border-radius: var(--r-lg); background: #fff;
}
.oc-trust svg { color: var(--c-ok); flex: none; margin-top: 1px; }

/* --- motion: one short reveal on the success mark ------------------------ */
@keyframes oc-mark { from { opacity: 0; transform: scale(.82); } to { opacity: 1; transform: none; } }
@keyframes oc-tick { from { stroke-dashoffset: 36; } to { stroke-dashoffset: 0; } }
.oc-hero-icon { animation: oc-mark .34s var(--ease) both; }
.oc-hero-icon svg path { stroke-dasharray: 36; animation: oc-tick .4s var(--ease) .18s both; }
@media (prefers-reduced-motion: reduce) {
  .oc-hero-icon, .oc-hero-icon svg path { animation: none; stroke-dashoffset: 0; }
}

/* The order-received layout: details column plus a sticky summary rail. Real
   CSS, because the reference writes it as `lg:grid-cols-[minmax(0,1fr)_360px]`
   and that arbitrary value is not in the compiled Tailwind sheet. */
.mf-oc-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

@media (min-width: 1024px) {
  .mf-oc-layout { grid-template-columns: minmax(0, 1fr) 360px; }
}

/* Auto-fit, not a fixed three. The number of cards depends on the order — a
   digital order has no shipping address — and `repeat(3, 1fr)` left a card-sized
   hole beside the two that did render. `auto-fit` collapses the empty track, so
   two cards share the row and three fill it. */
.mf-oc-addresses {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 16px;
  margin-top: 16px;
}

.mf-oc-card-title {
  font-size: 15.5px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 7px;
}

.mf-oc-pay-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--r-md);
  display: grid;
  place-items: center;
  background: var(--c-blue-soft);
  color: var(--c-blue);
  flex: none;
}

/* The gateway's own instructions. WooCommerce prints whatever the gateway
   supplies here, so the container styles it without assuming its shape — and
   collapses when the gateway says nothing. */
.mf-oc-pay-note:empty { display: none; }
.mf-oc-pay-note { margin-top: 14px; font-size: 13.5px; color: var(--c-text-2); line-height: 1.6; }
.mf-oc-pay-note > :last-child { margin-bottom: 0; }

/* Order updates on the View Order screen — the notes a shop has sent the
   customer. A plain list, because each note is a short paragraph and a card
   per note would drown three sentences in chrome. */
.mf-order-notes { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 14px; }
.mf-order-notes > li { padding-left: 14px; border-left: 2px solid var(--c-border); }
.mf-order-notes > li > div { font-size: 14px; color: var(--c-text-2); line-height: 1.6; margin-top: 3px; }
.mf-order-notes > li > div > :last-child { margin-bottom: 0; }

/* Add to cart on a wishlist card. Sits at the foot of the card body, pushed
   down so cards of different heights keep their buttons on one line. */
/* Raised above the card's stretched title link (.p-link::after, z-index 1), as the
   badges and the heart are. Under it, a click on Add to cart opened the listing. */
.mf-card-cart { margin-top: 12px; position: relative; z-index: 2; }
.mf-card-cart .button,
.mf-card-cart .add_to_cart_button { width: 100%; }

/* WooCommerce marks a button mid-request and then done. Both states need to
   read as the same control rather than shifting the card. */
.mf-card-cart .add_to_cart_button.loading { opacity: .7; pointer-events: none; }
.mf-card-cart .added_to_cart {
  display: block;
  margin-top: 8px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--c-blue);
  text-align: center;
}

/* The confirmation strip and the note run the full measure, so they need the
   same rhythm as the cards above them. */
.oc-note, .oc-trust { margin-top: 16px; }

/* Save for later, in the cart.
 *
 * The design system fills a saved heart through `.fav` and `.fav-btn`; this
 * button is a `.btn.btn-quiet`, so neither rule reached it and the outline
 * heart looked identical whether the item was saved or not — the only feedback
 * was a toast that then disappeared.
 *
 * `aria-pressed` is already correct on the server and `main.js` keeps it in
 * step, so the state is there to style; it just had nothing styling it. */
.cart-save svg { transition: fill var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }

.cart-save[aria-pressed="true"] { color: var(--c-blue); }
.cart-save[aria-pressed="true"] svg { fill: currentColor; }

/* The store's own wrapper. It sits inside page.php's `.shell`, so it needs the
   vertical rhythm and nothing horizontal — the measure is already set. */
.mf-store { min-width: 0; }

/* The copy button's label. Hidden on a narrow screen, where the icon alone is
   unambiguous next to an order number and the row has no width to spare. */
.oc-copy-text { display: none; }

@media (min-width: 480px) {
  .oc-copy-text { display: inline; }
}

/* ── The seller's subscriptions, in My Account ──────────────────────────────
   Real CSS, not Tailwind utilities: `sm:grid-cols-2` and the arbitrary values
   this layout wants are not in the compiled sheet, and a class that is not
   there fails silently as a single stacked column. */
/* grid-template-columns is required here, not optional: a bare "display: grid"
   with no explicit columns gives its single implicit column an "auto" sizing
   function, which grows to fit the widest child (the payment table, 560px
   min-width) instead of the container width. minmax(0, 1fr) is the same fix
   .mf-subs__grid already uses below, applied to the outer wrapper too - without
   it the whole section, and everything after it in normal flow, was forced
   wide enough to scroll the entire page sideways on a phone. */
.mf-subs { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; margin-bottom: 24px; }

.mf-subs__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
}

@media (min-width: 640px) {
  .mf-subs__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1100px) {
  .mf-subs__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.mf-subs__card { display: flex; flex-direction: column; gap: 10px; }

.mf-subs__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.mf-subs__cat { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; margin: 0; }

.mf-subs__meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 16px;
  margin: 4px 0 0;
}

.mf-subs__meta > div { min-width: 0; }
.mf-subs__meta dt { font-size: 12px; color: var(--c-muted); margin: 0 0 2px; }
.mf-subs__meta dd { font-size: 14px; font-weight: 600; margin: 0; }

.mf-subs__pending { margin: 0; }

.mf-subs__list { margin: 8px 0 12px; padding-left: 18px; }
.mf-subs__list li { margin-bottom: 4px; }

.mf-subs__chips { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 12px 0; padding: 0; }

.mf-subs__form { display: grid; gap: 14px; margin-top: 14px; justify-items: start; }

.mf-subs__checks {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}

@media (min-width: 560px) {
  .mf-subs__checks { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.mf-subs__check { display: flex; align-items: center; gap: 8px; font-size: 14px; }

/* A checkbox the seller cannot tick because the plan is full still has to look
   unavailable rather than merely do nothing when clicked. */
.mf-subs__check input:disabled + span { opacity: 0.5; }

.mf-subs__promo,
.mf-subs__excess { border-color: var(--c-warn); }

/* The Premium panel carries more inside it than a subscription card does, so it
   gets its own rhythm rather than inheriting the card's tighter one. */
.mf-subs__premium { display: grid; gap: 6px; }

/* ── Premium's advanced analytics ───────────────────────────────────────────
   Real CSS rather than utilities: the bar chart needs its own flex column
   behaviour and `lg:grid-cols-3` is not in the compiled Tailwind sheet, so a
   utility class here would fail silently as one stacked column. */
.mf-adv { display: grid; gap: 20px; margin-top: 28px; }

.mf-adv__block { display: grid; gap: 10px; }

.mf-adv__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
}

@media (min-width: 720px) {
  .mf-adv__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1100px) {
  .mf-adv__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.mf-adv__figure { font-size: 30px; font-weight: 800; letter-spacing: -0.02em; margin: 6px 0 2px; }

.mf-adv__list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }

.mf-adv__list li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 14px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--c-line);
}

.mf-adv__list li:last-child { border-bottom: 0; padding-bottom: 0; }

.mf-adv__note { margin-top: 12px; }

/* The trend. One bar per month, height scaled against the tallest. */
.mf-adv__bars {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 160px;
}

.mf-adv__bar {
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  gap: 6px;
}

.mf-adv__bar-fill {
  width: 100%;
  background: var(--c-primary);
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  min-height: 2px;
}

.mf-adv__bar-label { font-size: 11px; color: var(--c-muted); white-space: nowrap; }

.mf-adv__advice { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 14px; }

.mf-adv__advice li { display: grid; gap: 4px; }

.mf-adv__why { font-size: 13px; color: var(--c-muted); }

/* ── The team screen ────────────────────────────────────────────────────────
 *
 * A list rather than a table, because the row has four parts of very different
 * widths — a person, their role, their state and two forms — and a table makes
 * the narrow ones wide. At phone width the parts stack and the controls go full
 * width, which is the only layout where a role select and two buttons are still
 * usable with a thumb.
 *
 * Real CSS rather than utility classes: the responsive variants used here are
 * not in the compiled Tailwind sheet, and a class that is not in the sheet is a
 * class that silently does nothing.
 */

.mf-team-list { display: grid; }

.mf-team-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 14px clamp(16px, 2vw, 22px);
  border-top: 1px solid var(--c-border-soft);
}

.mf-team-row:first-child { border-top: 0; }

.mf-team-who { display: grid; gap: 2px; min-width: 0; flex: 1 1 220px; }

.mf-team-who strong {
  font-weight: 600;
  font-size: 14.5px;
  overflow-wrap: anywhere;
}

.mf-team-tags { display: flex; flex-wrap: wrap; gap: 6px; flex: none; }

.mf-team-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.mf-team-actions form { display: flex; align-items: center; gap: 8px; margin: 0; }

.mf-team-role .select { height: 36px; padding: 0 30px 0 11px; font-size: 13.5px; }

@media (max-width: 640px) {
  .mf-team-actions { margin-left: 0; width: 100%; }
  .mf-team-actions form { width: 100%; }
  .mf-team-role .select { flex: 1 1 auto; min-width: 0; }
  .mf-team-actions .btn { flex: 1 1 auto; }
}

/* ── Elementor widgets ──────────────────────────────────────────────────────
 *
 * The CVList widgets reuse the design system wherever the design system
 * already has the piece — `.card`, `.btn`, `.chip`, `.sec-head`, `.badge`, the
 * listing card, the plan card. What is below is only the arrangement each
 * widget needs on top of those, which is why it is short.
 *
 * Written as real CSS against the existing tokens and the existing two
 * breakpoints (640px and 1024px). No new scale, no `!important`, and nothing
 * that Elementor generates inline — a page composed of these widgets carries
 * the same stylesheet as a page the theme rendered, so the two cannot drift.
 */

.mf-el-empty {
  border: 1px dashed var(--c-border);
  border-radius: var(--r-md);
  padding: 22px;
  text-align: center;
  color: var(--c-muted);
  font-size: 13.5px;
}

/* Hero */

.mf-el-hero { display: grid; gap: 22px; align-items: center; }

.mf-el-hero.is-centred { justify-items: center; text-align: center; }

.mf-el-hero__body { min-width: 0; }

.mf-el-hero__eyebrow {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--c-blue);
  margin: 0 0 8px;
}

.mf-el-hero__title {
  font-size: clamp(1.7rem, 3.4vw, 2.6rem);
  line-height: 1.15;
  font-weight: 700;
  margin: 0;
}

.mf-el-hero__text {
  margin: 12px 0 0;
  color: var(--c-text-2);
  font-size: 15.5px;
  max-width: 56ch;
}

.mf-el-hero.is-centred .mf-el-hero__text { margin-inline: auto; }

.mf-el-hero__search { margin-top: 20px; max-width: 640px; }

.mf-el-hero.is-centred .mf-el-hero__search { margin-inline: auto; }

.mf-el-hero__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }

.mf-el-hero.is-centred .mf-el-hero__actions { justify-content: center; }

.mf-el-hero__media img { width: 100%; height: auto; border-radius: var(--r-lg); display: block; }

@media (min-width: 1024px) {
  .mf-el-hero.has-media { grid-template-columns: 1.05fr .95fr; gap: 40px; }
  .mf-el-hero.has-media.is-centred { grid-template-columns: 1fr; }
}

/* Categories */

.mf-el-cats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 640px) {
  .mf-el-cats[data-columns="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .mf-el-cats[data-columns="4"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .mf-el-cats[data-columns="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.mf-el-cat { display: flex; min-width: 0; }

.mf-el-cat__link {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  height: 100%;
  padding: 14px;
  background: #fff;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}

.mf-el-cat__link:hover { border-color: var(--c-blue); box-shadow: var(--sh-card); }

.mf-el-cat__link:focus-visible { outline: 2px solid var(--c-blue); outline-offset: 2px; }

.mf-el-cat__art {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  background: var(--c-blue-soft);
  color: var(--c-blue);
  overflow: hidden;
}

.mf-el-cat__art img { width: 100%; height: 100%; -o-object-fit: cover; object-fit: cover; }

.mf-el-cat__name { font-weight: 600; font-size: 14.5px; }

.mf-el-cat__count { font-size: 12.5px; color: var(--c-muted); }

/* Popular searches */

.mf-el-searches { min-width: 0; }

.mf-el-searches__label { font-size: 12.5px; color: var(--c-muted); margin: 0 0 8px; }

.mf-el-searches__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Listings */

.mf-el-listings {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 640px) { .mf-el-listings { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

@media (min-width: 1024px) { .mf-el-listings { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.mf-el-listings.is-list { grid-template-columns: 1fr; }

/* Plans */

.mf-el-plans .mf-plans-note { margin-top: 14px; }

/* Call to action */

.mf-el-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: clamp(20px, 3vw, 34px);
  border-radius: var(--r-lg);
  border: 1px solid var(--c-border);
  background: #fff;
}

.mf-el-cta.is-soft { background: var(--c-blue-soft); border-color: #BFDBFE; }

.mf-el-cta.is-strong { background: #1F2937; border-color: #1F2937; color: #fff; }

.mf-el-cta.is-strong .mf-el-cta__text { color: #D1D5DB; }

.mf-el-cta__body { flex: 1 1 320px; min-width: 0; }

.mf-el-cta__title { margin: 0; font-size: clamp(1.2rem, 2vw, 1.6rem); line-height: 1.25; font-weight: 700; }

.mf-el-cta__text { margin: 8px 0 0; font-size: 14.5px; color: var(--c-text-2); max-width: 60ch; }

.mf-el-cta__actions { display: flex; flex-wrap: wrap; gap: 10px; }

/* FAQ */

.mf-el-faq { display: grid; gap: 10px; }

.mf-el-faq__item {
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: #fff;
  padding: 0 16px;
}

.mf-el-faq__q {
  cursor: pointer;
  padding: 14px 0;
  font-weight: 600;
  font-size: 14.5px;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.mf-el-faq__q::-webkit-details-marker { display: none; }

.mf-el-faq__q::after {
  content: '+';
  font-weight: 400;
  font-size: 20px;
  line-height: 1;
  color: var(--c-muted);
  flex: none;
}

.mf-el-faq__item[open] .mf-el-faq__q::after { content: '\2212'; }

.mf-el-faq__q:focus-visible { outline: 2px solid var(--c-blue); outline-offset: 2px; border-radius: var(--r-sm); }

.mf-el-faq__a { padding: 0 0 14px; color: var(--c-text-2); font-size: 14.5px; }

.mf-el-faq__a p { margin: 0 0 10px; }

.mf-el-faq__a p:last-child { margin-bottom: 0; }

/* Contact */

.mf-el-contact { display: grid; gap: 20px; }

@media (min-width: 1024px) {
  .mf-el-contact.has-details { grid-template-columns: 1.15fr .85fr; gap: 28px; align-items: start; }
}

.mf-el-contact__form,
.mf-el-contact__details { min-width: 0; }

/* ── Elementor pages inside the CVList shell ────────────────────────────────
 *
 * Elementor's default kit caps a container at 1140px. The theme's shell is
 * 1320px, so an Elementor-composed page sat visibly narrower than every page
 * beside it — About and Help against Marketplace, Contact and Seller Plans on
 * the same screen. Handing Elementor the theme's own token rather than editing
 * the kit means the two cannot drift again, and a kit reset does not undo it.
 *
 * The containers already sit inside `.shell`, which owns the gutter, so the
 * inner cap only needs to stop fighting the outer one.
 */

.elementor .e-con,
.elementor .e-con-inner {
  --container-max-width: var(--shell);
}

/*
 * Section rhythm.
 *
 * Elementor spaces its own containers, but the gap between one CVList section
 * and the next is a design-system decision rather than a per-page one — the
 * theme's own screens run `.sec-head` blocks at a consistent distance, and an
 * Elementor page that used whatever an editor last dragged would read as a
 * different site. Applied to the top-level containers only, so an editor
 * nesting containers for a two-column row is not also given section spacing.
 */

.elementor .e-con.e-parent + .e-con.e-parent { margin-top: clamp(28px, 4vw, 48px); }

/*
 * A hero is the first thing under the header and carries its own weight, so it
 * gets the room the theme gives a page opening rather than a section gap.
 */

.elementor .e-con.e-parent:first-child .mf-el-hero { padding-block: clamp(8px, 2vw, 22px) 0; }

/* -------------------------------------------------------------------------
   Boost and Feature at the seller's listings (inc/marketflow/promotions.php)
   ------------------------------------------------------------------------- */

/* The controls: buy buttons, or a live promotion's status in their place. */
.mf-promote { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; }
.mf-promote__btn { gap: 6px; }
.mf-promote__btn svg { flex: none; }
.mf-promote__status { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-width: 0; }
.mf-promote__status .t-meta { font-size: 12.5px; }

/* In the My Listings table: under the row's own actions, aligned with them. */
.mf-promote--row { justify-content: flex-end; margin-top: 8px; }

/* On the stacked (mobile) table every cell is a flex row, which would squeeze
   the controls in beside the listing actions. Give them a line of their own. */
@media (max-width: 900px) {
  .table.stack tbody td:has(> .mf-promote--row) { flex-wrap: wrap; }
  .mf-promote--row { flex-basis: 100%; justify-content: flex-start; margin-top: 4px; }
}

/* Under a listing card. Raised above the card's stretched title link, like
   .mf-card-cart, or a click on Boost would open the listing instead. */
.mf-promote--card { margin-top: 12px; position: relative; z-index: 2; }
.mf-promote--card .mf-promote__btn { flex: 1 1 0; min-width: 0; padding-inline: 8px; }
.mf-promote--card .mf-promote__status { flex-basis: 100%; }

.mf-promote--bar { margin-top: 12px; }

/* "Promote this listing" on the edit screen. */
.mf-promote-panel {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 12px 20px; margin-bottom: 18px;
}
.mf-promote-panel > div { flex: 1 1 260px; }
.mf-promote-panel .mf-promote--bar { margin-top: 0; }

/* The prompt after publishing. */
.mf-promote-prompt {
  display: flex; gap: 14px; align-items: flex-start; margin-bottom: 18px;
  border-color: #FDE68A; background: linear-gradient(0deg, #fff, var(--c-yellow-soft));
}
.mf-promote-prompt__icon {
  flex: none; display: grid; place-items: center; width: 40px; height: 40px;
  border-radius: 11px; background: var(--c-yellow-soft); color: var(--c-yellow-deep);
}
.mf-promote-prompt__body { flex: 1; min-width: 0; }
.mf-promote-prompt__prices { margin: 10px 0 0; padding: 0; list-style: none; display: grid; gap: 4px; }
.mf-promote-prompt__prices li { display: flex; flex-wrap: wrap; gap: 2px 8px; font-size: 13.5px; }
@media (max-width: 480px) {
  .mf-promote-prompt__icon { display: none; }
}

/* The purchase dialog: a form wrapping the modal's head, body and foot, so it
   has to pass on the flex column the modal gives them or the body stops
   scrolling on a short screen. */
.mf-promote-form { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.mf-promote-form__listing { margin-top: 2px; overflow-wrap: anywhere; }
.mf-promote-options { border: 0; margin: 0; padding: 0; display: grid; gap: 8px; min-width: 0; }
.mf-promote-option {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; cursor: pointer;
  border: 1px solid var(--c-border); border-radius: var(--r-md); background: #fff;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.mf-promote-option:hover { border-color: var(--c-blue); }
.mf-promote-option:has(input:checked) { border-color: var(--c-blue); background: var(--c-blue-soft); }
.mf-promote-option input { flex: none; margin: 0; accent-color: var(--c-blue); width: 18px; height: 18px; }
.mf-promote-option__text { flex: 1; min-width: 0; display: grid; }
.mf-promote-option__type { font-size: 12px; color: var(--c-muted); }
.mf-promote-option__len { font-weight: 600; }
.mf-promote-option__price { flex: none; font-weight: 700; white-space: nowrap; }

/* -------------------------------------------------------------------------
   GRID BLOWOUT SAFETY NET
   Tailwind's bare `.grid` utility only sets `display: grid` - it never sets
   `grid-template-columns`, because the theme uses it as a plain single-column
   stacking wrapper in most places and adds `sm:grid-cols-N` / `xl:grid-cols-N`
   only where a real multi-column layout is wanted above some breakpoint (see
   the dashboard's own comment on comma-bearing arbitrary values like
   `grid-cols-[1fr_360px]` never compiling: plain `grid-cols-N` plus `min-w-0`
   is the pattern used instead).

   A grid with no declared columns gets ONE implicit column whose sizing
   function is `auto`. On a grid container with a definite width that is
   normally harmless, but `auto` still lets the track grow to the width of its
   widest child's intrinsic content - a wide table, an unbroken row of figures
   - rather than clipping to the container, and nothing then constrains it back
   down. On My Account this took the Payment history table's 560px minimum and
   stretched the whole Subscriptions section, and the page around it, to match:
   the entire page scrolled sideways on a phone instead of just that one table.

   `minmax(0, 1fr)` is the fix already used throughout this file for exactly
   this (`.mf-subs__grid`, `.grid-products`, `.p-detail-grid`): a floor of 0
   lets the track shrink to the container regardless of content, and 1fr fills
   the available width when there is only one column.

   Safe to declare unconditionally: this stylesheet (`marketflow-design`) is
   enqueued as its own <link>, before `marketflow-utilities` (tailwind.css) -
   see inc/setup/assets.php - and at equal specificity the later stylesheet
   wins. A real `grid-cols-N` / `sm:grid-cols-N` utility, generated into
   tailwind.css, therefore still overrides this default above its breakpoint
   exactly as designed; this rule only ever takes effect where no such utility
   is present or active. */
.grid { grid-template-columns: minmax(0, 1fr); }

