/* AJAW Trade — authoritative mobile layer.

   style.css carries six separate @media(max-width:700px) blocks that were added
   over time and now contradict each other; the browse tabs alone were styled in
   three places. Rather than add a seventh patch, this file is linked LAST and
   owns the mobile layout for the areas below. Selectors here deliberately match
   or exceed the specificity of the rules they replace.

   Brand tokens come from :root in style.css. Touch targets are >=44px. */

@media (max-width: 700px) {

/* ---------- browse tabs: AI Mode / Products / Manufacturers / By country ----
   reference-style marketplace picker: four grouped tiles in a 2x2 grid, each with
   an icon and a 16px label. The active marketplace fills with the brand
   gradient. Earlier 6-column spans and underline bars are gone - each tab is a
   tap-anything card with a >=48px target. */
.search-hero .search-tabs,
.browse-strip .search-tabs,
.search-tabs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  width: 100%;
  min-width: 0;
  margin: 0 0 16px;
  padding: 0;
  overflow: visible;
  justify-content: stretch;
}
.search-hero .search-tabs > a,
.browse-strip .search-tabs > a,
.search-tabs > a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 0;
  min-height: 50px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--canvas);
  font-family: var(--body);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: var(--ink);
  text-align: center;
  white-space: nowrap;
  text-decoration: none;
}
.search-hero .search-tabs > a > span,
.browse-strip .search-tabs > a > span,
.search-tabs > a > span { white-space: nowrap; }
/* The old rule drew the active state as a wide underline bar, which no longer
   makes sense once each tab is its own card. */
.search-hero .search-tabs > a::after,
.browse-strip .search-tabs > a::after,
.search-tabs > a::after { display: none; }

.search-hero .search-tabs > a.active,
.browse-strip .search-tabs > a.active,
.search-tabs > a.active {
  border-color: transparent;
  background: var(--ajaw-brand-gradient);
  color: #fff;
  box-shadow: 0 3px 9px #251f9535;
}
.search-hero .search-tabs > a .icon,
.browse-strip .search-tabs > a .icon,
.search-tabs > a .icon { width: 17px; height: 17px; flex-shrink: 0; }
.search-hero .search-tabs > a.active .icon,
.browse-strip .search-tabs > a.active .icon,
.search-tabs > a.active .icon { stroke: #fff; color: #fff; }

/* ---------- search box ----------------------------------------------------
   The submit button used to wrap onto the tool row and collide with "Ask AI".
   Input and button share one grid row; the tools sit on their own line. */
.search-box { padding: 10px; border-radius: 14px; }
.search-box .search-input {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
}
.search-box .search-input > .icon { display: none; }
.search-box .search-input input {
  min-width: 0;
  font-size: 15px;         /* >=16px avoids iOS zoom-on-focus; 15 is the */
  padding: 12px 4px;       /* largest that still fits the placeholder */
  line-height: 1.4;
}
/* On desktop the submit button floats bottom-right over the box. At phone
   width that drops it straight on top of the "Ask AI" tool row, so it has to
   rejoin the normal flow and become a real grid cell. */
.search-box:not(.compact) .search-input > .btn,
.search-box .search-input .btn {
  position: static;
  inset: auto;
  min-width: 0;
  min-height: 44px;
  padding: 10px 16px;
  font-size: 13px;
  gap: 6px;
  white-space: nowrap;
}
.search-box .search-input .btn > .icon { width: 16px; height: 16px; }

/* Image Search · Search with File · Ask AI.
   A horizontal scroller kept clipping the first label, so at phone width the
   three tools become an even 3-column grid that always fits. The separator
   spans are dropped - the columns already separate them. */
/* style.css reserves `padding-right:100px` here to clear the floating desktop
   submit button. That button is inline on mobile, so the reservation only
   squeezed the tool row down to 219px of the 319 available. */
.search-box:not(.compact) .search-bottom,
.search-box .search-bottom {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding-right: 0;
  padding-left: 0;
  padding: 10px 0 0;
  margin-top: 2px;
  border-top: 1px solid var(--line);
  overflow: visible;
}
.search-box .search-bottom > span { display: none; }
.search-box .search-modes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: center;
  gap: 4px;
  width: 100%;
  min-width: 0;
  margin: 0;
}
.search-box .search-modes .mode-split { display: none; }
/* style.css's mobile block sets these to 8-10px via `.search-bottom a` and
   `.search-bottom button`; this selector is deeper so the readable size wins. */
.search-box .search-bottom .search-modes > button,
.search-box .search-bottom .search-modes > a,
.search-box .search-modes > button,
.search-box .search-modes > a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  min-width: 0;
  min-height: 40px;
  padding: 6px 2px;
  font-size: 11.5px;
  font-weight: 550;
  letter-spacing: -.01em;
  line-height: 1.2;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.search-box .search-modes .icon { width: 14px; height: 14px; flex-shrink: 0; }

/* ---------- welcome strip -------------------------------------------------- */
.welcome-strip-inner {
  display: block;
  padding-top: 14px;
  padding-bottom: 14px;
}
.welcome-strip-hi { font-size: 15px; margin: 0 0 10px; }
.welcome-strip-links {
  display: flex;
  flex-wrap: nowrap;          /* promos.css wraps these; a scroller reads better */
  gap: 8px;
  width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.welcome-strip-links::-webkit-scrollbar { display: none; }
.welcome-strip-links > a {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 10px 14px;
  font-size: 13px;
  white-space: nowrap;
}

/* ---------- any chip / facet row must scroll, never overflow the page ------
   .capability-chips and the Deep Search facet rows were pushing content past
   the right edge, clipping the last chip mid-word. */
.capability-chips,
.deep-panel .facet-row,
.deep-facets > div,
.manufacturer-facts,
.order-progress {
  display: flex;
  flex-wrap: nowrap;
  gap: 8px;
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.capability-chips::-webkit-scrollbar,
.deep-panel .facet-row::-webkit-scrollbar,
.deep-facets > div::-webkit-scrollbar,
.manufacturer-facts::-webkit-scrollbar,
.order-progress::-webkit-scrollbar { display: none; }
.capability-chips > *,
.deep-panel .facet-row > *,
.deep-facets > div > * { flex: 0 0 auto; }

/* ---------- product thumbnails: price chip must sit on the image ----------
   The chip was positioned with a fixed `top`, so it drifted off the picture as
   soon as the image height changed with the viewport. Anchor it to the bottom. */
.mini-products > a { position: relative; display: block; }
.mini-products > a > span {
  position: absolute;
  top: auto;
  bottom: 10px;
  left: 10px;
  right: auto;
  font-size: 11px;
}
.mini-products img { width: 100%; height: 150px; object-fit: cover; }

/* ---------- country flag rail --------------------------------------------
   regions.css bleeds this rail past the wrap with `margin:0 -20px`. At 375px
   that makes the document 383px wide and the whole page scrolls sideways.
   The rail keeps its own horizontal scroll; it just stops widening the page. */
.region-flags {
  margin-left: 0;
  margin-right: 0;
  padding-left: 2px;
  padding-right: 2px;
  max-width: 100%;
}

/* ---------- tap targets ---------------------------------------------------
   Facet chips, sort links and card actions were rendering 20-28px tall, which
   is below the 44px guidance and genuinely hard to hit on a phone. */
/* `.results-layout a` matched EVERY link in the results — including
   `.product-title`, whose `-webkit-line-clamp` only works on `display:
   -webkit-box`. Forcing inline-flex silently killed the clamp and the titles
   rendered as overlapping two-column text. The chips and sort links that
   actually needed the height are named instead of blanket-selecting `a`. */
.results-layout .chip,
.results-layout .facet a,
.results-layout .sort a,
.deep-panel a,
.filters a,
.results-toolbar a,
.trending > a,
.capability-chips > * {
  min-height: 36px;
  display: inline-flex;
  align-items: center;
}
/* Belt and braces: whatever else tries, a clamped title stays a box. */
#app .product-title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.product-card .compare-small,
.product-card .save-btn { min-height: 36px; }

/* ---------- global guards -------------------------------------------------
   Nothing may force the page wider than the screen. Wide-by-nature content
   (tables, the compare grid) gets its own scroller instead. */
img, video, svg:not(.icon) { max-width: 100%; }
.table-wrap, .specification, .compare-table-wrap { overflow-x: auto; max-width: 100%; }

}

/* Tablet: two tabs per row already reads well, so only the orphan row needs
   correcting between 700px and 900px. */
@media (min-width: 701px) and (max-width: 900px) {
  .search-tabs { gap: 18px; }
  .search-tabs > a { font-size: 17px; white-space: nowrap; }
}

/* ---------------------------------------------------------------------------
   Product page on a phone.
   Two defects: the fixed "Chat for pricing" bar sat on top of the last 62px of
   the page with nothing reserving that space, and the gallery thumbnails were
   display:none - so three of the four product photos simply did not exist on
   mobile. the reference marketplace puts them in a scrolling strip under the main image.
   --------------------------------------------------------------------------- */
@media (max-width: 700px) {
  main.pdp { padding-bottom: 86px; }          /* clears the 62px fixed bar */

  .pdp-layout.retail-layout .gallery { display: flex; flex-direction: column; gap: 10px; }
  .pdp-layout.retail-layout .gallery-main { order: 1; }
  .pdp-layout.retail-layout .thumbs {
    order: 2;
    display: flex;
    flex-direction: row;      /* the base rule stacks them in a column */
    gap: 8px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .pdp-layout.retail-layout .thumbs::-webkit-scrollbar { display: none; }
  .pdp-layout.retail-layout .thumbs > button {
    flex: 0 0 64px;
    width: 64px;
    height: 78px;
    padding: 0;
    border-radius: 8px;
    overflow: hidden;
  }
  .pdp-layout.retail-layout .thumbs > button img { width: 100%; height: 100%; object-fit: cover; }
  .pdp-layout.retail-layout .thumbs > button.selected { outline: 2px solid var(--violet); outline-offset: -2px; }
}

/* ---------------------------------------------------------------------------
   Header height on a phone.
   style.css line 16 sets `.main-nav{overflow:visible;height:auto}`, which lets
   the secondary nav wrap onto a third row and costs ~55px of every fold. One
   scrolling row is what the reference marketplace does and what the row was designed for.
   --------------------------------------------------------------------------- */
@media (max-width: 700px) {
  .main-nav {
    height: 44px;
    min-height: 44px;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
  }
  .main-nav::-webkit-scrollbar { display: none; }
  .main-nav > div { flex-wrap: nowrap; flex-shrink: 0; }
  .main-nav a, .main-nav button { white-space: nowrap; }
}

/* ---------------------------------------------------------------------------
   Currency badge on a phone.
   .locale-short used to drop the currency entirely below 980px (language only,
   e.g. "EN"), so a visitor could not see COP/USD anywhere without scrolling the
   secondary nav row sideways to find .locale-mob. It now always shows the
   currency (app.js). At <=390px width the five icons plus that badge are tight
   enough to touch the edge, so the gap between them tightens here to keep the
   account icon fully on screen instead of flush against it.
   --------------------------------------------------------------------------- */
@media (max-width: 390px) {
  .utilities { gap: 10px; }
}

/* ---- Mobile hero: reverted to white/plain on every page (Giuliano 2026-09-17) ----
   The vibrant purple band (2026-09-16) was tried on the home and manufacturers-
   directory heroes only; Giuliano called it "really ugly" the next day and asked
   for Productos and Fabricantes to match the plain white treatment that the
   By-country and AI Mode pages already used (neither of those two ever had this
   override). Removing the whole block lets every hero fall back to the base
   light lavender-white gradient in style.css, and every tab pill fall back to
   the generic rule above (light gray inactive, brand-gradient fill only on the
   active tab) — i.e. all four tabs now behave exactly like "Por país" already did. */

/* ---- Mobile: no purple wash behind the hero (Giuliano 2026-09-17, 3rd report) ----
   Removing the hero's own background above was not enough. style.css paints the
   "top glow" on the whole #app — four stacked radial gradients under
   `#app:has(>.search-hero:not(.country-search-hero))` — and the mobile layer of it
   drops a 520x300 rgba(120,113,251,.40) blob at 50%/470px, which on a 375px screen
   lands directly behind the tab pills and reads as a solid purple band. That
   `:not(.country-search-hero)` is also exactly why By-country looked white while
   Productos and Fabricantes did not.

   The glow is deliberate on desktop (it is the reference-parity hero treatment), so
   this kills it on phones only. Every hero variant is listed so no page keeps a
   wash: home/products, the manufacturers directory, AI Mode, By country and /sell. */
@media (max-width: 760px) {
  #app:has(> .search-hero),
  #app:has(> .search-hero:not(.country-search-hero)),
  #app:has(> .sell-page) {
    background: #fff;
  }
  #app:has(> .search-hero) .search-hero,
  #app:has(> .search-hero:not(.country-search-hero)) .search-hero,
  .search-hero,
  .search-hero.factory-hero,
  .search-hero.country-search-hero {
    background: #fff;
  }
  #app:has(> .search-hero) header,
  #app:has(> .sell-page) header {
    background: #fff;
  }
}

/* ===========================================================================
   PHONE LAYOUT PASS — Giuliano, 2026-09-17
   "the responsive can be a lot better ... when I zoom out of the mobile it
    breaks ... you're trying to put four widgets but in mobile it shouldn't
    look like that"

   Measured with scripts/mobile_audit.py at 320/390/768px rather than guessed.
   Four defects, in the order they cause damage:

   1. THE PAGE WAS WIDER THAN THE PHONE. `.wrap` in style.css is
      `width: calc(100% - 80px)` with no mobile override anywhere, so a 320px
      screen got 40px gutters and only 240px of usable width. `.head-main` then
      could not fit the brand plus six utility items in 240px, overflowed to
      392px, and took the whole document with it. That sideways scroll is why
      zooming out "breaks" — the browser is showing a 392px document in a 320px
      window and everything left of the fold is cut off.
   2. EVERY GRID INHERITED THAT. Four-column panels collapsed only as far as two
      columns, so on his screenshot `.factory-tile-pair` columns were 55px wide
      and "Request for Quotation" was 117px of text in a 95px box.
   3. HOVER PANELS WERE LAID OUT ON TOUCH. `.hover-widget` popovers cannot be
      hovered on a phone, but they were still painted, off the right edge.
   4. TAP TARGETS. Header controls were 20-23px tall against a 44px minimum.

   A 16px gutter is the standard phone margin (iOS HIG, Material, and what
   the reference marketplace’s own mobile web uses), and it hands every grid below 288px of usable
   width at 320 instead of 240 — a 20% gain before a single grid rule changes.
   =========================================================================== */

