
  .wa-fab {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 40;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 56px;
    padding: 0 20px 0 16px;
    border-radius: var(--fichi-radius-full);
    background: #25D366;
    /* Not white: white on WhatsApp green is 1.98:1. This ink measures 8.6:1. */
    color: #062E16;
    font-weight: 700;
    font-size: 15px;
    text-decoration: none;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
  }
  .wa-fab:hover { filter: brightness(0.95); }
  .wa-fab:focus-visible { outline: 3px solid var(--fichi-text-primary); outline-offset: 3px; }
  .wa-fab svg { width: 24px; height: 24px; }
  @media (max-width: 480px) { .wa-fab-label { display: none; } .wa-fab { padding: 0 16px; } }
  @media (prefers-reduced-motion: no-preference) { .wa-fab { transition: transform 0.15s; } .wa-fab:hover { transform: translateY(-1px); } }

  .cart-bar {
    position: fixed;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
    z-index: 62;
    width: min(560px, calc(100% - 24px));
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 8px 8px 6px;
    border-radius: var(--fichi-radius-full);
    background: var(--fichi-bg-elevated);
    border: 1px solid var(--fichi-border-subtle);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
  }
  .cart-bar[hidden] { display: none !important; }
  /* While the list is up it owns the corner. */
  body:has(.cart-bar:not([hidden])) .wa-fab { display: none; }
  .cart-open {
    display: flex;
    align-items: center;
    gap: 9px;
    flex: 1;
    min-width: 0;
    min-height: 44px;
    padding: 0 12px;
    border: 0;
    background: none;
    border-radius: var(--fichi-radius-full);
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--fichi-text-primary);
    cursor: pointer;
    text-align: left;
  }
  .cart-open .cart-n {
    min-width: 24px;
    padding: 2px 8px;
    border-radius: var(--fichi-radius-full);
    background: var(--store-accent);
    color: var(--store-accent-contrast);
    font-size: 13px;
    text-align: center;
  }
  .cart-send {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 18px;
    border-radius: var(--fichi-radius-full);
    background: #25D366;
    color: #06301A;
    font-size: 14px;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
  }
  .cart-panel {
    position: fixed;
    left: 50%;
    bottom: 78px;
    transform: translateX(-50%);
    z-index: 61;
    width: min(560px, calc(100% - 24px));
    max-height: 70dvh;
    display: flex;
    flex-direction: column;
    border-radius: var(--fichi-radius-xl);
    background: var(--fichi-bg-elevated);
    border: 1px solid var(--fichi-border-subtle);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
    overflow: hidden;
  }
  .cart-panel[hidden] { display: none !important; }
  .cart-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 10px 12px 20px;
    border-bottom: 1px solid var(--fichi-border-subtle);
    font-family: var(--fichi-font-display);
    font-size: 16px;
    font-weight: 700;
    color: var(--fichi-text-primary);
  }
  .cart-close {
    width: 44px; height: 44px;
    display: flex; align-items: center; justify-content: center;
    border: 0; background: none; color: var(--fichi-text-secondary); cursor: pointer;
  }
  .cart-items { list-style: none; margin: 0; padding: 6px 20px; overflow-y: auto; }
  .cart-items li {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--fichi-border-subtle);
  }
  .cart-items li:last-child { border-bottom: 0; }
  .cart-items .who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .cart-items .who b { font-size: 14px; font-weight: 600; color: var(--fichi-text-primary); }
  .cart-items .who span { font-size: 13px; color: var(--fichi-text-muted); font-variant-numeric: tabular-nums; }
  .cart-items .qty { display: flex; align-items: center; gap: 2px; }
  .cart-items .qty button {
    width: 34px; height: 34px;
    border-radius: var(--fichi-radius-md);
    border: 1px solid var(--fichi-border-subtle);
    background: var(--fichi-bg-surface);
    color: var(--fichi-text-primary);
    font: inherit; font-size: 16px; font-weight: 700; cursor: pointer;
  }
  .cart-items .qty output { min-width: 30px; text-align: center; font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
  .cart-foot { padding: 14px 20px calc(14px + env(safe-area-inset-bottom)); border-top: 1px solid var(--fichi-border-subtle); }
  .cart-total { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 12px; font-size: 14px; color: var(--fichi-text-secondary); }
  .cart-total strong { font-size: 19px; color: var(--fichi-text-primary); font-variant-numeric: tabular-nums; }
  .cart-foot .cart-send { display: flex; justify-content: center; }
  .cart-notice {
    margin: 0 0 10px;
    padding: 8px 10px;
    border-radius: var(--fichi-radius-md);
    background: var(--fichi-warning-bg);
    color: var(--fichi-warning-text);
    font-size: 12.5px;
    line-height: 1.45;
  }
  .cart-notice[hidden] { display: none !important; }
  .cart-zone { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; font-size: 14px; }
  .cart-zone select {
    min-height: 40px;
    padding: 0 10px;
    border: 1px solid var(--fichi-border-default);
    border-radius: var(--fichi-radius-md);
    background: var(--fichi-bg-page);
    color: var(--fichi-text-primary);
    font: inherit;
    font-size: 14px;
  }
  .cart-ship { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; font-size: 13.5px; color: var(--fichi-text-secondary); }
  /* The UA gives [hidden] display:none from its OWN stylesheet, which any
     author rule outranks — so the line above kept this row on screen while the
     script had marked it hidden, printing a bare "Envío" with no amount above
     every total. Four siblings already carry this guard; this one did not. */
  .cart-ship[hidden] { display: none !important; }
  .cart-address { display: block; margin-bottom: 12px; font-size: 14px; }
  .cart-address[hidden] { display: none !important; }
  .cart-address span { display: block; margin-bottom: 6px; }
  .cart-address textarea {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--fichi-border-default);
    border-radius: var(--fichi-radius-md);
    background: var(--fichi-bg-page);
    color: var(--fichi-text-primary);
    font: inherit;
    font-size: 14px;
    resize: vertical;
  }
  .cart-address textarea::placeholder { color: var(--fichi-text-muted); opacity: 1; }
  @media (max-width: 640px) {
    .cart-bar { bottom: 12px; }
    .cart-panel { bottom: 74px; max-height: 66dvh; }
    .cart-open .cart-word { display: none; }
  }

  .topbar {
    max-width: var(--store-content);
    margin: 0 auto;
    width: calc(100% - var(--store-inset));
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 0 4px;
  }
  .topbar .back {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--fichi-radius-full);
    background: var(--fichi-bg-surface);
    border: 1px solid var(--fichi-border-subtle);
    color: var(--fichi-text-primary);
    text-decoration: none;
    box-shadow: var(--fichi-shadow-sm);
    flex-shrink: 0;
  }
  .topbar .store-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--fichi-text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .collection-head {
    max-width: var(--store-content);
    margin: 12px auto 0;
    width: calc(100% - var(--store-inset));
  }
  .crumbs ol { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; padding: 0; list-style: none; font-size: 13px; color: var(--fichi-text-secondary); }
  .crumbs li > span { margin-right: 4px; }
  .crumbs a { color: var(--fichi-text-secondary); text-underline-offset: 3px; }
  .collection-head h1 {
    margin: 8px 0 0;
    font-family: var(--fichi-font-display);
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -0.5px;
    line-height: 1.2;
    color: var(--fichi-text-primary);
  }
  .subcats ul { display: flex; flex-wrap: wrap; gap: 8px; margin: 16px 0 0; padding: 0; list-style: none; }
  .subcats a {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 0 16px;
    border-radius: var(--fichi-radius-full);
    border: 1px solid var(--fichi-border-subtle);
    background: var(--fichi-bg-surface);
    color: var(--fichi-text-primary);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
  }
  .subcats a:hover { border-color: var(--store-accent); }

  .collection-banner {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 5;
    object-fit: cover;
    margin: 14px 0 0;
    border-radius: var(--fichi-radius-xl);
    background: var(--fichi-bg-surface);
  }
  .collection-desc {
    margin: 10px 0 0;
    max-width: 64ch;
    font-size: 15px;
    line-height: 1.6;
    color: var(--fichi-text-secondary);
    white-space: pre-line;
  }
  @media (max-width: 640px) {
    .collection-banner { aspect-ratio: 16 / 9; }
  }
  .section-head {
    max-width: var(--store-content);
    margin: var(--store-gap) auto 0;
    width: calc(100% - var(--store-inset));
    display: flex;
    align-items: baseline;
    justify-content: space-between;
  }
  .section-head h2 {
    margin: 0;
    font-family: var(--fichi-font-display);
    font-size: 19px;
    font-weight: 600;
  }
  .section-head .count { font-size: 13px; color: var(--fichi-text-muted); }
  .catalog {
    max-width: var(--store-content);
    margin: var(--store-gap-inner) auto 0;
    width: calc(100% - var(--store-inset));
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 16px;
  }
  /* A phone at 390px minus the 32px inset leaves 358px, and this grid had no
     breakpoint of its own: minmax(200px, 1fr) resolved to ONE column of 358px
     cards, which for a 252-item rentals catalog is ~6,000px of scrolling even
     after filtering. Two columns halve it.

     It belongs HERE, in the CSS every catalog ships, not in the filter
     module's: a shop that turns "Mostrar buscador y filtros" off still has
     customers on phones. */
  @media (max-width: 640px) {
    .catalog { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  }
  .cell { position: relative; display: flex; }
  .cell > .card { flex: 1; min-width: 0; }
  /* The quick-add sits ON the photo, out of the link's way. 40px so a thumb
     hits it without hitting the card underneath. */
  .cell .add {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 2;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--fichi-radius-full);
    border: 1px solid var(--fichi-border-subtle);
    background: var(--fichi-bg-surface);
    color: var(--fichi-text-primary);
    box-shadow: var(--fichi-shadow-sm);
    cursor: pointer;
    padding: 0;
  }
  .cell .add .i-ok { display: none; }
  .cell .add[aria-pressed="true"] {
    background: var(--store-accent);
    border-color: var(--store-accent);
    color: var(--store-accent-contrast);
  }
  .cell .add[aria-pressed="true"] .i-add { display: none; }
  .cell .add[aria-pressed="true"] .i-ok { display: block; }
  .card {
    display: flex;
    flex-direction: column;
    border-radius: var(--fichi-radius-lg);
    background: var(--fichi-bg-surface);
    border: 1px solid var(--fichi-border-subtle);
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    box-shadow: var(--fichi-shadow-sm);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .card:hover { transform: translateY(-3px); box-shadow: var(--fichi-shadow-md); }
  .card .media { background: var(--fichi-bg-muted); }
  .card img, .card .placeholder {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    display: block;
  }
  .card .placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 44px;
    font-weight: 700;
    font-family: var(--fichi-font-display);
    color: var(--fichi-text-muted);
  }
  .card-body { display: flex; flex-direction: column; gap: 6px; padding: 14px 14px 16px; }
  /* "En 3 colores" — a fact about the model, sized under the price it follows.
     When every colour has a photo the row shows those photos: the label a shop
     types is a word ("Carey", "Palo de rosa") and only the shop knows what it
     looks like, but the photo of that colour's own product does. */
  .card .variants { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--fichi-text-muted); }
  .card .variants img {
    width: 16px;
    height: 16px;
    border-radius: var(--fichi-radius-full);
    object-fit: cover;
    display: block;
    background: var(--fichi-bg-muted);
  }
  .card .name {
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--fichi-text-primary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .card .price {
    font-size: 15px;
    font-weight: 700;
    color: var(--store-accent-text);
    font-variant-numeric: tabular-nums;
  }
  .catalog .cell[hidden], .catalog .card[hidden] { display: none; }
  .catalog-wrap [hidden] { display: none !important; }
  .catalog-wrap {
    max-width: var(--store-content);
    margin: var(--store-gap-inner) auto 0;
    width: calc(100% - var(--store-inset));
    display: grid;
    grid-template-columns: 232px minmax(0, 1fr);
    gap: 28px;
    align-items: start;
  }
  /* The grid lives inside the wrap now, so it drops the column of its own. */
  .catalog-wrap .catalog { max-width: none; width: 100%; margin: 0; }

  .facets { position: sticky; top: 16px; }
  .facets-head, .facets-foot { display: none; }
  .facets-body { display: flex; flex-direction: column; gap: 22px; }
  .facet { display: flex; flex-direction: column; gap: 9px; }
  .facet h3 {
    margin: 0;
    font-family: var(--fichi-font-display);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--fichi-text-muted);
  }
  .facet .opts { display: flex; flex-direction: column; gap: 2px; }

  /* One row per option: a real checkbox, its label, and how many products it
     would leave. 44px tall so a thumb can hit it. */
  .opt {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 0 8px;
    margin: 0 -8px;
    border-radius: var(--fichi-radius-md);
    font-size: 14px;
    color: var(--fichi-text-primary);
    cursor: pointer;
  }
  .opt input { width: 17px; height: 17px; margin: 0; accent-color: var(--store-accent); flex-shrink: 0; }
  .opt .lbl { flex: 1; min-width: 0; }
  .opt .n {
    font-size: 12.5px;
    color: var(--fichi-text-muted);
    font-variant-numeric: tabular-nums;
  }
  /* Zero is shown, not hidden: a disabled option still tells the visitor the
     category exists and that THIS combination empties it. */
  .opt.none { color: var(--fichi-text-muted); cursor: default; }
  .opt.none input { opacity: 0.45; }
  /* Subcategories sit under their parent, indented and tied to it. */
  .opt.sub { margin-left: 18px; padding-left: 12px; border-left: 2px solid var(--fichi-border-subtle); font-size: 13.5px; }
  .opt.sub .lbl { color: var(--fichi-text-secondary); }

  .facet .filter-search {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 0 14px;
    height: 44px;
    border-radius: var(--fichi-radius-full);
    background: var(--fichi-bg-surface);
    border: 1px solid var(--fichi-border-subtle);
  }
  .facet .filter-search input {
    flex: 1;
    min-width: 0;
    border: 0;
    outline: none;
    background: transparent;
    font: inherit;
    font-size: 14px;
    color: var(--fichi-text-primary);
  }
  /* The input inside is borderless and kills its own outline, so a keyboard
     reaching this field showed NOTHING (FIC-194 section 3). The pill is what a
     visitor sees as the field, so the pill takes the ring — the same one every
     other control on the storefront draws. focus-within, because the thing that
     receives focus is the input and the thing that has to show it is its
     wrapper. */
  .facet .filter-search:focus-within {
    outline: 2px solid var(--store-ring, var(--store-accent));
    outline-offset: 2px;
  }
  .facet .prices { display: flex; align-items: center; gap: 8px; }
  .facet .prices input {
    width: 100%;
    min-width: 0;
    height: 40px;
    padding: 0 10px;
    border-radius: var(--fichi-radius-md);
    border: 1px solid var(--fichi-border-subtle);
    background: var(--fichi-bg-surface);
    color: var(--fichi-text-primary);
    font: inherit;
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
  }
  .facet .prices input::-webkit-outer-spin-button,
  .facet .prices input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .facet .prices input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
  .facet .filter-search input::placeholder, .facet .prices input::placeholder { color: var(--fichi-text-muted); opacity: 1; }

  /* Two range inputs on one rail, pointer-transparent except for their thumbs. */
  .price-slider { position: relative; height: 30px; }
  .price-slider .track {
    position: absolute; left: 9px; right: 9px; top: 13px; height: 4px;
    border-radius: 2px; background: var(--fichi-border-default);
  }
  .price-slider .fill { position: absolute; top: 0; bottom: 0; background: var(--store-accent); border-radius: 2px; }
  .price-slider input[type="range"] {
    position: absolute; left: 0; top: 0; width: 100%; height: 30px; margin: 0;
    background: none; pointer-events: none; -webkit-appearance: none; appearance: none;
  }
  .price-slider input[type="range"]::-webkit-slider-runnable-track { height: 30px; background: transparent; border: 0; }
  .price-slider input[type="range"]::-moz-range-track { height: 30px; background: transparent; border: 0; }
  .price-slider input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none; pointer-events: auto; margin-top: 6px;
    width: 18px; height: 18px; border-radius: 50%;
    background: var(--fichi-bg-surface); border: 2px solid var(--store-accent);
    box-shadow: var(--fichi-shadow-sm); cursor: pointer;
  }
  .price-slider input[type="range"]::-moz-range-thumb {
    pointer-events: auto; width: 14px; height: 14px; border-radius: 50%;
    background: var(--fichi-bg-surface); border: 2px solid var(--store-accent); cursor: pointer;
  }
  .price-slider input[type="range"]:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--store-ring, var(--store-accent)); outline-offset: 2px; }

  /* ── Above the results ─────────────────────────────────────────────────── */
  .catalog-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 14px;
  }
  .applied { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex: 1; min-width: 0; }
  /* Every applied filter is removable where the visitor can see it. Hiding
     them is the single most reported filtering failure on phones. */
  .applied .tag {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 8px 7px 13px;
    border-radius: var(--fichi-radius-full);
    background: var(--store-accent);
    color: var(--store-accent-contrast);
    border: 0;
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
  }
  .applied .tag svg { opacity: 0.8; }
  .applied .clear-all {
    border: 0; background: none; padding: 6px 2px; font: inherit;
    font-size: 13px; font-weight: 600; color: var(--store-accent-text);
    text-decoration: underline; cursor: pointer;
  }
  .sortwrap { position: relative; display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--fichi-text-secondary); }
  .sortwrap select {
    appearance: none; -webkit-appearance: none;
    height: 42px; padding: 0 36px 0 14px;
    border-radius: var(--fichi-radius-full);
    border: 1px solid var(--fichi-border-subtle);
    background: var(--fichi-bg-surface); color: var(--fichi-text-primary);
    font: inherit; font-size: 13.5px; font-weight: 600; cursor: pointer;
  }
  .sortwrap .chev { position: absolute; right: 13px; display: flex; pointer-events: none; color: var(--fichi-text-muted); }

  .filters-open { display: none; }
  .catalog-empty {
    margin: 24px auto 0;
    text-align: center;
    font-size: 14px;
    color: var(--fichi-text-muted);
  }

  @media (max-width: 860px) {
    /* One column, and the facets become a sheet that rises from the bottom —
       the pattern a phone shopper already knows from every other catalog. */
    .catalog-wrap { grid-template-columns: minmax(0, 1fr); gap: 0; }
    .catalog { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
    .filters-open {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      width: fit-content;
      min-height: 44px;
      padding: 0 18px;
      margin-bottom: 14px;
      border-radius: var(--fichi-radius-full);
      border: 1px solid var(--fichi-border-subtle);
      background: var(--fichi-bg-surface);
      font: inherit; font-size: 14px; font-weight: 600;
      color: var(--fichi-text-primary); cursor: pointer;
    }
    .filters-open .badge {
      min-width: 20px; padding: 1px 7px; border-radius: var(--fichi-radius-full);
      background: var(--store-accent); color: var(--store-accent-contrast);
      font-size: 12px; text-align: center;
    }
    /* Only the script opens and closes the sheet, and it adds .facets-sheet
       to the wrap when it starts. Until then there is no sheet: the page's
       scripts are deferred, so a phone showed it fixed open over 86% of the
       screen until they ran, and for good where none ran (JavaScript off,
       the editor's sandboxed preview, a bundle that never arrived). The
       filters do nothing without the script, so nothing stands in for them.
       The sheet's ground stays on .facets, where a band gives it the page's
       inks back. */
    .facets {
      display: none;
      background: var(--fichi-bg-page);
      border-radius: var(--fichi-radius-xl) var(--fichi-radius-xl) 0 0;
      box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.28);
    }
    .facets-sheet .facets {
      position: fixed;
      inset: 0;
      top: auto;
      /* Above the list's bar (62) and its panel (61): the sheet is a modal, so
         its own "Ver N productos" must never sit under anything, and the scrim
         has to dim the bar rather than leave it floating on top. */
      z-index: 70;
      max-height: 86dvh;
      display: flex;
      flex-direction: column;
    }
    .facets[hidden] { display: none !important; }
    .facets-head {
      display: flex; align-items: center; justify-content: space-between;
      padding: 16px 20px 10px;
      font-family: var(--fichi-font-display); font-size: 17px; font-weight: 700;
      color: var(--fichi-text-primary);
    }
    .facets-close {
      width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
      border: 0; background: none; color: var(--fichi-text-secondary); cursor: pointer;
    }
    .facets-body { overflow-y: auto; padding: 0 20px 16px; }
    .facets-foot {
      display: flex; align-items: center; gap: 12px;
      padding: 12px 20px calc(12px + env(safe-area-inset-bottom));
      border-top: 1px solid var(--fichi-border-subtle);
      background: var(--fichi-bg-surface);
    }
    .facets-clear {
      border: 0; background: none; padding: 12px 4px; font: inherit;
      font-size: 14px; font-weight: 600; color: var(--fichi-text-secondary); cursor: pointer;
    }
    /* The count lives ON the button, so the visitor commits knowing the size
       of what they are about to see. */
    .facets-apply {
      flex: 1;
      min-height: 48px;
      border: 0;
      border-radius: var(--fichi-radius-full);
      background: var(--store-accent);
      color: var(--store-accent-contrast);
      font: inherit; font-size: 15px; font-weight: 700; cursor: pointer;
    }
    .facets-scrim { position: fixed; inset: 0; z-index: 69; background: rgba(0,0,0,0.45); border: 0; }
    .sortwrap { flex: 1 1 100%; }
    .sortwrap select { flex: 1; min-width: 0; }
  }
  /* Nor the button that opens it, where no script can run. Before a deferred
     script runs it stays, so it never turns up late and pushes the grid down. */
  @media (scripting: none) {
    .filters-open { display: none; }
  }

  .card .media { position: relative; }
  .rail .rail-card .rail-photo { display: block; position: relative; }
  /* Selectors one step heavier than the images' own rules: the rail sizes its
     pictures with .rail .rail-card img (0,2,1), and a lighter hide lost to it —
     the second photo rendered as a block under the cover, doubling the card. */
  .card .media .alt, .rail .rail-card .alt { display: none; }
  @media (hover: hover) and (pointer: fine) {
    .card .media .alt, .rail .rail-card .alt {
      display: block;
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      opacity: 0;
      transition: opacity 0.2s ease;
    }
    .card:hover .media .alt, .card:focus-visible .media .alt,
    .rail .rail-card:hover .alt, .rail .rail-card:focus-visible .alt { opacity: 1; }
  }
  .navbar {
    position: sticky;
    top: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 12px 24px;
    background: var(--fichi-bg-surface);
    border-bottom: 1px solid var(--fichi-border-subtle);
    /* The bar's accent surface: without this the section's accent override
       had almost nothing to colour (search and cart are neutral chrome), so
       changing "Color" looked like it did nothing. */
    box-shadow: inset 0 -3px 0 0 var(--store-accent);
  }
  .navbar .brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: var(--fichi-font-display);
    font-size: 17px;
    font-weight: 700;
    color: var(--fichi-text-primary);
    text-decoration: none;
    flex-shrink: 0;
  }
  .navbar .brand img { height: 30px; max-width: 150px; object-fit: contain; display: block; }
  /* Text brand (no logo) carries the accent — the most visible surface a
     store without a logo has. */
  .navbar .brand.text-brand { color: var(--store-accent-text); }
  .navbar .links { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
  .navbar .links a {
    font-size: 14px;
    font-weight: 500;
    color: var(--fichi-text-secondary);
    text-decoration: none;
  }
  .navbar .links a:hover { color: var(--store-accent-text); }
  .navbar .search {
    flex: 1;
    min-width: 120px;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    border-radius: var(--fichi-radius-full);
    border: 1px solid var(--fichi-border-subtle);
    background: var(--fichi-bg-page);
    color: var(--fichi-text-muted);
  }
  /* 16px, not 13px: beside a 17px brand the field read as an afterthought, and
     iOS Safari zooms the whole page when a field under 16px takes focus. */
  .navbar .search input {
    flex: 1;
    border: 0;
    outline: 0;
    background: transparent;
    font-size: 16px;
    color: var(--fichi-text-primary);
    font-family: inherit;
    min-width: 0;
  }
  /* The visitor's theme toggle is FIXED at top:14/right:14 and 40px wide, and
     it paints above this bar (z 50 over 40). Measured on the live storefront,
     it covered the cart icon completely — 20px of icon inside 40px of button,
     at every desktop width. Reserving its corner is the only fix that holds:
     the toggle cannot know whether a navbar exists below it. */
  .navbar { padding-right: 64px; }
  .navbar .cart {
    color: var(--store-accent);
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex-shrink: 0;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
  }
  .navbar button.cart { cursor: pointer; min-height: 44px; }
  .navbar .cart .cart-count {
    min-width: 18px;
    padding: 1px 5px;
    border-radius: var(--fichi-radius-full);
    background: var(--store-accent);
    color: var(--store-accent-contrast);
    font-size: 11.5px;
    font-weight: 700;
    line-height: 1.4;
    text-align: center;
  }
  /* A phone: three rows, in the order a thumb expects them.
     Row 1 — the brand at the left and the cart at the right, just inside the
     corner reserved for the theme toggle. Row 2 — the links, on a line of
     their own. Row 3 — the search, full width. Before this the children
     wrapped in DOM order: brand and links filled the first row, the cart fell
     to a second row by itself at the left, and the search came third —
     which read as a header that had broken rather than one that adapted. */
  /* The burger, hidden until a phone asks for it. Sized to the 44px tap target
     the audit holds every control to. */
  .navbar .nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 1px solid var(--fichi-border-subtle);
    border-radius: 10px;
    background: transparent;
    color: var(--fichi-text-primary);
    cursor: pointer;
  }
  .navbar .nav-toggle:hover { background: var(--fichi-bg-elevated); }

  @media (max-width: 720px) {
    .navbar { flex-wrap: wrap; padding: 10px 64px 10px 16px; gap: 10px 12px; }
    .navbar .brand { order: 0; flex: 1 1 auto; min-width: 0; }
    .navbar .brand.text-brand { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .navbar .cart { order: 1; margin-left: auto; }
    .navbar .links { order: 2; flex-basis: 100%; gap: 6px 16px; }
    .navbar .search { order: 3; flex-basis: 100%; }

    /* «Botón de menú»: the links collapse behind the toggle and drop as a
       panel when it is pressed. Everything else on the bar keeps its place,
       so the brand, the cart and the search do not move when the menu opens.

       Toggled with a CLASS on the nav rather than the [hidden] attribute:
       [hidden] comes from the UA stylesheet and loses to any rule that sets
       display, which is exactly what the .links rule above does. */
    .navbar-burger .nav-toggle { display: inline-flex; order: 1; }
    .navbar-burger .cart { order: 2; margin-left: 0; }
    .navbar-burger .links { display: none; }
    .navbar-burger.nav-open .links,
    .navbar-burger.nav-closing .links {
      display: flex;
      flex-direction: column;
      align-items: stretch;
      gap: 0;
      padding-top: 4px;
      border-top: 1px solid var(--fichi-border-subtle);
    }
    .navbar-burger.nav-open .links a,
    .navbar-burger.nav-closing .links a {
      padding: 12px 4px;
      border-bottom: 1px solid var(--fichi-border-subtle);
    }
    .navbar-burger.nav-open .links a:last-child,
    .navbar-burger.nav-closing .links a:last-child { border-bottom: 0; }

    /* «Desde un lado»: a drawer over the page instead of a panel that pushes
       it. The page keeps its scroll position, so a visitor who opens the menu
       by accident does not lose their place, and the links get the whole
       screen rather than shoving the article off the bottom.

       It is NOT a display change like the drop panel, so it needs none of that
       one's machinery: the drawer is always in the layout and travels on a
       transform, which transitions in BOTH directions by itself. visibility is
       what keeps it out of the tab order and away from a screen reader while
       it is shut, delayed on the way out so it outlives its own exit. */
    /* Where the drawer's own content starts: clear of the bar's row, so the
       first link never sits under the X. Declared here and overwritten by the
       script when the drawer opens, the way --store-navbar-height already
       works — a var() that only ever exists in JS drops its whole declaration
       for the frame before the script runs, and the guard in
       token-exists.test.ts refuses one. 68px is the X's row on a bare bar. */
    .navbar-burger.nav-side { --store-drawer-top: 68px; }
    .navbar-burger.nav-side .links,
    .navbar-burger.nav-side.nav-closing .links {
      display: flex;
      flex-direction: column;
      align-items: stretch;
      gap: 0;
      position: fixed;
      /* The WHOLE height of the screen: the owner asked for the menu and
         nothing else — no search field, no cart, no announcement strip showing
         past its edge. Only the X stays on top of it, because the control that
         opened the drawer has to be the one that closes it.

         The content starts below the bar's row, and that number is MEASURED
         when the drawer opens: a fixed box cannot know where a STICKY bar
         currently sits, since above the fold an announcement band is still
         pushing it down. */
      inset: 0 auto 0 0;
      width: min(86vw, 340px);
      z-index: 70;
      padding: var(--store-drawer-top) 20px 24px;
      overflow-y: auto;
      overscroll-behavior: contain;
      background: var(--fichi-bg-surface);
      border-top: 0;
      border-right: 1px solid var(--fichi-border-subtle);
      box-shadow: var(--fichi-shadow-lg);
      transform: translateX(-101%);
      visibility: hidden;
      transition: transform 260ms cubic-bezier(0.2, 0, 0, 1), visibility 0s linear 260ms;
    }
    .navbar-burger.nav-side.nav-open .links {
      transform: none;
      visibility: visible;
      transition: transform 260ms cubic-bezier(0.2, 0, 0, 1), visibility 0s;
    }
    /* The scrim is a real button: tapping beside a drawer to shut it is what
       everyone expects, and a div would hand that gesture to a mouse alone. */
    .navbar-burger .nav-scrim {
      position: fixed;
      inset: 0;
      z-index: 69;
      padding: 0;
      border: 0;
      background: rgba(0, 0, 0, 0.4);
      opacity: 0;
      visibility: hidden;
      transition: opacity 260ms ease, visibility 0s linear 260ms;
    }
    .navbar-burger.nav-side.nav-open .nav-scrim {
      opacity: 1;
      visibility: visible;
      transition: opacity 260ms ease, visibility 0s;
    }
    /* The toggle ALONE rides above the drawer. The burger is the X: the
       control that opened the menu closes it, in the corner the thumb left it.
       Everything else on the bar stays under the drawer, which is the point of
       a full-height panel. */
    .navbar-burger.nav-side .nav-toggle { position: relative; z-index: 71; }
    /* An open drawer has to clear the page's own stacked things: the cart bar
       sits at 62 and the catalogue's filter sheet at 70. */
    .navbar-burger.nav-side.nav-open { z-index: 80; }

  }

  /* The panel is a display change, so it cannot be TRANSITIONED — an animation
     is what runs when an element appears, and it needs no @starting-style, so
     it works on every phone that will ever open this. The close is the mirror,
     driven from the script: .nav-closing holds the panel in the layout for
     exactly as long as the animation lasts.

     The whole block is behind no-preference rather than reset inside a
     reduce query, because the stagger below is keyed on :nth-child and would
     OUT-SPECIFY any reset: the delays would survive it, and with a both fill a
     link sits at opacity 0 for the length of its delay. Someone who asked for
     less movement would get a menu whose links arrive blank — the one thing
     reduced motion must never produce. Declaring the movement only for whoever
     wants it cannot fail that way. */
  @media (max-width: 720px) and (prefers-reduced-motion: no-preference) {
    /* :not(.nav-side) throughout — the drawer moves on a transform that
       transitions both ways by itself, and laying a keyframed slide over a
       transition on the same property makes one of them win at random. */
    .navbar-burger:not(.nav-side).nav-open .links { animation: nav-in 240ms cubic-bezier(0.2, 0, 0, 1) both; }
    .navbar-burger:not(.nav-side).nav-closing .links { animation: nav-out 160ms cubic-bezier(0.4, 0, 1, 1) both; }
    /* The links arrive just behind the panel, close enough together to read as
       one movement. Capped at six: past that the last link waits on a queue.
       The drawer gets them too: there the panel travels and the links fade in
       behind it, which is the same idea on a different axis. */
    .navbar-burger.nav-open .links > * { animation: nav-item-in 220ms cubic-bezier(0.2, 0, 0, 1) both; }
    .navbar-burger.nav-open .links > :nth-child(2) { animation-delay: 30ms; }
    .navbar-burger.nav-open .links > :nth-child(3) { animation-delay: 60ms; }
    .navbar-burger.nav-open .links > :nth-child(4) { animation-delay: 90ms; }
    .navbar-burger.nav-open .links > :nth-child(5) { animation-delay: 120ms; }
    .navbar-burger.nav-open .links > :nth-child(n + 6) { animation-delay: 150ms; }
  }

  @keyframes nav-in { from { opacity: 0; transform: translateY(-8px); } }
  @keyframes nav-out { to { opacity: 0; transform: translateY(-8px); } }
  @keyframes nav-item-in { from { opacity: 0; transform: translateY(-6px); } }

  /* The burger becomes the X that closes it: the top and bottom rules meet in
     the middle of the 24-unit box (y=7 and y=17 both travel 5 to y=12) and
     cross there, and the middle one leaves. Translate THEN rotate — the other
     order swings the line off the centre before it turns. The X itself is not
     movement for its own sake, so it stays under reduce; only its travel
     goes, which leaves the icon telling the truth about the menu's state. */
  .navbar .nav-toggle svg path {
    transform-box: view-box;
    transform-origin: 12px 12px;
    transition: transform 240ms cubic-bezier(0.2, 0, 0, 1), opacity 140ms ease;
  }
  .navbar.nav-open .nav-toggle svg path:nth-child(1) { transform: rotate(45deg) translateY(5px); }
  .navbar.nav-open .nav-toggle svg path:nth-child(2) { opacity: 0; }
  .navbar.nav-open .nav-toggle svg path:nth-child(3) { transform: rotate(-45deg) translateY(-5px); }

  @media (prefers-reduced-motion: reduce) {
    .navbar .nav-toggle svg path { transition-duration: 0.01ms; }
  }

  /* The catalogue's filter panel sticks at 16px, which is under this bar:
     measured at 1280px, the bar held 0-69px and covered the panel's first
     53px, its search field whole. Below a bar that sticks, the panel sticks
     16px below the bar's bottom edge. The bar's script writes its real height
     on the panel, so links that wrap to a second row (92px with eight at
     1280px, 127px at 861px) no longer cover it. Without the script it is the
     bar on one row: 12px of padding, the cart's 44px, 12px and the 1px rule.
     ".navbar ~ *" is a catalogue after the bar, in the box the bar sticks in:
     main on the home, body on a page that borrows it. A styled bar sticks in
     its .sec wrapper instead, with rules of its own. Only while the panel is
     a sidebar; at 860px and under it is a bottom sheet with top: auto.
     «Encabezado fijo» off puts the 16px back (appearance.ts). */
  @media (min-width: 861px) {
    .navbar ~ * .facets { --store-navbar-height: 69px; top: calc(var(--store-navbar-height) + 16px); }
  }

  .navbar .nav-item { position: relative; display: inline-flex; align-items: center; gap: 2px; }
  .navbar .sub-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-width: 32px;
    min-height: 32px;
    padding: 0 4px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--fichi-text-secondary);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
  }
  .navbar .sub-toggle:hover { color: var(--store-accent-text); }
  /* «Categorías» is text, and text in this bar starts flush with its gap —
     a plain link has no padding, so 4px here showed as a stagger on a phone,
     where the row below starts at the same edge. */
  .navbar .sub-label { padding-left: 0; }
  .navbar .sub-toggle .chev { display: inline-flex; transition: transform 0.15s; }
  .navbar .nav-item.sub-open > .sub-toggle .chev { transform: rotate(180deg); }
  .navbar .submenu {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    z-index: 45;
    min-width: 220px;
    max-width: min(320px, calc(100vw - 32px));
    margin: 0;
    padding: 8px;
    list-style: none;
    background: var(--fichi-bg-surface);
    border: 1px solid var(--fichi-border-subtle);
    border-radius: 12px;
    box-shadow: var(--fichi-shadow-lg);
  }
  .navbar .nav-item.sub-open > .submenu { display: block; }
  .navbar .submenu a {
    display: block;
    padding: 8px 10px;
    border-radius: 8px;
    color: var(--fichi-text-primary);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
  }
  .navbar .submenu a:hover { background: var(--fichi-bg-page); color: var(--store-accent-text); }
  .navbar .submenu ul { margin: 0 0 4px; padding: 0 0 0 12px; list-style: none; }
  .navbar .submenu ul a { padding: 6px 10px; font-weight: 400; color: var(--fichi-text-secondary); }

  @media (max-width: 720px) {
    .navbar .nav-item { flex-wrap: wrap; }
    /* «Take the whole row» — and that is only what flex-basis: 100% MEANS
       while .links is a row. In the drawer .links is a COLUMN, where the main
       axis is the height: the same declaration made an open submenu 717px
       tall, swallowing the panel and stacking the other links on top of it.
       There the item already spans the width, from align-items: stretch, so
       the rule is scoped away rather than undone afterwards. */
    .navbar:not(.nav-side) .nav-item.sub-open { flex-basis: 100%; }
    .navbar .sub-toggle { min-width: 44px; min-height: 44px; }
    .navbar .submenu { position: static; flex-basis: 100%; min-width: 0; max-width: none; margin-top: 4px; box-shadow: none; }
    .navbar-burger.nav-open .links .nav-item,
    .navbar-burger.nav-closing .links .nav-item { border-bottom: 1px solid var(--fichi-border-subtle); }
    .navbar-burger.nav-open .links .nav-item > a,
    .navbar-burger.nav-closing .links .nav-item > a { flex: 1; border-bottom: 0; }
    .navbar-burger.nav-open .sub-label { flex: 1; justify-content: space-between; padding: 0 4px; }
    .navbar-burger.nav-open .submenu { border: 0; padding: 0 0 8px 12px; }
    .navbar-burger.nav-open .submenu a { padding: 8px 10px; border-bottom: 0; }
  }

  .navbar .search { position: relative; }
  /* The field sets outline: 0 for its own box, which also took the store's one
     focus ring off it (.navbar .search input outranks input:focus-visible). The
     pill carries the ring instead — a combobox nobody can see focused is one a
     keyboard user cannot find. */
  .navbar .search:focus-within { outline: 2px solid var(--store-ring, var(--store-accent)); outline-offset: 2px; }
  .navbar .search input::placeholder { color: var(--fichi-text-muted); opacity: 1; }
  .navbar .suggest {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    right: 0;
    z-index: 45;
    max-height: min(70vh, 460px);
    overflow-y: auto;
    padding: 6px;
    background: var(--fichi-bg-surface);
    border: 1px solid var(--fichi-border-subtle);
    border-radius: 14px;
    box-shadow: var(--fichi-shadow-lg);
    color: var(--fichi-text-primary);
  }
  /* [hidden] comes from the UA stylesheet and loses to any rule that sets
     display; this one says it outright. */
  .navbar .suggest[hidden] { display: none; }
  .navbar .suggest-group + .suggest-group,
  .navbar .suggest-group + .suggest-all { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--fichi-border-subtle); }
  .navbar .suggest-label {
    padding: 8px 10px 4px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--fichi-text-muted);
  }
  .navbar .suggest [role="option"] {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 44px;
    padding: 6px 10px;
    border-radius: 10px;
    cursor: pointer;
  }
  .navbar .suggest [role="option"]:hover,
  .navbar .suggest [role="option"][aria-selected="true"] { background: var(--fichi-bg-page); }
  /* The active option is marked by a shape as well as a tint: on the dark base
     the tint alone is a step of a few percent. */
  .navbar .suggest [role="option"][aria-selected="true"] { box-shadow: inset 3px 0 0 var(--store-accent); }
  .navbar .suggest .thumb {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    object-fit: cover;
    background: var(--fichi-bg-muted);
    font-family: var(--fichi-font-display);
    font-weight: 700;
    color: var(--fichi-text-muted);
  }
  .navbar .suggest .txt { flex: 1; min-width: 0; display: flex; flex-direction: column; }
  .navbar .suggest .name,
  .navbar .suggest .meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .navbar .suggest .name { font-size: 14px; font-weight: 600; line-height: 1.3; }
  .navbar .suggest .meta { font-size: 12.5px; color: var(--fichi-text-secondary); }
  .navbar .suggest .price {
    flex-shrink: 0;
    font-size: 14px;
    font-weight: 700;
    color: var(--store-accent-text);
    font-variant-numeric: tabular-nums;
  }
  .navbar .suggest .suggest-all { font-size: 14px; font-weight: 600; color: var(--store-accent-text); }
  /* The live region that says how many suggestions there are: read, not seen. */
  .navbar .suggest-status {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
  /* A styled band clips what overflows it (that is how its rounded corners
     hold), and the list hangs below the bar. The band lets it out only while
     it is open. */
  .sec-band:has(.navbar .search [aria-expanded="true"]) { overflow: visible; }
  @media (max-width: 720px) {
    .navbar .suggest { max-height: 60vh; }
  }
  .shop-footer {
    margin-top: 40px;
    padding: 32px 24px 12px;
    background: color-mix(in srgb, var(--store-accent) 16%, var(--fichi-bg-page));
  }
  .shop-footer .inner {
    max-width: var(--store-content);
    margin: 0 auto;
    display: flex;
    flex-wrap: wrap;
    gap: 28px 40px;
    justify-content: space-between;
  }
  /* The shop's own block takes the room the link columns leave: one column of
     links used to sit alone at the left of a band that was otherwise empty. */
  .shop-footer .shop { flex: 1 1 240px; max-width: 360px; }
  .shop-footer .shop-name {
    margin: 0 0 8px;
    font-family: var(--fichi-font-display);
    font-size: 15px;
    font-weight: 700;
    color: var(--fichi-text-primary);
  }
  .shop-footer .shop-line {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin: 0 0 6px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--fichi-text-secondary);
  }
  .shop-footer .shop-line svg { flex-shrink: 0; margin-top: 2px; }
  .shop-footer a.shop-line { color: var(--store-accent-text); font-weight: 500; }
  /* The layout's «Tienda creada con Rachi» line comes right after <main> on
     every page. Left alone under this tinted band it sat on the page
     background and read as a second, unrelated footer. Only when this footer
     is the LAST thing in <main> and not boxed by a section style does it make
     sense to pull the line in — a boxed footer is a card, and a tinted strip
     under a card would be the same mistake the other way round. */
  main:has(> .shop-footer:last-child) ~ .fichi-footer {
    margin-top: 0;
    flex-grow: 1;
    padding: 14px 24px 22px;
    background: color-mix(in srgb, var(--store-accent) 16%, var(--fichi-bg-page));
    border-top: 1px solid color-mix(in srgb, var(--store-accent) 28%, transparent);
    /* The layout paints this line in the muted ink, which is fine on the page
       background and measures 3.94:1 on the tint (axe, light theme). The
       band's own links are the secondary ink on the same tint and pass. */
    color: var(--fichi-text-secondary);
  }
  main:has(> .shop-footer:last-child) ~ .fichi-footer strong { color: var(--fichi-text-primary); }
  main:has(> .shop-footer:last-child) > .shop-footer { padding-bottom: 24px; }
  .shop-footer h3 {
    margin: 0 0 10px;
    font-size: 13px;
    font-weight: 700;
    color: var(--fichi-text-primary);
  }
  .shop-footer ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
  .shop-footer a { font-size: 13px; color: var(--fichi-text-secondary); text-decoration: none; }
  .shop-footer a:hover { color: var(--store-accent-strong); }
  .shop-footer .social { display: flex; gap: 10px; }
  .shop-footer .social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: var(--fichi-radius-full);
    background: var(--fichi-bg-surface);
    color: var(--store-accent-text);
    box-shadow: var(--fichi-shadow-sm);
  }

  body > .shop-footer ~ .fichi-footer {
    margin-top: 0;
    flex-grow: 1;
    padding: 14px 24px 22px;
    background: color-mix(in srgb, var(--store-accent) 16%, var(--fichi-bg-page));
    border-top: 1px solid color-mix(in srgb, var(--store-accent) 28%, transparent);
    color: var(--fichi-text-secondary);
  }
  body > .shop-footer ~ .fichi-footer strong { color: var(--fichi-text-primary); }
  body > .shop-footer { padding-bottom: 24px; }
