/*
 * Cart shell and item rows (Task 2 — see woocommerce/cart/cart.php's own
 * docblock for scope). `.st-cart__side` only ever gets a `min-width: 0`
 * safety net here: Task 3's cart-totals.php owns `.st-cart__summary`
 * (including its own `position: sticky`), and Task 4's cart-empty.php /
 * cross-sells own everything else that can land inside it.
 */

.st-cart-page {
  padding-block: 32px 64px;
}

.st-cart {
  display: grid;
  grid-template-columns: 1fr 400px;
  gap: var(--st-grid-gap);

  /* align-items: stretch (the grid default) would stretch .st-cart__side to
     match .st-cart__items's height, which defeats `position: sticky` on
     whatever Task 3 puts inside it — sticky needs room to move within a
     box taller than its own content, not a box pre-stretched to fill it. */
  align-items: start;
}

.st-cart__items,
.st-cart__side {
  /* A grid item defaults to min-width: auto, which will not shrink below
     its content's intrinsic width — the same fix archive.css's own
     .st-archive__aside/.st-archive__main needed (see that file's comment)
     for the same reason: an unshrinkable item plus a fixed-width sibling
     track forces the whole grid, and the page, wider than the viewport. */
  min-width: 0;
}

/*
 * Task 8 replaces Task 2's interim `@media (max-width: 1099px)` collapse
 * (which that block's own comment called a stopgap and asked this task to
 * remove) with the handoff's own breakpoint table — README.md,
 * "Responsividade", the ONE shared set of values every screen in this theme
 * uses:
 *
 *   >= 1200   full desktop: the `1fr 400px` shell above, untouched.
 *   900-1199  fluid container. The shell stays two columns; what the 1099px
 *             stopgap was really working around is the ROW, not the shell —
 *             see the row's own compact shape further down.
 *   600-899   "carrinho empilha com resumo fixo no rodapé": one column, with
 *             the total and the checkout button pinned to the foot of the
 *             viewport (the bar, below).
 *   < 600     the M5 · Carrinho layout of
 *             design_handoff_sleeptime_ecommerce/design/Sleep Time -
 *             Mobile.dc.html: full-bleed cards, an 84px/1fr item row, and
 *             the same pinned bar.
 *
 * Each range's rules live beside the thing they change, not in one block per
 * breakpoint — mobile is the small end of this component sheet, not a sheet
 * of its own (2026-09-02-sleeptime-redesign-design.md, "Responsividade").
 */
@media (max-width: 899px) {
  .st-cart {
    grid-template-columns: 1fr;
  }
}

/* --- Item list card --------------------------------------------------- */

.st-cart__rows {
  background: var(--st-surface);
  border: var(--st-border-width) solid var(--st-ink);
}

.st-cart__row {
  display: grid;
  grid-template-columns: 120px 1fr 150px 130px 40px;
  align-items: center;
  gap: 16px;
  padding: 16px;
  border-block-end: var(--st-rule-thin);
}

.st-cart__row:last-child {
  border-block-end: 0;
}

/*
 * A grid item's automatic minimum size is its own content's min-content
 * width, not zero — the same overflow shape documented in archive.css
 * (.st-archive__aside/.st-archive__main) and card.css. Confirmed live: the
 * row's fixed tracks (120/150/130/40px) plus gaps already consume ~504px,
 * so any positive min-content floor under the 1fr description column
 * (longer product names, or a variation <dl> with dt/dd of their own) pushes
 * the whole row past its own box — and because .st-cart__row has no
 * `overflow` rule, the overflowing content (the remove button, the last
 * track) renders outside the row entirely, on top of .st-cart__side, not
 * merely clipped. That is not a cosmetic bug: it made the remove button
 * unclickable (Playwright's own actionability check correctly refused the
 * click, "element intercepts pointer events" against a cross-sell card
 * image sitting where the button visually landed).
 */
.st-cart__row > * {
  min-width: 0;
}

.st-cart__image img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  background: var(--st-surface-2);
  object-fit: cover;
}