@media (max-width: 760px) {

  /* ---- 1. Gutter, and a hard stop on sideways scroll ---------------------- */
  .wrap { width: calc(100% - 32px); }

  /* A backstop, not the fix — the widths above are. `clip` rather than `hidden`
     on purpose: `overflow-x:hidden` turns the element into a scroll container
     and silently kills `position:sticky` for everything inside it, which is
     exactly what the PDP price rail relies on. `overflow-x:clip` trims the same
     pixels without creating that container, so the rail keeps sticking. */
  html, body { overflow-x: clip; max-width: 100%; }
  /* Deliberate horizontal strips (the category nav row, the chip rails) scroll
     inside their own `overflow-x:auto` box and are unaffected by this. */
  #app, header, footer, main, .announcement { max-width: 100%; }

  /* ---- 2. Header: one row that fits ------------------------------------- */
  /* The row has 288px to work with at 320px wide. It has to hold the wordmark
     and the utility icons without either one leaving the screen — clipping the
     overflow is not a fix, it just moves the account button somewhere a thumb
     cannot reach. The budget below is measured, not guessed:
        brand  72px logo + 6 gap + ~39 "Trade"      = 117px
        icons  4 x 36px + 3 x 2px gap               = 150px
        row gap                                        8px
                                                    = 275px  (of 288)
     The fifth icon (the delivery flag) comes back at 361px, where the row has
     343px and can afford it. */
  .head-main {
    height: 60px;
    gap: 8px;
    min-width: 0;
  }
  .brand { min-width: 0; gap: 6px; flex-shrink: 0; }
  .brand img { width: 72px; max-height: 28px; }
  .brand > span { font-size: 15px; padding-left: 7px; }

  .utilities {
    gap: 2px;
    min-width: 0;
    flex-shrink: 0;
  }
  /* "Deliver to / United States" is a two-line block that cost ~70px of a 288px
     row. It is a real control though (it sets the country that minimums, lead
     times and currency are quoted against), so it is reduced to its flag rather
     than dropped — tapping it still opens the location picker, which headPop()
     renders as a full modal below 760px. app.js wraps the label and the place
     name so this can be done without touching the desktop header. */
  .utilities .deliver { min-width: 36px; min-height: 44px; }
  .utilities .deliver .deliver-label,
  .utilities .deliver .deliver-place,
  .utilities .deliver br { display: none; }
  .utilities .deliver > b { font-size: 17px; line-height: 1; }

  /* The globe/currency button is a duplicate on a phone: app.js already renders
     `.locale-mob` in the secondary nav row, which is the one a thumb can reach. */
  .utilities > .head-widget > .locale { display: none; }

  /* 44px targets. Width is held to 36px so the four icons plus the wordmark fit
     a 288px row; 44px of height is the part a thumb actually needs. */
  .utilities > .hover-widget > a,
  .utilities > .hover-widget > button,
  .utilities > .msg-widget > a,
  .utilities > .head-widget > a,
  .utilities > .head-widget > button,
  .utilities > a,
  .utilities > button {
    min-height: 44px;
    min-width: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* The delivery flag is the fifth icon and the least-used of them. Below 361px
   there is no room for it without pushing the account button off the screen, so
   it appears only once the row can afford it. Delivery stays reachable either
   way from Account -> Addresses.

   Measured at 320px: wrap 288, brand 127.3, row gap 8 — which leaves 152.7 for
   the utilities. Four icons at 36 plus three 2px gaps is 150. Five is 192, and
   that is exactly the 39px that was pushing the account button off the screen.

   The selector has to reach (0,3,1) because the tap-target rule above sets
   `display:inline-flex` on `.utilities > .head-widget > button` — at (0,3,1) it
   beat a plain `.utilities .deliver` at (0,2,0) and put the button back. */
@media (max-width: 360px) {
  .utilities > .head-widget > .deliver,
  .utilities > .head-widget,
  .utilities .deliver { display: none; }
}

@media (max-width: 760px) {

  /* ---- 3. Hover popovers are desktop-only -------------------------------- */
  /* These open on :hover. A phone has no hover, so they were unreachable UI that
     still took part in layout and painted past the right edge. The icon that
     anchors each one stays; only the panel goes. */
  .hover-panel,
  .msg-panel { display: none !important; }

  /* ---- 4. Grids: nothing narrower than a readable card ------------------- */
  /* The rule of thumb below is one column under 380px of available width for
     anything that holds a sentence or a button, two columns for pure product
     tiles (which is what the reference marketplace’s own phone grid does). */

  /* The four discovery panels in his screenshot. Each is a heading + prose +
     buttons: at 139px they were unusable, stacked they read like app cards. */
  .factory-discovery { grid-template-columns: 1fr; gap: 12px; }
  .factory-discovery > article { padding: 16px; }
  .factory-tile-pair img { height: 150px; }
  .factory-product-previews { grid-template-columns: 1fr 1fr; gap: 12px; }
  .factory-product-previews img { height: 150px; }
  .factory-product-previews span,
  .factory-product-previews small { font-size: 11px; }

  /* Buttons inside those panels: full width, one line, real tap height. */
  .factory-buyer .btn,
  .factory-request .btn,
  .factory-discovery .btn {
    min-height: 44px;
    font-size: 14px;
    padding: 11px 14px;
    white-space: normal;
    line-height: 1.25;
  }

  .footer-grid { grid-template-columns: 1fr 1fr; gap: 22px 16px; }
  .sell-kpis { grid-template-columns: 1fr; }
  .sell-kpis > * + * { border-top: 1px solid var(--line); }
  .store-preview-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .form-grid { grid-template-columns: 1fr; }
  .benefit-strip { grid-template-columns: 1fr; gap: 14px; }
  .panel-duo { grid-template-columns: 1fr; }
  /* The results filter form put a country select and an Apply button side by
     side at 123px each; the select then showed three characters of a category
     name. */
  .results-layout form,
  .directory-filters { grid-template-columns: 1fr; }

  /* A product title is clamped to two lines but its box was still being laid out
     against the untruncated string, which pushed the card past the screen edge. */
  .product-title, .card-supplier, .product-card, .product-grid > * { min-width: 0; }
  .product-card { overflow: hidden; }

  /* ---- 7. Tap targets outside the header --------------------------------- */
  .main-nav > div > a,
  .main-nav > div > button,
  .main-nav .demo-link,
  .main-nav .locale-mob,
  .nav-widget > a { min-height: 44px; display: inline-flex; align-items: center; }
  .announcement { min-height: 40px; height: auto; padding: 6px 16px; }
  .announcement a { display: inline-flex; align-items: center; min-height: 32px; }

  /* ---- 5. Search box ----------------------------------------------------- */
  /* `.search-box .search-input` (line 82 of this file) is a two-column grid, so
     a bare `.search-input` rule loses the cascade to it. Same selector depth
     here on purpose. At 240px the query field was 96px wide - narrower than the
     word "Buscar" sitting next to it. Stacking the field over a full-width
     button is what every phone search does. */
  .search-box .search-input {
    display: grid;
    grid-template-columns: 1fr;
    gap: 8px;
    align-items: stretch;
  }
  .search-box .search-input input { min-height: 46px; width: 100%; min-width: 0; }
  .search-box .search-input .btn { min-height: 46px; width: 100%; justify-content: center; }
  .search-box .search-modes { flex-wrap: wrap; gap: 6px 10px; font-size: 12px; }
  .search-box .search-modes > a,
  .search-box .search-modes > button { min-height: 40px; }

  /* ---- 6. Long controls stop clipping ------------------------------------ */
  /* Spanish labels run 20-30% longer than the English they were laid out for
     ("Request for Quotation" -> "Solicitar cotizacion"), so any button sized to
     the English string clips. Let them wrap to two lines instead of overflowing. */
  .btn, .btn.full, .text-link {
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .btn.full { width: 100%; justify-content: center; }
}

/* ---------------------------------------------------------------------------
   AI Mode on a phone — "the chat ... looks so tight and kind of like ruins it"

   `.ai-console` already collapses to one column at 980px, so the rail was not
   the problem. What made it feel tight was everything else: 28px of side padding
   on a 320px screen, bubbles capped at 72% (207px) with 16px of their own
   padding left ~175px of actual text, and the history rail turning into a
   horizontal scroll strip that ate a chunk of the fold before the conversation
   even started.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .ai-console { min-height: calc(100dvh - 150px); }
  .ai-scroll { padding: 16px 12px; }
  .ai-dock { padding: 0 12px 10px; }

  /* A chat bubble on a phone is nearly full width in every messaging app there
     is; 72% is a desktop proportion. */
  .ai-bubble {
    max-width: 88%;
    font-size: 15px;
    line-height: 1.55;
    padding: 11px 14px;
  }
  .ai-thread { gap: 18px; }

  /* The composer is the one control that must never feel cramped. */
  .ai-composer { padding: 10px 12px 8px; border-radius: 16px; }
  .ai-composer textarea { font-size: 16px; line-height: 1.45; }  /* 16px stops iOS zooming the page on focus */
  .ai-send { width: 40px; height: 40px; }
  .ai-attach { width: 38px; height: 38px; }
  .ai-model { display: none; }               /* model name is not worth the row */

  .ai-welcome { margin-top: 3vh; }
  .ai-rail { padding: 8px 12px; gap: 8px; }
  .ai-new { min-height: 40px; white-space: nowrap; }
  .ai-topbar { padding: 10px 12px; font-size: 12px; }
}

/* ---------------------------------------------------------------------------
   iOS focus zoom. Safari zooms the whole page in when a focused field has text
   under 16px, and never zooms back out — this is the other half of "when I zoom
   out of the mobile it breaks". Every text entry on the site gets 16px.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  input[type="text"], input[type="search"], input[type="email"],
  input[type="tel"], input[type="number"], input[type="password"],
  input:not([type]), textarea, select {
    font-size: 16px;
  }
}

/* ---------------------------------------------------------------------------
   Very narrow phones (<=380px). Two columns of prose stop being two columns and
   start being two stacks of hyphens.
   --------------------------------------------------------------------------- */
@media (max-width: 380px) {
  .footer-grid { grid-template-columns: 1fr; gap: 18px; }
  .factory-product-previews { grid-template-columns: 1fr; }
  .factory-product-previews img { height: 200px; }
  .store-preview-grid { grid-template-columns: 1fr 1fr; }
  .search-tabs { gap: 6px; }
  .search-tabs > a { font-size: 14px; padding: 10px 8px; }
}

/* ---------------------------------------------------------------------------
   Tap targets, second pass — measured, not assumed.

   The first pass set 44px on the header. These are the controls that were still
   under the minimum when re-measured at 390px, with the class chain each one
   actually has (several were guessed wrong the first time: the announcement
   link is `.campaign-strip a`, not `.announcement a`).
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .campaign-strip a { display: inline-flex; align-items: center; min-height: 40px; }

  /* The wordmark link collapses to the height of its text when the logo image
     has not painted yet, which is also its tap height. */
  .brand { min-height: 44px; }

  /* Category rows, "All categories", the filter-panel tabs and the three
     buttons on a manufacturer card were 18-38px. */
  .factory-category { min-height: 44px; }
  .factory-discovery .text-link,
  .factory-discovery a.text-link { min-height: 44px; display: inline-flex; align-items: center; }
  .factory-filter-panel > nav a { min-height: 44px; display: inline-flex; align-items: center; }
  .factory-contact .btn.small { min-height: 44px; }
  .footer-grid a { display: inline-flex; align-items: center; min-height: 40px; }

  /* style.css uses `.search-box:not(.compact) .search-bottom .search-modes
     button` — (0,4,1), one class more specific than the rule above in this file,
     which is why Image Search stayed 30px tall. Matched here. */
  .search-box:not(.compact) .search-bottom .search-modes > button,
  .search-box:not(.compact) .search-bottom .search-modes > a { min-height: 44px; }
}

/* ---------------------------------------------------------------------------
   "Image Search · Search with File · Ask AI" — the row under the search box.

   Three labels in three 107px columns with `text-overflow:ellipsis`, which is
   why his screenshot reads "Sear  Search with |  Ask AI". Ellipsis on a control
   label is a last resort; the labels fit fine if the icon sits above the text
   instead of beside it, which is also how a phone app would draw three actions.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .search-box .search-modes > button,
  .search-box .search-modes > a,
  .search-box:not(.compact) .search-bottom .search-modes > button,
  .search-box:not(.compact) .search-bottom .search-modes > a {
    flex-direction: column;
    gap: 3px;
    padding: 6px 2px;
    font-size: 11px;
    line-height: 1.25;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    text-align: center;
    hyphens: none;
  }
  .search-box .search-modes .icon { width: 17px; height: 17px; }
}

/* ---------------------------------------------------------------------------
   Tap targets, general rule.

   Chasing these selector by selector was the wrong shape - there is always one
   more `.btn.small` somewhere. Every control gets the 44px minimum by default
   here, and the exceptions are listed rather than the inclusions.

   Exceptions, all deliberate:
   * links inside running prose - they are words in a sentence, and padding them
     to 44px would space the paragraph out;
   * anything inside a table row, where the row sets the rhythm;
   * the gallery thumbnails and colour swatches, whose size IS the information.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .btn,
  button.btn,
  a.btn,
  summary,
  select,
  input[type="text"], input[type="search"], input[type="email"],
  input[type="tel"], input[type="number"], input[type="password"],
  .search-tabs > a,
  .chip, .capability-chips > a,
  .help-tabs > button,
  .work-shortcuts > a {
    min-height: 44px;
  }
  .btn, button.btn, a.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  p a, li a, small a, .prose a,
  td .btn, th .btn, tr .btn,
  .thumbs button, .swatch, .variation-swatch,
  .gallery button {
    min-height: 0;
  }
  .thumbs button, .gallery button { display: block; }
}

/* ---------------------------------------------------------------------------
   The oversized country numeral on the home hero.

   `.country-art` is decoration: a 160px "CO" pinned at `right:-20px` so it bleeds
   off the panel edge on purpose. The panel clips it on desktop; on a phone the
   panel is narrower than the numeral, so it reached 408px on a 390px screen and
   was the last thing still widening the document. Clipping it at the panel keeps
   the effect and keeps it on the page.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .country-tile, .country-panel, .country-card { overflow: hidden; }
  .country-art { font-size: 96px; right: -8px; bottom: -28px; }
}

/* ---------------------------------------------------------------------------
   Tap targets, final pass — specificity.

   The rule above lost. style.css sizes buttons by context, and every one of
   those selectors (`.search-input .btn`, `.spotlight-copy .btn`,
   `.results-head .btn`, `.page-heading .btn`, `.button-row .btn` ...) is at
   least (0,2,0) against a bare `.btn` at (0,1,0), so they kept their 27-42px
   heights. Listing them all here would mean finding every one and then finding
   the next one somebody adds.

   `#app` is the SPA's single root element, so prefixing with it lifts these to
   (1,1,0) and they win against any class-based rule without !important — which
   would be unarguable by later authors. The exceptions carry the same prefix so
   they still override the rule they are an exception to.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  #app .btn,
  #app button.btn,
  #app a.btn,
  #app summary,
  #app .search-input .btn,
  #app .search-modes > a,
  #app .search-modes > button { min-height: 44px; }

  #app summary { display: list-item; align-items: initial; }

  /* Still the exceptions: prose links, table controls, thumbnails and swatches,
     and the genuinely compact header search inside the sticky bar. */
  #app p a, #app li a, #app small a,
  #app td .btn, #app th .btn, #app tr .btn,
  #app .thumbs button, #app .swatch, #app .variation-swatch,
  #app .gallery button,
  #app .qty-step,
  #app .compact .search-input .btn { min-height: 0; }
  #app .thumbs button, #app .gallery button { display: block; }
}

