/*  Leaf & Bloom - Commerce templates
 *  ---------------------------------------------------------------------------
 *  Shop / category archive, single product, cart. In the theme this file is
 *  enqueued only on WooCommerce pages (is_woocommerce() || is_cart() ||
 *  is_checkout() || is_account_page()), so it never loads on the blog or
 *  the legal pages.
 *  ------------------------------------------------------------------------- */

/* == Editorial archive header ============================================= */
/*  == The page head ======================================================
 *  This was a single centred-left column: an eyebrow, a 62px heading
 *  capped at 16 characters so it always wrapped to two lines, and a
 *  paragraph under it. Measured on the category page it spent 340px of the
 *  first screen to say three things, and the entire right-hand half of
 *  that band was empty. A shop whose first screen is mostly nothing reads
 *  as unfinished no matter how good the type is.
 *
 *  The heading and the sentence now sit side by side, bottom-aligned, so
 *  the band is a little over half as tall and both halves of the page are
 *  used. Anything else inside the head — the FAQ's jump list — spans the
 *  full width underneath, which is where it was anyway.
 *  -------------------------------------------------------------------- */
.archive-head { padding-block: var(--sp-6) var(--sp-6); display: grid; gap: var(--sp-4); }
.archive-head .section-title { max-width: 18ch; }
.archive-head__lede { color: var(--c-text-soft); max-width: 52ch; }

@media (min-width: 900px) {
  .archive-head {
    grid-template-columns: minmax(0, 1fr) minmax(0, .88fr);
    column-gap: var(--sp-9);
    align-items: end;
  }
  /*  Optical, not mathematical: aligning the baseline of a 16px sentence to
   *  the baseline of a 62px Cormorant heading leaves the sentence looking
   *  as though it has slipped. A third of a line of lift settles it. */
  .archive-head__lede { padding-bottom: .4em; }
  .archive-head > :not(.archive-head__title):not(.archive-head__lede) { grid-column: 1 / -1; }
}

/* Sticky toolbar: filter trigger + result count + sort. */
.shop-bar {
  position: sticky; top: 68px; z-index: 10;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  padding-block: var(--sp-4);
  background: var(--c-bg);
  border-block: 1px solid var(--c-line);
  margin-bottom: var(--sp-7);
}
@media (min-width: 1024px) { .shop-bar { top: 84px; } }
.shop-bar__left { display: flex; align-items: center; gap: var(--sp-4); }
.shop-bar__count { font-size: var(--fs-small); color: var(--c-text-soft); }
@media (max-width: 519px) { .shop-bar__count { display: none; } }

.filter-trigger {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-2) var(--sp-5);
  border: 1.5px solid var(--c-line-strong);
  border-radius: var(--r-pill);
  font-size: var(--fs-small);
  color: var(--c-text);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.filter-trigger:hover { border-color: var(--c-accent); background: var(--c-tint); }
.filter-trigger svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.filter-trigger__n {
  min-width: 20px; height: 20px; padding: 0 6px;
  display: grid; place-items: center;
  background: var(--c-brand-fill); color: var(--c-on-brand);
  border-radius: var(--r-pill); font-size: var(--fs-nano);
}

.sort-select { min-height: 44px; width: auto; min-width: 190px; padding-block: var(--sp-2); font-size: var(--fs-small); }
@media (max-width: 519px) { .sort-select { min-width: 0; max-width: 46vw; } }

/* Applied-filter pills */
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-6); }
/*  44px tall so the remove control inside it can be a full-height target
 *  rather than a 20px dot people miss on a phone. */
.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  min-height: 44px;
  padding: var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-4);
  background: var(--c-tint);
  border-radius: var(--r-pill);
  font-size: var(--fs-small);
  color: var(--c-heading);
}
.chip button { display: grid; place-items: center; width: 32px; height: 44px; color: inherit; opacity: .7; }
.chip button:hover { opacity: 1; }
.chip svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 2; }