/*
 * --- The row below 1200px (Task 8) --------------------------------------
 *
 * The five-track row is a desktop shape and stops being one well ABOVE the
 * stacking breakpoint, which is what Task 2's 1099px stopgap was really
 * reacting to. Measured, not assumed: at 1024px the items column is 556px
 * wide, and 120 + 150 + 130 + 40 of fixed track plus four 16px gaps and the
 * row's own 32px of padding consume 536 of it — the 1fr description track
 * resolves to single digits, and the row's own controls then overlap each
 * other's hit areas (confirmed live at 600px BEFORE this rule existed: a tap
 * at the centre of the product-name link landed on a `<use>` inside a
 * neighbouring control's icon — the "row-overflow" Task 2's fix round named
 * and left to this task).
 *
 * So below 1200px the row keeps every one of its five children but takes the
 * artboard's own mobile shape (M5 · Carrinho): the picture spans both rows,
 * the description and the remove control share the first, the stepper and
 * the price the second.
 *
 * `minmax(136px, 1fr)` on the middle track is the load-bearing part. 136px is
 * this project's already-measured stepper floor — 44 + 44 + 44 of touch
 * target plus the control's own 2px borders (product.css's `.st-buy-bar`
 * arrives at the same number for the same reason, including the borders that
 * `box-sizing: border-box` eats) — so the track can never resolve narrower
 * than the stepper's own minimum and push it out of the row. The price track
 * is `minmax(0, auto)`: content-sized where there is room, shrinkable (the
 * amount wraps at its own space) rather than overflowing where there is not.
 */
@media (max-width: 1199px) {
  .st-cart__row {
    grid-template-columns: 96px minmax(136px, 1fr) minmax(0, auto);
    grid-template-areas:
      "image desc   remove"
      "image qty    price";
    align-items: start;
    gap: 12px 14px;
  }

  .st-cart__image {
    grid-area: image;
  }

  .st-cart__desc {
    grid-area: desc;
  }

  .st-cart__qty {
    grid-area: qty;
    align-self: center;
  }

  .st-cart__price {
    grid-area: price;
    place-self: center end;
    text-align: end;
  }

  /*
   * Only the PLACEMENT is declared here. The compact row also wants this
   * control flush with the row's right edge rather than centred, and that
   * `justify-content` cannot be written in this block: the base rule that sets
   * `justify-content: center` sits further down the file (the "Remove" section),
   * a media query adds no specificity, and the later rule would simply win —
   * measured live before this comment existed, the control rendered 31px short
   * of the row's right edge at 1024px while this block still read `flex-end`.
   * The override lives beside that base rule instead, in its own media block.
   */
  [class~="product-remove"] {
    grid-area: remove;
  }

  /* The stepper filled the old 150px track; in a `1fr` track it would
     stretch to the full width of the description column above it. */
  .st-cart__row .st-stepper {
    width: 136px;
  }
}

/* --- Description: name, chosen variations, stock notice ---------------- */

.st-cart__desc {
  display: grid;
  gap: 6px;
}

.st-cart__name {
  color: var(--st-ink);
  font-size: var(--st-size-body);
  font-weight: var(--st-weight-bold);
  text-decoration: none;
}

a.st-cart__name:hover,
a.st-cart__name:active {
  color: var(--st-accent-deep);
}

/*
 * wc_get_formatted_cart_item_data()'s own markup (cart/cart-item-data.php,
 * not overridden) — see cart.php's file docblock for why the slug->name
 * join is core's, not this template's. This is the styling half only.
 *
 * Targeted by tag (dl/dt/dd), not core's own `.variation` class: this
 * project's selector-class-pattern lint requires every CLASS selector to
 * carry the `st-` prefix (or one of a short allowlist — see
 * .stylelintrc.json), and there is exactly one <dl> inside .st-cart__desc,
 * so no class is needed to scope this precisely.
 */
.st-cart__desc dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 6px;
  margin: 0;
  font-size: var(--st-size-caption);
}

.st-cart__desc dt {
  color: var(--st-muted);
  font-weight: var(--st-weight-bold);
}

.st-cart__desc dd {
  margin: 0;
  color: var(--st-ink-2);
}

.st-cart__desc dd p {
  margin: 0;
}

.st-cart__notice {
  margin: 0;
  color: var(--st-accent-deep);
  font-size: var(--st-size-caption);
  font-weight: var(--st-weight-bold);
}

/* --- Quantity stepper: 42px here vs .st-product__actions's 58px -------- */

.st-cart__row .st-stepper {
  height: 42px;
}

/*
 * The stepper buttons' shared min-height (variations.css, --st-h-touch =
 * 44px) would force this 42px control 2px taller than the handoff's own
 * value, so the row's own stepper drops that floor — then restores the
 * 44px minimum tap target on a coarse pointer only, via the same
 * hit-area-overlay technique components.css already uses for the 18px chip
 * remove (chip.css: "the × stays 18px visually... an overlay that doesn't
 * affect layout"). Do not "simplify" this away.
 */
.st-cart__row .st-stepper__minus,
.st-cart__row .st-stepper__plus {
  min-width: 0;
  min-height: 0;
}