/* ---------------------------------------------------------------------------
   Campaign strip on a phone.

   The strip is `flex-wrap:wrap` with five children — badge, name, tagline,
   countdown, link. At 390px they wrap onto three rows and the bar takes ~190px
   of an ~850px fold, on every page, before any content. It is a promo, not the
   page.

   The badge, the name and the link are what the bar is for and they stay on one
   row. The tagline ("Volume deals across South American factories") is the copy
   a phone has no room for, and the countdown is repeated on the campaign page
   itself, so both drop below 760px. The link is right there if they want detail.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .campaign-strip {
    flex-wrap: nowrap;
    gap: 8px;
    padding: 7px 12px;
    font-size: 12px;
    min-height: 40px;
    justify-content: center;
  }
  .campaign-strip > span:not(.campaign-off):not(.campaign-left),
  .campaign-strip .campaign-left { display: none; }
  .campaign-strip .campaign-off { font-size: 11px; padding: 2px 7px; flex: none; }
  .campaign-strip b {
    font-size: 12px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .campaign-strip a { flex: none; font-size: 12px; white-space: nowrap; min-height: 32px; }
  .campaign-strip a .icon { width: 13px; height: 13px; }
}

/* ---------------------------------------------------------------------------
   AI Mode: drop the duplicate search furniture.

   /ai opens with the marketplace tab grid and the keyword search box stacked
   above the assistant's own composer — roughly 600px of a phone fold spent
   offering two other ways to search before the one the page is for. On desktop
   they sit beside each other and cost nothing; on a phone they push the chat
   below the fold, which is the "looks so tight" complaint from the other end.
   The tabs stay reachable from the nav row.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .ai-page > .search-hero .search-box,
  #app:has(> .ai-console) > .search-hero .search-box { display: none; }
  .ai-page > .search-hero, .ai-page .search-hero { padding-bottom: 6px; }
}

/* ===========================================================================
   PHONE HOME SCREEN — rebuilt against the the reference marketplace app, 2026-09-17
   Giuliano: "the the reference marketplace mobile homepage looks way cooler ... way more
   organized ... when I scroll down a little bit it hides the September thing
   on the top ... Buscar looks so tight, make it a little bit larger"

   The measurement that mattered, from scripts/mobile_audit.py at 390px:

       home page height          9,017px
       distance to first product 4,966px   <- 55% of the page is furniture

   the reference marketplace’s phone home reaches product cards in roughly the first 800px. That
   gap is the whole difference; no amount of restyling the panels fixes it,
   because the panels ARE the problem. Everything below follows from that.
   =========================================================================== */

@media (max-width: 760px) {

  /* ---- 1. Products first -------------------------------------------------
     Reordering rather than rewriting home(): the sections are already direct
     children of .home-main, so a flex column plus `order` moves the recommended
     grid above the four discovery panels without touching the markup, and
     desktop keeps its existing document order untouched. */
  .home-main {
    display: flex;
    flex-direction: column;
    gap: 0;
  }
  .home-main > *              { order: 5; }
  .home-main > .section-head  { order: 1; }
  .home-main > .product-grid  { order: 2; }
  .home-main > .home-panels   { order: 3; }

  /* The four discovery panels stack one per row and become scannable cards
     instead of a 2x2 of 139px columns. */
  .home-panels { grid-template-columns: 1fr; gap: 12px; }

  /* ---- 2. The campaign banner is the first fold, then it leaves ----------
     On the phone home the live campaign gets a real banner the way the reference marketplace’s
     does — badge, name, tagline, countdown, CTA — instead of the one-line strip
     every other page keeps. It is NOT sticky, so it scrolls away under the
     search: that is the "it hides the September thing" behaviour. */
  .campaign-strip.is-hero {
    display: grid;
    grid-template-columns: 1fr;
    justify-items: start;
    align-content: center;
    gap: 6px;
    min-height: 168px;
    padding: 20px 18px 24px;
    text-align: left;
    /* Brand purple. This is AJAW, not the reference marketplace — the layout is the reference,
       the colour is ours. */
    background:
      radial-gradient(120% 140% at 88% 12%, #8f88ff 0%, rgba(143,136,255,0) 58%),
      linear-gradient(118deg, var(--deep) 0%, var(--violet) 52%, var(--soft) 100%);
  }
  .campaign-strip.is-hero .campaign-off {
    order: 1;
    font-size: 13px;
    font-weight: 800;
    padding: 4px 11px;
    border-radius: 7px;
  }
  .campaign-strip.is-hero b {
    order: 2;
    font-size: 27px;
    line-height: 1.12;
    letter-spacing: -.03em;
    font-family: var(--display);
    white-space: normal;
    overflow: visible;
    max-width: 100%;
  }
  /* The tagline comes back on the hero — there is room for it here, unlike the
     one-line strip, where it is still hidden. */
  .campaign-strip.is-hero > span:not(.campaign-off):not(.campaign-left) {
    order: 3;
    display: block;
    font-size: 13px;
    opacity: .92;
    max-width: 30ch;
  }
  .campaign-strip.is-hero .campaign-left {
    order: 4;
    display: inline-flex;
    font-size: 12px;
    opacity: .9;
    margin-top: 2px;
  }
  .campaign-strip.is-hero a {
    order: 5;
    margin-top: 10px;
    background: #fff;
    color: var(--deep);
    font-weight: 700;
    font-size: 13px;
    padding: 0 18px;
    min-height: 40px;
    border-radius: 21px;
    text-decoration: none;
    box-shadow: 0 4px 14px rgba(20, 12, 80, .22);
  }

  /* ---- 3. The search group sticks, everything above it scrolls away ------
     `.search-hero` is a direct child of #app, so its containing block is the
     whole page and it stays pinned for the entire scroll — the same trap as the
     PDP rail, used deliberately this time. Sticking a wrapper INSIDE the hero
     would only stick for the height of the hero, which is nothing. */
  #app > .search-hero {
    position: sticky;
    top: 0;
    z-index: 40;
    padding: 8px 0 6px;
    background: #fff;
    border-bottom: 1px solid var(--line);
    box-shadow: 0 6px 16px -12px rgba(9, 9, 11, .35);
  }
  /* "Popular searches" is not worth 60px of a pinned bar; the placeholder in the
     field already rotates through the same terms. */
  #app > .search-hero .trending { display: none; }

  /* ---- 4. Tabs: one row, not a 2x2 grid ---------------------------------
     The 2x2 tile grid was my earlier guess at the reference marketplace. Their app uses a single
     underlined row, which is both correct and ~60px shorter — and 60px of a
     sticky bar is worth more than four tiles. */
  .search-hero .search-tabs,
  .browse-strip .search-tabs,
  .search-tabs {
    display: flex;
    grid-template-columns: none;
    gap: 0;
    justify-content: flex-start;
    align-items: stretch;
    margin: 0 0 8px;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .search-tabs::-webkit-scrollbar { display: none; }
  .search-hero .search-tabs > a,
  .browse-strip .search-tabs > a,
  .search-tabs > a {
    flex: 0 0 auto;
    min-height: 40px;
    padding: 6px 13px;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    font-size: 15px;
    font-weight: 600;
    color: var(--gray);
    position: relative;
  }
  .search-hero .search-tabs > a .icon,
  .browse-strip .search-tabs > a .icon,
  .search-tabs > a .icon { display: none; }
  .search-hero .search-tabs > a.active,
  .browse-strip .search-tabs > a.active,
  .search-tabs > a.active {
    background: none;
    color: var(--ink);
    font-weight: 750;
    box-shadow: none;
  }
  /* The underline the earlier rule removed — it is right for a row, wrong for
     tiles, and this is a row again. */
  .search-hero .search-tabs > a.active::after,
  .browse-strip .search-tabs > a.active::after,
  .search-tabs > a.active::after {
    display: block;
    content: "";
    position: absolute;
    left: 13px; right: 13px; bottom: 0;
    height: 3px;
    border-radius: 2px;
    background: var(--violet);
  }

  /* ---- 5. "Buscar" is bigger -------------------------------------------
     Giuliano, twice. It was a 36px button stacked under the field. the reference marketplace puts
     the field and a chunky pill on one row inside a 2px accent border, and that
     is what stops it reading as cramped. Budget at 390px: wrap 358, box padding
     2x8 = 342 inner; camera 0 + field 224 + gap 8 + button 110 = 342. */
  .search-box {
    padding: 7px 8px;
    border: 2px solid var(--violet);
    border-radius: 27px;
    box-shadow: 0 2px 10px rgba(62, 52, 249, .08);
  }
  .search-box .search-input {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;
  }
  .search-box .search-input input {
    min-height: 40px;
    font-size: 15px;
    padding: 8px 6px 8px 12px;
    width: 100%;
    min-width: 0;
  }
  .search-box .search-input .btn,
  .search-box:not(.compact) .search-input > .btn {
    width: auto;
    min-width: 104px;
    min-height: 42px;
    padding: 10px 20px;
    font-size: 15px;
    font-weight: 700;
    border-radius: 21px;
    white-space: nowrap;
  }
  .search-box .search-input .btn > .icon { width: 18px; height: 18px; }

  /* ---- 6. Quick actions: the reference marketplace’s three cards --------------------------
     promos.js already renders exactly these three (Solicitar cotización / Top
     Ranking / Fast customization) as `.welcome-strip-links`; they only needed to
     stop being text chips. */
  .welcome-strip-inner { padding: 12px 0 14px; }
  .welcome-strip-links { gap: 10px; }
  .welcome-strip-links > a {
    flex: 0 0 auto;
    min-width: 156px;
    min-height: 62px;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: #fff;
    font-size: 13.5px;
    font-weight: 650;
    line-height: 1.25;
    white-space: normal;
    box-shadow: 0 1px 3px rgba(9, 9, 11, .05);
  }
  .welcome-strip-links > a .icon {
    width: 26px; height: 26px;
    flex: none;
    color: var(--violet);
  }

  /* ---- 7. Product cards ------------------------------------------------- */
  .home-main > .section-head { padding: 16px 0 10px; }
  .home-main > .section-head .eyebrow { font-size: 10px; }
  .home-main > .section-head h2 { font-size: 19px; line-height: 1.2; }
  .product-grid { gap: 16px 10px; }
  .product-card .product-title { font-size: 13px; height: auto; }
  .product-card .price { font-size: 17px; font-weight: 750; }

  /* ---- 8. Tap targets the audit still had under 44px --------------------- */
  #app .text-link,
  #app a.text-link,
  #app .section-head > a { min-height: 40px; display: inline-flex; align-items: center; }
  /* Carousel dots were 4px tall. The dot stays 4px; the target around it does not. */
  #app .spotlight-dots button,
  #app [data-spotlight] button {
    min-height: 24px;
    min-width: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* ---------------------------------------------------------------------------
   The sticky bar has to earn its height.

   First measurement after making `.search-hero` sticky: 236px pinned on an
   860px viewport — 27% of the screen permanently spent on chrome. the reference marketplace’s
   equivalent is ~110px. The excess is `.search-bottom`, the Image Search /
   Search with File / Ask AI row, which is ~60px and is NOT in their sticky bar.

   It is dropped from the pinned hero only, and nothing is lost: the side dock
   already carries Image search and AI Mode, and the camera is inside the field.
   Inner pages keep the row exactly as it was.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  #app > .search-hero .search-bottom { display: none; }
  #app > .search-hero .search-tabs > a { min-height: 36px; padding: 4px 13px; }
  #app > .search-hero { padding: 6px 0 8px; }
  #app > .search-hero .search-box { margin-bottom: 0; }

  /* The four labels total ~412px against 358 of width, so the row scrolls.
     Fade the right edge so it reads as "more this way" instead of a cut word. */
  #app > .search-hero .search-tabs {
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
            mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
  }
}

/* The section heading above the product grid put an eyebrow, a three-line title
   and "Explorar todos los productos" in one row, so the title wrapped to three
   lines in half the width while the link sat beside it. On a phone it stacks. */
@media (max-width: 760px) {
  .home-main > .section-head {
    display: block;
    padding: 18px 0 12px;
  }
  .home-main > .section-head > a {
    margin-top: 8px;
    font-size: 13px;
  }
  .home-main > .section-head h2 { max-width: 100%; }
}