/* == Filter drawer contents (the shop-filters widget area) ================ */
.filter-group + .filter-group { margin-top: var(--sp-6); padding-top: var(--sp-6); border-top: 1px solid var(--c-line); }
.filter-group h3 {
  font-family: var(--ff-sans); font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: var(--ls-micro); text-transform: uppercase;
  color: var(--c-text-soft); margin-bottom: var(--sp-4);
}
.check { display: flex; align-items: center; gap: var(--sp-3); min-height: 44px; cursor: pointer; font-size: var(--fs-small); }
.check input {
  appearance: none;
  width: 20px; height: 20px; min-height: 0; flex: none;
  border: 1.5px solid var(--c-line-strong);
  border-radius: var(--r-sm);
  background: var(--c-surface);
  display: grid; place-items: center;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.check input:checked { background: var(--c-brand-fill); border-color: var(--c-brand-fill); }
.check input:checked::after {
  content: ''; width: 10px; height: 6px;
  border-left: 2px solid var(--c-on-brand); border-bottom: 2px solid var(--c-on-brand);
  transform: rotate(-45deg) translate(1px, -1px);
}
.check__n { margin-left: auto; color: var(--c-text-soft); font-size: var(--fs-micro); }

.swatch-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/*  A real 44px button with the 34px dot drawn inside it, rather than a 34px
 *  button with its hit area faked outwards - the target and the element agree,
 *  so it measures as 44px in an audit as well as feeling like it. */
.swatch-dot {
  position: relative;
  width: 44px; height: 44px;
  background: none;
  border: 0;
  border-radius: var(--r-pill);
}
.swatch-dot::after {
  content: '';
  position: absolute; inset: 5px;
  border-radius: inherit;
  background: inherit;                     /* the inline colour on the button */
  background-color: var(--swatch, currentColor);
  border: 1px solid var(--c-line-strong);
  box-shadow: inset 0 0 0 2px var(--c-surface);
}

/* == Empty state ========================================================== */
.empty { text-align: center; padding-block: var(--sp-11); display: grid; justify-items: center; gap: var(--sp-4); }
.empty svg { width: 46px; height: 46px; fill: none; stroke: var(--c-accent-soft); stroke-width: 1.2; }
.empty p { color: var(--c-text-soft); }

/* == Single product ======================================================= */
.product-main { display: grid; gap: var(--sp-7); }
@media (min-width: 900px) {
  .product-main { grid-template-columns: 55fr 45fr; gap: var(--sp-10); align-items: start; }
}

/* Gallery */
.gallery { display: grid; gap: var(--sp-3); }
@media (min-width: 900px) { .gallery { position: sticky; top: 108px; } }
.gallery__main {
  position: relative;
  aspect-ratio: 4 / 5;
  background: var(--c-well);
  border-radius: var(--card-radius);
  border: var(--card-edge);
  overflow: hidden;
}
.gallery__main img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.gallery__zoom {
  position: absolute; right: var(--sp-3); bottom: var(--sp-3);
  width: 44px; height: 44px;
  display: grid; place-items: center;
  background: var(--c-surface);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-card);
  border: var(--card-border);
  color: var(--c-accent);
}
.gallery__zoom svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; }

.gallery__thumbs {
  display: grid; grid-auto-flow: column; grid-auto-columns: 21%;
  gap: var(--sp-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
}
/*  On desktop each thumb is locked to a quarter of the row and the strip is
 *  left-aligned, so a product with two photos gets thumbs the same size as one
 *  with four rather than two oversized halves. */
@media (min-width: 900px) {
  .gallery__thumbs {
    grid-auto-columns: minmax(0, calc((100% - var(--sp-3) * 3) / 4));
    justify-content: start;
    overflow: visible;
  }
}
.gallery__thumbs button {
  scroll-snap-align: start;
  aspect-ratio: 1;
  background: var(--c-well);
  border: 1.5px solid transparent;
  border-radius: var(--r-sm);
  overflow: hidden;
  transition: border-color var(--dur) var(--ease);
}
.gallery__thumbs button img { width: 100%; height: 100%; object-fit: cover; }
.gallery__thumbs button[aria-current="true"] { border-color: var(--c-accent); }
.gallery__thumbs button:hover { border-color: var(--c-accent-soft); }

/*  Square gallery. The toner's images are 1:1 panels with text on them, so the
 *  frame matches them rather than cropping the text off. Six thumbnails share
 *  one row on desktop; on a phone the strip scrolls as it always has. */
.gallery--square .gallery__main { aspect-ratio: 1; }
@media (min-width: 900px) {
  .gallery--square .gallery__thumbs { grid-auto-columns: minmax(0, calc((100% - var(--sp-3) * 5) / 6)); }
}

/*  Trust row under the buy buttons. Confirmed facts only - never a "best seller"
 *  or "best quality" badge: this shop has no sales yet, and a seal like that
 *  makes a premium brand look cheap. */
.trust { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); grid-template-columns: 1fr; }
/*  Two-up, every box takes the tallest one's height. At 1440 they measured
 *  67, 67 and then four at 87: one box big, one small, in the same grid. */
@media (min-width: 480px) { .trust { grid-template-columns: 1fr 1fr; grid-auto-rows: 1fr; } }
.trust li {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--c-surface);
  border: var(--card-edge);
  font-size: var(--fs-small); line-height: var(--lh-copy); color: var(--c-text-soft);
}
.trust svg { flex: none; width: 22px; height: 22px; margin-top: 1px; color: var(--c-accent); }
.trust strong { display: block; font-weight: 500; color: var(--c-text); }
.trust a { display: inline-flex; align-items: center; min-height: 24px; color: var(--c-accent); }

/* Buy box */
.buybox > * + * { margin-top: var(--sp-5); }
.buybox__title { font-size: var(--fs-h2); color: var(--c-heading-deep); }
.buybox__rating { display: flex; align-items: center; gap: var(--sp-3); }
.buybox__rating a { display: inline-flex; align-items: center; min-height: 44px; font-size: var(--fs-small); color: var(--c-text-soft); }
.buybox__promise { color: var(--c-text-soft); max-width: 46ch; }