@media (pointer: coarse) {
  .st-cart__row .st-stepper__minus,
  .st-cart__row .st-stepper__plus {
    position: relative;
  }

  .st-cart__row .st-stepper__minus::after,
  .st-cart__row .st-stepper__plus::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    width: var(--st-h-touch);
    height: var(--st-h-touch);
    transform: translate(-50%, -50%);
  }
}

/* --- Price: struck regular + current, 20px/800 ------------------------- */

.st-cart__price {
  gap: 2px;
}

.st-cart__price .st-price__now {
  font-size: var(--st-size-price-row);
  font-weight: var(--st-weight-extrabold);
}

/* --- Remove: 36x36, red on hover ---------------------------------------- */

/*
 * `[class~="product-remove"]` rather than `.product-remove`: it's core
 * WooCommerce's own class, load-bearing for cart.js's AJAX remove-click
 * delegate (cart.php's own docblock) — not renameable to fit the `st-`
 * prefix this project's selector-class-pattern lint requires of class
 * selectors. An attribute selector matches the identical element with
 * identical specificity and isn't a class selector the lint rule inspects.
 */
[class~="product-remove"] {
  display: flex;
  justify-content: center;
}

/* The compact row's own alignment, declared AFTER the rule above for the
   reason that rule's sibling comment in the `@media (max-width: 1199px)` block
   spells out: below 1200px this control shares its grid line with the product
   name instead of owning a 40px track, so it goes to the end of the line. */
@media (max-width: 1199px) {
  [class~="product-remove"] {
    justify-content: flex-end;
  }
}

/*
 * Idle and hover states measured against the design source, not guessed
 * from the token names: design_handoff_sleeptime_ecommerce/design/Sleep
 * Time - Redesign.dc.html's own cart-row remove button (lines ~519, 534)
 * is `border: 2px solid #201e1d; background: #ffffff; color: #201e1d`
 * idle, `background: #ec3013; color: #ffffff; border-color: #ec3013` on
 * hover — a solid red FILL with a white icon, not a border/icon tint on an
 * otherwise white button. #201e1d/#ec3013/#ffffff map to --st-ink/
 * --st-accent/--st-surface respectively (tokens.css), confirmed directly
 * against that file rather than assumed.
 */
.st-cart__remove {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: var(--st-border-width) solid var(--st-ink);
  background: var(--st-surface);
  color: var(--st-ink);
  font-size: 20px;
  line-height: 1;
  text-decoration: none;
  transition:
    background-color var(--st-transition),
    color var(--st-transition),
    border-color var(--st-transition);
}

.st-cart__remove:hover,
.st-cart__remove:active {
  background: var(--st-accent);
  border-color: var(--st-accent);
  color: var(--st-surface);
}

/* Same hit-area-overlay technique as the stepper buttons above — the
   36x36 visual stays put, a coarse pointer gets the 44px minimum. */
@media (pointer: coarse) {
  .st-cart__remove {
    position: relative;
  }

  .st-cart__remove::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    width: var(--st-h-touch);
    height: var(--st-h-touch);
    transform: translate(-50%, -50%);
  }
}

/* --- Coupon + update-cart actions --------------------------------------- */

.st-cart__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 12px;
  padding: 16px;
}

.st-cart__coupon {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.st-cart__coupon .st-field {
  width: auto;
  min-width: 200px;
}

/*
 * --- Order summary (Task 3, cart/cart-totals.php) --------------------------
 *
 * `position: sticky` alone proves nothing (task-3-brief.md's own defect
 * class: "an ancestor's overflow or a too-short column silently defeats
 * it") — this was not a hypothetical here. `.st-cart` sets `align-items:
 * start` (above, Task 2), which lets `.st-cart__side` shrink to its own
 * content's height rather than stretching to match `.st-cart__items`'s
 * (that rule's own comment argues this is what sticky needs). Measured live
 * with a real scroll instead: it is backwards. A sticky element's move
 * range is bounded by its CONTAINING block's own box — with align-items:
 * start, `.st-cart__side` (the containing block for `.st-cart__summary`
 * below, its child) collapses to exactly the summary card's own height, so
 * the card has zero room to separate from it; scrolling 600px moved
 * `.st-cart__summary` to `top: ~820px`, not the ~20px a working sticky
 * element would hold (cart.spec.js's own "stays in view while the page
 * scrolls past it" test caught this — the getComputedStyle risk the brief
 * itself names). `align-self: stretch` on `.st-cart__side` ALONE restores
 * the tall containing block (matching `.st-cart__items`'s height, same as
 * the grid's own pre-Task-2 default) without touching `.st-cart` itself or
 * `.st-cart__items`'s own alignment — an addition, not the restructure
 * task-2-brief.md's own scope boundary rules out.
 */
.st-cart__side {
  align-self: stretch;
}

.st-cart__summary {
  position: sticky;
  top: 20px;
  border: var(--st-border-width) solid var(--st-ink);
  background: var(--st-surface);
}

.st-cart__summary-heading {
  margin: 0;
  padding: 16px 20px;
  border-block-end: var(--st-rule);
  font-size: var(--st-size-label);
  font-weight: var(--st-weight-extrabold);
  letter-spacing: var(--st-track-eyebrow);
  text-transform: uppercase;
}

.st-cart__summary-body {
  padding: 20px;
}

.st-cart__summary-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  font-size: 15px;
  color: var(--st-ink-2);
}