/* ===========================================================================
   PHONE PDP GALLERY — full bleed, 2026-09-17

   Giuliano: "the product images look horrendous ... when you click it on mobile
   it's like a very small product image."

   Measured on a 390px screen: the main photo was rendering at 115 x 115px.

   Why: `.gallery` is `grid-template-columns: 54px 1fr` (pdp.css narrows it to
   44px), a desktop layout with a vertical thumbnail rail beside the photo. It
   was never collapsed for the phone, so the rail took its 44px, `.gallery-main`
   kept a fixed height, and the photo ended up a thumbnail with half the screen
   empty beside it.

   the reference marketplace’s phone PDP (docs/reference-mobile/raw/pdp-01-gallery.png) puts the
   photo edge to edge, square, with the controls floating on top of it and a
   "Photos 1/6" pill at the bottom. That is what a product photo is for on a
   phone, so that is what this does: one column, full bleed out through the
   .wrap gutter, 1:1, and the thumbnails become a horizontal strip underneath
   instead of a rail beside.
   =========================================================================== */
@media (max-width: 760px) {
  .pdp-layout,
  .pdp-layout.pdp-v2-layout,
  .pdp-layout.retail-layout { display: block; }

  /* Flex column, not block: the thumbnail rail comes FIRST in the DOM (it was
     the left column of the desktop grid), so on a phone it rendered above the
     photo. the reference marketplace leads with the picture and nothing else. `order` puts the
     photo first without touching the markup. */
  .gallery {
    display: flex;
    flex-direction: column;
    grid-template-columns: none;
    /* Escape the 16px page gutter so the photo reaches both edges. */
    margin-left: -16px;
    margin-right: -16px;
    width: calc(100% + 32px);
  }
  .gallery > .gallery-main { order: 1; }
  .gallery > .thumbs { order: 2; }
  .gallery > * { order: 3; }

  /* The reference marketplace’s phone PDP has no breadcrumb — the back arrow is the way up, and
     the trail costs two lines above the photo. Desktop keeps it. */
  .pdp-shell .breadcrumb,
  .pdp-page .breadcrumb,
  main > .breadcrumb { display: none; }

  /* pdp.css sets `.pdp-v2-layout .gallery-main { height: min(30vw, 400px) }` —
     (0,2,0), which beat a bare `.gallery-main` at (0,1,0) and kept the photo
     117px tall even after the width was fixed. Prefixed with #app to settle it. */
  #app .gallery-main,
  #app .pdp-v2-layout .gallery-main,
  #app .pdp-layout.retail-layout .gallery-main {
    height: auto;
    aspect-ratio: 1 / 1;          /* the reference marketplace’s is square; ours matches */
    width: 100%;
    border-radius: 0;
    border: 0;
    background: #fff;
  }
  /* `contain`, not `cover`. the reference marketplace’s hero photos are lifestyle shots that crop
     safely; ours are studio product shots on white, and cover would cut heads
     and hems off the garment. Contain fills the full width and still shows the
     whole product. */
  #app .gallery-main > img,
  #app #main-photo {
    width: 100%;
    height: 100%;
    max-width: none;
    object-fit: contain;
    padding: 0;
    border-radius: 0;
    display: block;
  }

  /* The thumbnail rail becomes a strip under the photo. It keeps its job —
     picking a frame — without stealing width from the thing being looked at. */
  .thumbs {
    flex-direction: row;
    gap: 8px;
    margin: 10px 16px 0;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .thumbs::-webkit-scrollbar { display: none; }
  .thumbs button { flex: 0 0 auto; padding: 2px; }
  .thumbs img { width: 56px; height: 62px; object-fit: cover; border-radius: 5px; }

  /* Controls float on the photo the way the reference marketplace’s heart and image-search do,
     instead of sitting in the layout and pushing it around. */
  .gallery-main .save-btn,
  .gallery-main [data-save] {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 2;
  }
  .pdp-media-toggle { grid-column: auto; margin: 12px 16px 0; }
  .pdp-store { grid-column: auto; }
}

/* ===========================================================================
   The search bar does NOT follow you. (Giuliano, reversing my earlier call.)

   "the search bar cannot be a sticky bar okay that makes everything look
    horrendous ... it needs to be its own bar that i just scroll down and it
    doesn't follow me okay at all so i can just keep scrolling down and looking
    for products"

   I had made `.search-hero` sticky to copy the the reference marketplace app, where the tabs and
   search stay pinned. On our page it ate 173px of every screen and he hated it.
   His call, and he is the one using it. It scrolls away with everything else.
   =========================================================================== */
@media (max-width: 760px) {
  #app > .search-hero {
    position: static;
    box-shadow: none;
    border-bottom: 1px solid var(--line);
  }
  /* The tool row comes back now that the bar is not pinned — it was only hidden
     to buy height for a sticky bar that no longer exists. */
  #app > .search-hero .search-bottom { display: block; }
}

/* ===========================================================================
   PHONE PARITY PASS 2 — the six gaps the board exposed, 2026-09-17

   Read off docs/reference-mobile/pairs/home.png, the reference marketplace left, AJAW right, same
   scale. Their fold reaches products in ~420px; ours took ~700px, and the
   difference was almost entirely structural rather than stylistic.
   =========================================================================== */

@media (max-width: 760px) {

  /* ---- 1. No desktop header ---------------------------------------------
     the reference marketplace’s phone app has NO logo row and NO secondary nav row. It opens on
     the tabs and the search field. We were carrying ~180px of desktop chrome
     that exists on their site but not in their app.

     This is only safe because of the tab bar below: cart, messages, account and
     home all move there, one tap away, instead of being lost. Hiding the header
     WITHOUT that would strand people, so the two changes ship together. */
  #app > header > .head-main,
  #app > header > .main-nav { display: none; }
  #app > header { border-bottom: 0; }

  /* ---- 2. Campaign strip is a strip again -------------------------------
     I had made it a 230px hero. Theirs is a ~90px band: badge, name, deal line,
     arrow. The hero was mine, not theirs — the board made that obvious. */
  .campaign-strip.is-hero {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    gap: 9px;
    min-height: 0;
    padding: 10px 14px;
    text-align: left;
  }
  .campaign-strip.is-hero .campaign-off {
    order: 0; font-size: 11px; padding: 3px 8px; flex: none;
  }
  .campaign-strip.is-hero b {
    order: 1; font-size: 14px; line-height: 1.2; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis; font-family: var(--body);
  }
  .campaign-strip.is-hero > span:not(.campaign-off):not(.campaign-left),
  .campaign-strip.is-hero .campaign-left { display: none; }
  .campaign-strip.is-hero a {
    order: 2; margin: 0 0 0 auto; min-height: 32px; padding: 0 12px;
    font-size: 12px; border-radius: 16px; flex: none; box-shadow: none;
  }

  /* ---- 3. Personalised rail --------------------------------------------- */
  .home-fold { padding-top: 12px; }
  .home-rail {
    display: flex;
    gap: 10px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
  }
  .home-rail::-webkit-scrollbar { display: none; }
  .rail-card {
    flex: 0 0 auto;
    width: 122px;
    min-width: 0;
    text-decoration: none;
    color: inherit;
  }
  .rail-shot {
    position: relative;
    display: block;
    height: 108px;
    border-radius: 10px;
    overflow: hidden;
    background: var(--canvas);
  }
  .rail-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
  /* The reference marketplace floats the price on the picture rather than under it, which is what
     keeps these cards short enough to be a rail and not a grid. */
  .rail-shot em {
    position: absolute;
    left: 6px; bottom: 6px;
    max-width: calc(100% - 12px);
    padding: 3px 7px;
    border-radius: 7px;
    background: rgba(255,255,255,.94);
    font: 700 11px/1.2 var(--body);
    font-style: normal;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .rail-card b {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-top: 7px;
    font-size: 12px;
    line-height: 1.3;
    font-weight: 650;
  }

  /* ---- 4. Filter chip row ------------------------------------------------ */
  .home-chips {
    display: flex;
    gap: 8px;
    margin: 14px 0 4px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .home-chips::-webkit-scrollbar { display: none; }
  .home-chips > a {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 38px;
    padding: 7px 13px;
    border: 1px solid var(--line);
    border-radius: 20px;
    background: #fff;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    text-decoration: none;
    white-space: nowrap;
  }
  .home-chips > a.on { border-color: var(--ink); font-weight: 700; }
  .home-chips .bico { width: 18px; height: 18px; }

  /* ---- 5. Card trust line ------------------------------------------------ */
  .card-trust {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 5px 0 0;
    font-size: 11.5px;
    color: var(--gray);
    line-height: 1.3;
  }
  .ct-verified { display: inline-flex; align-items: center; gap: 3px; color: var(--violet); font-weight: 650; }
  .ct-verified .icon { width: 13px; height: 13px; }
  /* Their card carries one promise line, not three. */
  .product-card .card-foot { display: none; }
  .product-card .card-guarantee { font-size: 11.5px; margin-top: 4px; }

  /* ---- 6. Bottom tab bar ------------------------------------------------- */
  .tabbar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 55;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    background: rgba(255,255,255,.97);
    -webkit-backdrop-filter: saturate(1.6) blur(10px);
            backdrop-filter: saturate(1.6) blur(10px);
    border-top: 1px solid var(--line);
    /* Clears the iPhone home indicator. */
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .tabbar > a {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: 54px;
    padding: 6px 2px;
    font-size: 10.5px;
    font-weight: 600;
    color: var(--gray);
    text-decoration: none;
  }
  .tabbar > a .icon { width: 21px; height: 21px; }
  .tabbar > a.on { color: var(--violet); }
  .tabbar > a em {
    position: absolute;
    top: 3px; left: 50%; margin-left: 4px;
    min-width: 16px; height: 16px;
    padding: 0 4px;
    border-radius: 9px;
    background: #e5484d;
    color: #fff;
    font: 700 10px/16px var(--body);
    font-style: normal;
    text-align: center;
  }
  /* Nothing may hide behind the bar. */
  body { padding-bottom: calc(54px + env(safe-area-inset-bottom, 0px)); }
  /* The side dock duplicated messages and AI Mode; the bar covers both. */
  .side-dock { display: none; }
}

/* Rail cards picked up card chrome (white panel, border, padding) from a
   generic rule and grew to ~200px tall. the reference marketplace’s are a picture and a caption,
   nothing else — that is what keeps the rail a rail. */
@media (max-width: 760px) {
  .home-rail .rail-card,
  .home-fold .rail-card {
    background: none;
    border: 0;
    border-radius: 0;
    padding: 0;
    box-shadow: none;
  }

  /* The section heading above the grid was an eyebrow, a 2-line display title
     and a link — ~200px before a single product. the reference marketplace has no heading there
     at all; products simply begin. Ours keeps a single compact line. */
  .home-main > .section-head { padding: 14px 0 8px; }
  .home-main > .section-head .eyebrow { display: none; }
  .home-main > .section-head h2 { font-size: 16px; line-height: 1.25; }
  .home-main > .section-head > a { margin-top: 4px; font-size: 12.5px; min-height: 32px; }

  /* Quick actions: three across like theirs, not two big ones. */
  .welcome-strip-inner { padding: 10px 0 12px; }
  .welcome-strip-hi { font-size: 13px; margin-bottom: 8px; color: var(--gray); }
  .welcome-strip-links > a {
    min-width: 0;
    flex: 1 1 0;
    min-height: 56px;
    flex-direction: column;
    gap: 5px;
    padding: 9px 6px;
    font-size: 11.5px;
    text-align: center;
  }
  .welcome-strip-links { flex-wrap: nowrap; }
  .welcome-strip-links > a .icon,
  .welcome-strip-links > a .bico { width: 24px; height: 24px; }
}

/* ---------------------------------------------------------------------------
   Fold budget, pass 3.

   Measured: 738px to the first product against the reference marketplace’s ~420px. The six
   structural pieces are in place now, so what is left is padding. Their column,
   top to bottom: campaign 90, tabs 36, search 44, quick actions 70, rail 130,
   chips 44 = 414. Ours was spending 290px on tabs + search alone, because the
   field is tall, the box has 2px border plus padding, and the tool row sits
   underneath in its own bordered section.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  /* Tabs: 70px -> ~40px. */
  #app > .search-hero { padding: 4px 0 10px; }
  #app > .search-hero .search-tabs { margin-bottom: 4px; }
  #app > .search-hero .search-tabs > a { min-height: 34px; padding: 3px 12px; font-size: 14.5px; }

  /* Search box: tighter shell, shorter field, and the tool row loses its own
     border and padding so it reads as part of the box rather than a section. */
  .search-box { padding: 5px 6px; }
  .search-box .search-input input { min-height: 38px; padding: 6px 4px 6px 10px; }
  .search-box .search-input .btn,
  .search-box:not(.compact) .search-input > .btn { min-height: 38px; padding: 8px 16px; }
  .search-box:not(.compact) .search-bottom,
  .search-box .search-bottom {
    padding: 4px 0 0;
    margin-top: 4px;
    border-top: 1px solid var(--line);
  }
  .search-box .search-modes > button,
  .search-box .search-modes > a,
  .search-box:not(.compact) .search-bottom .search-modes > button,
  .search-box:not(.compact) .search-bottom .search-modes > a {
    min-height: 34px;
    padding: 2px 2px;
    font-size: 10.5px;
    gap: 2px;
  }
  .search-box .search-modes .icon { width: 15px; height: 15px; }

  /* The reference marketplace’s home has no greeting line above the quick actions. */
  .welcome-strip-hi { display: none; }
  .welcome-strip-inner { padding: 8px 0 10px; }

  /* ...and no section heading above the grid. One compact line, link inline. */
  .home-main > .section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 0 8px;
  }
  .home-main > .section-head h2 { font-size: 15px; margin: 0; }
  .home-main > .section-head > a { margin: 0; font-size: 12px; white-space: nowrap; }

  .home-fold { padding-top: 8px; }
  .home-chips { margin: 10px 0 2px; }
}