/* Variation swatches - pills, never a dropdown */
.varset__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.varset__label { font-size: var(--fs-small); font-weight: 500; }
.varset__chosen { font-size: var(--fs-small); color: var(--c-text-soft); }
.varset__opts { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.varopt {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-2) var(--sp-4);
  background: var(--c-surface);
  border: 1.5px solid var(--c-line-strong);
  border-radius: var(--r-pill);
  font-size: var(--fs-small);
  color: var(--c-text);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.varopt:hover { border-color: var(--c-accent-soft); }
.varopt[aria-pressed="true"] { border-color: var(--c-accent); background: var(--c-tint); font-weight: 500; }
.varopt__dot { width: 18px; height: 18px; border-radius: var(--r-pill); border: 1px solid color-mix(in srgb, var(--c-ink) 18%, transparent); flex: none; }
.varopt[data-stock="out"] { opacity: .45; text-decoration: line-through; pointer-events: none; }

.buybox__actions { display: grid; gap: var(--sp-3); }
.buybox__row { display: flex; gap: var(--sp-3); align-items: stretch; }
.buybox__row .btn { flex: 1; }
.buy-hint { font-size: var(--fs-small); color: var(--c-text-soft); display: flex; align-items: center; gap: var(--sp-2); }
.buy-hint svg { width: 15px; height: 15px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.6; }

.payline {
  display: grid; gap: var(--sp-3);
  padding: var(--sp-5);
  background: var(--c-tint);
  border-radius: var(--r-md);
  font-size: var(--fs-small);
}
.payline li { display: flex; align-items: center; gap: var(--sp-3); min-height: 24px; }
.payline a { display: inline-flex; align-items: center; min-height: 24px; }
.payline svg { width: 18px; height: 18px; flex: none; fill: none; stroke: var(--c-accent); stroke-width: 1.5; }

/* == Delivery estimator ===================================================
 *  "When will it reach ME?" is the question a Pakistani shopper asks before
 *  they will hand cash to a courier, and most small stores answer it with a
 *  vague line about nationwide delivery. This answers it for their own city,
 *  before they commit to anything, and remembers the answer for next time.
 *
 *  Every figure comes from the owner's courier table, not from us.
 *  ---------------------------------------------------------------------- */
.deliv {
  display: grid;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
}
.deliv__head { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-small); font-weight: 500; }
.deliv__head svg { width: 18px; height: 18px; flex: none; fill: none; stroke: var(--c-accent); stroke-width: 1.5; }

.deliv__row { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }
.deliv__row select { flex: 1; min-width: 0; min-height: 44px; padding-block: var(--sp-2); font-size: var(--fs-small); }

/* The answer. Reserved height, so filling it in cannot shift the page. */
.deliv__out {
  display: grid; gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-3) var(--sp-4);
  background: var(--c-tint);
  border-radius: var(--r-sm);
  font-size: var(--fs-small);
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity var(--dur-3) var(--ease), transform var(--dur-3) var(--ease);
}
.deliv__out.is-in { opacity: 1; transform: none; }
.deliv__when { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.deliv__days { font-family: var(--ff-display); font-size: var(--fs-h4); font-weight: 600; color: var(--c-heading); }
.deliv__cost { color: var(--c-text-soft); }
.deliv__cost strong { color: var(--c-ok); font-weight: 500; }
.deliv__note { font-size: var(--fs-micro); color: var(--c-text-soft); }

@media (prefers-reduced-motion: reduce) { .deliv__out { transition: none; } }

/* Sticky mobile buy bar */
.buybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-buybar);
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--gutter);
  padding-bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  background: var(--c-bg);
  border-top: 1px solid var(--c-line);
  box-shadow: 0 -4px 20px rgba(47, 74, 60, .10);
  transform: translateY(102%);
  transition: transform var(--dur-3) var(--ease);
}
.buybar.is-in { transform: none; }
@media (min-width: 900px) { .buybar { display: none; } }
.buybar__thumb { width: 46px; height: 56px; flex: none; border-radius: var(--r-sm); overflow: hidden; background: var(--c-well); }
.buybar__thumb img { width: 100%; height: 100%; object-fit: cover; }
.buybar__meta { min-width: 0; flex: 1; }
.buybar__name { font-size: var(--fs-small); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/*  This declared a family and a weight but no size, so it inherited 16px and
 *  the sticky purchase bar carried the SMALLEST price anywhere on the site.
 *  It takes the price size every other price takes. */
.buybar__price { font-family: var(--ff-display); font-size: var(--fs-h3); font-weight: 600; color: var(--c-text); }
.buybar .btn { flex: none; }

/* == Product detail accordions + rating breakdown ======================== */
.product-detail { display: grid; gap: var(--sp-8); }
@media (min-width: 900px) { .product-detail { grid-template-columns: 55fr 45fr; gap: var(--sp-10); align-items: start; } }

.ratebars { display: grid; gap: var(--sp-2); }
.ratebar { display: grid; grid-template-columns: 3.4rem 1fr 2.6rem; align-items: center; gap: var(--sp-3); font-size: var(--fs-small); }
.ratebar__track { height: 7px; background: var(--c-tint); border-radius: var(--r-pill); overflow: hidden; }
.ratebar__fill { height: 100%; background: var(--c-gold-line); border-radius: var(--r-pill); }
.ratebar__n { text-align: right; color: var(--c-text-soft); }

.rate-summary { display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap; }
.rate-summary__score { font-family: var(--ff-display); font-size: var(--fs-h2); font-weight: 600; line-height: var(--lh-flat); color: var(--c-heading-deep); }

/* == Frequently bought together ========================================== */
.fbt {
  display: grid; gap: var(--sp-6);
  padding: var(--sp-6);
  background: var(--c-surface);
  border: var(--card-edge);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
}
@media (min-width: 900px) { .fbt { grid-template-columns: 1fr auto; align-items: center; gap: var(--sp-8); } }
.fbt__items { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.fbt__item { display: grid; gap: var(--sp-2); justify-items: center; width: 104px; }
.fbt__item img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--r-sm); background: var(--c-well); }
.fbt__item span { font-size: var(--fs-micro); text-align: center; color: var(--c-text-soft); line-height: var(--lh-snug); }
.fbt__plus { font-size: var(--fs-h3); color: var(--c-accent-soft); }
.fbt__side { display: grid; gap: var(--sp-3); justify-items: start; }
@media (min-width: 900px) { .fbt__side { justify-items: end; text-align: right; } }
.fbt__save { font-size: var(--fs-small); color: var(--c-sale-text); }