.st-cart__summary-value {
  color: var(--st-ink);
  font-weight: var(--st-weight-bold);
}

/* Discount amount and a free delivery line — the handoff's own red text
   uses ("Grátis", a discount), never --st-accent itself (tokens.css: "never
   a body-text colour"). */
.st-cart__summary-value--accent {
  color: var(--st-accent-deep);
}

/*
 * `.woocommerce-remove-coupon` — the remove-coupon link core's own
 * `wc_cart_totals_coupon_html()` prints — used to be styled here. It now
 * lives in assets/css/components/woo.css, because Task 7's checkout summary
 * renders the same control and `Assets::screen()` loads exactly ONE screen
 * sheet per request: cart.css's rules never reached /finalizar-compra/, so
 * the checkout shipped that control with no colour, no `:active` and no
 * touch target at all (task-7-report.md, fix round 1). Component sheets load
 * on every page, so one rule now serves both screens and the two cannot
 * drift apart again.
 */

.st-cart__summary-total {
  margin-block-start: 14px;
  padding-block-start: 14px;
  border-block-start: var(--st-rule);
}

.st-cart__summary-total-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.st-cart__summary-total-label {
  font-size: 15px;
  font-weight: var(--st-weight-extrabold);
}

.st-cart__summary-total-value {
  font-size: var(--st-size-cart-total);
  font-weight: var(--st-weight-black);
  letter-spacing: var(--st-track-h1);
}

.st-cart__summary-installment {
  margin: 6px 0 0;
  font-size: var(--st-size-body-sm);
  color: var(--st-ink-2);
}

.st-cart__summary-pix {
  margin: 2px 0 0;
  font-size: var(--st-size-body-sm);
  font-weight: var(--st-weight-bold);
  color: var(--st-accent-deep);
}

/* .st-btn--primary/.st-btn--block already give the 56px height, the
   label-left/icon-right layout and the hover+active pair (button.css) the
   handoff's own "Finalizar compra" button needs — this only adds the gap
   above it. */
.st-cart__summary-checkout {
  margin-block-start: 18px;
}

/*
 * Fix round 1 (task-3-report.md): `display: block` at 13px with no padding
 * and no min-height measured ~20px tall live — well under the binding
 * "touch targets ≥44px on both axes" constraint. `.st-btn--sm`/
 * `.st-btn--outline` already pair this exact label size with
 * `min-height: var(--st-h-touch)` (button.css), but reusing either adds a
 * 2px border (and, on `--outline`, an ink-fill hover) the handoff's own
 * markup for this link does not have (design/Sleep Time -
 * Redesign.dc.html, screen 05: no border, no background, plain underline-
 * free text) — reusing them would visibly change the design, not just fix
 * the target size. `min-height` + flex centering instead keeps the exact
 * plain-link look at every width (already `display: block`, so full-width
 * `>44px` on the inline axis was never the problem) while reaching 44px on
 * the block axis too.
 */
.st-cart__summary-continue {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--st-h-touch);
  margin-block-start: 10px;
  color: var(--st-ink);
  font-size: var(--st-size-label);
  font-weight: var(--st-weight-bold);
  letter-spacing: var(--st-track-button);
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
}

.st-cart__summary-continue:hover,
.st-cart__summary-continue:active {
  color: var(--st-accent-deep);
}

.st-cart__summary-secure {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-block-start: 18px;
  padding-block-start: 14px;
  border-block-start: 1px solid var(--st-hairline);
  font-size: var(--st-size-label);
  color: var(--st-muted);
}

.st-cart__summary-secure .st-icon {
  flex-shrink: 0;
  color: var(--st-accent);
}

