/* 🔴 THE `hidden` ATTRIBUTE MUST ALWAYS WIN.
   The browser implements it with `display: none`, which is the LOWEST-weight declaration
   there is: any rule of ours that sets `display` on the same element beats it, and then
   `hidden` stops hiding anything. It does not fail anywhere — the element simply stays
   put.

   It bit us three times in this same stylesheet:
     .cookie-notice   the cookie notice COULD NOT be closed. The button did work (the
                      server set the cookie), but the banner stayed, and on a phone that is
                      ~30% of the screen eaten on EVERY page.
     .btn-secondary   the link to the datasheet showed up on articles that had no datasheet
                      too.
     .modal           was already patched by hand further down — the sign that the pattern
                      repeats and it had to be fixed at the root.

   `!important` is justified here and almost nowhere else: `hidden` is an HTML assertion
   about whether the element exists for the user, not a style suggestion. It is what
   `normalize.css` has done for a decade. */
[hidden] { display: none !important; }

/* store_v1 — public catalogue.
   AI-AGENT: the visual identity comes from the catalogue the customer was already using: navy
   blue header, white cards over an almost-white background and the basket as a column on the
   right. Before changing colours, look at the screenshots of the original AppSheet in docs/. */

:root {
  /* AI-AGENT: these values come from the CSS of the site the customer uses TODAY
     (script.google.com/…/exec, copy in docs/brand/current_catalogue.css). NOT from the
     Index.html in the zip, which is an older version —it does not even have a basket— and
     carried a different gradient. When in doubt about a colour, read the live CSS; do not
     deduce it from a screenshot. */
  --navy: #0a2540;
  --navy-light: #13385f;
  --navy-soft: rgba(10, 37, 64, .55);
  --ink: #0a2540;
  --text-main: #1c2733;
  /* 🔴 THESE TWO WERE DARKENED BECAUSE THEY WERE UNREADABLE, and the number says it better than
     the eye. Over the grey `--bg` background they sat at 4.26 and 1.99 contrast, with the legible
     minimum at 4.5: the faint text was literally HALF of what is needed. It is used in per-unit
     prices, basket notes and form help — places where putting something unreadable is worse than
     putting nothing, because it takes the slot of the explanation.

     Now 5.38 and 4.62 over grey, and the hierarchy holds: main very dark, soft, faint. There is a
     test that measures this; if someone lightens them again, it fails. */
  --text-soft: #5b6675;
  --text-faint: #667080;
  --bg: #f4f6f8;
  --surface: #ffffff;
  --gray-mid: #e3e7ec;
  --border: #dbe1e8;
  --border-2: #dbe1e8;
  --success: #1f9254;
  --success-bg: #eaf7f0;
  --warning: #b26a00;
  --warning-bg: #fdf4e5;
  --error: #c62828;
  --error-bg: #fdecec;
  --sale: #c2410c; /* the «−X %» badge of the home strips (rc000377) */
  --shadow: 0 4px 18px rgba(10, 37, 64, .08);
  --shadow-2: 0 10px 30px rgba(10, 37, 64, .14);
  --radius: 11px;
  --radius-md: 11px;
  --radius-sm: 8px;
  --max-width: 1440px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* What the top bar measures, which is FIXED.
     🔴 Without this, anything that sticks on scroll sticks to the BROWSER edge and the bar covers
     it: the basket anchored at 22px and lost its top 57px —the title and the total— without
     anything failing. It is declared here and `.header-inner` respects it with a `min-height`, so
     the number is true and not a guess that drifts when a padding is touched. */
  --alto-cabecera: 79px;
}

* { box-sizing: border-box; }

html { font-size: 16px; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text-main);
  font-family: var(--font);
  line-height: 1.45;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* 🔴 A full-bleed section (`.blk.width-full`, Fase 2b) is 100vw wide. Without clipping the root, that is
     wider than the content whenever a vertical scrollbar is present and the browser shows a spurious
     horizontal scrollbar. `clip` (not `hidden`) prevents it WITHOUT creating a scroll container, so
     `position: sticky` (the topbar) keeps working and nested `overflow-x:auto` tables still scroll. */
  overflow-x: clip;
}

a { color: var(--navy-soft); text-decoration: none; }

/* ---------- Header ---------- */

.header-bar {
  /* 🔴 The gradient is built WITH THE BRAND VARIABLES. There used to be three hard-coded blues
     here —copied from the first customer's catalogue— and it was the most visible spot on the
     whole site: the colour was changed in Settings, everything changed except the top bar, and it
     looked as if the setting did not work. The two tones come from `/brand.css`. */
  background: linear-gradient(100deg, var(--navy) 0%, var(--navy-light) 100%);
  color: #fff;
  position: sticky;
  top: 0;
  z-index: 40;
}

.header-inner {
  /* Makes the value of `--alto-cabecera` TRUE: it is a minimum, so on mobile it keeps growing when
     the search box moves to its own line. */
  min-height: var(--alto-cabecera);
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 16px 32px;
  display: flex;
  align-items: center;
  gap: 18px;
  justify-content: space-between;
  flex-wrap: wrap;
}

/* Customer login: a discreet button on the right of the bar (over the dark gradient, hence
   currentColor = #fff). Only painted when the customer realm is on (see base.html). */
.account-toggle {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  color: #fff;
  background: rgba(255, 255, 255, .10);
}
.account-toggle:hover { background: rgba(255, 255, 255, .20); }

/* The LOGGED-IN customer's header uses the shared bar (`.topbar*`, `.user-dd`) from chrome.css,
   not its own menu: one design for the panel and the store. The search box and the basket live
   inside that bar; these rules only accommodate their size there. */
/* Placement «B» (rc000404): the search box is a child of the bar, centred between the links and the
   right-hand group, as wide as the room allows (up to the visitor header's width). The right group no
   longer pushes itself away with an auto margin — the box's own auto margins do the centring. Below
   1200px the account shrinks to its avatar to give the box room; below 980px (where chrome.css lets the
   bar wrap) it becomes three rows: brand + basket + account · the links · the search at full width. */
.topbar-store > .search-box { flex: 1 1 260px; max-width: 600px; min-width: 0; margin: 0 auto; }
.topbar-store > .search-box input { padding: 10px 18px 10px 42px; }
.topbar.topbar-store .topbar-right { margin-left: 0; flex: none; }
.topbar-store .topbar-nav { flex: none; flex-wrap: nowrap; }
@media (max-width: 1200px) {
  .topbar-store .user-info, .topbar-store .user-btn .chevron { display: none; }
}
@media (max-width: 980px) {
  .topbar-store .topbar-brand { order: 1; }
  .topbar.topbar-store .topbar-right { order: 2; width: auto; margin-left: auto; }
  .topbar-store .topbar-nav { order: 3; flex: 1 1 100%; flex-wrap: wrap; }
  .topbar-store > .search-box { order: 4; flex: 1 1 100%; max-width: none; margin: 0; }
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  color: #fff;
  text-decoration: none;
  /* 🔴 BEFORE: `flex: none`, that is, "never shrink". With zoom raised, the subtitle grows and
     pushes the bar off the screen. Now it can shrink, and the overflowing text is trimmed with an
     ellipsis: the brand is still recognisable and the bar does not break. */
  flex: 0 1 auto;
  min-width: 0;
}

/* The logo is single-colour, so it is painted with a mask: the same file works white over the
   header and blue over a light background. */
.brand-logo {
  /* 🔴 An IMAGE, not a CSS mask. The mask served to paint a single SVG white, and that
     only works with a single-colour logo: any given company's has whatever colours it
     has. That is why there are two files, one per background. */
  width: auto;
  max-width: 108px;
  height: 47px;
  display: block;
  object-fit: contain;
  object-position: left center;
}

/* The logo does NOT shrink: it is an image with its own proportions, and squashing it is worse
   than trimming text. The one that yields space is the subtitle beside it, which has an ellipsis
   for exactly that. */
.brand-logo { flex: none; }

.search-box {
  margin-left: auto;
  position: relative;
  /* 🔴 BEFORE: `width: min(430px, 42vw)`, AND THAT IS WHAT BROKE THE HEADER ON ZOOM.
     `vw` measures the VIEWPORT, and browser zoom does not change it: as the type is enlarged, the
     text grows and the slot does NOT, so the field becomes too small for its own content and the
     bar comes apart. Measured on a phone, `42vw` of 360px is 151px: a two-word search box.
     With `flex` the width is decided by the room left in the bar, which is what matters. */
  flex: 1 1 240px;
  max-width: 430px;
  min-width: 0;
}

.search-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  /* Light: this magnifier sits inside the search box, and the search box sits over the DARK bar.
     The `var(--text-faint)` that was here was overridden by a second rule further down. */
  color: rgba(255, 255, 255, .6);
  pointer-events: none;
}

.search-box input {
  width: 100%;
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 24px;
  padding: 9px 16px 9px 40px;
  font: inherit;
  font-size: 14.5px;
  background: rgba(255, 255, 255, .1);
  color: #fff;
}

.search-box input::placeholder { color: rgba(255, 255, 255, .55); }

.search-box input:focus {
  outline: none;
  background: rgba(255, 255, 255, .16);
  border-color: rgba(255, 255, 255, .34);
}

/* ---------- Filter bar ---------- */