/* == Cart ================================================================ */
.cart-layout { display: grid; gap: var(--sp-8); }
@media (min-width: 900px) { .cart-layout { grid-template-columns: 1.6fr 1fr; gap: var(--sp-10); align-items: start; } }

.cart-items { display: grid; }
.cart-line {
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: var(--sp-4);
  padding-block: var(--sp-5);
  border-bottom: 1px solid var(--c-line);
}
.cart-line:first-child { border-top: 1px solid var(--c-line); }
@media (min-width: 620px) { .cart-line { grid-template-columns: 108px 1fr auto; gap: var(--sp-5); align-items: start; } }
.cart-line__media { aspect-ratio: 4 / 5; background: var(--c-well); border-radius: var(--r-sm); overflow: hidden; }
.cart-line__media img { width: 100%; height: 100%; object-fit: cover; }
/* Same reason as .pcard__media--square in base.css: the oil's photograph is a
   square composition, and a 4:5 crop of it slices the brand name in half. */
.cart-line__media--square { aspect-ratio: 1 / 1; }
.cart-line__body { display: grid; gap: var(--sp-2); align-content: start; }
.cart-line__title { font-family: var(--ff-display); font-size: var(--fs-h4); font-weight: 600; }
/* The way back to the product page - a primary route out of the cart, so it
   gets a full-height target rather than the 22px the type alone would give. */
.cart-line__title a { display: inline-flex; align-items: center; min-height: 44px; color: inherit; text-decoration: none; }
.cart-line__var { font-size: var(--fs-small); color: var(--c-text-soft); }
.cart-line__controls { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; margin-top: var(--sp-2); }
.cart-line__remove { display: inline-flex; align-items: center; min-height: 44px; font-size: var(--fs-small); color: var(--c-text-soft); text-decoration: underline; text-underline-offset: .25em; }
.cart-line__remove:hover { color: var(--c-bad); }
.cart-line__price { font-family: var(--ff-display); font-size: var(--fs-h4); font-weight: 600; }
@media (min-width: 620px) { .cart-line__price { text-align: right; } }

/* Free-shipping progress */
.ship-progress { display: grid; gap: var(--sp-3); padding: var(--sp-5); background: var(--c-tint); border-radius: var(--r-md); }
.ship-progress__msg { font-size: var(--fs-small); display: flex; align-items: center; gap: var(--sp-3); }
.ship-progress__msg svg { width: 18px; height: 18px; flex: none; fill: none; stroke: var(--c-accent); stroke-width: 1.5; }
.ship-progress__msg strong { font-weight: 500; color: var(--c-heading); }
.ship-progress__track { height: 8px; background: color-mix(in srgb, var(--c-ink) 10%, transparent); border-radius: var(--r-pill); overflow: hidden; }
.ship-progress__fill { height: 100%; background: var(--c-brand-fill); border-radius: var(--r-pill); transition: width var(--dur-3) var(--ease); }

/* Coupon, collapsed behind a link */
.coupon summary { list-style: none; cursor: pointer; font-size: var(--fs-body); color: var(--c-accent); text-decoration: underline; text-underline-offset: .25em; padding-block: var(--sp-2); min-height: 44px; display: flex; align-items: center; }
.coupon summary::-webkit-details-marker { display: none; }
.coupon__form { display: flex; gap: var(--sp-3); margin-top: var(--sp-3); }