/*
 * --- "Resumo fixo no rodapé" (Task 8) -----------------------------------
 *
 * The handoff's 600-899 row ("carrinho empilha com resumo fixo no rodapé")
 * and the M5 · Carrinho artboard both end in the same thing: a bar pinned to
 * the foot of the viewport carrying the total, the instalment line and
 * "Finalizar compra", over a page that scrolls behind it. The artboard draws
 * it as `position: absolute; left/right/bottom: 0` inside a 390x844 frame —
 * a static mockup's way of spelling `position: fixed` — with `border-top: 2px
 * solid #201e1d` and `box-shadow: 0 -8px 24px rgba(45,43,43,0.18)`, which are
 * `--st-rule` and `--st-shadow-bar` verbatim. `.st-buy-bar` (product.css)
 * already builds exactly this on the product screen, down to the
 * `env(safe-area-inset-bottom)` term; this is the same construction, reusing
 * the same tokens.
 *
 * WHAT GOES IN THE BAR, and why it is not the whole card. This theme's CSS
 * cannot introduce markup, and cart-totals.php (Task 3) has no wrapper around
 * "total + button" — so the bar is built from the two elements that ARE
 * adjacent there: `.st-cart__summary-total` (the total row, the instalment
 * line and the Pix line) and the checkout button that follows it. The rest of
 * the card — the "Resumo do pedido" band, the subtotal and delivery rows,
 * "Continuar comprando" and the secure-environment line — stays in the flow
 * of the stacked column, above the bar and fully reachable by scrolling.
 * Pinning the WHOLE card instead was measured first and rejected: at 360px it
 * renders 427px tall, half the viewport, and the only way to shrink it is to
 * hide shopper-facing content (a navigation link among it) on exactly the
 * viewport where content is scarcest.
 *
 * The bar is ONE box, not two: `.st-cart__summary-total` is the bar (surface,
 * rule, shadow, full width), and its own bottom padding reserves the strip
 * the button is then pinned into. That is what makes the two halves
 * impossible to misalign — there is no seam whose height has to match a
 * number written somewhere else, only a padding that is guaranteed to be at
 * least as tall as what sits in it. cart.spec.js asserts the button's box is
 * inside the bar's box at every stacked width, so a future change to either
 * cannot silently split them.
 */
@media (max-width: 899px) {
  body.woocommerce-cart {
    /* The pinned button's own box plus the gap beneath it. Declared on the
       body unconditionally — it is a value, not an effect — so both the bar (a
       descendant) and the page-foot reservation (below) resolve the identical
       one, and so the bar itself never depends on the `:has()` support the
       reservation does. */
    --st-cart-bar-cta: calc(
      var(--st-h-button) + var(--st-grid-gap-mobile) + env(safe-area-inset-bottom, 0px)
    );
  }

  /*
   * `:has(.st-cart__summary-total)` — the reservation applies only where the
   * bar it is reserving for actually renders (fix round 1).
   *
   * `body.woocommerce-cart` alone is not that condition. WooCommerce puts the
   * IDENTICAL body classes on the empty cart and the full one (measured on both
   * states: `woocommerce-cart woocommerce-page woocommerce-js`, character for
   * character) — `wc_body_class()` branches on `is_cart()`, which is the PAGE,
   * not its contents — while cart-empty.php renders no `.st-cart__summary-total`
   * at all. Unguarded, this rule therefore reserved 208px of dead space beneath
   * the footer of a page with nothing pinned over it, at every width <= 899.
   * Confirmed in a browser at 800x900 before the fix: body `padding-bottom:
   * 208px`, zero `.st-cart__summary-total` elements, 208px of empty document
   * after the footer's last pixel.
   *
   * This is the one condition in this theme that PHP genuinely does not already
   * compute, which is what archive.css's own "drive state from PHP rather than
   * reach for `:has()`" note turns on: there is no server-side signal to key
   * off here without inventing one (a new body class from a `body_class`
   * filter), and that invented signal would be a PROXY — "the cart is empty" —
   * for the thing actually being asked, "is there a bar on this page". The
   * `:has()` states the real condition, in the same file and against the same
   * selector that creates the bar a few rules below, so the two cannot drift:
   * rename that element and the bar and its reservation break together, loudly,
   * in the same test. It also survives the path a body class would not: cart.js
   * swaps the empty state in over AJAX with no page load, so a server-rendered
   * class would still read "full" — and the dead band would return on exactly
   * the page a shopper reaches by emptying their cart — while a `:has()`
   * re-matches the moment the element leaves the DOM (cart.spec.js's own
   * phase 3 removes the item and re-measures).
   *
   * (Checked rather than assumed, because it was reported to
   * me as settled: `:has()` is NOT forbidden by .stylelintrc.json — this exact
   * selector lints clean. The archive.css note is a convention about where
   * state should live, and it is a convention this case genuinely falls
   * outside.)
   *
   * Support is the reason `--st-cart-bar-cta` is declared above rather than
   * here: an engine without `:has()` drops this whole rule as an invalid
   * selector, and it must lose only the reservation, never the custom property
   * the bar's own padding is built from.
   */
  body.woocommerce-cart:has(.st-cart__summary-total) {
    /*
     * Reserve the bar's height at the foot of the document, or the footer's
     * last line sits under it permanently — the defect class this task's own
     * brief names ("a control is cut off while document-level assertions
     * pass"), and the exact rule `body.single-product` already carries for
     * `.st-buy-bar`. The 128px term is the bar's own upper half measured
     * live at 360px with every optional line present (total row 47 +
     * instalment 22 + Pix 22 + 10px top padding + the 2px rule = 103) plus
     * 25px of slack for a wrapped instalment line at a narrower width still.
     * Over-reserving costs blank space below the footer; under-reserving
     * costs a line of the footer, so the slack is deliberate.
     * cart.spec.js's "never covers the last thing on the page" measures the
     * real footer against the real bar at every stacked width rather than
     * trusting this arithmetic.
     */
    padding-block-end: calc(var(--st-cart-bar-cta) + var(--st-grid-gap-mobile) + 128px);
  }

  /* Sticky is a two-column affordance. In one column `.st-cart__side` is no
     taller than its own content, so the card has nowhere to travel anyway —
     and the total inside it is pinned by the bar instead. */
  .st-cart__summary {
    position: static;
  }

  .st-cart__summary-total {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 80;
    margin-block-start: 0;
    padding-block: 10px calc(var(--st-cart-bar-cta) + var(--st-grid-gap-mobile));
    padding-inline: var(--st-grid-gap-mobile);
    background: var(--st-surface);
    border-block-start: var(--st-rule);
    box-shadow: var(--st-shadow-bar);
  }

  /* No z-index of its own: it is the bar's next sibling in the DOM, so at the
     same stacking level it paints over the bar's reserved strip. */
  .st-cart__summary-checkout {
    position: fixed;
    inset-inline: var(--st-grid-gap-mobile);
    inset-block-end: calc(var(--st-grid-gap-mobile) + env(safe-area-inset-bottom, 0px));
    z-index: 80;

    /*
     * `inline-size: auto` because `.st-btn--block`'s own `width: 100%`
     * resolves against the VIEWPORT once this element is fixed, which put the
     * button's right edge 12px past the screen (measured live: an 800px-wide
     * button starting at x=12 in an 800px window); `auto` is what lets the
     * two inline insets above size it instead.
     *
     * `block-size` rather than `.st-btn`'s own `min-height`, which is 56px
     * here and 52px below 600px (button.css): the bar's reserved strip is one
     * expression, so the thing pinned inside it has to be one height.
     */
    inline-size: auto;
    block-size: var(--st-h-button);
    min-height: 0;
    margin-block-start: 0;
  }
}