/* ---------------------------------------------------------------------------
   The logo comes back, and the search shrinks to the reference marketplace’s.

   Giuliano, on removing the header entirely: "we need the logo on the top at
   least somewhere on mobile ... we're still on a web ... I do need the logo
   right above. Property, brother, property."

   He is right and the distinction is his: in the App Store build the brand is
   implicit — you opened AJAW — but a web page has to say whose it is. So the
   brand row returns, stripped to the wordmark alone. The cart, messages,
   orders and account icons stay gone from it, because the tab bar now carries
   all four; the row is ~46px instead of the ~110px it was.

   And the search: "the the reference marketplace search is a lot smaller because it's mobile and
   it has just a little camera on the left side." Theirs is one ~44px pill —
   camera, placeholder, mic, button. No tool row underneath. Ours was 123px
   because the tool row sat below the field in its own bordered section. The
   camera moves inside the field (app.js) and the row goes.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  #app > header > .head-main {
    display: flex;
    height: 46px;
    min-height: 46px;
    gap: 8px;
    padding: 0;
    justify-content: flex-start;
  }
  /* The utilities moved to the tab bar; the row is the wordmark and nothing else. */
  #app > header > .head-main > .utilities,
  #app > header > .head-main > .brand-note { display: none; }
  #app > header > .head-main .brand { min-height: 46px; }
  #app > header > .head-main .brand img { width: 84px; max-height: 30px; }
  #app > header > .head-main .brand > span { font-size: 16px; padding-left: 8px; }

  /* ---- the reference marketplace’s slim search pill --------------------------------------- */
  .search-box { padding: 4px 5px 4px 4px; border-radius: 24px; }
  .search-box .search-input {
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 4px;
  }
  .search-cam {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    flex: none;
    border-radius: 50%;
    background: none;
    color: var(--gray);
  }
  .search-cam .icon { width: 20px; height: 20px; }
  .search-box .search-input input { min-height: 38px; padding: 6px 2px; font-size: 15px; }
  .search-box .search-input .btn,
  .search-box:not(.compact) .search-input > .btn {
    min-width: 0;
    min-height: 38px;
    padding: 8px 18px;
    font-size: 14px;
    border-radius: 19px;
  }
  /* The tool row is what made the box 123px. Image search is the camera inside
     the field now, and Ask AI is a tab; neither is lost. */
  #app > .search-hero .search-bottom,
  .search-box .search-bottom { display: none; }
}
/* Desktop keeps its tool row, so the in-field camera would be a duplicate. */
@media (min-width: 761px) { .search-cam { display: none; } }

/* Two earlier passes are still winning here and must be settled explicitly.

   1. The "stack the field over a full-width button" pass set
      `.search-box .search-input { grid-template-columns: 1fr }`. With the camera
      now inside the field there are three children, so a single column stacked
      them into two rows and the box measured 86px instead of 44.
   2. `.search-box { padding: 10px }` from the very first mobile pass was still
      contributing a 17px bottom padding under a tool row that no longer exists.

   #app prefix so this is the last word on both. */
@media (max-width: 760px) {
  #app .search-box {
    padding: 4px 5px 4px 4px;
  }
  /* FOUR columns, not three: camera, field, voice mic, submit. voice-search.js
     injects the mic as a fourth child, and with a three-column track it wrapped
     onto a second row — which is why the box measured 92px instead of 46 after
     the stacking rule was already fixed. Explicit placement so a fifth child
     (whatever gets added next) cannot silently do the same thing again. */
  #app .search-box .search-input {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 4px;
  }
  #app .search-box .search-cam { grid-column: 1; grid-row: 1; }
  #app .search-box .search-input > input { grid-column: 2; grid-row: 1; }
  #app .search-box .search-input > [data-voice-search-btn] { grid-column: 3; grid-row: 1; }
  #app .search-box .search-input > .btn { grid-column: 4; grid-row: 1; min-height: 38px; }
}

/* The three quick-action cards must be the SAME width.

   Giuliano: "why did you make the squares larger than the other ones when the
   the reference marketplace squares are all the same size?" He is right — in their app the three
   are an even third each. Ours were sized by their text, because an earlier
   pass set `flex: 0 0 auto; min-width: 156px` for a scrolling rail and a later
   `flex: 1 1 0` never beat it.

   A 3-column grid removes the argument entirely: equal tracks, no flex-basis to
   lose, and `minmax(0, 1fr)` so a long Spanish label cannot widen its own cell.
   The scroller is gone with it — three cards fit 358px. */
@media (max-width: 760px) {
  #app .welcome-strip-links {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    overflow: visible;
  }
  #app .welcome-strip-links > a {
    flex: none;
    min-width: 0;
    width: 100%;
    min-height: 66px;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
    padding: 9px 5px;
    font-size: 11.5px;
    line-height: 1.22;
    text-align: center;
    white-space: normal;
  }
}

/* Equal WIDTH was not equal SIZE. Measured live: 114/114/114 wide but 78/66/78
   tall, because "Top Ranking" is one line and the other two labels wrap to
   two — so the short card sat shorter than its neighbours and the row read as
   uneven. Grid items stretch by default, so something was collapsing them;
   stating stretch and a full-height child settles it. */
@media (max-width: 760px) {
  #app .welcome-strip-links { align-items: stretch; }
  #app .welcome-strip-links > a { height: 100%; align-self: stretch; }
  /* Reserve two lines for every label so the row height stops depending on how
     long a given Spanish word happens to be. */
  #app .welcome-strip-links > a > span,
  #app .welcome-strip-links > a { min-height: 76px; }
}

/* ===========================================================================
   PHONE PRODUCT PAGE — carbon copy of the reference marketplace’s, 2026-09-17

   Giuliano: "the product page looks horrendous compared to the reference marketplace ... the
   the reference marketplace one at least shows you the search bar again at the top ... carbon
   copy." Reference is his own capture of their PDP.

   Their fold, measured off it, top to bottom:
     56px   back arrow | search pill with camera | cart | overflow
     1:1    photo, heart + image-search stacked top-right, a dark segmented
            "Photos 1/6 | Video" pill centred at the bottom OF the image
     -      title (2 lines) + share, then "Store rating: 5.0 * (59)"
     -      grey card of price tiers side by side, then sample price + Get sample
     72px   fixed bar: Store | Send inquiry | Chat now

   Ours was: campaign strip, wordmark, photo, thumbnails, Photos/Video buttons —
   and no title or price anywhere near the fold. They have no campaign strip and
   no logo on a PDP at all, so both go; the top bar replaces them.
   =========================================================================== */
@media (max-width: 760px) {

  /* ---- 1. Their header, not ours ---------------------------------------- */
  #app:has(.pdp-topbar) > .campaign-strip,
  #app:has(.pdp-topbar) > .announcement,
  #app:has(.pdp-topbar) > header { display: none; }

  .pdp-topbar {
    position: sticky;
    top: 0;
    z-index: 45;
    display: grid;
    grid-template-columns: 34px minmax(0, 1fr) 40px;
    align-items: center;
    gap: 6px;
    height: 56px;
    padding: 0 10px;
    background: #fff;
    border-bottom: 1px solid var(--line);
  }
  .pdp-back {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 44px;
    color: var(--ink);
  }
  /* Their chevron points left; ours is a generic right-pointing one. */
  .pdp-back .icon { width: 22px; height: 22px; transform: rotate(180deg); }

  .pdp-topsearch {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    height: 38px;
    padding: 0 12px;
    border: 1.5px solid var(--violet);
    border-radius: 19px;
    color: var(--muted);
    font-size: 14px;
    text-decoration: none;
  }
  .pdp-topsearch > span {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .pdp-topsearch .icon { width: 20px; height: 20px; color: var(--ink); flex: none; }

  .pdp-topcart {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 44px;
    color: var(--ink);
  }
  .pdp-topcart .icon { width: 23px; height: 23px; }
  .pdp-topcart em {
    position: absolute;
    top: 2px; right: 0;
    min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 9px;
    background: #e5484d; color: #fff;
    font: 700 10px/16px var(--body); font-style: normal; text-align: center;
  }

  /* ---- 2. Controls live ON the photo ------------------------------------ */
  #app .gallery-main { position: relative; }
  #app .gallery-main .save-btn,
  #app .gallery-main [data-save] {
    position: absolute;
    top: 12px; right: 12px;
    z-index: 3;
    width: 40px; height: 40px;
    display: grid; place-items: center;
    border-radius: 50%;
    background: rgba(255,255,255,.94);
    box-shadow: 0 2px 8px rgba(9,9,11,.16);
  }

  /* The segmented "Photos | Video" pill moves out of the layout and onto the
     bottom of the picture, exactly where theirs sits. */
  #app .pdp-media-toggle {
    position: absolute;
    left: 50%;
    bottom: 12px;
    transform: translateX(-50%);
    z-index: 3;
    display: inline-flex;
    gap: 0;
    margin: 0;
    padding: 3px;
    border-radius: 18px;
    background: rgba(24, 22, 40, .72);
    -webkit-backdrop-filter: blur(6px);
            backdrop-filter: blur(6px);
  }
  #app .pdp-media-toggle button {
    min-height: 28px;
    padding: 4px 16px;
    border: 0;
    border-radius: 15px;
    background: none;
    color: rgba(255,255,255,.85);
    font-size: 12.5px;
    font-weight: 650;
  }
  #app .pdp-media-toggle button.is-on { background: #fff; color: var(--ink); }
  #app .pdp-media-toggle button[disabled] { opacity: .5; }
  /* With no video there is nothing to toggle to, so the pill just counts the
     photos the way theirs does. */
  #app .pdp-media-toggle.is-photos-only button[data-pdp-media="video"] { display: none; }

  /* The gallery is the positioning context for all of the above. */
  #app .gallery { position: relative; }
  #app .gallery > .pdp-media-toggle { order: 1; }

  /* ---- 3. Bottom action bar --------------------------------------------- */
  .pdp-mobile-bar {
    position: fixed;
    left: 0; right: 0;
    bottom: calc(55px + env(safe-area-inset-bottom, 0px));  /* sits above the tab bar */
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    background: #fff;
    border-top: 1px solid var(--line);
    box-shadow: 0 -4px 16px -10px rgba(9,9,11,.4);
  }
  .pdp-mobile-bar .btn { flex: 1; min-height: 44px; border-radius: 23px; font-size: 14px; }
  /* Room for both bars so the page never ends underneath them. */
  #app:has(.pdp-mobile-bar) ~ * { }
  body:has(.pdp-mobile-bar) { padding-bottom: calc(118px + env(safe-area-inset-bottom, 0px)); }
}

/* Two corrections to the phone PDP, both caught by measuring the render.

   1. The Photos/Video pill was `position:absolute; bottom:12px`, but its
      containing block is `.gallery` — which is the image PLUS the thumbnails
      PLUS the supplier card, ~1400px tall. So it pinned to the bottom of all
      that and floated in the middle of the page. It stays in normal flow and is
      pulled up onto the picture instead, which cannot drift no matter how tall
      the gallery gets.

   2. The title measured 807px down, because the supplier card sits inside the
      gallery column (it is the desktop grid's left rail) and therefore rendered
      between the photo and the title. the reference marketplace puts the title immediately under
      the picture and the supplier far below. Ordering the gallery's children
      moves it out of the way without touching the markup. */
@media (max-width: 760px) {
  #app .gallery > .gallery-main      { order: 1; }
  #app .gallery > .pdp-media-toggle  { order: 2; }
  #app .gallery > .thumbs            { order: 3; }
  #app .gallery > .pdp-store         { order: 9; }

  #app .pdp-media-toggle {
    position: relative;
    left: auto;
    bottom: auto;
    transform: none;
    align-self: center;
    /* Lift it onto the bottom of the square photo. */
    margin: -46px 0 0;
  }

  /* The supplier card repeats the manufacturer block further down the page, and
     on a phone it is 380px of duplication between the photo and the title. */
  #app .gallery > .pdp-store { display: none; }

  /* Thumbnails tighten so the title clears the fold. */
  #app .gallery > .thumbs { margin: 12px 16px 0; }
  #app .gallery > .thumbs img { width: 50px; height: 56px; }
}

/* The reference marketplace’s PDP shows ONE bar at the bottom — Store / Send inquiry / Chat now —
   and hides the app's tab bar while you are on a product. We were stacking both,
   118px of fixed furniture over the page. On a product page the action bar wins. */
@media (max-width: 760px) {
  body:has(.pdp-mobile-bar) .tabbar { display: none; }
  body:has(.pdp-mobile-bar) { padding-bottom: calc(66px + env(safe-area-inset-bottom, 0px)); }
  .pdp-mobile-bar { bottom: 0; }
}

/* The PDP top bar is a phone replacement for the header. On desktop the real
   header is right there, so it would be a second search box on the same page. */
@media (min-width: 761px) { .pdp-topbar { display: none; } }

/* ---------------------------------------------------------------------------
   PDP price tiers as the reference marketplace renders them on a phone.

   Theirs: one light grey card, the bands side by side as columns —
     $3,950            $3,850        $3,650        $3,550
     Min. order: 1 set 10-99 sets    100-499 sets  >=500 sets
   scrolling sideways when there are more than fit. Price big and bold, band
   label small and grey underneath. Ours stacked them, which on four bands was
   four rows of a single number.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  #app .pdp-pricing {
    background: var(--canvas);
    border-radius: 12px;
    padding: 14px 0 12px;
    margin: 12px 0;
  }
  #app .pdp-tiers {
    display: flex;
    gap: 22px;
    padding: 0 14px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  #app .pdp-tiers::-webkit-scrollbar { display: none; }
  #app .pdp-tier {
    flex: 0 0 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    border: 0;
    padding: 0;
    background: none;
  }
  #app .pdp-tier b {
    font-size: 23px;
    font-weight: 750;
    letter-spacing: -.02em;
    line-height: 1.1;
    white-space: nowrap;
  }
  #app .pdp-tier s { font-size: 12px; color: var(--muted); }
  #app .pdp-tier span {
    font-size: 12px;
    color: var(--gray);
    white-space: nowrap;
  }
  #app .pdp-price-note { padding: 0 14px; margin-top: 10px; font-size: 11px; }
  #app .pdp-campaign, #app .pdp-deal { padding: 0 14px 10px; }

  /* ---- bottom bar: Store | Send inquiry | Chat now --------------------- */
  .pdp-mobile-bar { gap: 8px; padding: 8px 12px; }
  .pdp-bar-store {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    flex: 0 0 auto;
    width: 48px;
    min-height: 44px;
    color: var(--ink);
    font-size: 10px;
    font-weight: 600;
    text-decoration: none;
  }
  .pdp-bar-store .icon { width: 21px; height: 21px; }
  .pdp-mobile-bar .btn { flex: 1 1 0; min-width: 0; font-size: 14px; }
  .pdp-mobile-bar .btn.outline { background: #fff; border-color: var(--ink); color: var(--ink); }
}

/* The reference marketplace’s card price line: bold current price, the former price struck
   through beside it, then the percentage in their accent colour. Ours is the
   same shape in purple, and the sold count sits with the minimum order. */