/* Order summary */
.summary {
  display: grid; gap: var(--sp-4);
  padding: var(--sp-6);
  background: var(--c-surface);
  border: var(--card-edge);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
}
@media (min-width: 900px) { .summary { position: sticky; top: 108px; } }
.summary h2 { font-size: var(--fs-h3); }
.summary__row { display: flex; justify-content: space-between; gap: var(--sp-4); font-size: var(--fs-small); }
.summary__row span:last-child { font-weight: 500; color: var(--c-text); }
.summary__total {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--c-line);
}
.summary__total .price { font-size: var(--fs-h3); }
.summary__trust { display: grid; gap: var(--sp-2); font-size: var(--fs-micro); color: var(--c-text-soft); }
.summary__trust li { display: flex; align-items: center; gap: var(--sp-2); min-height: 24px; }
.summary__trust svg { width: 14px; height: 14px; flex: none; fill: none; stroke: var(--c-accent-soft); stroke-width: 1.6; }

/* == Not sure which =======================================================
 *  Three routes into a shop that only has three products. Deliberately not
 *  cards-with-photographs: the photographs are already directly above, and
 *  repeating them would say "here are the products again" rather than "here
 *  is which one you want".
 *  ---------------------------------------------------------------------- */
.chooser { display: grid; gap: var(--sp-6); }
@media (min-width: 760px)  { .chooser { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .chooser { grid-template-columns: repeat(3, 1fr); gap: var(--sp-7); } }

.chooser__card {
  display: flex;
  flex-direction: column;
  padding: var(--sp-6);
  background: var(--c-surface);
  border: var(--card-edge);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
}
.chooser__icon {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  margin-bottom: var(--sp-4);
  border-radius: 50%;
  background: color-mix(in srgb, var(--c-leaf) 20%, transparent);
  color: var(--c-accent);
}
.chooser__icon svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.6; }

.chooser__card h3 {
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: 500;
  color: var(--c-heading-deep);
  margin-bottom: var(--sp-3);
}
.chooser__card p { color: var(--c-text-soft); }

.chooser__list {
  list-style: none;
  margin: var(--sp-5) 0 0;
  padding: var(--sp-4) 0 0;
  border-top: 1px solid var(--c-line);
  display: grid;
  gap: var(--sp-2);
  margin-top: auto;              /* the links line up across cards of unequal text */
}
.chooser__list a {
  /*  WCAG 2.5.8 wants 24px on a standalone link in a list. Padding alone gave
   *  23px — one pixel short, and the suite said so. min-height states the
   *  requirement outright instead of leaving it to arithmetic on a line box
   *  whose height depends on the font that happens to load. */
  display: flex;
  align-items: center;
  min-height: 24px;
  padding-block: 5px;
  font-variant-numeric: tabular-nums;
}

/* == Jump-to (FAQ) ========================================================
 *  In-page anchors, not a script. They work with JavaScript off and the
 *  browser handles the smooth scroll and the history entry itself.
 *  ---------------------------------------------------------------------- */
.jumpto {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3) var(--sp-4);
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--c-line);
}
.jumpto__label {
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--c-text-soft);
}
.jumpto ul {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
}
.jumpto a {
  display: flex;
  align-items: center;
  min-height: 32px;                /* WCAG 2.5.8 with room to spare */
  padding-inline: var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-pill);
  font-size: var(--fs-small);
  text-decoration: none;
  color: var(--c-text);
  transition: background var(--dur-2) var(--ease-settle),
              border-color var(--dur-2) var(--ease-settle);
}
.jumpto a:hover {
  background: var(--c-tint);
  border-color: color-mix(in srgb, var(--c-leaf) 60%, transparent);
}

/*  The header is sticky, so a heading landed on by an anchor would otherwise
 *  arrive underneath it. */
[id^="faq-"] { scroll-margin-top: calc(var(--header-h) + var(--sp-5)); }

/* == The product in use ===================================================
 *  A two-column band: the loop on the left, the routine on the right. The
 *  media column is the NARROWER one on purpose. A 4:5 clip given half of a
 *  1240px column comes out about 620x775 — taller than the fold, so the copy
 *  beside it scrolls away before it has been read. At 46% the clip and the
 *  paragraphs finish at roughly the same place.
 *
 *  minmax(0, …) on both tracks, not 46% / 1fr: a grid item's automatic
 *  minimum size is its content, and a <video> with intrinsic dimensions will
 *  push a 1fr track wider than its share rather than shrink. That is the
 *  overflow this component would otherwise produce at 860px, where the
 *  columns are at their tightest.
 *  --------------------------------------------------------------------- */