/*
 * --- Below 600px: the M5 · Carrinho layout (Task 8) ----------------------
 *
 * The artboard's own 390px frame has no page gutter: its header band, its two
 * item cards, the cross-sell strip and the bar all run edge to edge, and the
 * 14px of breathing room is INSIDE each card. This theme's `.st-container`
 * gutter (24px a side) is what stands between that and the row arithmetic
 * below, and it is worth more as row width than as margin here: at 360px the
 * row needs 84 (picture) + 136 (the stepper's touch-target floor) + the price
 * + two 12px gaps, which is 322px of the 332px a full-bleed card leaves and
 * 10px MORE than the 312px a gutter would leave. Measured at 360px, the
 * narrowest width this task covers; every wider phone gains slack.
 */
@media (max-width: 599px) {
  .st-cart-page {
    padding-inline: 0;
    padding-block-start: var(--st-section-y-mobile);
  }

  .st-cart__row {
    grid-template-columns: 84px minmax(136px, 1fr) minmax(0, auto);
    gap: 10px 12px;
    padding: 14px;
  }

  /* M5's own 14.5px/700 name and its smaller row price. The price size is
     not the artboard's 18px: the artboard prints "R$ 2.699" with no cents
     and this cart prints them (dropping them is not this task's to decide,
     and `text-overflow` is ruled out project-wide — a price that ellipsises
     away passes every assertion while the shopper sees nothing). At 14px
     "R$ 1.899,00" measures ~78px, which is what keeps the second row inside
     360px with the stepper at its 136px floor. */
  .st-cart__name {
    font-size: var(--st-size-body-sm);
  }

  .st-cart__price .st-price__now {
    font-size: var(--st-size-body-sm);
  }

  .st-cart__actions {
    padding: 14px;
  }

  /*
   * M5's cross-sell strip is NOT declared here, even though it belongs to this
   * breakpoint: every rule it needs overrides one of the desktop cross-sell
   * rules at the very end of this file, and a media query adds no specificity,
   * so declaring it here would lose to them silently. It lives immediately
   * after those rules instead — see "M5's cross-sell strip" down there.
   */
}