.price-off {
  margin-left: 7px;
  font-size: 12px;
  font-weight: 700;
  color: var(--violet);
  white-space: nowrap;
}
.price-was { margin-left: 7px; font-size: 12px; font-weight: 500; color: var(--muted); text-decoration: line-through; }
.card-sold { margin-left: 8px; color: var(--gray); }
@media (max-width: 760px) {
  .card-sold { font-size: 11.5px; }
  .price-off { font-size: 11.5px; margin-left: 6px; }
  .price-was { font-size: 11.5px; margin-left: 6px; }
}

/* "20% de descuento" was printing twice on a card: once as a badge over the
   photo and again beside the price. the reference marketplace states a discount once, inline with
   the price, where it can be read against the number it applies to. The photo
   badge goes on the phone; desktop keeps it, where there is room for both. */
@media (max-width: 760px) {
  .product-card .card-promo { display: none; }
}

/* ---------------------------------------------------------------------------
   Footer on a phone.

   Giuliano: "it looks so bad at the bottom on the mobile ... this really weird
   small column that looks horrendous."

   Measured: 1,005px tall. It is the desktop footer — four link columns plus a
   brand block — folded into two 171px tracks, so every link sat ~56px from the
   next and the last section spanned alone with half the row empty.

   app.js now renders each column as a <details>, collapsed below 760px. The
   payment methods and the legal line stay visible: those are the parts a
   marketplace footer actually owes the visitor.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  .footer-grid {
    display: block;
    padding-top: 6px;
  }
  .footer-brand { margin-bottom: 14px; }
  .footer-brand p { font-size: 12px; line-height: 1.5; }

  .foot-sec {
    border-top: 1px solid var(--line);
    padding: 0;
  }
  .foot-sec > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 48px;
    padding: 0 2px;
    font-size: 14px;
    font-weight: 650;
    color: var(--ink);
    cursor: pointer;
    list-style: none;
  }
  .foot-sec > summary::-webkit-details-marker { display: none; }
  /* A chevron that turns, rather than the default disclosure triangle. */
  .foot-sec > summary::after {
    content: "";
    width: 8px; height: 8px;
    border-right: 2px solid var(--muted);
    border-bottom: 2px solid var(--muted);
    transform: rotate(45deg);
    transition: transform .18s ease;
    margin-right: 4px;
  }
  .foot-sec[open] > summary::after { transform: rotate(-135deg); }
  .foot-sec > a {
    display: block;
    min-height: 40px;
    padding: 9px 2px;
    font-size: 13px;
    color: var(--gray);
  }
  .foot-sec:last-of-type { border-bottom: 1px solid var(--line); }
}
@media (prefers-reduced-motion: reduce) {
  .foot-sec > summary::after { transition: none; }
}

/* ===========================================================================
   SEARCH RESULTS on a phone — one chip row, like theirs.

   From the wireframe board (scripts/wireframe.py, docs/reference-mobile/
   wireframes/search.png), measured at 390px:

     REFERENCE  top bar 56 | tab row 36 | Deep Search 40 | filter chips 44
              -> products at 176px

     AJAW     campaign 46 | logo 46 | tab row 80 | search 50 | Deep Search 70
              | results head 79 | filter panel 74 | results-chips 124
              | sort + view toggle 108
              -> products at 723px

   Four separate pieces of filtering furniture (the filters aside, the chip row,
   the toolbar and "Más filtros") where they have one 44px scroller. The pieces
   all still work — they are collapsed into a single horizontal row, and the
   deep-search explainer becomes a closed summary instead of an open 190px list.
   =========================================================================== */
@media (max-width: 760px) {

  /* The results heading printed the query, the count AND two full-width buttons.
     the reference marketplace prints the count inside the chip row. */
  .results-head { display: block; padding: 8px 0 6px; }
  .results-head h1 { font-size: 16px; }
  .results-head p { font-size: 12px; margin-top: 2px; }
  .results-head .btn { display: none; }

  /* The Deep Search explainer is the band, not the essay. The steps and the
     hand-off stay available behind the summary. */
  .deep-panel > summary { min-height: 40px; font-size: 13px; }
  .deep-panel .deep-steps,
  .deep-panel .deep-handoff { font-size: 12px; }

  /* One row, scrolling sideways: the filter entry, the facet chips and the sort
     control together. */
  .results-layout.is-topfilters { display: block; }
  .results-layout > aside.filters {
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
  }
  .results-layout > aside.filters > details > summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 38px;
    padding: 6px 14px;
    border: 1px solid var(--line);
    border-radius: 20px;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
  }
  .results-chips {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    margin: 8px 0;
    padding-bottom: 2px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .results-chips::-webkit-scrollbar { display: none; }
  .results-chips > * { flex: 0 0 auto; white-space: nowrap; }

  /* Sort and the grid/list toggle join the same row instead of owning 108px. */
  .results-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 10px;
    padding: 0;
    border: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .results-toolbar::-webkit-scrollbar { display: none; }
  .results-toolbar > * { flex: 0 0 auto; }
  .results-toolbar select { min-height: 38px; font-size: 13px; }
  /* The grid/list toggle is a desktop affordance; a phone has one sensible
     layout and the switch costs a row. */
  .results-toolbar .view-toggle { display: none; }
}

/* Last trim on the results page. Measured against the reference marketplace block for block:

     block          theirs   ours (before)   ours (after)
     top bar          56          56             56
     tab row          36          80             40
     Deep Search      40          70             44
     results head      0          78             30   (count only; they put the
                                                       count inside the chips)
     chips + sort     44          82             44   (one row)

   The browse-strip tabs were 80px because they keep the hero's vertical padding
   on a page that has no hero. */
@media (max-width: 760px) {
  .browse-strip { padding: 4px 0 0; }
  .browse-strip .search-tabs { margin: 0; }
  .browse-strip .search-tabs > a { min-height: 36px; padding: 4px 12px; font-size: 14px; }

  .deep-panel { margin: 6px 0; }
  .deep-panel > summary { min-height: 38px; padding: 6px 10px; }

  /* Their results header is the count, nothing else — the query is already in
     the search pill at the top of the screen. */
  .results-head { padding: 6px 0 2px; }
  .results-head h1 { display: none; }
  .results-head p { font-size: 12.5px; color: var(--gray); margin: 0; }

  /* Sort joins the chip row rather than owning one below it. */
  .results-toolbar { margin: 0 0 8px; }
  .results-chips { margin: 6px 0 6px; }
}

/* ===========================================================================
   PHONE PDP, BELOW THE PRICE — the seven blocks, 2026-09-18

   Section map of the phone PDP before this pass (scripts: pdp_map), 390px:
     .pdp-quick-attrs   270px   key attributes, copy 1
     .pdp-supplier-card 262px   supplier, copy 1
     #pdp-service       446px   three generic service tiles the reference marketplace does not have
     #pdp-attributes    757px   key attributes, copy 2, as a long paired table
     #pdp-supplier      339px   supplier, copy 2
     .pdp-rail         1414px   the DESKTOP sticky rail, dumped at the bottom —
                                price, shipping and protection a third time
   Everything below replaces those with the reference marketplace’s own sequence and removes the
   duplicates. Desktop is untouched: every rule is inside the phone query except
   the two display utilities and the share button.
   =========================================================================== */

/* Display utilities: markup that exists only for one layout. */
.m-only { display: none; }
@media (max-width: 760px) {
  .d-only { display: none !important; }
  .m-only { display: revert; }
}

/* Share sits beside the title on desktop too — the reference marketplace has it there as well. */
.pdp-title-line { display: flex; align-items: flex-start; gap: 8px; }
.pdp-title-line h1 { flex: 1; min-width: 0; }
.pdp-share {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  color: var(--ink);
}
.pdp-share .icon { width: 21px; height: 21px; }
.pdp-share:hover { background: var(--canvas); }

@media (max-width: 760px) {

  /* ---- duplicates and desktop-only furniture -------------------------- */
  #app .pdp-quick-attrs,
  #app .pdp-custom,
  #app .pdp-main > .pdp-supplier-card,
  #app .pdp-tabs,
  #app #pdp-service,
  #app .pdp-rail { display: none; }

  /* Sections read as the reference marketplace’s: a bold heading, and an 8px grey band between
     blocks rather than hairlines, full-bleed out through the page gutter. */
  #app .pdp-main > .pdp-section,
  #app .pdp-m-sec {
    margin: 0 -16px;
    padding: 18px 16px;
    border-top: 8px solid #f2f2f6;
  }
  #app .pdp-main > .pdp-section > h2,
  #app .pdp-main > .pdp-section .section-head h2 {
    font: 700 17px/1.3 var(--body);
    letter-spacing: -.01em;
    margin: 0 0 12px;
  }
  #app .pdp-section { scroll-margin-top: 104px; }
  #app #pdp-overview { scroll-margin-top: 104px; }

  /* ---- 1. title row --------------------------------------------------- */
  #app .pdp-title-row { margin: 10px 0 4px; }
  #app .pdp-title-line { gap: 2px; }
  #app .pdp-title-line h1 {
    font: 500 16px/1.4 var(--body);
    letter-spacing: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  #app .pdp-title-line h1.is-open { -webkit-line-clamp: unset; display: block; }
  #app .pdp-title-more {
    display: inline-flex; align-items: center; justify-content: center;
    flex: none; width: 28px; height: 40px; color: var(--ink);
  }
  #app .pdp-title-more .icon { width: 18px; height: 18px; transition: transform .18s ease; }
  #app .pdp-title-more.is-open .icon { transform: rotate(180deg); }
  /* Their divider between the title and the share arrow. */
  #app .pdp-share { border-left: 1px solid var(--line); border-radius: 0; width: 44px; }
  #app .pdp-title-meta { margin-top: 4px; font-size: 13px; }

  /* ---- 2. deliver / customization / protection ----------------------- */
  .pdp-m-sections { display: block; margin-top: 14px; }
  .pdp-m-head {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    width: 100%; min-height: 32px; padding: 0; margin: 0 0 8px;
    background: none; border: 0; text-align: left;
    color: var(--ink); text-decoration: none;
  }
  .pdp-m-head b { font: 700 17px/1.3 var(--body); }
  .pdp-m-head u { text-underline-offset: 3px; }
  .pdp-m-head .icon { width: 18px; height: 18px; flex: none; color: var(--gray); }
  .pdp-m-line {
    display: flex; align-items: center; flex-wrap: wrap; gap: 7px;
    margin: 6px 0; font-size: 14px; color: var(--ink);
  }
  .pdp-m-line .icon { width: 19px; height: 19px; color: var(--gray); flex: none; }
  .pdp-m-box {
    margin-top: 10px; padding: 12px 14px;
    background: var(--canvas); border-radius: 10px;
  }
  .pdp-m-box p { margin: 3px 0; font-size: 13.5px; color: var(--gray); }
  .pdp-m-box b { color: var(--ink); margin-right: 6px; }
  .pdp-m-link {
    margin-top: 6px; padding: 0; min-height: 32px; background: none; border: 0;
    color: var(--ink); font-size: 13px; text-decoration: underline; text-underline-offset: 3px;
  }
  .pdp-m-checks { list-style: none; margin: 0; padding: 0; }
  .pdp-m-checks li {
    display: flex; align-items: center; gap: 9px;
    min-height: 34px; font-size: 14.5px; color: var(--ink);
  }
  .pdp-m-checks .icon {
    width: 18px; height: 18px; flex: none; padding: 2px;
    border: 1.5px solid var(--gray); border-radius: 50%; color: var(--gray);
  }
  .pdp-m-logos { display: inline-flex; gap: 5px; flex-wrap: wrap; }
  .pdp-m-logos img {
    height: 18px; width: auto; padding: 2px 4px;
    border: 1px solid var(--line); border-radius: 3px; background: #fff;
  }
  .pdp-m-note { font-size: 12.5px; line-height: 1.5; color: var(--gray); margin: 8px 0 0; }

  /* ---- 3. key attributes: grey 2-column grid, value over label -------- */
  #app #pdp-attributes .attr-table.paired,
  #app #pdp-attributes .attr-table.paired tbody {
    display: block; width: 100%; border: 0;
  }
  #app #pdp-attributes .attr-table.paired tbody {
    background: var(--canvas); border-radius: 10px; padding: 6px 0;
  }
  #app #pdp-attributes .attr-table.paired tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "v1 v2" "l1 l2";
    padding: 8px 0;
    border: 0;
  }
  #app #pdp-attributes .attr-table.paired tr > * {
    display: block; border: 0; background: none;
    padding: 0 16px; text-align: left; min-width: 0;
    overflow-wrap: anywhere;
  }
  #app #pdp-attributes .attr-table.paired tr > :nth-child(1) { grid-area: l1; }
  #app #pdp-attributes .attr-table.paired tr > :nth-child(2) { grid-area: v1; }
  #app #pdp-attributes .attr-table.paired tr > :nth-child(3) { grid-area: l2; border-left: 1px solid var(--line); }
  #app #pdp-attributes .attr-table.paired tr > :nth-child(4) { grid-area: v2; border-left: 1px solid var(--line); }
  #app #pdp-attributes .attr-table.paired td { font: 650 15px/1.35 var(--body); color: var(--ink); }
  #app #pdp-attributes .attr-table.paired th { font: 400 13px/1.4 var(--body); color: var(--gray); margin-top: 2px; }

  /* ---- 4. store reviews ---------------------------------------------- */
  #app #pdp-reviews .pdp-rev-tabs,
  #app #pdp-reviews .pdp-rev-filters { display: none; }
  #app #pdp-reviews .pdp-rev-summary {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px;
    padding: 0; background: none; border: 0;
  }
  #app #pdp-reviews .pdp-rev-score {
    flex: 1 1 100%; display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  }
  #app #pdp-reviews .pdp-rev-score > b { font: 400 34px/1 var(--body); }
  #app #pdp-reviews .pdp-rev-score > span { font-size: 13px; color: var(--gray); flex: 1 1 100%; }
  #app #pdp-reviews .pdp-rev-sub { display: inline-flex; gap: 6px; align-items: baseline; font-size: 14px; }
  #app #pdp-reviews .pdp-rev-sub b { font-size: 17px; }
  .pdp-rev-verified {
    flex: 1 1 100%; display: flex; align-items: center; gap: 6px;
    margin: 4px 0 0; font-size: 14px; color: var(--green);
  }
  .pdp-rev-verified .icon { width: 17px; height: 17px; }
  /* Their block shows one review and a chevron to the rest; two is the most a
     phone section should carry before it becomes a page of its own. */
  #app #pdp-reviews .pdp-review:nth-child(n+3) { display: none; }
  #app #pdp-reviews .pdp-review { padding: 12px 0 0; border: 0; }
  .pdp-review-flag { margin-left: 4px; }

  /* ---- 5. supplier card ---------------------------------------------- */
  .pdp-sup-m { display: block; }
  .pdp-sup-m-top { display: flex; gap: 12px; align-items: flex-start; }
  .pdp-sup-m .store-logo,
  .pdp-sup-m .store-logo.has-img {
    flex: none; width: 72px; height: 72px;
    border: 1px solid var(--line); border-radius: 10px; background: #fff;
  }
  .pdp-sup-m .store-logo.has-img img { width: 100%; height: 100%; object-fit: contain; padding: 6px; }
  .pdp-sup-m-id { min-width: 0; }
  .pdp-sup-m-name {
    display: block; font: 700 16px/1.3 var(--body); color: var(--ink);
    text-decoration: underline; text-underline-offset: 3px;
  }
  .pdp-sup-m-id p {
    display: flex; align-items: center; gap: 5px;
    margin: 4px 0 0; font-size: 13.5px; color: var(--gray);
  }
  .pdp-sup-m-id .icon { width: 15px; height: 15px; }
  .pdp-sup-m-ver { display: inline-flex; align-items: center; gap: 3px; color: var(--violet); font-weight: 650; }
  .pdp-sup-m-over {
    margin-top: 14px; padding: 14px 16px;
    background: var(--canvas); border-radius: 12px;
  }
  .pdp-sup-m-over > b { display: block; font-size: 15px; margin-bottom: 8px; }
  .pdp-sup-m-over > div { display: flex; flex-wrap: wrap; gap: 8px 26px; }
  .pdp-sup-m-over span { display: flex; flex-direction: column; }
  .pdp-sup-m-over strong { font-size: 18px; }
  .pdp-sup-m-over small { font-size: 12px; color: var(--gray); }
  .pdp-sup-m-ctas { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
  .pdp-sup-m-ctas .btn {
    min-height: 46px; border: 1.5px solid var(--ink); color: var(--ink);
    border-radius: 24px; font-weight: 700; background: #fff;
  }

  /* ---- 6. recommendation rails: horizontal, picture + price + MOQ ---- */
  #app .pdp-rec .section-head {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    margin-bottom: 10px;
  }
  #app .pdp-rec .section-head small { display: none; }
  #app .pdp-rec .section-head .text-link { font-size: 0; min-height: 32px; }
  #app .pdp-rec .section-head .text-link .icon { width: 18px; height: 18px; font-size: 14px; }
  #app .pdp-rec-row {
    display: flex; gap: 8px;
    overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    margin: 0 -16px; padding: 0 16px;
    scroll-snap-type: x proximity;
  }
  #app .pdp-rec-row::-webkit-scrollbar { display: none; }
  #app .pdp-rec-card {
    flex: 0 0 124px; min-width: 0;
    display: flex; flex-direction: column; gap: 3px;
    padding: 0; border: 0; background: none; scroll-snap-align: start;
  }
  #app .pdp-rec-card img {
    width: 124px; height: 124px; object-fit: cover;
    border-radius: 8px; background: var(--canvas);
  }
  #app .pdp-rec-card > b,
  #app .pdp-rec-card .pdp-rec-guarantee { display: none; }
  #app .pdp-rec-card .pdp-rec-price { font: 750 16px/1.2 var(--body); margin-top: 4px; }
  #app .pdp-rec-card .pdp-rec-price.onrequest { font-size: 13px; }
  #app .pdp-rec-card small { font-size: 12px; color: var(--gray); }
  #app .pdp-rec-card .pdp-rec-off { font-size: 11.5px; }

  /* ---- 7. Overview / Details / Recommended ---------------------------- */
  .pdp-m-tabs {
    position: fixed;
    top: 56px; left: 0; right: 0;
    z-index: 44;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    height: 44px;
    background: #fff;
    border-bottom: 1px solid var(--line);
    transform: translateY(-100%);
    opacity: 0;
    pointer-events: none;
    transition: transform .2s ease, opacity .2s ease;
  }
  .pdp-m-tabs.is-shown { transform: none; opacity: 1; pointer-events: auto; }
  .pdp-m-tabs a {
    position: relative;
    display: flex; align-items: center; justify-content: center;
    font-size: 15px; color: var(--ink); text-decoration: none;
  }
  .pdp-m-tabs a.is-on { font-weight: 700; }
  .pdp-m-tabs a.is-on::after {
    content: ""; position: absolute; left: 22%; right: 22%; bottom: 0;
    height: 3px; border-radius: 2px; background: var(--ink);
  }
  /* The top bar sits above the tabs, so it must stack over them. */
  #app .pdp-topbar { z-index: 46; }
}
@media (prefers-reduced-motion: reduce) {
  .pdp-m-tabs, #app .pdp-title-more .icon { transition: none; }
}