.inuse { display: grid; gap: var(--sp-6); align-items: center; }
@media (min-width: 860px) {
  .inuse {
    grid-template-columns: minmax(0, 46fr) minmax(0, 54fr);
    gap: var(--sp-8);
  }
}
/*  The clip is capped so it cannot become the whole page on a wide screen.
 *  Left-aligned rather than centred: it sits against the text column. */
.inuse .clip { max-width: 420px; }
@media (min-width: 860px) { .inuse .clip { max-width: none; } }

/*  THE CAPTION DOES NOT SIT ON THE WELL — dark mode, and it is a real
 *  failure, not a preference. base.css grounds .clip in --g-well, and
 *  --c-well is deliberately light in BOTH themes so a product photograph is
 *  never dark-filtered. Correct behind the poster; wrong behind the caption,
 *  because .clip__cap is --c-text-soft, which lifts to #AEB49A in dark mode
 *  and measures 2.11:1 on that near-white ground. The caption is text, not
 *  photography, so it takes the page ground, which flips. Dark goes to 8.1:1
 *  and light is unchanged.
 *
 *  Scoped to .inuse because this is the only captioned clip on the site
 *  today. A second one and this belongs in base.css with the component. */
.inuse .clip__cap { background: var(--c-bg); }

.inuse__copy > p { margin-top: var(--sp-4); color: var(--c-text-soft); }
.inuse__copy .section-title { margin-bottom: 0; }

/* == What arrives =========================================================
 *  .unbox itself is a base component. Only the two pieces that are specific
 *  to a product page live here: the delivered-total arithmetic, and the
 *  closing line under the three steps.
 *  --------------------------------------------------------------------- */

/*  THE TABLET GAP. base.css stacks .unbox into one column below 860px, and
 *  .owner-slot is capped at 300px tall with a 4:5 ratio — so between about
 *  560px and 860px each step was a 240px card sitting alone at the left of a
 *  700px column, with the sentence running the full width beside nothing.
 *  The section measured 1,625px at 768px against 800px at 1,440px, and the
 *  right-hand half of it was empty.
 *
 *  So in that band only, the step turns on its side: media left, words right.
 *  The media spans the rows because a step has two of them (head + text) or
 *  three (head + sum + text) depending on which step it is — spanning three
 *  covers both, and the unused row collapses to nothing. */
/*  .unbox__body groups the words so the media can sit beside them as ONE
 *  flex item. The first attempt kept the base grid and spanned the media
 *  across three rows — grid distributes a spanning item's height across the
 *  rows it spans, so the number, the sum and the paragraph were pushed apart
 *  to fill 300px of card. Flex, with the text as a single child, does not. */
.unbox__body { display: grid; gap: var(--sp-4); align-content: start; }

@media (min-width: 560px) and (max-width: 859px) {
  .unbox__step { display: flex; align-items: flex-start; gap: var(--sp-6); }
  .unbox__media { flex: none; width: 240px; }
  .unbox__body { flex: 1; }
}

/*  The sum is set as a line of arithmetic, not as a price. Tabular figures so
 *  the digits line up under each other on the toner and balm pages, and the
 *  operators are dimmed so the eye lands on the two numbers that matter: what
 *  the thing costs, and what the courier will ask for.
 *
 *  It repeats what the buy box computes from data-delivered / data-flat. That
 *  duplication is deliberate — this section is read by someone who has already
 *  scrolled past the buy box — but it means the two must be changed together. */
.unbox__sum {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2);
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  /*  lining-nums, not just tabular. Cormorant defaults to OLD-STYLE figures,
   *  where the 8 and the 5 drop below the baseline — lovely in a sentence,
   *  wrong in a sum, because the digits stop lining up and the total stops
   *  reading as money. */
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--c-heading-deep);
}
.unbox__sum span { color: var(--c-text-soft); }
.unbox__sum strong { font-weight: 600; color: var(--c-gold-ink); }

/*  DARK MODE, and it is a real defect rather than a preference.
 *
 *  .owner-slot inherits --g-well from base.css, and --c-well is deliberately
 *  LIGHT in both themes — "product photos are never dark-filtered". That is
 *  right for a photo well, and wrong here: an owner slot never holds a
 *  photograph, it holds a gold icon and a gold .verify label, and in dark
 *  mode --c-gold lifts to #CBCB67. Gold on the near-white well measures
 *  1.68:1. The icon was effectively invisible and the label unreadable.
 *
 *  --g-warm instead: surface -> surface-2, so it flips with the theme on its
 *  own with no theme selector to keep in sync. Light is unchanged in practice
 *  (--c-surface and --c-well are both --c-ivory there); dark goes to 8.9:1.
 *
 *  These two pages are the only consumers of .owner-slot today. When a second
 *  page wants one, this belongs in base.css beside the component. */
.unbox .owner-slot { background: var(--g-warm); }