/*
 * --- Empty cart (Task 4, woocommerce/cart/cart-empty.php) --------------
 *
 * The handoff's own "screen 07 big red card" composition ("Carrinho vazio,
 * busca sem resultado: mesma composição do card grande vermelho da tela
 * 07", README.md) — a dedicated `.st-cart__empty*` family rather than
 * reusing `.st-search__empty*` (search.css is never loaded on the cart
 * page, one screen stylesheet per request — see cart-empty.php's own
 * docblock), but the identical solid `--st-accent` / white-text / 2px
 * ink-border / white-CTA-that-inverts values.
 */
.st-cart__empty {
  border: var(--st-rule);
  background: var(--st-accent);
  color: var(--st-surface);
  padding: 32px;
}

.st-cart__empty-eyebrow {
  margin: 0;
  font-size: 12px;
  font-weight: var(--st-weight-extrabold);
  letter-spacing: var(--st-track-eyebrow);
  text-transform: uppercase;
}

.st-cart__empty-title {
  margin-top: 10px;
  font-size: 21px;
  line-height: 1.2;
}

.st-cart__empty-body {
  margin-top: 16px;
  max-width: 50ch;
  font-size: var(--st-size-body-sm);
  line-height: var(--st-lh-loose);
}

.st-cart__empty-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--st-h-search);
  margin-top: 18px;
  padding: 0 18px;
  background: var(--st-surface);
  color: var(--st-ink);
  font-size: var(--st-size-label);
  font-weight: var(--st-weight-extrabold);
  letter-spacing: var(--st-track-button);
  text-decoration: none;
  text-transform: uppercase;
  transition:
    background-color var(--st-transition),
    color var(--st-transition);
}

.st-cart__empty-cta:hover,
.st-cart__empty-cta:active {
  background: var(--st-ink);
  color: var(--st-surface);
}

.st-cart__empty-cta:focus-visible {
  outline: var(--st-focus-width) solid var(--st-accent);
  outline-offset: var(--st-focus-offset);
}

@media (max-width: 599px) {
  .st-cart__empty {
    padding: 24px;
  }
}

/*
 * --- Cross-sells (Task 4) ----------------------------------------------
 *
 * "Quem levou esse baú também levou" — the handoff's 88px/1fr horizontal
 * mini-card (README.md, screen 05). There is deliberately NO theme
 * template override for this block: WooCommerce's own
 * templates/cart/cross-sells.php already renders exactly the markup this
 * theme wants, because it calls `wc_get_template_part( 'content',
 * 'product' )` per item and this theme already overrides
 * woocommerce/content-product.php with `ProductCard::render( $product )`.
 *
 * An earlier override of cart/cross-sells.php justified itself by
 * claiming `setup_postdata()` "never fires the `the_post` action", so
 * `global $product` would be stale. That claim is false, verified by
 * reading core rather than assuming: `WP_Query::setup_postdata()` ends
 * with `do_action_ref_array( 'the_post', array( &$post, &$this ) )`
 * (wp-includes/class-wp-query.php:4891) and `wc_setup_product_data()` is
 * registered with `add_action( 'the_post', 'wc_setup_product_data' )`
 * (woocommerce/includes/wc-template-functions.php:175), which sets
 * `$GLOBALS['product']`. Confirmed on the running site with the override
 * removed: `.cross-sells > h2 + ul.products` containing three
 * `li.st-card-item > article.st-card`, identical card markup, correct
 * pt-BR heading, correct count. The override was deleted.
 *
 * So the selectors here are core's own (`.cross-sells`, its `h2`,
 * `ul.products`) plus `ProductCard`'s, scoped to `.cart-collaterals` so
 * nothing else that reuses ProductCard is touched. The heading text comes
 * from WooCommerce\Support::crosssell_heading() on core's own
 * `woocommerce_product_cross_sells_products_heading` filter (which core's
 * template applies and the deleted override ignored); the count from
 * Support::crosssell_total() on `woocommerce_cross_sells_total`, applied
 * upstream in `woocommerce_cross_sell_display()`.
 *
 * Everything the full card shows that has no room in an 88px-tall row
 * (brand eyebrow, swatches, size chips, the CTA button) is hidden here —
 * "do not build a second card component" (task-4-brief.md) rules out a
 * second template, not a scoped restyle of the one component.
 */
.cart-collaterals .cross-sells {
  margin-top: 24px;
  padding: 16px;
  border: var(--st-border-width) solid var(--st-ink);
  background: var(--st-surface);
}