/* Fixes from looking at the first render of the seven blocks. */
@media (max-width: 760px) {

  /* Supplier logo box rendered EMPTY for a supplier without a logo: the
     monogram fallback text was there but inherited nothing that made it
     visible at 72px. It now reads as a proper monogram tile. */
  .pdp-sup-m .store-logo:not(.has-img) {
    display: grid; place-items: center;
    background: var(--tint); color: var(--deep);
    font: 800 22px/1 var(--body); letter-spacing: .02em;
  }

  /* Rails: the first one started flush against the screen edge while the others
     sat on the 16px gutter. With scroll-snap and no scroll-padding, the snapport
     is the whole box, so the first card snapped to x=0 and dragged the row 16px
     left. scroll-padding makes the gutter part of the snap area. */
  #app .pdp-rec-row { scroll-padding: 0 16px; }
  /* The reference marketplace’s rail card is picture, price, minimum — nothing else. The struck
     price and "20% de descuento" wrapped to three lines in a 124px card. */
  #app .pdp-rec-card .pdp-rec-off { display: none; }
  #app .pdp-rec-card small { line-height: 1.3; }

  /* Reviews: score, stars and "Very satisfied" on one line, the three
     sub-scores on the next with the value inline, as in their block. */
  #app #pdp-reviews .pdp-rev-score { flex-wrap: wrap; row-gap: 4px; }
  #app #pdp-reviews .pdp-rev-score > b { font-size: 30px; }
  #app #pdp-reviews .pdp-rev-score .stars { display: inline-flex; }
  #app #pdp-reviews .pdp-rev-sub { flex-direction: row; gap: 5px; }
  #app #pdp-reviews .pdp-rev-sub span::after { content: ":"; }
  #app #pdp-reviews .pdp-review-head > div { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
  #app #pdp-reviews .pdp-review-head > div > b { flex: 1 1 100%; }
}

/* Measured: `.stars` is display:flex at 358px wide — a full-width row — so it
   could never sit beside the score. Sized to its content, it does. In a review
   head the order becomes the reference marketplace’s: stars, then the masked name, then the flag,
   on one line. */
@media (max-width: 760px) {
  #app #pdp-reviews .pdp-rev-score { align-items: center; }
  #app #pdp-reviews .pdp-rev-score > .stars { width: auto; flex: 0 0 auto; }
  #app #pdp-reviews .pdp-review-head > div {
    display: flex; flex-direction: row; flex-wrap: nowrap; align-items: center; gap: 6px;
  }
  #app #pdp-reviews .pdp-review-head > div > .stars { order: 0; width: auto; flex: 0 0 auto; }
  #app #pdp-reviews .pdp-review-head > div > b { order: 1; flex: 0 1 auto; font-weight: 500; color: var(--gray); }
  #app #pdp-reviews .pdp-review-head > div > b::before { content: "· "; }
  #app #pdp-reviews .pdp-review-head > div > .pdp-review-flag { order: 2; display: inline-flex; }
}

/* ---------------------------------------------------------------------------
   Inner pages: the search box was drawn ON TOP of the tabs.

   Giuliano, on /ai at 283px: "why does it look like this". Measured on seven
   pages (/ai /categories /custom /guaranteed /help /country /about): every
   non-home page renders a compact search box INSIDE the logo row, and the
   logo-row rule above pins that row to 46px. The box is ~100px tall, so it
   overflowed the row by 58px and landed on whatever came next — the tab strip.

   The row now grows: wordmark on the first line, the search box full width on
   the second. That is also the reference marketplace’s shape (their inner screens lead with the
   search bar) and it keeps the logo on top, which Giuliano asked for.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
  #app > header > .head-main {
    height: auto;
    min-height: 46px;
    flex-wrap: wrap;
    row-gap: 6px;
    padding-bottom: 8px;
  }
  #app > header > .head-main > .search-box.compact {
    order: 2;
    flex: 1 1 100%;
    width: 100%;
    max-width: none;
    margin: 0;
  }
  /* AI Mode is a chat: its composer IS the input, directly below. A second
     search field above it only pushes the conversation down. */
  #app:has(> .ai-console) > header > .head-main > .search-box { display: none; }

  /* The browse tabs on inner pages measured 72px — two rows at 283px. One
     scrolling row, the same as the home page. */
  #app .browse-strip .search-tabs {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    gap: 0;
  }
  #app .browse-strip .search-tabs::-webkit-scrollbar { display: none; }
  #app .browse-strip .search-tabs > a { flex: 0 0 auto; white-space: nowrap; }
}

/* Manufacturer names in the directory result header wrapped to three lines at
   283px ("Puebla Agroexportadora S.A. de C.V." in 157px), pushing the three
   action buttons below them. Two lines, then an ellipsis; the full name is on
   the profile one tap away. */
@media (max-width: 760px) {
  .factory-result-head h2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

/* ===========================================================================
   HOME + SEARCH, second frame-by-frame pass against the reference marketplace — 2026-09-18

   Measured before (390px, Spanish):
     home   quick actions 145px tall (theirs ~48), a 69px "Descubre tu próximo
            éxito" heading between the chips and the grid (theirs: none).
     search tab row ABOVE the top bar (theirs: bar, then tabs); Deep Search a
            70px bordered box (theirs a ~40px band); then a count + two
            buttons, a "Filtrar productos" box, a chip row and a sort row —
            four rows of furniture where they have ONE chip row.
     cards  photo inset 22px on a lavender plate, 128x158 inside a 173px
            card; theirs is edge to edge. Heart top-right where they keep a
            compare checkbox, and no "find similar" mark bottom-left.
   =========================================================================== */
.card-check, .card-similar, .compare-fab, .chip-filter { display: none; }
/* desktop keeps its toolbar 'More filters' button; this chip is the phone's only way in */
.results-chips .chip.chip-filter { display: none; }

@media (max-width: 760px) {
  /* --- quick actions: three even pills, icon left, label right ----------- */
  #app .welcome-strip-links > a,
  #app .welcome-strip-links > a > span { min-height: 0; }
  #app .welcome-strip-links > a {
    height: 52px;
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
    gap: 6px;
    padding: 6px 8px;
    text-align: left;
    font-size: 11.5px;
    line-height: 1.2;
    font-weight: 600;
  }
  #app .welcome-strip-links > a > .bico,
  #app .welcome-strip-links > a > .icon { width: 28px; height: 28px; flex: none; }
  #app .welcome-strip-links > a > span {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; min-width: 0;
  }
  #app .welcome-strip-inner { padding: 8px 0; }

  /* --- no section heading between the chips and the grid ----------------- */
  #app .home-main > .section-head { display: none; }

  /* --- search: one chip row, a thin band, nothing else above the grid ---- */
  #app .search-results .results-head,
  #app .search-results .results-layout > .filters,
  #app .search-results .results-toolbar,
  #app .search-results .results-chips > span { display: none; }
  #app .chip-filter {
    display: inline-flex; align-items: center; justify-content: center;
    flex: 0 0 auto; width: 44px; padding: 0; background: #fff;
  }
  #app .chip-filter .icon { width: 18px; height: 18px; margin: 0; }
  #app .search-results .results-chips { margin: 0 0 8px; padding: 0; }

  #app .search-results > .deep-panel {
    margin: 0 -16px 8px;
    border: 0; border-radius: 0;
    padding: 0 16px;
    background: linear-gradient(90deg, #efedff 0%, #f7f6ff 55%, #fff 100%);
  }
  #app .search-results > .deep-panel > summary {
    display: flex; align-items: center; gap: 6px;
    min-height: 44px; padding: 0;
    font-size: 17px; font-weight: 750; color: var(--violet);
  }
  #app .search-results > .deep-panel > summary > span {
    margin-left: auto; font-size: 12px; color: var(--gray);
  }
  #app .search-results > .deep-panel > summary > span::after { content: ' \2304'; }
  #app .search-results > .deep-panel[open] { padding-bottom: 10px; }

  /* --- product card: photo edge to edge, checkbox + find-similar -------- */
  #app .product-grid .product-card { position: relative; overflow: hidden; }
  #app .product-grid .product-photo {
    display: block; padding: 0; aspect-ratio: 1 / 1;
    background: #f4f4f6; border-radius: 0;
  }
  #app .product-grid .product-photo img {
    width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%;
    border-radius: 0; background: transparent;
  }
  #app .product-grid .save-btn { display: none; }
  #app .product-grid .card-check {
    display: grid; place-items: center;
    position: absolute; top: 8px; right: 8px; z-index: 2;
    width: 24px; height: 24px; min-height: 0; padding: 0;
    border: 1.5px solid #c9c9d2; border-radius: 6px;
    background: rgba(255,255,255,.92); color: transparent;
  }
  /* 24px drawn, 44px to the finger */
  #app .product-grid .card-check::before { content: ''; position: absolute; inset: -10px; }
  #app .product-grid .card-check .icon { width: 16px; height: 16px; stroke-width: 2.4; }
  #app .product-grid .card-check.is-on { background: var(--violet); border-color: var(--violet); color: #fff; }
  #app .product-grid .card-similar {
    display: grid; place-items: center;
    position: absolute; left: 8px; z-index: 2;
    /* bottom-left corner of the square photo, whatever the card width */
    top: calc(min(100%, (100vw - 42px) / 2) - 44px);
    width: 36px; height: 36px; border-radius: 50%;
    background: rgba(255,255,255,.94); color: var(--ink);
    box-shadow: 0 1px 4px rgba(20,20,40,.12);
  }
  #app .product-grid .card-similar .icon { width: 20px; height: 20px; }

  /* Their card copy: title, price, MOQ, "2 yrs · CN  Verified", the return
     promise. Origin and supplier name live on the product page. */
  #app .product-grid .product-copy > .country,
  #app .product-grid .product-copy > .card-supplier,
  #app .product-grid .product-copy > .card-foot { display: none; }
  #app .product-grid .product-copy { padding: 8px 10px 10px; }
  #app .product-grid .product-title { -webkit-line-clamp: 1; font-size: 14px; font-weight: 600; }

  /* the compare pill appears only once something is ticked */
  #app .compare-fab:not([hidden]) {
    display: inline-flex; align-items: center;
    position: fixed; z-index: 40; left: 50%; transform: translateX(-50%);
    bottom: calc(66px + env(safe-area-inset-bottom));
    height: 40px; padding: 0 18px; border-radius: 999px;
    background: var(--ink); color: #fff; font-weight: 650; font-size: 14px;
    box-shadow: 0 6px 18px rgba(0,0,0,.2);
  }
}