/* == FAQ: sidebar and questions ==========================================
 *  The questions were a single 860px column centred on the page, so on a
 *  laptop two thirds of every screen were empty cream and the four category
 *  chips scrolled away with the page head. Now the categories are a column
 *  of their own, pinned while you read, with a way to reach a person at the
 *  foot of it — the question behind every FAQ page is "and if my answer is
 *  not here?", and the answer should be visible the whole time.
 *
 *  Below 1024px there is no room for two columns, so the sidebar falls back
 *  to exactly what it was: the chip row above the questions, unpinned.
 *  ---------------------------------------------------------------------- */
.faq-layout { display: grid; gap: var(--sp-6); }
.faq-layout__groups > .section:first-child { padding-top: 0; }

.faq-help {
  margin-top: var(--sp-6);
  padding: var(--sp-5);
  border-radius: var(--card-radius);
  background: var(--c-surface);
  border: var(--card-edge);
  box-shadow: var(--card-shadow);
  font-size: var(--fs-small);
  color: var(--c-text-soft);
}
.faq-help__title {
  font-family: var(--ff-display);
  font-size: var(--fs-h4);
  font-weight: 600;
  color: var(--c-heading-deep);
  margin-bottom: var(--sp-2);
}
.faq-help .btn { margin-top: var(--sp-4); }
/*  On a phone the help card would sit between the chips and the first
 *  question, pushing the answers down a screen. The brand band at the foot
 *  of the page already carries the same invitation there. */
@media (max-width: 1023px) { .faq-help { display: none; } }

@media (min-width: 1024px) {
  .faq-layout {
    grid-template-columns: 240px minmax(0, 1fr);
    gap: var(--sp-10);
    align-items: start;
  }
  .faq-layout__side {
    position: sticky;
    top: calc(var(--header-h) + var(--sp-6));
  }
  .faq-layout__nav {
    display: block;
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
  }
  .faq-layout__nav .jumpto__label { display: block; margin-bottom: var(--sp-3); }
  .faq-layout__nav ul { flex-direction: column; gap: 0; border-left: 1px solid var(--c-line); }
  .faq-layout__nav li a {
    min-height: 40px;
    padding-inline: var(--sp-4);
    border: 0;
    border-left: 2px solid transparent;
    margin-left: -1px;
    border-radius: 0;
  }
  .faq-layout__nav li a:hover { border-left-color: var(--c-gold-line); background: none; color: var(--c-accent); }
}

/* == Product pages: the loop and the arrival, tightened ===================
 *  Two modifiers. .inuse--portrait is the toner page's alone: it is drawn
 *  for its 9:16 clip. .unbox--cards is carried by all three product pages,
 *  so "What actually arrives" is the same three cards wherever it appears -
 *  one step card, one medallion, one icon position - rather than three
 *  pages each solving it their own way. Appended at the end on purpose:
 *  both have to come after the .inuse and .unbox rules they refine.
 *  --------------------------------------------------------------------- */

/*  .inuse--portrait: for a 9:16 clip. The 46/54 split above was drawn for a
 *  4:5 loop. Given a phone-shaped clip it made the clip about 520 x 920 at
 *  1,440 and the section 1,050px tall, with the seven steps floating in the
 *  middle of a column of cream. At 1 : 2.4 the clip comes out about
 *  330 x 630, close to the height of the steps beside it, which is the whole
 *  point of putting the two side by side.
 *
 *  From 560px the clip already sits beside the copy, where the 860px
 *  breakpoint above left a tablet with one very tall column. Below 560px
 *  there is only one column, so the clip is narrowed and centred instead:
 *  at full width a 9:16 clip is over 600px of phone screen before step one.
 *
 *  width, not max-width, below 560px: the clip is a grid item, and auto
 *  margins on a grid item without a width shrink it to its content rather
 *  than centring it. */
.inuse--portrait .clip { width: 70%; margin-inline: auto; }
@media (min-width: 560px) {
  .inuse--portrait { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--sp-6); }
  .inuse--portrait .clip { width: auto; max-width: none; margin-inline: 0; }
}
@media (min-width: 860px) {
  .inuse--portrait { grid-template-columns: minmax(0, 1fr) minmax(0, 2.4fr); gap: var(--sp-10); }
}

/*  .unbox--cards: the three steps with no media, as three equal cards.
 *  The dashed owner slots were 300px each and held an icon and a note; the
 *  owner read them as empty boxes, and said so. Without them each step is
 *  only words, and words loose on cream in three columns read as notes. The
 *  same words in three equal cards read as a sequence. Grid stretch keeps
 *  the three the same height in the row.
 *
 *  The gold top edge is the same hairline language as .section--edged: one
 *  deliberate line, the rest of the border left to --card-border so dark
 *  mode still gets its outline.
 *
 *  The numeral takes the gold medallion from the homepage's "How to use it"
 *  (.ritual__n: same 36px, same --c-on-gold on --c-gold, which
 *  contrast-check already covers as the badge pair), so a step number looks
 *  the same wherever the site counts steps. The icon that used to sit in the
 *  empty slot moves to the card's corner, gold on the card surface: 3.78:1
 *  light and 7.72:1 dark against the 3:1 a graphic needs.
 *
 *  color, not stroke: the sprite's symbols set stroke="currentColor" on
 *  themselves, and that presentation attribute beats a stroke inherited
 *  from the <svg>, so only currentColor reaches the line. */