.cart-collaterals .cross-sells > h2 {
  margin: 0 0 12px;
  font-size: var(--st-size-label);
  font-weight: var(--st-weight-extrabold);
  letter-spacing: var(--st-track-eyebrow);
  text-transform: uppercase;
}

/* Overrides card.css's `ul.products` grid — three 1fr tracks inside the
   narrow collaterals column would squeeze each mini-card to ~90px wide. */
.cart-collaterals .cross-sells .products {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 0;
  margin: 0;
  list-style: none;
}

.cart-collaterals .cross-sells .st-card {
  flex-direction: row;
  align-items: stretch;
}

.cart-collaterals .cross-sells .st-card__media {
  flex: 0 0 88px;
  width: 88px;
  border-block-end: 0;
  border-inline-end: var(--st-rule);
}

.cart-collaterals .cross-sells .st-card__image {
  height: 100%;
  min-height: 88px;
}

.cart-collaterals .cross-sells .st-card__body {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
}

.cart-collaterals .cross-sells .st-badge--floating,
.cart-collaterals .cross-sells .st-eyebrow,
.cart-collaterals .cross-sells .st-card__swatches,
.cart-collaterals .cross-sells .st-card__sizes,
.cart-collaterals .cross-sells .st-card__cta {
  display: none;
}

/*
 * Touch target (global-constraints.md: >=44px on both axes). Hiding
 * `.st-card__cta` just above removes the mini-card's only control that
 * already cleared that floor, and `.st-card__media-link` cannot take over
 * — components/product-card.php gives it `tabindex="-1" aria-hidden="true"`,
 * so it is not keyboard-reachable and is hidden from assistive tech. The
 * title link is the one real focusable control left in this block, so it
 * carries the floor itself: a full-height flex box rather than plain
 * inline text (which measured ~17px tall). Unlike the coarse-pointer
 * hit-area overlays used for the stepper and `.st-cart__remove` above,
 * this is unconditional — there is no fixed visual size to preserve here,
 * and a 44px row fits inside the 88px card with room to spare.
 * Covered by tests/visual/cart.spec.js, "the cross-sell mini-card keeps a
 * 44px keyboard-reachable target".
 */
.cart-collaterals .cross-sells .st-card__title {
  min-width: 0;
}

.cart-collaterals .cross-sells .st-card__title a {
  display: flex;
  align-items: center;
  min-width: var(--st-h-touch);
  min-height: var(--st-h-touch);
}

.cart-collaterals .cross-sells .st-card__price {
  flex-shrink: 0;
  margin-top: 0;
  padding-top: 0;
}

.cart-collaterals .cross-sells .st-price__installment {
  display: none;
}

/*
 * M5's cross-sell strip (Task 8) — "Quem levou também levou" as a sideways row
 * of 150px vertical cards, not the column of 88px horizontal mini-rows the
 * desktop sidebar uses.
 *
 * This block is placed HERE, at the end of the file, rather than with the rest
 * of the `< 600` rules further up, and the placement is the whole point:
 * every declaration below overrides one of the desktop cross-sell rules
 * immediately above it, `@media` contributes nothing to specificity, and the
 * later rule wins. Written in the earlier block it was inert in exactly the
 * half-applied way that is hardest to see — `flex: 0 0 150px` (no desktop rule
 * to lose to) took effect while `flex-direction: row` (one to lose to) did
 * not, so the strip rendered as a column of horizontal cards with a 150px
 * flex-basis on the BLOCK axis and the third card's price cut off mid-digit.
 * Found in a screenshot, not in a measurement; cart.spec.js now asserts the
 * resolved direction, the 150px card width and the strip's own overflow.
 *
 * The scroll is the LIST's, never the page's — `min-width: 0` on the item is
 * what keeps a long card title from forcing the flex line wider than its
 * container and turning this into a document that scrolls sideways.
 */
@media (max-width: 599px) {
  .cart-collaterals .cross-sells {
    padding: 14px;
  }

  .cart-collaterals .cross-sells .products {
    flex-direction: row;
    gap: 10px;
    overflow-x: auto;
  }

  .cart-collaterals .cross-sells .st-card-item {
    flex: 0 0 150px;
    min-width: 0;
  }

  /* Back to the component's own vertical card (card.css), which the desktop
     rules above turn on its side for the sidebar column. */
  .cart-collaterals .cross-sells .st-card {
    flex-direction: column;
  }

  .cart-collaterals .cross-sells .st-card__media {
    flex: none;
    width: auto;
    border-block-end: var(--st-rule);
    border-inline-end: 0;
  }

  .cart-collaterals .cross-sells .st-card__image {
    height: 84px;
    min-height: 0;
  }

  .cart-collaterals .cross-sells .st-card__body {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 8px;
  }
}