/* Home fold spacing: the hero kept its desktop 22px/34px padding, which on a
   phone was 56px of white between the logo, the tabs, the search pill and the
   quick actions. Theirs stacks them with ~8px between. */
@media (max-width: 760px) {
  /* style.css sets 22px/34px through #app:has(>.search-hero:not(...)) .search-hero,
     specificity (1,3,0) — this has to match it to win, being later. */
  #app:has(> .search-hero:not(.country-search-hero)) > .search-hero { padding: 2px 0 6px; }
  #app .home-main { padding-top: 8px; }
}
/* On home the logo row carries only the wordmark (the search sits in the hero
   below), so the 46px + 8px budget meant for "logo + wrapped search" left ~30px
   of white under the logo. */
@media (max-width: 760px) {
  #app:has(> .search-hero) > header > .head-main { min-height: 40px; padding-bottom: 0; }
}

/* The personalised rail + chip row are the PHONE home's fold (the reference marketplace’s app).
   Their styles live only in the phone media queries, so on a wide screen the
   rail rendered raw — its first photo at natural size, filling the page under
   the welcome strip. Desktop has its own panels for the same content. */
@media (min-width: 761px) {
  .home-fold { display: none; }
}

/* No configured sign-in provider → no buttons → no "OR" divider under nothing. */
.provider-stack:empty, .provider-stack:empty + .auth-or { display: none; }

/* ===========================================================================
   Home below the grid — "Pedir muestras" was 808px on a phone.

   An early rule forced .panel-duo to ONE column, so its two square photos
   stacked at 324px each (and were usually the same product — the newest
   listing is also the sample-ready one; app.js now picks a different one).
   the reference marketplace’s home never shows a panel that size while you scroll: everything
   below the fold is grid-cell sized. Two squares side by side, and a lone
   item (one top manufacturer) as a compact row instead of a full-width photo.
   =========================================================================== */
@media (max-width: 760px) {
  #app .home-panels { gap: 10px; }
  #app .home-panels .panel-card { padding: 12px 12px 10px; gap: 8px; }
  #app .home-panels .panel-card h3 { font-size: 15px; }
  #app .home-panels .panel-duo { grid-template-columns: 1fr 1fr; gap: 8px; }
  #app .home-panels .panel-duo img { object-position: 50% 18%; border-radius: 8px; }
  #app .home-panels .panel-duo span { font-size: 12px; margin-top: 5px; color: var(--ink); font-weight: 600; }
  #app .home-panels .panel-duo > a:only-child {
    grid-column: 1 / -1;
    display: grid; grid-template-columns: 88px 1fr; align-items: center; gap: 12px;
  }
  #app .home-panels .panel-duo > a:only-child span { margin: 0; font-size: 14px; }
}

/* ===========================================================================
   Phone home feed — grid-cell promos, endless grid, back-to-top (2026-09-18,
   from Giuliano's recording of the reference marketplace’s home scroll). See homeGrid() in app.js.
   =========================================================================== */
.grid-promo, .grid-more, .to-top { display: none; }
@media (max-width: 760px) {
  /* past the grid the reference marketplace has no panels — the cells below replace them */
  #app .home-main > .home-panels,
  #app .home-main > .promo-divider,
  #app .home-main > .promo-row,
  #app .home-main > .discovery-row,
  #app .home-main > .benefit-strip,
  #app .home-main > .supplier-banner { display: none; }

  #app .home-grid > .grid-promo {
    display: flex; flex-direction: column; overflow: hidden;
    border: 1px solid var(--line); border-radius: 12px; background: #fff;
    color: var(--ink); text-decoration: none;
  }
  #app .grid-promo .gp-shot { position: relative; display: block; aspect-ratio: 1 / 1; background: #f4f4f6; }
  #app .grid-promo .gp-shot img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%; display: block; }
  /* their "Recently viewed >" / "Worldwide Picks >" bar across the photo foot */
  #app .grid-promo .gp-shot em {
    position: absolute; left: 0; right: 0; bottom: 0;
    display: flex; align-items: center; justify-content: space-between;
    padding: 5px 10px; font-style: normal; font-size: 13px; font-weight: 700; color: #fff;
    background: linear-gradient(90deg, var(--deep), var(--violet));
  }
  #app .grid-promo .gp-shot em .icon { width: 14px; height: 14px; }
  #app .grid-promo .gp-copy { display: flex; flex-direction: column; gap: 3px; padding: 8px 10px 10px; }
  #app .grid-promo .gp-copy b { font-size: 15px; line-height: 1.2; }
  #app .grid-promo .gp-copy small {
    font-size: 12.5px; color: var(--gray); line-height: 1.3;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }

  /* campaign cell: the purple card with three thumbnails and a CTA */
  #app .home-grid > .grid-promo.gp-campaign {
    gap: 6px; padding: 14px 12px 12px; border: 0; color: #fff;
    background: linear-gradient(160deg, var(--violet) 0%, var(--deep) 100%);
  }
  #app .gp-campaign .gp-eyebrow { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; opacity: .85; }
  #app .gp-campaign > b { font-size: 26px; line-height: 1.05; font-family: var(--display); }
  #app .home-grid > .gp-campaign > small,
  #app .home-grid > .gp-campaign > .gp-eyebrow,
  #app .home-grid > .gp-campaign > b { color: #fff; }
  #app .gp-campaign > small { font-size: 12.5px; line-height: 1.3; opacity: .9; }
  #app .gp-campaign .gp-pics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; margin-top: auto; }
  #app .gp-campaign .gp-pics img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; object-position: 50% 20%; border-radius: 6px; background: #fff; }
  #app .gp-campaign .gp-cta {
    align-self: stretch; text-align: center; padding: 9px 0; border-radius: 999px;
    background: #fff; color: var(--deep); font-weight: 700; font-size: 14px;
  }

  /* the loader at the grid foot: our gear where theirs has a logo spinner */
  #app .grid-more {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    padding: 18px 0 8px; color: var(--gray); font-size: 13px;
  }
  #app .grid-more img { width: 22px; height: 22px; animation: ajawGearSpin 1s linear infinite; }
  @keyframes ajawGearSpin { to { transform: rotate(360deg); } }

  .to-top:not([hidden]) {
    display: grid; place-items: center;
    position: fixed; z-index: 45; right: 14px;
    bottom: calc(70px + env(safe-area-inset-bottom));
    width: 44px; height: 44px; border-radius: 50%; padding: 0;
    border: 1px solid var(--line); background: rgba(255,255,255,.96); color: var(--ink);
    box-shadow: 0 4px 14px rgba(20,20,40,.14);
  }
  .to-top .icon { width: 20px; height: 20px; }
}
@media (max-width: 760px) and (prefers-reduced-motion: reduce) {
  #app .grid-more img { animation: none; }
}

/* Footer accordion chevron drew as a bare "|" after each heading: a later,
   more specific summary rule reset the row to display:list-item, so the
   8x8 ::after chevron went inline and only its right border showed. */
@media (max-width: 760px) {
  #app footer .foot-sec > summary { display: flex; }
  #app footer .foot-sec > summary::after { display: block; flex: none; }
}

/* ===========================================================================
   Phone "Mi AJAW" hub (acctHub() in workspace.js) — the reference marketplace’s My the reference marketplace.
   Desktop keeps the dashboard; the phone gets the hub and loses the sidebar.
   =========================================================================== */
.acct-hub { display: none; }
@media (max-width: 760px) {
  #app .acct-hub { display: block; margin: 0 -16px; padding: 10px 12px 8px; background: #f4f4f7; }
  #app .work-shell:has(.acct-hub) > .work-nav,
  #app .acct-desk { display: none; }
  #app .work-shell:has(.acct-hub) { display: block; padding-top: 0; }

  .acct-hub .ah-top { display: flex; align-items: center; gap: 10px; padding: 4px 2px 12px; }
  .acct-hub .ah-avatar {
    flex: none; width: 44px; height: 44px; border-radius: 50%;
    display: grid; place-items: center; font-weight: 700; font-size: 18px;
    background: var(--tint); color: var(--violet);
  }
  .acct-hub .ah-who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .acct-hub .ah-who b { font-size: 17px; }
  .acct-hub .ah-who small { font-size: 12.5px; color: var(--gray); display: flex; align-items: center; gap: 4px; }
  .acct-hub .ah-who small .icon { width: 13px; height: 13px; }
  .acct-hub .ah-round { flex: none; width: 40px; height: 40px; display: grid; place-items: center; color: var(--ink); }
  .acct-hub .ah-round .icon { width: 22px; height: 22px; }

  .acct-hub .ah-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .acct-hub .ah-tile {
    display: flex; align-items: center; justify-content: space-between; gap: 4px;
    height: 54px; padding: 0 6px 0 10px; border-radius: 10px; background: #fff; color: var(--ink);
  }
  .acct-hub .ah-tile > span:first-child { display: flex; flex-direction: column; min-width: 0; }
  .acct-hub .ah-tile b { font-size: 13px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .acct-hub .ah-tile small { font-size: 11.5px; color: var(--gray); }
  .acct-hub .ah-tile img, .acct-hub .ah-thumb-empty {
    flex: none; width: 38px; height: 38px; border-radius: 6px; object-fit: cover; object-position: 50% 20%;
    background: #f1f0f7; display: grid; place-items: center; color: var(--violet);
  }
  .acct-hub .ah-thumb-empty .icon { width: 18px; height: 18px; }

  .acct-hub .ah-strip {
    display: flex; align-items: center; gap: 8px; margin-top: 8px; padding: 12px;
    border-radius: 10px; background: #fff; color: var(--ink); font-size: 13.5px;
  }
  .acct-hub .ah-strip > span { flex: 1; }
  .acct-hub .ah-strip b { color: var(--violet); font-weight: 650; }
  .acct-hub .ah-strip > .icon:first-child { color: var(--violet); width: 18px; height: 18px; }
  .acct-hub .ah-strip > .icon:last-child { width: 18px; height: 18px; }

  .acct-hub .ah-card { margin-top: 10px; padding: 12px 6px 10px; border-radius: 12px; background: #fff; }
  .acct-hub .ah-head { display: flex; align-items: center; justify-content: space-between; padding: 0 8px 8px; }
  .acct-hub .ah-head h2 { margin: 0; font-size: 17px; font-family: var(--body); font-weight: 700; }
  .acct-hub .ah-head a { display: inline-flex; align-items: center; gap: 2px; font-size: 12.5px; color: var(--gray); }
  .acct-hub .ah-head a .icon { width: 14px; height: 14px; }
  .acct-hub .ah-row { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .acct-hub .ah-row-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .acct-hub .ah-ico {
    display: flex; flex-direction: column; align-items: center; gap: 6px;
    min-height: 64px; padding: 4px 2px; color: var(--ink); text-align: center;
  }
  .acct-hub .ah-ico > span { position: relative; display: grid; place-items: center; }
  .acct-hub .ah-ico .icon { width: 24px; height: 24px; stroke-width: 1.5; }
  .acct-hub .ah-ico em {
    position: absolute; top: -6px; right: -10px; min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 999px; background: #e5322d; color: #fff; font-style: normal;
    font-size: 10px; font-weight: 700; line-height: 16px; text-align: center;
  }
  .acct-hub .ah-ico small { font-size: 11px; line-height: 1.2; color: var(--gray); }

  .acct-hub .ah-links { margin-top: 10px; border-radius: 12px; background: #fff; overflow: hidden; }
  .acct-hub .ah-links a { display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 12px; color: var(--ink); font-size: 14px; }
  .acct-hub .ah-links a + a { border-top: 1px solid var(--line); }
  .acct-hub .ah-links a > span { flex: 1; }
  .acct-hub .ah-links .icon { width: 18px; height: 18px; }

  .acct-hub .ah-inspired { margin-top: 14px; }
  .acct-hub .ah-inspired h2 { margin: 0 4px 8px; font-size: 17px; font-family: var(--body); font-weight: 700; }
  .acct-hub .ah-chips { display: flex; gap: 16px; overflow-x: auto; scrollbar-width: none; padding: 0 4px 8px; }
  .acct-hub .ah-chips a { flex: none; font-size: 14px; color: var(--gray); padding-bottom: 4px; }
  .acct-hub .ah-chips a.on { color: var(--ink); font-weight: 700; border-bottom: 2px solid var(--ink); }
  .acct-hub .product-grid { gap: 8px; }
}
@media (max-width: 760px) {
  /* "Favoritos" was cut to "Favorit…" beside a 38px thumbnail in a 114px tile */
  .acct-hub .ah-tile { padding: 0 5px 0 8px; }
  .acct-hub .ah-tile b { font-size: 12.5px; }
  .acct-hub .ah-tile img, .acct-hub .ah-thumb-empty { width: 32px; height: 32px; }
  /* My the reference marketplace has no search field; the logo row stays (a web property) */
  #app:has(.acct-hub) > header .search-box { display: none; }
}
@media (max-width: 760px) {
  #app:has(.acct-hub) > header > .head-main { min-height: 40px; padding-bottom: 0; }
}

/* The phone tab bar only exists on phones. It had no rule above 760px, so every
   desktop page printed "Home Guaranteed Messages Cart Account" as raw text
   under the footer. */
@media (min-width: 761px) { .tabbar { display: none !important; } }