.unbox--cards { gap: var(--sp-5); }
.unbox--cards .unbox__step {
  padding: var(--sp-5);
  background: var(--c-surface);
  border: var(--card-border);
  border-top: 1px solid color-mix(in srgb, var(--c-gold-line) 55%, transparent);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
}
.unbox--cards .unbox__head { align-items: center; }
.unbox--cards .unbox__n {
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--c-gold);
  color: var(--c-on-gold);
  font-size: var(--fs-h4);
  font-weight: 600;
  font-variant-numeric: lining-nums tabular-nums;
}
.unbox--cards .unbox__icon {
  flex: none;
  width: 30px; height: 30px;
  margin-left: auto;
  color: var(--c-gold-line);
}

/* == Lip balm page: the buy box, pulled level with its gallery ============
 *  At 1,440px the buy box ran to 1,104px beside a 920px gallery, so the
 *  photographs stopped and a column of text carried on alone. Three rows
 *  were paying for nothing: the review link sat on a 44px row of its own,
 *  the delivery answer reserved 44px of blank tint before any city was
 *  chosen, and the estimator's question and its select were stacked when
 *  there was room for them side by side.
 *
 *  Every selector here is a modifier that only product.html carries, so the
 *  toner and oil pages are untouched until they opt in. When they do, this
 *  block moves up beside .buybox and .deliv.
 *  --------------------------------------------------------------------- */

/*  Price first, review link at the end of the same line. It wraps under the
 *  price on a narrow phone rather than squeezing either one. */
.buybox__priceline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-5);
}

/*  The answer takes no room until there is an answer. The reserved height
 *  under .deliv__out exists so that filling it cannot shift the page, but
 *  for a first-time visitor it was 44px of blank tint on every load, and
 *  with JavaScript off it never fills at all. Two things fill it: the
 *  visitor choosing a city, which is a change they made themselves, and
 *  ui.js restoring a city remembered from an earlier page, which happens
 *  as the deferred script runs at the end of loading, normally before the
 *  first paint. That second case is the one to watch if a layout-shift
 *  report ever names this box. */
.deliv--fold .deliv__out:not(.is-in) { display: none; }
@starting-style {
  .deliv--fold .deliv__out.is-in { opacity: 0; transform: translateY(-3px); }
}
/*  1080px, not 900. The buy box is 45fr of the product grid, so at 900px
 *  it is about 355px wide, and the select would get about 100px beside the
 *  question: not enough for "Choose your city". At 1080px it gets about
 *  175px. */
@media (min-width: 1080px) {
  .deliv--fold {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    column-gap: var(--sp-4);
  }
  .deliv--fold .deliv__out,
  .deliv--fold .deliv__note { grid-column: 1 / -1; }
}

/* == Lip balm page: reviews, one card not two =============================
 *  The empty state (413px) sat beside the form (933px) as two separate
 *  cards, which is exactly the "one box big, one box small" the owner keeps
 *  pointing at. Joined, they are two panels of one card and the same height
 *  by construction. The warm panel keeps its gradient, so the invitation
 *  still reads apart from the form, and its words sit in the middle of it
 *  rather than stranded at the top. overflow: clip, not hidden: it trims the
 *  panel to the rounded corners without making a scroll container.
 *
 *  The thank-you keeps its own tinted box, so inside the joined card it is
 *  inset rather than pressed against the card's edge. */
.reviews-grid--joined {
  gap: 0;
  align-items: stretch;
  overflow: clip;
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--shadow-soft);
}
.reviews-grid--joined .reviews-empty,
.reviews-grid--joined .review-form {
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.reviews-grid--joined .reviews-empty { border-bottom: 1px solid var(--c-line); }
.reviews-grid--joined .review-thanks { margin: var(--sp-5); }
@media (min-width: 900px) {
  .reviews-grid--joined .reviews-empty {
    align-content: center;
    border-bottom: 0;
    border-right: 1px solid var(--c-line);
  }
}

/* == Oil page: the two bands with no media yet ============================
 *  The oil has no photograph of itself in use and none of its parcel, and
 *  the dashed owner slots that stood in for them were the empty boxes the
 *  owner called unprofessional. .inuse--solo is what "The oil, in use"
 *  looks like with words only; only product-oil.html carries it. Its
 *  arrival steps use .unbox--cards, the card all three product pages share
 *  (see "Product pages: the loop and the arrival" above).
 *
 *  .inuse--solo: the heading takes the narrow left column and the routine
 *  the wide right one, both from the top, and the three facts run as one
 *  line under the routine instead of a column of three.
 *  --------------------------------------------------------------------- */
@media (min-width: 860px) {
  .inuse--solo {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    align-items: start;
  }
}
.inuse--solo .inuse__copy > p:first-child { margin-top: 0; }
.inuse--solo .microline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-6);
}