.filter-bar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.filters {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 13px 26px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.filters-label {
  font-size: 12.5px;
  letter-spacing: .12em;
  color: var(--text-soft);
  font-weight: 600;
}

.filters select {
  appearance: none;
  border: 1px solid var(--border-2);
  border-radius: var(--radius-md);
  background: #fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%236b7684' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 12px center/11px;
  padding: 9px 34px 9px 14px;
  font: inherit;
  font-size: 14.5px;
  color: var(--text-main);
  min-width: 168px;
  cursor: pointer;
}

.filters select:focus { outline: 2px solid #9dbde0; outline-offset: 1px; }

.filters-clear {
  margin-left: auto;
  color: var(--ink);
  font-weight: 700;
  font-size: 14.5px;
  text-decoration: none;
}

/* 🔴 The line underneath was NOT `text-decoration`: it was a `border-bottom: 1px solid currentColor`,
   which looks the same. Out entirely — in a bar full of dropdowns it competed with them for
   attention while saying nothing.

   What responds to the mouse is the TONE, not a line. A line that appears and disappears moves the
   text half a pixel and it shows; a colour moves nothing. */
.filters-clear:hover { color: var(--accent, var(--navy-soft)); }

/* ---------- Page ---------- */

.page {
  flex: 1;
  max-width: var(--max-width);
  width: 100%;
  margin: 0 auto;
  padding: 26px;
  display: grid;
  /* One column: the basket is a drawer at every width (rc000380), so the products take the full width. */
  grid-template-columns: minmax(0, 1fr);
  gap: 26px;
  align-items: start;
}

.search-summary {
  margin: 0 0 16px;
  color: var(--text-soft);
  font-size: 14.5px;
}

.grid {
  display: grid;
  /* 🔴 `minmax(232px, 1fr)` ON ITS OWN OVERFLOWS THE PAGE, and it is the reason zoom "broke the
     layout". `232px` is a HARD minimum: when the available room drops below it —a narrow screen,
     or browser zoom, which reduces the width in CSS pixels— the column still measures 232px and
     spills off the side. A horizontal scrollbar appears and the whole page can be dragged.
     Measured at 360px with zoom 1.5: the page asked for 483px of width for 360 available.
     `min(232px, 100%)` says "232, or all there is if that is less", and is the right way to write
     a grid that shrinks. */
  grid-template-columns: repeat(auto-fill, minmax(min(232px, 100%), 1fr));
  gap: 20px;
}

/* ---------- Card ---------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: box-shadow .15s, transform .15s;
}

.card:hover { box-shadow: var(--shadow-2); transform: translateY(-4px); }

.card-image {
  border: 0;
  background: #f1f3f6;
  padding: 0;
  height: 205px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: zoom-in;
  width: 100%;
}

.card-image img {
  max-width: 86%;
  max-height: 86%;
  object-fit: contain;
  mix-blend-mode: multiply;
}

.no-image {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--text-faint);
  font-size: 13px;
}

.card-body {
  padding: 14px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  flex: 1;
}

.card-title { margin: 0; font-size: 16.5px; line-height: 1.25; min-height: 41px; }

.card-meta { margin: 0; display: flex; flex-direction: column; gap: 2px; }
.card-meta > div { display: flex; gap: 5px; font-size: 14px; line-height: 1.35; color: var(--text-soft); }
.card-meta dt { color: var(--ink); font-weight: 700; margin: 0; }
.card-meta dd { margin: 0; color: var(--text-soft); }

/* Availability on the card (Phase 4c). «Bajo pedido» goes in amber + its small note. */
.card-stock { margin: 6px 0 0; display: flex; flex-direction: column; gap: 1px; font-size: 14px; }
.card-stock-label { font-weight: 700; color: var(--ink); }
.card-stock-ask .card-stock-label { color: #b26a00; }
.card-stock-low .card-stock-label { color: #b26a00; }
.card-stock-note { font-size: 13px; color: var(--text-soft); }
/* 3-state availability dot before the label: green = in stock, amber = few units left, red = on request. */
.card-stock-label::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-right: 6px; vertical-align: middle; background: var(--text-soft); }
.card-stock-ok  .card-stock-label::before { background: #1f9d55; }
.card-stock-low .card-stock-label::before { background: #e2a400; }
.card-stock-ask .card-stock-label::before { background: #c0392b; }

.card-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
  /* `margin-top: auto` pins the price (and its divider line) to the BOTTOM of the card, so the line
     and the price line up across every card in a row regardless of how much availability text sits
     above (one-line «Stock 100+» vs «Bajo pedido» + its two-line note). The cards stretch to equal
     height in the grid, so the flexible gap absorbs the difference. */
  margin: auto 0 0;
  padding-top: 11px;
  border-top: 1px solid var(--border);
  font-size: 16px;
  font-weight: 700;
  color: var(--navy);
}

/* ---------- Product page (rc000130) ----------
   The dedicated product page reuses the catalogue's `.page` grid, and the same basket partial (a drawer
   since rc000380, out of the grid's flow). `.product-column` is the content side. Everything not-yet-built (stars, wishlist, social, brand block, variety
   dropdown, EAN, multiple images) is simply absent — Fase B will add varieties/variants. */
.product-column { display: flex; flex-direction: column; gap: 22px; min-width: 0; }

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  font-size: 14px;
  color: var(--text-soft);
}
.breadcrumb a { color: var(--text-soft); }
.breadcrumb a:hover { color: var(--navy); }
.breadcrumb [aria-current="page"] { color: var(--ink); font-weight: 600; }
.breadcrumb-sep { color: var(--text-faint); }

.product-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 28px;
  align-items: start;
}

/* Fase B: the gallery is a column — the boxed main image (pg-stage) + a thumbnail strip. When the
   product has no gallery markup (older single-image), the `no-image` placeholder sits here directly. */
.product-gallery { display: flex; flex-direction: column; gap: 12px; }
.pg-stage {
  position: relative;
  background: #f1f3f6;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  min-height: 320px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  overflow: hidden;
  cursor: zoom-in;
}
.product-photo { max-width: 100%; max-height: 460px; object-fit: contain; mix-blend-mode: multiply; }
.pg-zoom {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 38px;
  height: 38px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow);
}
.pg-zoom:hover { box-shadow: var(--shadow-2); }
.pg-thumbs { display: flex; gap: 10px; flex-wrap: wrap; }
.pg-thumb {
  width: 72px;
  height: 72px;
  padding: 6px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  background: #f1f3f6;
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
}
.pg-thumb img { max-width: 100%; max-height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.pg-thumb.is-active { border-color: var(--navy); box-shadow: 0 0 0 1px var(--navy); }

.pg-lightbox {
  position: fixed;
  inset: 0;
  height: 100dvh;
  background: rgba(6, 14, 24, .82);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 60;
}
.pg-lightbox[hidden] { display: none; }
/* The figure boxes the image so the close (×) and prev/next arrows sit ON the image area, not at the
   screen corners (operator). Images are square (normalized 1000×1000), so the figure hugs the image. */
.pg-lb-figure {
  position: relative;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 92%;
  max-height: 88dvh;
}
.pg-lb-figure img { max-width: 100%; max-height: 88dvh; object-fit: contain; border-radius: 8px; background: #fff; }
.pg-lb-close,
.pg-lb-nav {
  position: absolute;
  z-index: 2;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pg-lb-close:hover,
.pg-lb-nav:hover { background: rgba(0, 0, 0, .82); }
.pg-lb-close { top: 8px; right: 8px; width: 40px; height: 40px; font-size: 24px; }
.pg-lb-nav { top: 50%; transform: translateY(-50%); width: 44px; height: 44px; font-size: 30px; line-height: 1; }
.pg-lb-prev { left: 8px; }
.pg-lb-next { right: 8px; }

.product-info { display: flex; flex-direction: column; gap: 12px; }
.product-title { margin: 0; font-size: 25px; line-height: 1.2; color: var(--ink); }
.product-ref { margin: 0; font-size: 14px; color: var(--text-soft); }

/* This product carries a live discount (its tariff price is shown struck-through). It is NOT the
   generic «promotions» feature the reference mock-up showed — that is deferred. */
.product-promo {
  margin: 0;
  align-self: flex-start;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--warning);
  background: var(--warning-bg);
  padding: 3px 10px;
  border-radius: 999px;
}

.product-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
  margin: 4px 0 0;
}
.product-was { font-size: 17px; color: var(--text-faint); }
.product-now { font-size: 30px; font-weight: 800; color: var(--navy); }
.product-tax { margin: 0; font-size: 13.5px; color: var(--text-soft); }

.product-stock { margin: 4px 0 0; display: flex; flex-direction: column; gap: 1px; font-size: 14px; }
.product-stock .card-stock-label { font-weight: 700; color: var(--ink); }
.product-stock.card-stock-ask .card-stock-label { color: var(--warning); }
.product-stock.card-stock-low .card-stock-label { color: var(--warning); }
.product-stock .card-stock-note { font-size: 13px; color: var(--text-soft); }

/* No card chrome: the quantity + «Comprar» sit directly on the page, not in a white box
   (operator, rc000132). Just the flex layout that keeps the stepper and the button aligned. */
.product-buy {
  margin-top: 8px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
}
.product-add { flex: 1 1 auto; min-width: 140px; }
.product-detail { display: flex; flex-direction: column; gap: 4px; }
.product-section { padding-top: 4px; }
.product-section h2 { margin: 0 0 10px; font-size: 17px; color: var(--ink); }
/* Downloads sit right under the technical-data table; give them extra breathing room and a hairline
   divider so the list reads as its own block, not a continuation of the table (operator 2026-09-24). */
.product-documents { margin-top: 18px; padding-top: 20px; border-top: 1px solid var(--border); }
.product-desc { margin: 0; color: var(--text-main); line-height: 1.55; white-space: pre-line; }

.tech-table { width: 100%; border-collapse: collapse; font-size: 15px; }
.tech-table th,
.tech-table td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--border); vertical-align: top; }
.tech-table th { width: 34%; color: var(--text-soft); font-weight: 600; }
.tech-table td { color: var(--ink); }

@media (max-width: 720px) {
  .product-main { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .product-gallery { min-height: 240px; }
  .product-now { font-size: 26px; }
}

/* ---------- Stepper and buttons ---------- */

.stepper { display: flex; align-items: center; gap: 4px; }

.stepper button {
  width: 26px;
  height: 26px;
  border: 1px solid var(--border-2);
  background: #fff;
  border-radius: 6px;
  color: var(--text-soft);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}

.stepper button:hover { border-color: var(--navy-soft); color: var(--navy-soft); }

.stepper input {
  width: 34px;
  text-align: center;
  border: 1px solid transparent;
  border-radius: 6px;
  font: inherit;
  font-size: 14.5px;
  padding: 4px 0;
  background: transparent;
  color: var(--text-main);
}

.stepper input:focus { border-color: var(--border-2); outline: none; }

/* A button must not decide the width of its box: with large type, «Pedir oferta» widened the
   basket and with it the page. Let the text wrap before breaking the layout. */
.btn-primary,
.btn-secondary { max-width: 100%; overflow-wrap: anywhere; }

.btn-primary {
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--navy);
  color: #fff;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 7px 12px;
  cursor: pointer;
  transition: background .12s;
}

.btn-primary:hover { background: var(--navy-light); }
.btn-primary:disabled { background: #b9c2ce; cursor: not-allowed; }
/* The error page uses it on an <a>, which would otherwise come out underlined. */
a.btn-primary { display: inline-block; text-decoration: none; }

.btn-secondary {
  border: 1px solid var(--border-2);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 8px 16px;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}

.btn-secondary:hover { border-color: var(--navy-soft); }

.btn-block { width: 100%; }

/* ---------- Basket ----------
   rc000380 (operator chose proposal B of the basket mockup): ONE design at every width — a panel that
   slides in from the right, opened from the header's «Cesta» button (count + estimated total) or from
   the «Añadido a la cesta» notice. Before it was three: a 300px column on desktop (it took that width
   from the grid on every page, even empty), a bottom sheet on mobile and a drawer on the showcase home. */

.basket {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  /* Above the cookie notice (60): open, the panel's footer — «Finalizar pedido» — must not be covered. */
  z-index: 62;
  width: min(420px, 100%);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  box-shadow: -8px 0 30px rgba(10, 37, 64, .25);
  /* Off screen and out of the tab order while closed; `:target` opens it without JavaScript (the
     header button is a `#basket` link). */
  transform: translateX(100%);
  visibility: hidden;
  transition: transform .22s ease, visibility .22s;
}
body.basket-open .basket, .basket:target { transform: translateX(0); visibility: visible; }
/* The veil closes on a tap outside; the body paints it so as not to add one more element. */
body.basket-open::after { content: ""; position: fixed; inset: 0; z-index: 61; background: rgba(10, 37, 64, .38); }

.basket-head { display: flex; align-items: center; gap: 10px; min-width: 0; padding: 16px 18px; border-bottom: 1px solid var(--border); }
.basket-title { font-size: 17px; font-weight: 700; color: var(--ink); }
.basket-count { font-size: 13px; color: var(--text-soft); white-space: nowrap; }
.basket-close {
  flex: none; display: inline-flex; align-items: center; justify-content: center; margin-left: auto; width: 32px; height: 32px;
  border: 0; border-radius: 50%; background: var(--bg); color: var(--ink); font-size: 20px; line-height: 1; cursor: pointer;
}
.basket-close:hover { background: var(--gray-mid); }

.basket-lines { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 4px 18px; }
.basket-empty { display: grid; justify-items: center; gap: 8px; padding: 44px 10px; text-align: center; color: var(--text-soft); font-size: 14px; }
.basket-empty svg { width: 40px; height: 40px; color: var(--border); }
.basket-empty b { color: var(--ink); font-size: 15px; }

/* A line: thumbnail | name + line total | stepper, format and «Quitar» under the name. */
.basket-line { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 4px 12px; align-items: start; padding: 14px 0; border-top: 1px solid var(--border); }
.basket-line:first-child { border-top: 0; }
.basket-thumb {
  grid-row: span 2; width: 64px; height: 64px; display: flex; align-items: center; justify-content: center; overflow: hidden;
  border: 1px solid var(--border); border-radius: 9px; background: #f1f3f6;
}
.basket-thumb img { max-width: 100%; max-height: 100%; object-fit: contain; mix-blend-mode: multiply; }
.basket-name { font-size: 13.5px; font-weight: 600; line-height: 1.3; color: var(--ink); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.basket-line-total { font-weight: 700; color: var(--ink); text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.basket-line-total.ask { font-size: 12.5px; color: var(--warning); }
.basket-row2 { grid-column: 2 / 4; display: flex; align-items: center; gap: 10px; min-width: 0; }
.basket-detail { min-width: 0; font-size: 12px; color: var(--text-soft); }
.basket-remove { flex: none; margin-left: auto; padding: 4px 2px; border: 0; background: none; color: var(--text-soft); font-size: 12.5px; cursor: pointer; }
.basket-remove:hover { color: var(--error); }

.basket-foot { display: grid; gap: 10px; padding: 14px 18px 18px; border-top: 1px solid var(--border); }
.basket-total { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 15px; }
.basket-total strong { font-size: 18px; color: var(--ink); font-variant-numeric: tabular-nums; }
.basket-ask { margin: -4px 0 0; font-size: 12.5px; color: var(--warning); }
.basket-actions { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: 8px; }
.basket-continue { padding: 11px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); font: inherit; font-size: 14px; font-weight: 600; cursor: pointer; }
.basket-continue:hover { border-color: var(--navy-soft); }
.basket-note { margin: 0; font-size: 12px; color: var(--text-faint); text-align: center; }

/* «Añadido a la cesta» notice (rc000380): under the header, right; «Ver cesta →» opens the panel. */
.basket-toast {
  position: fixed; top: calc(var(--alto-cabecera) + 12px); right: 16px; z-index: 58; display: flex; align-items: center; gap: 12px;
  max-width: min(400px, calc(100% - 32px)); padding: 10px 12px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface); box-shadow: var(--shadow); animation: basket-toast-in .25s ease;
}
.basket-toast.is-hiding { opacity: 0; transition: opacity .3s; }
.basket-toast-ok { flex: none; width: 26px; height: 26px; display: grid; place-items: center; border-radius: 50%; background: var(--success); color: #fff; }
.basket-toast-txt { min-width: 0; font-size: 13px; color: var(--text-soft); }
.basket-toast-txt b { display: block; overflow: hidden; color: var(--ink); white-space: nowrap; text-overflow: ellipsis; }
.basket-toast a { flex: none; color: var(--accent); font-size: 13px; font-weight: 700; text-decoration: none; }
@keyframes basket-toast-in { from { opacity: 0; transform: translateY(-8px); } }
.cart-toggle.bump { animation: cart-bump .4s ease; }
@keyframes cart-bump { 40% { transform: scale(1.08); } }
@media (prefers-reduced-motion: reduce) { .basket, .basket-toast, .cart-toggle.bump { transition: none; animation: none; } }

/* ---------- Paginator and empty state ---------- */

/* 🔑 The page control is a line with four things —«Anterior», «21–40 de 77 · página 1
   de 2», «Siguiente» and «Por página: 20 40 80»—, and on a narrow screen they do not fit. Without
   `flex-wrap` it does not break: it spills off the side and drags the whole page.
   Measured at 320px: it asked for 424px. */
.paginator {
  margin-top: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px 18px;
  color: var(--text-soft);
  font-size: 14px;
}

/* A fixed `margin-left: 14px` pushed the block out when the line was already tight. Once it can
   wrap, the gap is provided by the paginator's `gap`. */
.paginator-size { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 13px; color: var(--text-soft); }
.paginator-size a { padding: 2px 6px; border-radius: 5px; }
.paginator-size a.current { background: var(--navy); color: #fff; }

.paginator a {
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
  border: 1px solid var(--border-2);
  border-radius: 7px;
  padding: 7px 14px;
  background: #fff;
}

.empty {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 60px 20px;
  text-align: center;
  color: var(--text-soft);
}
.empty .btn-primary { margin-top: 6px; display: inline-block; }

/* ---------- Customer account pages (same design as the staff panel) ----------
   🔧 These components (card, def-list, status, two columns) are the panel's; here they are copied
   for the customer screens, which run on `public.css`. They were deliberately left OUT of
   `chrome.css`: there they would clash with `panel.css`'s definitions (which loads afterwards) and
   could change the look of the staff panel. Keep in line with panel.css. */
.page-simple { flex: 1; max-width: var(--max-width); width: 100%; margin: 0 auto; padding: 26px; }

/* The customer's own pages wear the panel's designs: «Presupuestos» / «Pedidos» its LISTING (rc000401) and
   one quote / one order its DETAIL page (rc000403). Both designs live in chrome.css (shared, moved verbatim
   from the panel); these lines only bring THIS shell to the panel's measures — the white page, its width,
   and the base table and paginator, which in this sheet are the catalogue's. Nothing here restyles a piece
   of either design: if it should change, it changes in chrome.css. */
body:has(.list-page, .detail) { background: var(--surface); }
.list-page { flex: 1; width: 100%; padding: 22px 24px 40px; }
.detail { flex: 1; width: 100%; max-width: 1360px; margin: 0 auto; padding: 24px 24px 44px; }
:is(.list-page, .detail) h1, :is(.list-page, .detail) h2 { color: var(--ink); }
:is(.list-page, .detail) .table { font-size: 14.5px; }
:is(.list-page, .detail) .table th { padding: 9px 12px; border-bottom: 1px solid var(--border); }
:is(.list-page, .detail) .table td { padding: 10px 12px; }
:is(.list-page, .detail) .table tbody tr:last-child td { border-bottom: 1px solid var(--border); }
:is(.list-page, .detail) .table tfoot td { border-top: 0; padding-top: 12px; }
:is(.list-page, .detail) .nowrap { white-space: nowrap; }
.detail .flat-cols h2 { margin: 0 0 12px; font-size: 22px; }
.detail .msg-ok, .detail .msg-error { margin-top: 16px; }
.list-page .paginator { justify-content: flex-start; margin-top: 16px; gap: 16px; }
.list-page .paginator > a { border: 0; padding: 0; background: none; }
.list-page .paginator-size { margin-left: auto; }
/* `:not(.current)`: the chosen size keeps its navy chip (a plain `background: none` here erased it and
   left white digits on a white page). */
.list-page .paginator-size a { border: 0; padding: 2px 6px; font-weight: 500; }
.list-page .paginator-size a:not(.current) { background: none; color: var(--text-soft); }
@media (max-width: 640px) {
  .list-page { padding: 18px 14px 32px; }
  .detail { padding: 18px 14px 36px; }
  .list-page .filters-admin input[type="search"] { min-width: 0; flex: 1 1 160px; }
}

.section-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 18px; }
.section-head h1 { margin: 0; font-size: 21px; color: var(--ink); }
.section-head .sub { margin: 0; color: var(--text-soft); font-size: 14.5px; }


.panel-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px 22px;
  margin-bottom: 20px;
}
.panel-card h2 { margin: 0 0 14px; font-size: 16.5px; color: var(--ink); }

.def-list > div { display: flex; justify-content: space-between; gap: 14px; padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 14.5px; }
.def-list > div:last-child { border-bottom: 0; }
.def-list dt { margin: 0; color: var(--text-soft); }
.def-list dd { margin: 0; text-align: right; }

.form-actions { display: flex; align-items: center; gap: 12px; margin-top: 16px; }
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
.form-grid .full-width { grid-column: 1 / -1; }

.msg-ok, .msg-error { border-radius: var(--radius); padding: 10px 14px; margin-bottom: 16px; font-size: 14.5px; }
.msg-ok { background: #eaf7f0; color: #1f7a44; border: 1px solid #bfe6cf; }
.msg-error { background: #fdecec; color: #b42318; border: 1px solid #f3c6c2; }

/* The 2FA components (.two-step, .totp-*, .backup-codes) live in chrome.css: they are shared by the
   customer account and staff «Mi perfil», and keeping them there stops them diverging between the two sheets. */

.muted { color: var(--text-soft); }
/* Help note under the «Mi cuenta» fields. Same rule as panel.css:279 (the customer catalogue does
   not load panel.css, so without this it came out as a full-size black paragraph). */
.help { margin: 5px 0 0; font-size: 12.5px; color: var(--text-faint); line-height: 1.45; }
.help + .help { margin-top: 8px; }
.price-ask { color: var(--text-soft); font-weight: 600; font-size: 16px; }
.btn-link { border: 0; background: none; padding: 0; font: inherit; font-weight: 600; color: var(--navy-soft, #1c4c7c); cursor: pointer; text-decoration: none; }
.btn-link:hover { text-decoration: underline; }
.btn-link-danger { color: #c62828; }
.section-head .btn-secondary, .section-head > a { margin-left: auto; }

/* Address blocks on the customer's pages. */
.addr-block { margin: 0; font-size: 14.5px; color: var(--text-main); line-height: 1.5; }
/* The billing address may hold a second line (line1\nline2 from registration): render the break. */
.addr-lines { white-space: pre-line; }

.status { display: inline-block; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 999px; white-space: nowrap; }
/* By TOKENS (not fixed hex): so a palette change reaches these pills too, just like in the panel
   (panel.css:219). They used to duplicate the colours and would have been left out of sync. */
.status-pending { background: var(--warning-bg); color: var(--warning); }
/* A new order / request, a draft, and one being worked on: the customer area paints them too
   (status-{{.StatusClass}}), and without these three the pill had no colour at all. */
.status-new { background: var(--success-bg); color: var(--success); }
.status-draft { background: #eef1f5; color: var(--text-soft); }
.status-in_progress { background: #eaf1fb; color: #1c4c7c; }
/* Order statuses in the customer area (Phase 4d): confirmed / delivered / cancelled. */
.status-accepted { background: var(--success-bg); color: var(--success); }
.status-closed { background: #eef1f5; color: var(--text-soft); }
.status-discarded { background: var(--error-bg); color: var(--error); }

/* CUSTOMER AREA tables (orders, lines). The panel has its own `.table`; this is the public site's,
   with the brand tokens. Customer tables used to come out UNSTYLED (they used a class that only
   existed in the panel) — hence the raw look. */
.table-wrap { overflow-x: auto; margin: 0 -6px; padding: 0 6px; }
.table { width: 100%; border-collapse: collapse; font-size: 15px; }
.table th {
  text-align: left;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-soft);
  font-weight: 700;
  padding: 11px 14px;
  border-bottom: 2px solid var(--border);
  white-space: nowrap;
}
.table td { padding: 13px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--bg); }
.table tfoot td { border-top: 2px solid var(--border); border-bottom: 0; padding-top: 13px; }
.table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.table a { color: var(--navy); font-weight: 700; text-decoration: none; }
.table a:hover { text-decoration: underline; }

/* Returns (RMA): return cards and the form's quantity input. */
.return-list { display: flex; flex-direction: column; gap: 12px; margin-bottom: 14px; }
.return-card { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 12px 14px; background: var(--bg); }
.return-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.return-lines { margin: 8px 0 0; padding-left: 18px; color: var(--text-soft); font-size: 14.5px; }
.qty-input { max-width: 90px; }

@media (max-width: 720px) {
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .page-simple { padding: 18px 14px; }
}

/* ---------- Modals ---------- */

/* 🔴 A `position: fixed; inset: 0` IS NOT THE SCREEN SEEN ON A PHONE.
   The mobile browser measures it against the LARGE viewport: the one there would be with the
   address bar hidden and no controls at the bottom. With the bars visible —which is how it is 90%
   of the time— the modal spills off the top and bottom, and what gets eaten is exactly the title
   and the send button. Reported in the quote request: it was covered by the URL on top and the
   controls at the bottom.

   🔑 `height: 100dvh` is the DYNAMIC viewport: what is visible NOW, with whatever bars there are. And
   it is its own fallback — a browser that does not understand `dvh` discards the line and keeps the
   usual `inset: 0`, which is exactly what it did before. There is nothing that can get worse.

   `env(safe-area-inset-*)` is the other half: on a phone with a notch or a gesture bar, the normal
   padding falls UNDER them. The `max()` keep the usual 22px where there are no notches. */
.modal {
  position: fixed;
  inset: 0;
  height: 100dvh;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding:
    max(22px, env(safe-area-inset-top))
    max(22px, env(safe-area-inset-right))
    max(22px, env(safe-area-inset-bottom))
    max(22px, env(safe-area-inset-left));
}

.modal[hidden] { display: none; }

.modal-backdrop { position: absolute; inset: 0; background: rgba(15, 30, 52, .55); }

.modal-box {
  position: relative;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: 0 26px 70px rgba(9, 20, 38, .38);
  width: min(580px, 100%);
  /* From the REAL height, not the large one: with `92vh` the box could be taller than the visible
     screen and the send button ended up below the browser controls, with no way to reach it. */
  max-height: 92dvh;
  overflow-y: auto;
  /* So the finger can scroll the box without dragging the page behind. */
  overscroll-behavior: contain;
}

.modal-narrow { width: min(560px, 100%); }
/* FORM modals of the customer's pages — «change password» and the shipping address, on «Mi cuenta» and in
   the checkout — with the panel's measures (rc000407, operator: «repasa los estilos…»). The base
   `.modal-box` has NO padding in this sheet, because the product and quote modals lay themselves out edge to
   edge; these two are a title over a plain form and were being drawn flush against the box, the title at
   the browser's default size, and «Guardar» at the storefront's compact 12.5px beside a larger «Cancelar».
   Scoped to `.modal-narrow`, which only these two use here (the PDF viewer is `.modal-wide`). */
.modal-narrow { padding: 24px; }
.modal-narrow h2 { margin: 0 0 16px; padding-right: 36px; font-size: 17px; line-height: 1.3; color: var(--ink); }
.modal-narrow .btn-primary, .modal-narrow .btn-secondary { font-size: 14.5px; padding: 9px 18px; border-radius: 8px; }
.modal-narrow .form-actions { margin-top: 18px; }
.modal-narrow .msg-error { margin: 0 0 12px; }
.modal-narrow .btn-block { margin-top: 14px; }
@media (max-width: 560px) { .modal-narrow { padding: 20px 16px; } }

.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  box-shadow: var(--shadow);
  color: var(--text-soft);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
}

.modal-close:hover { color: var(--text-main); }

/* ---------- Quote-request form ---------- */

.field { margin-bottom: 14px; }

.field label {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-main);
  margin-bottom: 5px;
}

.required { color: var(--error); }

/* `.co-coupon-row input` rides these rules: the discount-code box of the checkout is not inside a `.field`
   (it sits in a row with its «Aplicar» button) and was being drawn as a bare browser input (rc000407). */
.field input,
.field textarea,
.field select,
.co-coupon-row input {
  width: 100%;
  border: 1px solid var(--border-2);
  border-radius: 8px;
  padding: 9px 12px;
  font: inherit;
  font-size: 14.5px;
  color: var(--text-main);
  background: #fff;
}

.field input:focus,
.field textarea:focus,
.field select:focus,
.co-coupon-row input:focus { outline: none; border-color: var(--navy-soft); box-shadow: 0 0 0 3px rgba(29, 79, 134, .12); }

.field textarea { resize: vertical; }

.request-tick {
  width: 58px;
  height: 58px;
  margin: 0 auto;
  border-radius: 50%;
  background: #e8f6ee;
  color: var(--success);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ---------- Error page ---------- */

/* It had no styles of its own: a 404 came out as bare browser HTML. */
.page-error {
  flex: 1;
  max-width: 560px;
  margin: 0 auto;
  padding: 90px 26px;
  text-align: center;
}

.error-hint { color: var(--text-soft); font-size: 15px; margin-top: -6px; }
.error-code {
  margin: 0;
  font-size: 58px;
  font-weight: 800;
  line-height: 1;
  color: var(--gray-mid);
}

.page-error h1 { margin: 10px 0 6px; font-size: 22px; color: var(--ink); }
.page-error p { margin: 0 0 22px; color: var(--text-soft); }

/* ---------- Footer ---------- */

/* 🔴 THIS BLOCK WAS WRITTEN TWICE, here and under «Footer» 130 lines further down, with different
   `justify-content` and `gap`. The one below won by coming later, so half of what you read here did
   nothing: whoever came to adjust the footer touched these lines and nothing happened. Now it is
   just one. */
.footer-bar {
  padding: 16px 26px;
  border-top: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-faint);
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px 18px;
  flex-wrap: wrap;
}

/* ==== Site footer (rc000384): columns with the professional CTA + contact, over the bottom strip. ==== */
.site-footer { border-top: 1px solid var(--border); background: var(--surface); }
.site-footer-top {
  max-width: var(--max-width); margin: 0 auto; padding: 80px 26px 68px;
  display: grid; gap: 40px 44px; grid-template-columns: 1.4fr 1.2fr 1.3fr 1fr;
}
@media (max-width: 900px) { .site-footer-top { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .site-footer-top { grid-template-columns: 1fr; gap: 24px; } }
body.page-checkout .site-footer-top { display: none; } /* the checkout stays focused */
.ft-col h2 { margin: 0 0 12px; font-size: 13px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--ink); }
.ft-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 14px; color: var(--text-soft); }
.ft-col a { color: var(--text-soft); text-decoration: none; }
.ft-col a:hover { color: var(--ink); }
/* The house's own pages, under the shop links (rc000399): a rule, not a second heading. */
.ft-col ul.ft-pages { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.ft-pages a { overflow-wrap: anywhere; }
.ft-brand-link { display: inline-block; }
.ft-logo { height: 42px; width: auto; max-width: 160px; object-fit: contain; object-position: left center; }
.ft-name { font-size: 18px; font-weight: 800; color: var(--ink); }
.ft-tagline { margin: 12px 0 0; font-size: 13.5px; color: var(--text-soft); max-width: 36ch; }
.ft-pro p { margin: 0 0 14px; font-size: 14px; color: var(--text-soft); max-width: 34ch; }
/* The footer CTA is a proper button (the generic .btn-primary was tiny for a footer). 🔴 `color: #fff` is
   REQUIRED: the button is an <a> inside .ft-col, and `.ft-col a { color: var(--text-soft) }` (specificity
   0,1,1) otherwise beats `.btn-primary`'s white (0,1,0) → grey text on the navy button (rc000388 regression,
   fixed rc000389). The storefront is light-only, so no theme logic. */
.ft-pro .btn-primary {
  display: inline-block; margin-top: 6px; padding: 12px 22px; border-radius: 9px;
  font-size: 14.5px; font-weight: 700; text-decoration: none; color: #fff; transition: background .12s;
}
.ft-pro .btn-primary:hover { background: var(--navy-light); color: #fff; }
.ft-contact ul { gap: 7px; }
.ft-contact-name { color: var(--ink); font-weight: 600; }
.footer-bar { border-top: 1px solid var(--border); }

.footer-bar .heart { color: #e0245e; }
.footer-bar a { color: var(--text-soft); text-decoration: none; }
.footer-bar a:hover { color: var(--ink); }
.footer-sep { color: var(--border-2); }
.footer-version { font-variant-numeric: tabular-nums; }

/* ---------- Narrow screens ---------- */

/* ---------- The basket in the bar, and the collapsible filters ---------- */

/* The header's «Cesta» button (rc000380): at every width, with the units and — from tablet width up —
   the estimated total. It opens the basket panel; on a page without one it leads to /checkout. */
.cart-toggle {
  flex: none; display: inline-flex; align-items: center; gap: 8px; padding: 8px 13px; border-radius: 999px;
  background: rgba(255, 255, 255, .12); color: #fff; font-size: 14px; font-weight: 600; line-height: 1; white-space: nowrap; text-decoration: none;
}
.cart-toggle:hover { background: rgba(255, 255, 255, .2); }
.cart-toggle-count {
  min-width: 20px; height: 20px; padding: 0 6px; display: inline-grid; place-items: center; border-radius: 999px;
  background: #fff; color: var(--navy); font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
}
/* Empty does not shout: the number is still there for whoever looks, without demanding attention. */
.cart-toggle-count.is-empty { opacity: .6; }
.cart-toggle-total { font-weight: 800; font-variant-numeric: tabular-nums; }
body.page-checkout .cart-toggle { display: none; } /* the checkout IS the basket */
/* From 720px upwards the filters are open; on a phone they fold into a summary. */
.filters-summary { display: none; }

/* `<details>` with no visible `<summary>` must leave neither gap nor marker. */
.filters-drop > summary::-webkit-details-marker { display: none; }
.filters-drop > summary::marker { content: ""; }

@media (max-width: 720px) {
  .header-inner { flex-wrap: wrap; gap: 10px 12px; }
  .search-box { flex: 1 1 100%; max-width: none; margin-left: 0; order: 3; }

  .cart-toggle { margin-left: auto; }
  .cart-toggle-total { display: none; }

  /* ---- The filters, collapsed ---- */

  .filters-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 12px 16px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-main);
    cursor: pointer;
    list-style: none;
  }

  .filters-drop[open] .filters-summary svg { transform: rotate(180deg); }
  .filters-summary svg { transition: transform .15s ease; }

  /* One per row: two per row left «Proveedor (128)» cut in half, and the supplier's name is
     exactly what you have to read to choose it. */
  .filters { padding: 0 16px 14px; gap: 8px; }
  .filters select { flex: 1 1 100%; min-width: 0; }
  .filters-label { display: none; }
  .filters-clear { margin-left: 0; }

  .page { padding: 18px 14px; }

  /* ---- Pagination ---- */

  /* 18px of gap between «Anterior», the text and «Siguiente» pushed the block off the screen on a
     phone, and half a button ended up cut off by the edge. */
  .paginator {
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px 12px;
    margin-top: 20px;
  }
}

/* ---------- Sale by bag or box, and notices ---------- */

.per-pack {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-soft);
  margin-left: 3px;
}

.indicative-price {
  margin: 2px 0 0;
  font-size: 12px;
  color: #a7b2bf;
}

/* The notice ribbon goes OVER the image: it is the first thing you have to see about a
   discontinued product, even before its price. */
.card { position: relative; }

.notice-ribbon {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  background: #fdf4e5;
  border: 1px solid #f3ddb4;
  color: #8a5200;
  border-radius: 999px;
  padding: 3px 11px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  cursor: help;
}

/* ---------- Units in the basket ---------- */

.basket-stepper { flex: none; display: inline-flex; align-items: center; overflow: hidden; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); }
.basket-step { width: 30px; height: 30px; padding: 0; border: 0; background: transparent; color: var(--ink); font-size: 16px; line-height: 1; cursor: pointer; }
.basket-step:hover { background: var(--bg); }
.basket-qty { min-width: 30px; text-align: center; font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---------- Discount on the card ---------- */

.card-was {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-faint);
  text-decoration: line-through;
}

.card-off {
  font-size: 12px;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 999px;
  background: #e8f5ec;
  color: #1f7a44;
  white-space: nowrap;
}

/* ---------- Footer ---------- */

.footer-right { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }

@media (max-width: 640px) {
  .footer-bar {
    justify-content: center;
    text-align: center;
    /* It reads better in two centred blocks than in a line broken wherever it lands. */
    flex-direction: column;
    gap: 10px;
  }
  /* The separator dots are redundant once the links are spaced out: on a narrow screen they hung
     at the start of a line, like a stray bullet point. */
  .footer-sep { display: none; }
  .footer-right { justify-content: center; gap: 6px 14px; }
}

/* ---------- Legal pages ---------- */

.legal {
  max-width: 760px;
  margin: 0 auto;
  padding: 32px 20px 56px;
  color: var(--text-main);
  /* 🔴 WITHOUT THIS, THE LEGAL PAGE SPILLS OFF THE SCREEN ON A PHONE. Measured: 386px of width
     inside a 360 viewport.

     The `<body>` is a flex container (column, so the footer falls all the way down), and a flex
     item brings `min-width: auto`: it REFUSES to shrink below its minimum content. The minimum
     content of a paragraph is its longest word, and this text is written by each company in
     Settings → Legal pages: a long email address, a URL or a `store_session` is enough to push the
     whole block and make the horizontal scrollbar appear.

     🔑 `min-width: 0` gives it back permission to shrink, and `overflow-wrap` breaks that word
     instead of stretching the page. Both are needed: the first fixes the layout and the second
     keeps the text from being cut off at the edge. */
  min-width: 0;
  overflow-wrap: anywhere;
}

/* A table or a code block pasted in by whoever writes the policy cannot be wrapped: let THEM
   scroll, inside their box, instead of dragging the whole page. */
.legal table,
.legal pre { display: block; max-width: 100%; overflow-x: auto; }

.legal h1 { font-size: 24px; color: var(--navy); margin: 0 0 6px; }
.legal .legal-updated { color: var(--text-faint); font-size: 13.5px; margin: 0 0 26px; }
.legal h2 { font-size: 16px; color: var(--navy); margin: 26px 0 8px; }
.legal p, .legal li { font-size: 15px; line-height: 1.65; }
.legal ul { padding-left: 20px; }

.legal table { width: 100%; border-collapse: collapse; font-size: 14px; margin: 10px 0 4px; }
.legal th, .legal td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); vertical-align: top; }
.legal th { color: var(--text-soft); font-size: 12.5px; text-transform: uppercase; letter-spacing: .04em; }
.legal code { font-size: 13.5px; background: #f1f3f6; padding: 1px 5px; border-radius: 4px; }

/* ---------- The footer at the bottom, always ----------
   🔴 The body was already a flex column with `min-height:100vh`, but nothing inside it grew: with
   a short page —an error, the cookie policy, an empty search— the footer sat wherever the text
   ended, halfway up a screen full of background. Whatever the page's main block is has to take
   the leftover height.

   `100dvh` for phones, where `100vh` counts a browser bar that is not there and leaves the
   footer just below the fold; the `100vh` line stays in front of it for anything that does not
   understand the newer unit. */

body { min-height: 100vh; min-height: 100dvh; }

body > main,
body > .page,
body > .legal,
body > .content { flex: 1 0 auto; }

body > footer { flex: none; }

/* The honeypot: off screen, not `display:none`. Some programs skip whatever is hidden with
   display, and the whole point is for them to fill it in. */
.trap {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------- Address search ---------- */

.address-picker { position: relative; }

.address-suggest {
  position: absolute;
  z-index: 30;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  max-height: 240px;
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--border-2, #cfd6e0);
  border-radius: 8px;
  box-shadow: 0 10px 24px rgba(10, 37, 64, .16);
  padding: 4px;
}

.address-choice {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  background: none;
  padding: 8px 10px;
  border-radius: 6px;
  font: inherit;
  font-size: 14px;
  color: var(--text-main);
  cursor: pointer;
}

.address-choice:hover { background: #f1f4f8; color: var(--navy); }

.field-pair { display: grid; grid-template-columns: 1fr 1.4fr 1.2fr; gap: 10px; }

@media (max-width: 560px) {
  .field-pair { grid-template-columns: 1fr; }
}

/* ---------- Measurement notice ----------
   At the bottom and narrow: a notice that covers half the screen is what makes people press
   «aceptar» without reading it, and then the consent is worth nothing. */
.cookie-notice {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: 16px;
  max-width: 720px;
  margin: 0 auto;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
  padding: 15px 18px;
}

.cookie-text { flex: 1; min-width: 260px; font-size: 14px; line-height: 1.5; color: var(--text-main); }
.cookie-text a { color: var(--ink); }
.cookie-buttons { display: flex; gap: 8px; margin-left: auto; }
.cookie-buttons button { white-space: nowrap; }

@media (max-width: 560px) {
  .cookie-buttons { width: 100%; }
  .cookie-buttons button { flex: 1; }
}

/* ---------- Site pages ----------

   The look of the blocks lives HERE and not in what whoever lays out the page writes. That is the
   reason the editor is block-based: each block is laid out once, tested once at 320 px, and after
   that a page that breaks on a phone can no longer be published.

   🔴 And the technical reason: the CSP says `style-src 'self'`, so an inline style is DISCARDED. An
   editor that generated `style="..."` would give pages that look fine while editing and flat on the
   web, without a single error. */

.site-page {
  flex: 1;
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 26px 48px;
}

.site-page h1 { font-size: 30px; color: var(--navy); margin: 0 0 10px; line-height: 1.2; }
.site-page h2 { font-size: 21px; color: var(--navy); margin: 0 0 12px; }
.bl-body { color: var(--text-main); line-height: 1.65; font-size: 16px; }
.bl-body p { margin: 0 0 14px; }
.bl-body p:last-child { margin-bottom: 0; }

/* ---- Cover ---- */

.bl-cover {
  position: relative;
  margin: 0 -26px 32px;
  min-height: 260px;
  display: flex;
  align-items: center;
  background: var(--navy);
  overflow: hidden;
}

.bl-cover-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Dimmed: the headline goes on top and has to be readable over any photo they upload. */
  opacity: .45;
}

.bl-cover-text { position: relative; padding: 44px 26px; max-width: 720px; }
.bl-cover-text h1 { color: #fff; }
.bl-sub { color: #dbe4ef; font-size: 16px; margin: 0 0 18px; line-height: 1.5; }

/* ---- Text, data and separator ---- */

.bl-text, .bl-data { margin: 0 0 32px; max-width: 760px; }

.bl-data {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 22px;
}

.bl-separator { border: 0; border-top: 1px solid var(--border); margin: 32px 0; }

/* ---- Fase 1b/2b: per-section style (background band, alignment, width, spacing) ---- */

/* Spacing lives on the wrapper (Fase 2b), so every section shares the same vertical rhythm whatever it
   is; the inner block's own bottom margin is dropped and `.blk` provides the gap. opt_space tunes it. */
.blk { margin: 0 0 32px; }
.blk.space-compact  { margin-bottom: 16px; }
.blk.space-spacious { margin-bottom: 56px; }
.blk .blk-inner > * { margin-bottom: 0; }

.blk.align-center { text-align: center; }

/* Background band. The vertical padding scales with the spacing option. */
.blk.bg-light, .blk.bg-dark, .blk.bg-accent { padding: 36px 24px; border-radius: var(--radius); }
.blk.space-compact.bg-light, .blk.space-compact.bg-dark, .blk.space-compact.bg-accent { padding: 20px 24px; }
.blk.space-spacious.bg-light, .blk.space-spacious.bg-dark, .blk.space-spacious.bg-accent { padding: 56px 24px; }
.blk.bg-light { background: var(--surface); }
.blk.bg-dark { background: var(--navy); color: #fff; }
.blk.bg-accent { background: var(--accent); color: #fff; }
.blk.bg-dark h1, .blk.bg-dark h2, .blk.bg-dark h3,
.blk.bg-accent h1, .blk.bg-accent h2, .blk.bg-accent h3 { color: #fff; }

/* Width. normal (columna): as the rest of the page — the narrow inner caps apply. wide (ancha): the
   content fills the whole page column, dropping those caps. full (completa): the band bleeds to the
   VIEWPORT edges, and `.blk-inner` re-centers the content in the page column so the text stays readable.
   🔴 The full-bleed break-out needs `body { overflow-x: clip }` (see the body rule) or a vertical
   scrollbar makes 100vw spill into a spurious horizontal scrollbar. */
.blk.width-wide .bl-text, .blk.width-wide .bl-data, .blk.width-wide .bl-faq { max-width: none; }
/* Full-bleed via NEGATIVE MARGINS only — NOT `width: 100vw` (a vw width does not shrink with zoom and
   fails the mobile-CSS test). A block with auto width grows by its negative left/right margins, so these
   stretch it from the page column out to the viewport edges; `body { overflow-x: clip }` absorbs any
   sub-pixel spill. */
.blk.width-full {
  margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
  border-radius: 0;
}
.blk.width-full .blk-inner { max-width: var(--max-width); margin: 0 auto; padding: 0 26px; }

/* Fase 2: the product-page sections sit in the SAME page column as the home/content pages, so a
   normal-width section lines up with the product detail and a full-bleed one breaks out from the same
   reference (without this they spanned the whole body width, inconsistent with everywhere else). */
.product-sections { max-width: var(--max-width); margin: 0 auto; padding: 0 26px; }

/* ---- Fase 1a: richer section library (store personalization «A») ---- */

/* Hero: a smaller cousin of the cover, usable on any page. */
.bl-hero {
  position: relative; border-radius: 18px; overflow: hidden;
  /* rc000378 (mockup): navy → brand accent gradient instead of a flat navy panel. */
  background: linear-gradient(115deg, var(--navy) 0%, var(--accent) 75%); min-height: 240px;
  display: flex; align-items: center;
}
.bl-hero-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .5; }
.bl-hero-text { position: relative; padding: 40px 26px; max-width: 720px; }
.bl-hero-text h2 { color: #fff; margin: 0 0 10px; font-size: 28px; line-height: 1.2; text-wrap: balance; }
/* The navy primary button vanished on the navy hero (rc000375): light button, like the banner's. */
.bl-hero .btn-primary { background: #fff; color: var(--navy); margin-top: 8px; }

/* Call-to-action band. */
.bl-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  background: var(--accent); color: #fff; border-radius: var(--radius);
  padding: 24px 28px; margin: 0 0 32px;
}
.bl-banner-title { font-size: 20px; font-weight: 700; margin: 0; }
.bl-banner-sub { margin: 4px 0 0; opacity: .92; }
.bl-banner .btn-primary { background: #fff; color: var(--navy); }

/* Feature grid. */
.bl-features { margin: 0 0 32px; }
.bl-features > h2 { margin: 0 0 20px; }
.bl-features-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: 24px;
}
.bl-feature {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px 22px;
}
.bl-feature h3 { margin: 0 0 8px; }

/* Image + text, side by side (stacks on a phone). */
.bl-imagetext {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 28px; align-items: center; margin: 0 0 32px;
}
.bl-imagetext-img { width: 100%; height: auto; border-radius: var(--radius); }
.bl-imagetext-body h2 { margin: 0 0 12px; }

/* FAQ accordion. */
.bl-faq { margin: 0 0 32px; max-width: 760px; }
.bl-faq > h2 { margin: 0 0 16px; }
.bl-faq-item {
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 12px 16px; margin: 0 0 10px;
}
.bl-faq-item > summary { cursor: pointer; font-weight: 600; }
.bl-faq-item > .bl-body { margin-top: 10px; }

/* Testimonials. */
.bl-testimonials { margin: 0 0 32px; }
.bl-testimonials > h2 { margin: 0 0 20px; }
.bl-testimonials-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 24px;
}
.bl-testimonial {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 20px 22px; margin: 0;
}
.bl-testimonial blockquote { margin: 0; font-style: italic; line-height: 1.6; }
.bl-testimonial figcaption { margin-top: 12px; font-weight: 600; color: var(--accent); }

/* ---- Two columns ---- */

.bl-columns {
  display: grid;
  /* `min(340px, 100%)` and not plain `340px`: with a hard minimum, the grid overflows the page
     when it does not fit — the same bug the catalogue had before rc000064. */
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
  gap: 28px;
  margin: 0 0 32px;
}

/* ---- Gallery ---- */

.bl-gallery { margin: 0 0 32px; }

.bl-gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr));
  gap: 14px;
}

.bl-gallery-grid img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* ---- Call to action ---- */

.bl-cta {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 26px;
  margin: 0 0 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
}

.bl-cta-phrase { margin: 0; font-size: 18px; font-weight: 600; color: var(--navy); min-width: 0; }

@media (max-width: 720px) {
  .site-page { padding: 0 14px 36px; }
  .site-page h1 { font-size: 24px; }
  .bl-cover { margin: 0 -14px 24px; min-height: 200px; }
  .bl-cover-text { padding: 30px 14px; }
  .bl-cta { padding: 20px; }
}

/* An `#anchor` takes the browser to the window edge, where the fixed bar is, so the target ends
   up COVERED. `scroll-margin-top` tells it where to really stop. It is the same problem the basket
   had, in the other form it takes. */
[id] { scroll-margin-top: calc(var(--alto-cabecera) + 12px); }

/* ---------- The blocks when they go on the COVER ----------

   🔴 `.site-page` carries `flex: 1` because on a standalone page it is all there is and has to push
   the footer to the bottom. On the cover it is NOT alone: it shares a column with `.page`, and two
   siblings with `flex: 1` SPLIT the leftover height — the house-written band would stretch and the
   catalogue would shrink. It is cancelled here instead of removed from `.site-page`, which still needs it.

   🔑 The width and centring are inherited as they are, so whatever the house writes falls exactly
   over the same column as the filters and the cards. That is the only way for adding content not to
   throw the page off. */

.page-cover {
  flex: 0 0 auto;
  padding-top: 26px;
  padding-bottom: 0;
}

/* The top one breathes against the catalogue; the bottom one, against the footer. */
.page-cover:first-of-type { padding-bottom: 8px; }
.page-cover:last-of-type  { padding-bottom: 48px; }

/* ---------- A single card, to see it before publishing ----------

   🔑 This is only used in the panel's preview: a lone card, inside a frame. The rest of the sheet
   applies the same —that is the point of the preview— and here only the wrapper is adjusted.

   The width is fixed to that of ONE grid cell. Without it the card stretches to the whole frame and
   shows a shape it does not have in the catalogue: the name would fit on one line where on the web
   it takes two, and whoever looks will take as fine a text that is actually cut off. */

.card-standalone {
  background: var(--bg);
  padding: 18px;
  margin: 0;
  min-height: 100dvh;
}

.card-standalone .grid {
  /* A single column, the real width of a catalogue card. */
  grid-template-columns: min(300px, 100%);
  justify-content: center;
}

/* ---------- Product documents (Fase B) on the product page ---------- */
.doc-downloads { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.doc-download { display: inline-flex; align-items: center; gap: 8px; color: var(--navy); font-size: 15px; }
.doc-download:hover { text-decoration: underline; }
.doc-download svg { flex: none; color: var(--text-soft); }

/* ---------- Variety selector (Fase B) on the product page ---------- */
.product-variety { margin: 14px 0 4px; display: flex; flex-direction: column; gap: 6px; }
.product-variety-label { font-size: 14px; color: var(--text-soft); font-weight: 600; }
/* Variety switcher (operator 2026-10-02, same design as the panel): ‹ current ▾ › + a searchable list.
   The list is as wide as the switcher, which spans the product column — so no viewport units. */
.vsw { position: relative; display: flex; align-items: stretch; max-width: 460px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface); }
.vsw-step { display: flex; align-items: center; padding: 0 13px; font-size: 20px; line-height: 1;
  color: var(--navy); text-decoration: none; }
.vsw-step:first-child { border-right: 1px solid var(--border); }
.vsw-step:last-child { border-left: 1px solid var(--border); }
.vsw-step:not(.is-off):hover { background: var(--bg); }
.vsw-step.is-off { color: var(--border); pointer-events: none; }
.vsw-menu { flex: 1 1 auto; min-width: 0; }
.vsw-btn { display: flex; align-items: center; gap: 10px; padding: 10px 12px; cursor: pointer; list-style: none;
  color: var(--text-main); font-size: 16px; }
.vsw-btn::-webkit-details-marker { display: none; }
.vsw-btn:hover { background: var(--bg); }
.vsw-label { font-weight: 700; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vsw-pos { margin-left: auto; font-size: 12.5px; font-weight: 600; color: var(--navy); background: var(--bg);
  border-radius: 999px; padding: 1px 9px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.vsw-caret { color: var(--text-soft); font-size: 11px; }
.vsw-pop { position: absolute; left: -1px; right: -1px; top: calc(100% + 6px); z-index: 40; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: 0 14px 36px rgba(16, 33, 58, .18);
  overflow: hidden; }
.vsw-search { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--border); }
.vsw-search input { flex: 1; min-width: 0; font: inherit; font-size: 16px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 8px 10px; background: var(--surface); color: var(--text-main); }
.vsw-count { font-size: 12px; color: var(--text-soft); white-space: nowrap; font-variant-numeric: tabular-nums; }
.vsw-list { max-height: 320px; overflow-y: auto; }
.vsw-opt { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 12px; align-items: center;
  padding: 9px 14px; border-bottom: 1px solid var(--border); color: var(--text-main); text-decoration: none; font-size: 14.5px; }
.vsw-opt:hover, .vsw-opt:focus { background: var(--bg); outline: none; }
.vsw-opt.is-current { background: #eaf1fb; }
.vsw-o-main { display: flex; flex-direction: column; min-width: 0; }
.vsw-o-label { font-weight: 700; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vsw-o-ref { font-size: 12px; color: var(--text-soft); }
.vsw-o-price { font-weight: 700; color: var(--ink); white-space: nowrap; font-variant-numeric: tabular-nums; }
.vsw-o-stock { font-size: 12.5px; color: var(--text-soft); white-space: nowrap; }
.vsw-o-stock.is-ask { color: var(--warning); font-weight: 600; }
.vsw-empty { padding: 16px 14px; margin: 0; color: var(--text-soft); font-size: 14px; }

/* ---------- Checkout (Fase Checkout) ---------- */
/* (Base .co-steps rules removed — superseded by the Checkout v2 block below.) */

.co-note { color: var(--text-soft); font-size: 12.5px; margin: 6px 0 0; }

.co-actions { display: flex; justify-content: space-between; gap: 12px; margin-top: 16px; }
.co-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; align-items: start; }
@media (max-width: 760px) { .co-grid { grid-template-columns: 1fr; } }

/* «Ship to» choice of a signed-in customer (rc000406): the same option rows as the shipping methods, with
   room for two lines; the chosen one is tinted (`:has`, no JS needed for it). `.co-fixed` is the account's
   billing data, shown read only beside it — same box, no radio, not clickable. */
.co-choices { display: flex; flex-direction: column; gap: 8px; }
.co-choice { display: flex; align-items: flex-start; gap: 12px; padding: 11px 14px; border: 1px solid var(--border); border-radius: var(--radius); font-size: 14.5px; }
.co-choice:hover { border-color: var(--brand, #2b6cb0); }
.co-choice:has(input:checked) { border-color: var(--navy); background: #f3f7fc; }
.co-choice input { margin: 3px 0 0; flex: none; }
/* The radio, its label (the clickable body, taking the room) and — for a saved address — «Editar» at the
   end: a button cannot live inside the label, so the row is a box of three. */
.co-choice-body { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; cursor: pointer; }
.co-choice-edit { flex: none; font-size: 13.5px; }
.co-choice-body strong { color: var(--ink); }
.co-choice-body > span { display: block; color: var(--text-soft); font-size: 13.5px; }
.co-choice-body > .co-choice-tag { display: inline-block; margin-left: 6px; padding: 0 8px; border-radius: 999px; font-size: 11.5px; font-weight: 700;
  color: var(--success); background: var(--success-bg); vertical-align: 1px; }
.co-choice-help { margin: 8px 0 14px; }
.co-choice-help + [data-ship-other] { margin-top: 4px; }
.co-fixed { padding: 11px 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); font-size: 14.5px; overflow-wrap: anywhere; }
.co-fixed strong { display: block; color: var(--ink); }
.co-fixed > span { display: block; color: var(--text-soft); font-size: 13.5px; }
.co-ships { display: flex; flex-direction: column; gap: 8px; }
.co-ship { display: flex; align-items: center; gap: 12px; padding: 11px 14px; border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer; }
.co-ship:hover { border-color: var(--brand, #2b6cb0); }
.co-ship input { margin: 0; }
.co-ship-logo { width: 34px; height: 34px; object-fit: contain; border-radius: 6px; }
.co-ship-label { flex: 1; font-size: 14.5px; }
.co-ship-price { font-weight: 600; }
.co-pay { display: flex; align-items: center; gap: 10px; padding: 8px 0; font-size: 14.5px; }

.co-terms { display: flex; align-items: flex-start; gap: 10px; font-size: 14px; }
.co-terms input { margin-top: 3px; }

.co-done { text-align: center; }
.co-done .request-tick { color: #1f7a44; margin: 0 auto 8px; }
.co-bank { text-align: left; max-width: 420px; margin: 18px auto 0; padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-alt, #f9fafb); }
.co-bank h3 { margin: 0 0 6px; font-size: 15px; }
.co-bank-dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 14px; margin: 10px 0 0; font-size: 14px; }
.co-bank-dl dt { color: var(--text-soft); }
.co-bank-dl dd { margin: 0; text-align: right; }
.mono { font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; }

/* ---------- Checkout CESTA (rich cart, Fase Checkout) ---------- */
.co-steps { text-transform: uppercase; letter-spacing: .04em; font-weight: 700; }
.co-carttable-card { padding: 0; overflow: hidden; }
.co-carttable-wrap { overflow-x: auto; }
.co-carttable { width: 100%; border-collapse: collapse; font-size: 14px; }
.co-carttable thead th { text-align: left; font-size: 11.5px; letter-spacing: .04em; text-transform: uppercase; color: var(--text-soft); font-weight: 700; padding: 14px 12px; border-bottom: 2px solid var(--border); white-space: nowrap; }
.co-carttable th.num, .co-carttable td.num { text-align: right; }
.co-carttable tbody td { padding: 12px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.co-prod { display: flex; align-items: center; gap: 12px; min-width: 240px; }
.co-thumb { width: 46px; height: 34px; object-fit: contain; border-radius: 5px; background: #fff; border: 1px solid var(--border); flex: 0 0 auto; }
.co-thumb-empty { background: var(--surface-alt, #f4f4f5); }
.co-prod-info { display: flex; flex-direction: column; gap: 2px; }
.co-ref { font-size: 12px; font-weight: 700; color: var(--ink); }
.co-name { font-size: 13.5px; color: var(--text-main); }
.co-star { color: #e2a400; }
.co-dot { display: inline-block; width: 11px; height: 11px; border-radius: 50%; }
.co-dot-ok { background: #23a24a; }
.co-dot-ask { background: #e2a400; }
.co-min { color: var(--text-soft); }
.co-stepper { display: inline-flex; align-items: center; gap: 2px; border: 1px solid var(--border); border-radius: 999px; padding: 2px; }
.co-step { width: 26px; height: 26px; border: 0; background: var(--surface-alt, #f0f0f1); border-radius: 50%; cursor: pointer; font-size: 16px; line-height: 1; color: var(--ink); }
.co-step:hover { background: var(--border); }
.co-qtyval { min-width: 34px; text-align: center; font-weight: 600; }
.co-pvp s { color: #c0392b; }
.co-net { font-weight: 700; }
.co-ask { color: var(--text-soft); } /* «Precio a consultar» in place of the three amounts */
.co-trash { border: 0; background: transparent; cursor: pointer; font-size: 20px; line-height: 1; color: var(--text-soft); }
.co-trash:hover { color: #c0392b; }

.co-cart-foot { display: grid; grid-template-columns: 1fr minmax(0, 320px); gap: 20px; align-items: start; margin-top: 16px; }
@media (max-width: 760px) { .co-cart-foot { grid-template-columns: 1fr; } }
.co-freeship { font-weight: 700; color: var(--brand, #2b6cb0); margin: 0 0 4px; }
.co-freeship-ok { color: #23a24a; }
.co-legend-note { color: var(--text-soft); font-size: 12.5px; margin: 0 0 10px; }
.co-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 12px; color: var(--text-soft); }
.co-legend li { display: flex; align-items: center; gap: 6px; }
.co-totals { background: var(--surface-alt, #f7f8fa); border: 1px solid var(--border); border-radius: var(--radius); padding: 18px 20px; }
.co-tot-row { display: flex; justify-content: space-between; align-items: baseline; padding: 6px 0; font-size: 15px; }
.co-tot-net { border-bottom: 1px solid var(--border); padding-bottom: 8px; margin-bottom: 4px; }
.co-tot-grand { border-top: 2px solid var(--border); margin-top: 6px; padding-top: 10px; font-size: 18px; }
.co-actions-cart { justify-content: flex-end; gap: 10px; flex-wrap: wrap; }

/* ---------- Checkout v2: cleaner outer design (operator 2026-09-30) ---------- */
/* The steps bar is the page's header: centered, uppercase, connected by thin lines, the current one
   underlined in the shop's brand colour. The «Finalizar compra» h1 is kept for a11y but hidden. */
.checkout .section-head { flex-direction: column; align-items: center; gap: 0; margin-bottom: 22px; }
.checkout .section-head h1 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.co-steps { display: flex; align-items: center; justify-content: center; list-style: none; margin: 0 auto; padding: 0; flex-wrap: wrap; background: none; }
.co-steps li { display: flex; align-items: center; padding: 0; background: none; border-radius: 0; }
.co-steps li span { padding: 6px 4px; font-size: 15px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-soft); border-bottom: 3px solid transparent; }
.co-steps li.is-current span { color: var(--ink); border-bottom-color: var(--brand, #2b6cb0); }
.co-steps li.is-done span { color: var(--ink); }
.co-steps li:not(:last-child)::after { content: ""; width: 56px; max-width: 12vw; height: 2px; background: var(--border); margin: 0 16px; }

/* Flatter cart: the table sits on the page, no card border/shadow — thin rules only. */
.co-carttable-card { border: 0; box-shadow: none; background: none; border-radius: 0; margin-bottom: 10px; }
.co-carttable thead th { padding-top: 6px; }

/* Customer type selector + «same address» + pending shipping. */
.co-check { display: flex; align-items: center; gap: 8px; font-size: 14px; margin: 4px 0 12px; cursor: pointer; }
.co-pending { color: var(--text-soft); font-style: italic; }
.co-tot-note { color: var(--text-soft); font-size: 12px; margin: 8px 0 0; }

/* Checkout details: single-column form (operator 2026-09-30 — merged fiscal into contact). */
/* Details card is full width (holds Contact + Billing side by side). */
.co-detailscard .co-grid { align-items: start; }
.co-col { min-width: 0; }
.co-notes textarea { width: 100%; }
/* The NATIVE select arrow can't be moved (the browser pins it to the right edge). So we hide it
   (appearance:none) and draw our OWN chevron right next to the text: the box hugs its content (width:auto)
   and the custom arrow sits 10px from the right edge. Higher specificity than base `.field select`. */
.checkout .co-type-field select {
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  width: 100%; max-width: 300px; padding: 10px 32px 10px 12px; font-size: 15px;
  border: 1px solid var(--border); border-radius: var(--radius-sm, 6px); background-color: var(--surface); color: var(--text-main);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23555' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center; background-size: 14px 14px;
}

/* Checkout action buttons: uniform, comfortable size (operator 2026-09-30). */
.checkout .co-actions .btn-primary,
.checkout .co-actions .btn-secondary,
.checkout .co-actions-cart .btn-primary,
.checkout .co-actions-cart .btn-secondary {
  min-width: 150px; min-height: 46px; padding: 12px 24px; font-size: 15px; font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius, 8px);
}

/* Details: single column when there is no billing block (individual). */
.co-grid--single { grid-template-columns: 1fr; max-width: 640px; }
.co-type-field { padding-bottom: 14px; margin-bottom: 14px; border-bottom: 1px solid var(--border); }

/* Checkout: even, aligned field columns within each pair (operator 2026-09-30 «alinea los campos»). */
.co-details .field-pair { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.co-details .field-pair-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } /* the two delivery-contact fields */

/* Checkout mode choice: two big, obvious tiles (operator 2026-09-30 — must not be skippable). Not a
   card, and set well apart from the totals above it. */
.co-modecard { margin: 34px 0 8px; }
.co-modecard h2 { margin: 0 0 14px; text-align: center; }
.co-modes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 600px) { .co-modes { grid-template-columns: 1fr; } }
.co-mode { position: relative; display: flex; flex-direction: column; gap: 5px; padding: 16px 18px 16px 46px;
  border: 2px solid var(--border); border-radius: var(--radius, 10px); cursor: pointer; transition: border-color .12s, background .12s; }
.co-mode:hover { border-color: var(--brand, #2b6cb0); }
.co-mode input { position: absolute; left: 16px; top: 18px; margin: 0; width: 18px; height: 18px; accent-color: var(--brand, #2b6cb0); }
.co-mode.is-active { border-color: var(--brand, #2b6cb0); background: color-mix(in srgb, var(--brand, #2b6cb0) 7%, transparent); }
.co-mode-title { font-weight: 700; font-size: 16px; color: var(--ink); }
.co-mode-desc { font-size: 13px; color: var(--text-soft); line-height: 1.35; }

/* Checkout flat look (operator 2026-09-30): no cards, white sheet — the content column is white and the
   panel boxes lose their border/shadow/fill; headings + spacing separate the sections. */
body.page-checkout { background: var(--surface); }
.checkout.page-simple { background: transparent; border-radius: 0; box-shadow: none; }
.checkout .panel-card { background: transparent; border: 0; box-shadow: none; padding: 4px 0; margin-bottom: 22px; }
.checkout .panel-card:last-child { margin-bottom: 0; }
.checkout .co-detailscard, .checkout .co-carttable-card { padding: 0; }
.checkout .co-grid { gap: 20px 32px; }

/* Flat checkout, part 2 (operator 2026-09-30): the grey TOTALS box is flattened (plain right-aligned rows
   under a rule). The mode options KEEP a border — they are selectors and need definition (operator: «falta
   borde en los selectores»); only their fill is dropped, and the active one gets the brand border + tint. */
.checkout .co-totals { background: transparent; border: 0; padding: 0; }
.checkout .co-totals .co-tot-net { border-top: 1px solid var(--border); padding-top: 10px; }

/* Toast notifications (operator 2026-09-30): a coloured, slightly translucent card that floats at the
   top so a form error is not a black line nobody sees. Red = error, green = success. */
.co-toast { position: fixed; top: 18px; left: 50%; transform: translateX(-50%); z-index: 1000;
  display: flex; align-items: flex-start; gap: 12px; width: min(440px, calc(100vw - 32px));
  padding: 13px 16px; border-radius: 12px; color: #fff;
  box-shadow: 0 10px 30px rgba(0,0,0,.18); backdrop-filter: blur(14px) saturate(1.4); -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border: 1px solid rgba(255,255,255,.28); text-shadow: 0 1px 2px rgba(0,0,0,.35);
  animation: co-toast-in .22s ease-out; }
@keyframes co-toast-in { from { opacity: 0; transform: translate(-50%, -10px); } to { opacity: 1; transform: translate(-50%, 0); } }
.co-toast.is-hiding { opacity: 0; transform: translate(-50%, -10px); transition: opacity .3s, transform .3s; }
/* Clearly translucent (glassy) — you can see the page through it; the blur + saturate + text-shadow keep
   the white text crisp. */
.co-toast-error { background: rgba(200, 45, 55, .62); }
.co-toast-icon { flex: 0 0 auto; margin-top: 1px; }
.co-toast-body { display: flex; flex-direction: column; gap: 1px; }
.co-toast-title { font-weight: 700; font-size: 14.5px; }
.co-toast-msg { font-size: 13.5px; opacity: .95; line-height: 1.35; }

/* Standing note above the cart table (rc000419): what it says stays true while the page is open (the
   table shows part of the basket), so it is not a toast — those leave after 7 s. */
.co-cart-notice { margin: 0 0 14px; padding: 11px 14px; border: 1px solid #f3ddb4; border-radius: 10px;
  background: var(--warning-bg); color: #8a5200; font-size: 14px; line-height: 1.4; }

/* Checkout discount code (Fase 2). One coupon per order; «Apply» re-prices server-side. */
.co-coupon label { display: block; font-weight: 600; margin-bottom: 8px; }
.co-coupon-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.co-coupon-row input { flex: 1 1 12rem; min-width: 0; max-width: 360px; width: auto; text-transform: uppercase; letter-spacing: .04em; }
.co-coupon-row input::placeholder { text-transform: none; letter-spacing: 0; }
.co-coupon-err { margin: 8px 0 0; color: var(--danger, #b91c1c); font-size: 14px; }
.co-coupon-ok { margin: 8px 0 0; color: var(--brand, #166534); font-size: 14px; font-weight: 600; }
.co-tot-discount span { color: var(--brand, #166534); }

/* «Several varieties» badge on a catalogue card (a template with >1 published variety → open to choose). */

/* ==== Storefront home «propuesta A» (rc000373) ===================================================
   Category bar under the header, the «Categorías» block (mosaic of the featured categories + compact
   index of all), the «Ofertas» / «Novedades» strips and the SHOWCASE home (no grid; the basket is a
   drawer at every width). Category colours come from the shared `.tint-N` classes (chrome.css). */
.catbar { background: var(--surface); border-bottom: 1px solid var(--border); }
.catbar-in { max-width: var(--max-width); margin: 0 auto; padding: 0 20px; display: flex; gap: 2px; overflow-x: auto; scrollbar-width: thin; }
.catbar-link { display: inline-flex; align-items: center; gap: 8px; padding: 10px 12px; white-space: nowrap; font-size: 14px; font-weight: 600;
  color: var(--text-soft); text-decoration: none; border-bottom: 3px solid transparent; }
.catbar-link .cat-badge { width: 24px; height: 24px; padding: 4px; }
.catbar-link:hover { color: var(--ink); }
.catbar-link.on { color: var(--ink); border-bottom-color: var(--t); }

.bl-head { display: flex; align-items: baseline; gap: 12px; margin: 6px 0 14px; }
.bl-head h2 { margin: 0; }
.cat-mosaic { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: 150px; gap: 14px; }
@media (max-width: 780px) { .cat-mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 130px; } }
.cat-tile { position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; padding: 16px 18px;
  border-radius: 16px; background: var(--s); color: var(--t); text-decoration: none; transition: transform .15s; }
.cat-tile:hover { transform: translateY(-3px); }
.cat-tile.big { grid-column: span 2; grid-row: span 2; }
/* layoutMosaic shapes (rc000375): tiles that fill the free cells so the mosaic stays a rectangle. */
.cat-tile.wide { grid-column: span 2; }
.cat-tile.block { grid-column: span 2; grid-row: span 2; }
.cat-tile.full { grid-column: 1 / -1; }
.cat-tile-ic { width: 40px; height: 40px; position: relative; }
.cat-tile.big .cat-tile-ic { width: 64px; height: 64px; }
.cat-tile-ghost { position: absolute; right: -16px; bottom: -20px; width: 140px; height: 140px; opacity: .12; }
.cat-tile.big .cat-tile-ghost { width: 240px; height: 240px; right: -30px; bottom: -40px; }
.cat-tile-txt { position: relative; display: flex; flex-direction: column; min-width: 0; }
.cat-tile-name { font-size: 17px; font-weight: 700; color: var(--ink); line-height: 1.25; }
.cat-tile.big .cat-tile-name { font-size: 26px; }
.cat-tile-sub { font-size: 12.5px; color: var(--text-soft); margin-top: 2px; }
.cat-tile-fams { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.cat-tile-fams span { background: var(--surface); color: var(--ink); border-radius: 999px; padding: 4px 10px; font-size: 12.5px; font-weight: 600; }
.cat-tile-all { background: var(--gray-mid); color: var(--ink); justify-content: center; align-items: flex-start; gap: 4px; }
.cat-mosaic + .bl-head { margin-top: 28px; }
.bl-cats, .bl-strip { margin: 0 0 32px; }
.cat-index { display: flex; flex-wrap: wrap; gap: 8px; }
.cat-chip { display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px 6px 6px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); font-size: 14px; font-weight: 600; color: var(--ink); text-decoration: none; }
.cat-chip .cat-badge { border-radius: 999px; }
.cat-chip small { color: var(--text-soft); font-weight: 500; font-variant-numeric: tabular-nums; }
.cat-chip:hover { border-color: var(--t); }

/* Product strips: compact cards (mini-card, rc000377) in one row that scrolls sideways. */
.strip { display: grid; grid-auto-flow: column; grid-auto-columns: 200px; gap: 14px; overflow-x: auto;
  padding: 4px 2px 12px; scroll-snap-type: x proximity; }

/* SHOWCASE home: the blocks take the full width (the basket is the same drawer as everywhere). */
.page-showcase-main { display: block; padding: 0; }

/* Category page: breadcrumb + a SLIM one-line band (rc000382, operator «A»). The families moved into the
   filter bar's «Familia» dropdown, so the old tall band + «Familias» chip box are gone. */
.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 12px; font-size: 13.5px; color: var(--text-soft); }
.crumbs a { color: var(--accent); font-weight: 600; text-decoration: none; }
.crumbs [aria-current] { color: var(--ink); font-weight: 600; }
.cat-band { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 12px 16px; margin-bottom: 14px; border-radius: 12px;
  background: var(--s); color: var(--t); }
.cat-band-ic { width: 34px; height: 34px; flex: none; }
.cat-band-txt { min-width: 0; }
.cat-band-txt h1 { margin: 0; font-size: 20px; color: var(--ink); line-height: 1.1; }
.cat-band-tag, .cat-band-stats span { display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-soft); }
.cat-band-stats { margin-left: auto; display: flex; gap: 20px; text-align: right; }
.cat-band-stats b { display: block; font-size: 18px; color: var(--ink); font-variant-numeric: tabular-nums; line-height: 1; }

/* ==== Storefront «propuesta A», step 5 (rc000377): header, bar extras, section heads, compact cards ==== */
/* Header: the search box takes the CENTRE of the bar and grows with the room left (mockup); basket and
   account sit on the right with their labels from tablet width up. A phone keeps the search on its own line. */
.header-bar .search-box { flex: 1 1 320px; max-width: 640px; margin: 0 auto; }
.header-bar .search-box input { padding: 11px 18px 11px 42px; font-size: 15px; }
.hdr-label { display: none; }
@media (min-width: 721px) {
  .header-bar .account-toggle { width: auto; gap: 8px; padding: 0 14px; font-size: 14px; font-weight: 600; text-decoration: none; }
  .header-bar .hdr-label { display: inline; }
}
@media (max-width: 720px) {
  .header-bar .search-box { max-width: none; margin: 0; }
}

/* Category bar: «Todas las categorías» first, «Ofertas» / «Novedades» last. */
.catbar-all { color: var(--ink); font-weight: 700; }
.catbar-all .cat-ic { width: 18px; height: 18px; }
.catbar-extra.on { border-bottom-color: var(--accent); }

/* Section heads: title · tag · «more →» link on the right. */
.bl-head { flex-wrap: wrap; }
.bl-tag { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-soft); }
.bl-more { margin-left: auto; font-size: 14px; font-weight: 700; color: var(--accent); text-decoration: none; }
.bl-more:hover { color: var(--ink); }

/* Compact product card of the strips (mini-card). */
.mini-card { display: flex; flex-direction: column; gap: 6px; padding: 12px; border: 1px solid var(--border); border-radius: 14px;
  background: var(--surface); color: var(--ink); text-decoration: none; scroll-snap-align: start; transition: border-color .15s, transform .15s; }
.mini-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.mini-img { position: relative; display: grid; place-items: center; height: 130px; border-radius: 10px; background: var(--bg); overflow: hidden; }
.mini-img img { max-width: 100%; max-height: 100%; object-fit: contain; }
.mini-img .no-image { font-size: 12px; }
.mini-badge { position: absolute; top: 8px; left: 8px; border-radius: 6px; padding: 2px 7px; background: var(--sale); color: #fff;
  font-size: 11.5px; font-weight: 800; }
.mini-badge.new { background: var(--accent); }
.mini-name { font-size: 13.5px; font-weight: 600; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.mini-price { margin-top: auto; font-variant-numeric: tabular-nums; }
.mini-price s { margin-right: 6px; color: var(--text-soft); font-size: 12px; }
.mini-price b { font-size: 15px; }
.mini-price small { color: var(--text-soft); font-size: 12px; }
.mini-av { font-size: 12px; font-weight: 600; color: var(--success); }
.mini-av::before { content: "● "; }
.mini-av.ask, .mini-av.low { color: var(--warning); }

/* ==== Storefront «propuesta A», step 6 (rc000378): hero row with promos, values strip, pro + contact ==== */
.bl-hero-row { display: grid; gap: 14px; margin: 0 0 32px; }
.bl-hero-row.with-promos { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); }
@media (max-width: 780px) { .bl-hero-row.with-promos { grid-template-columns: minmax(0, 1fr); } }
.bl-hero-ghost { position: absolute; right: -30px; top: -20px; width: 260px; height: 260px; opacity: .14; color: #fff; pointer-events: none; }
.bl-hero-tag { display: inline-block; margin-bottom: 8px; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: #9ec7f5; }
.bl-hero-side { display: grid; gap: 14px; }
.bl-promo { display: flex; align-items: center; gap: 14px; padding: 18px 20px; border-radius: 18px; background: var(--s); color: var(--t); text-decoration: none; }
.bl-promo-ic { width: 46px; height: 46px; flex: none; }
.bl-promo b { display: block; font-size: 16px; color: var(--ink); }
.bl-promo small { font-size: 13px; color: var(--text-soft); }

.bl-values { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); margin: 0 0 32px;
  border: 1px solid var(--border); border-radius: 14px; background: var(--surface); }
.bl-value { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-left: 1px solid var(--border); }
.bl-value:first-child { border-left: 0; }
.bl-value-ic { width: 28px; height: 28px; flex: none; color: var(--accent); }
.bl-value b { display: block; font-size: 14px; color: var(--ink); }
.bl-value small { font-size: 12.5px; color: var(--text-soft); }
@media (max-width: 780px) {
  .bl-values { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bl-value { border-left: 0; border-top: 1px solid var(--border); }
  .bl-value:nth-child(-n+2) { border-top: 0; }
  .bl-value:nth-child(even) { border-left: 1px solid var(--border); }
}

/* ==== Category mega-menu (rc000390, operator chose mockup «A») ====
   A category with families opens a full-width panel under the bar: the category (icon, tint, figures, «see
   all») on the left, its families in columns on the right. The panel hangs off `.catbar` — NOT off the
   scrolling `.catbar-in`, which would clip it. catalogue.js opens it; `hidden` keeps it closed. */
.catbar { position: relative; }
.catbar-caret { width: 12px; height: 12px; flex: none; color: var(--text-faint); transition: transform .15s; }
.catbar-link.is-open { color: var(--ink); border-bottom-color: var(--t); }
.catbar-link.is-open .catbar-caret { transform: rotate(180deg); }
.mega {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 35; display: block;
  max-height: min(72dvh, 560px); overflow-y: auto; overscroll-behavior: contain;
  background: var(--surface); border-bottom: 1px solid var(--border); box-shadow: 0 18px 40px rgba(10, 37, 64, .16);
}
.mega[hidden] { display: none; }
.mega-in { max-width: var(--max-width); margin: 0 auto; display: grid; grid-template-columns: 260px minmax(0, 1fr); }
.mega-side { position: relative; overflow: hidden; display: flex; flex-direction: column; gap: 6px; padding: 22px 24px; background: var(--s); color: var(--t); }
.mega-ic { position: relative; width: 44px; height: 44px; }
.mega-ghost { position: absolute; right: -22px; bottom: -26px; width: 150px; height: 150px; opacity: .13; }
.mega-side b { position: relative; font-size: 19px; line-height: 1.15; color: var(--ink); }
.mega-side small { position: relative; font-size: 12.5px; color: var(--text-soft); }
.mega-side a { position: relative; margin-top: auto; padding-top: 14px; font-size: 13.5px; font-weight: 700; color: var(--ink); text-decoration: none; }
.mega-main { min-width: 0; padding: 18px 24px 22px; }
.mega-h { margin-bottom: 8px; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-soft); }
.mega-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr)); gap: 2px 18px; }
.mega-fam { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 8px 10px; border-radius: 8px;
  font-size: 14px; font-weight: 600; color: var(--ink); text-decoration: none; }
.mega-fam:hover, .mega-fam:focus-visible { background: var(--bg); }
.mega-fam small { color: var(--text-soft); font-weight: 500; font-variant-numeric: tabular-nums; }
.mega-more { color: var(--accent); }
@media (max-width: 720px) {
  .mega-in { grid-template-columns: minmax(0, 1fr); }
  .mega-side { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 14px 16px; }
  .mega-ghost { display: none; }
  .mega-ic { width: 30px; height: 30px; }
  .mega-side a { flex-basis: 100%; margin-top: 0; padding-top: 4px; }
  .mega-main { padding: 12px 16px 16px; }
}
@media (prefers-reduced-motion: reduce) { .catbar-caret { transition: none; } }
