/* ==========================================================================
   CraftNest — WooCommerce
   The product card is the load bearing component: get it right once and four
   pages are half built. Everything below restyles Woo rather than fighting it.
   ========================================================================== */

/* ==========================================================================
   Product card — 4:3 preview, two line title, mono meta, four states
   ========================================================================== */

.cn-product {
  position: relative;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  background: var(--cn-paper);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: box-shadow var(--cn-ease), border-color var(--cn-ease);
}
.cn-product:hover { box-shadow: var(--cn-shadow-hover); }

/* Media */
.cn-product__media {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
  background-color: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a05) 0 6px, transparent 6px 12px);
  display: block;
}
.cn-product__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Second image crossfades in on hover, no zoom, no parallax. */
.cn-product__media img.cn-product__alt {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--cn-ease);
}
.cn-product:hover .cn-product__alt { opacity: 1; }

/* Wishlist toggle, top right */
.cn-product__wish {
  position: absolute;
  top: 10px; inset-inline-end: 10px;
  width: 32px; height: 32px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-white-a90);
  border: 1px solid var(--cn-line);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 3;
  padding: 0;
  transition: background var(--cn-ease);
}
.cn-product:hover .cn-product__wish { background: var(--cn-paper); }
.cn-product__wish.is-on svg path { fill: var(--cn-warm); stroke: var(--cn-warm); }

/* Mono caption in the bottom left of the preview */
.cn-product__hint {
  position: absolute;
  bottom: 10px; inset-inline-start: 12px;
  font-family: var(--cn-font-mono);
  font-size: 11px;
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  z-index: 2;
}

/* Quick add, revealed on hover on pointer devices only */
.cn-product__quickadd {
  position: absolute;
  left: 12px; right: 12px;
  bottom: 36px;
  height: var(--cn-tap);
  border-radius: var(--cn-radius-button);
  background: var(--cn-accent);
  color: var(--cn-on-fill);
  border: 0;
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: 15px;
  cursor: pointer;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--cn-ease), transform var(--cn-ease), background var(--cn-ease);
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
}
.cn-product__quickadd:hover { background: var(--cn-accent-dark); color: var(--cn-on-fill); }
@media (hover: hover) and (pointer: fine) {
  .cn-product:hover .cn-product__quickadd,
  .cn-product:focus-within .cn-product__quickadd { opacity: 1; transform: none; }
}
@media (hover: none) {
  .cn-product__quickadd { display: none; }
}

/* Body */
.cn-product__body {
  padding: var(--cn-space-4);
  display: flex;
  flex-direction: column;
  flex: 1;
}
.cn-product__title {
  font-family: var(--cn-font-body);
  font-size: var(--cn-fs-16);
  font-weight: 500;
  line-height: 1.35;
  min-height: 44px;          /* two lines, so grids stay aligned */
  margin: 0;
  color: var(--cn-ink);
  text-wrap: pretty;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.cn-product__title a { color: inherit; }
.cn-product__title a:hover { color: var(--cn-accent); }

/* The proof line. File count, formats, size. Never optional. */
.cn-product__meta {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  margin: var(--cn-space-2) 0;
}
.cn-product__rating { margin-bottom: var(--cn-space-3); }

.cn-product__price {
  display: flex;
  align-items: baseline;
  gap: var(--cn-space-2);
  margin-top: auto;
  flex-wrap: wrap;
  /*
   * The bottom of a card is one slot, the height of a control.
   *
   * The price is 29px tall and the in-basket row is 44, so quick-add grew
   * every card it touched by 15px and shoved the rest of the grid down.
   * Reserving the taller of the two in both states means the card that was
   * just added is exactly the card that was there a moment ago.
   */
  min-height: var(--cn-tap);
  align-content: center;
}

/* The same slot, holding the in-basket state instead of the price. */
.cn-product__cartrow {
  margin-top: auto;
  align-items: center;
  min-height: var(--cn-tap);
}
.cn-product__price .amount,
.cn-price {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-18);
  color: var(--cn-ink);
}
.cn-product__price del,
.cn-price--was {
  font-family: var(--cn-font-body);
  font-size: var(--cn-fs-14);
  font-weight: 400;
  color: var(--cn-graphite);
  text-decoration: line-through;
}
.cn-product__price del .amount { font-family: inherit; font-size: inherit; font-weight: inherit; color: inherit; }
.cn-product__price ins { text-decoration: none; }
.cn-product__price--free .amount,
.cn-price--free { color: var(--cn-warm-text); }

/* Free variant puts the instant download pill beside the price. */
.cn-product__price--split {
  justify-content: space-between;
  align-items: center;
}
/* Badges are nowrap by default, which is right everywhere the pill has a row
   of its own. Here it does not: in a two column grid at 320px the card body is
   128px and the pill is 147px, so "Instant Download" was cut off at the edge
   of the card. Inside the card it may use two lines. */
.cn-product__price--split .cn-badge {
  white-space: normal;
  min-width: 0;
  text-align: center;
}

/* In cart state: success hairline and a quantity stepper. */
.cn-product.is-in-cart { border-color: var(--cn-success); }

.cn-qty {
  display: flex;
  align-items: center;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-button);
  height: var(--cn-tap);
  overflow: hidden;
}
.cn-qty button {
  width: 36px; height: var(--cn-tap);
  border: 0;
  background: transparent;
  cursor: pointer;
  color: var(--cn-graphite);
  font-size: var(--cn-fs-18);
  line-height: 1;
}
.cn-qty button:hover { background: var(--cn-surface); color: var(--cn-ink); }

/*
 * The card's stepper. The value used to be a lone span in a flex row, which
 * left the number hard against the left edge of a box that looked like it
 * should hold three things. It now holds three things.
 */
.cn-qty__step {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  align-self: stretch;
  flex: 0 0 36px;
  color: var(--cn-graphite);
  font-size: var(--cn-fs-18);
  line-height: 1;
  text-decoration: none;
  user-select: none;
}
.cn-qty__step:hover { background: var(--cn-surface); color: var(--cn-ink); }

/*
 * Sold individually: the line can only ever be one, so the card says what it
 * is rather than offering a number that will not move.
 */
.cn-qty--single { border-color: var(--cn-success); padding-inline-start: var(--cn-space-3); gap: var(--cn-space-2); }
.cn-qty--single .cn-qty__value {
  /*
   * width: auto, and it has to be said.
   *
   * The shared rule below sizes the value at a fixed 40px, which is right for
   * a digit and 36px too narrow for the words "In basket". With the box set
   * to overflow: hidden the text was simply cut off mid-word, so a card that
   * had just been added to read as broken rather than as added.
   */
  width: auto;
  flex: 0 0 auto;
  padding-inline: 0;
  min-width: 0;
  font-family: var(--cn-font-body);
  font-weight: 600;
  color: var(--cn-ink);
  white-space: nowrap;
}
.cn-qty__mark { color: var(--cn-success); font-size: var(--cn-fs-14); line-height: 1; }
.cn-qty__value { flex: 1; text-align: center; min-width: 32px; }
.cn-qty input,
.cn-qty__value {
  width: 40px;
  height: var(--cn-tap);
  border: 0;
  text-align: center;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-14);
  padding: 0;
  background: transparent;
}
.cn-qty input:focus { box-shadow: none; }

/* ==========================================================================
   Shop archive
   ========================================================================== */

.woocommerce-products-header { display: none; }

.cn-shop-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-4);
  flex-wrap: wrap;
  border-bottom: 1px solid var(--cn-line);
  padding-bottom: var(--cn-space-4);
}
.cn-shop-toolbar__count {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
}
.cn-shop-toolbar__controls { display: flex; align-items: center; gap: var(--cn-space-3); }
.cn-shop-toolbar select { height: var(--cn-tap); width: auto; min-width: 190px; font-size: 15px; }

.cn-density {
  display: inline-flex;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-button);
  overflow: hidden;
}
.cn-density button {
  width: var(--cn-tap); height: var(--cn-tap);
  border: 0;
  border-inline-start: 1px solid var(--cn-line);
  background: var(--cn-paper);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--cn-graphite);
}
.cn-density button:first-child { border-inline-start: 0; }
.cn-density button.is-active { background: var(--cn-ink); color: var(--cn-on-fill); }
.cn-density button.is-active svg [fill] { fill: var(--cn-on-fill); }

/* Active filter chips */
.cn-active-filters {
  display: flex;
  gap: var(--cn-space-2);
  flex-wrap: wrap;
  align-items: center;
  padding: var(--cn-space-4) 0 var(--cn-space-6);
}

/* Product grid. Density switch just changes the minimum track size. */
.cn-products {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--cn-card-min, 240px), 1fr));
  gap: var(--cn-space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}
.cn-products > li { margin: 0; }
.cn-products--dense { --cn-card-min: 200px; }
.cn-products--wide  { --cn-card-min: 280px; }

/*
 * Pinned column counts, for a band that has to be exactly four across.
 * They step down before the cards get too narrow to read a price in, so
 * six across on a desktop is still three on a tablet rather than six
 * slivers, and the 600px rule below turns every one of them into two.
 */
.cn-products--cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cn-products--cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cn-products--cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cn-products--cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.cn-products--cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }

@media (max-width: 1100px) {
  .cn-products--cols-5,
  .cn-products--cols-6 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .cn-products--cols-4,
  .cn-products--cols-5,
  .cn-products--cols-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/*
 * Two columns at 390, exactly as drawn. auto-fill would collapse to one
 * column here, and a single 4:3 card that wide turns the grid into a tower.
 */
@media (max-width: 600px) {
  .cn-products,
  .cn-products--dense,
  .cn-products--wide,
  [class*="cn-products--cols-"] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--cn-space-3);
  }
  .cn-product__body { padding: var(--cn-space-3); }
  .cn-product__title { font-size: var(--cn-fs-14); min-height: 38px; }
  .cn-product__meta { font-size: 11px; margin: 6px 0; }
  .cn-product__price .amount,
  .cn-product__price .cn-price { font-size: var(--cn-fs-16); }
  .cn-product__price del,
  .cn-price--was { font-size: 13px; }
  .cn-product__rating { display: none; }
  .cn-badges { top: var(--cn-space-2); inset-inline-start: var(--cn-space-2); }
  .cn-badges .cn-badge { font-size: 12px; padding: 4px 10px; }
  .cn-product__hint { display: none; }
}

/* Filter sidebar */
.cn-filters__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  border-bottom: 1px solid var(--cn-line);
  padding-bottom: var(--cn-space-3);
  margin-bottom: var(--cn-space-5);
}
.cn-filters__group {
  border-bottom: 1px solid var(--cn-line);
  padding-bottom: var(--cn-space-5);
  margin-bottom: var(--cn-space-5);
}
.cn-filters__group:last-child { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }
.cn-filters__legend {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  margin-bottom: var(--cn-space-2);
}
.cn-filters ul { list-style: none; margin: 0; padding: 0; }
.cn-filters li { margin: 0; }

/* Mobile filter trigger, sticky under the header */
.cn-filterbar {
  display: none;
  position: sticky;
  top: var(--cn-header);
  z-index: 5;
  background: var(--cn-paper);
  border-top: 1px solid var(--cn-line);
  border-bottom: 1px solid var(--cn-line);
  padding: 10px var(--cn-gutter);
  gap: var(--cn-space-2);
  align-items: center;
}
.cn-filterbar > * { flex: 1; }
.cn-filterbar select { height: var(--cn-tap); font-size: var(--cn-fs-14); }

@media (max-width: 900px) {
  .cn-filterbar { display: flex; top: 0; }
  .cn-shop-toolbar { justify-content: space-between; }
}

/* Long form SEO block below the grid */
.cn-shop-copy {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
  gap: var(--cn-space-12);
}
.cn-shop-copy p { color: var(--cn-graphite); }

/* ==========================================================================
   Single product
   ========================================================================== */

.cn-product-top {
  max-width: var(--cn-max);
  margin-inline: auto;
  padding: var(--cn-space-8) var(--cn-gutter) 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: var(--cn-space-12);
  align-items: start;
}
@media (max-width: 900px) {
  .cn-product-top { grid-template-columns: minmax(0, 1fr); gap: var(--cn-space-8); }
}

/* Gallery */
.cn-gallery__stage {
  position: relative;
  aspect-ratio: 1;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  overflow: hidden;
  cursor: zoom-in;
  background-color: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a05) 0 8px, transparent 8px 16px);
}
.cn-gallery__stage img { width: 100%; height: 100%; object-fit: cover; }
.cn-gallery__stage .cn-badges { top: var(--cn-space-4); inset-inline-start: var(--cn-space-4); }
.cn-gallery__wish {
  position: absolute;
  top: var(--cn-space-4); inset-inline-end: var(--cn-space-4);
  width: var(--cn-tap); height: var(--cn-tap);
  border-radius: var(--cn-radius-badge);
  background: var(--cn-white-a92);
  border: 1px solid var(--cn-line);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 3;
}
.cn-gallery__zoom {
  position: absolute;
  bottom: var(--cn-space-4); inset-inline-end: var(--cn-space-4);
  height: 40px;
  padding-inline: 14px;
  border-radius: var(--cn-radius-button);
  border: 1px solid var(--cn-line);
  background: var(--cn-white-a92);
  cursor: pointer;
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-14);
  display: inline-flex;
  align-items: center;
  gap: var(--cn-space-2);
  z-index: 3;
}
.cn-gallery__thumbs {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: var(--cn-space-2);
  margin-top: var(--cn-space-3);
}
.cn-gallery__thumb {
  position: relative;
  aspect-ratio: 1;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  overflow: hidden;
  cursor: pointer;
  padding: 0;
  background-color: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a06) 0 5px, transparent 5px 10px);
}
.cn-gallery__thumb img { width: 100%; height: 100%; object-fit: cover; }
.cn-gallery__thumb[aria-current="true"],
.cn-gallery__thumb.is-active { border-color: var(--cn-accent); }
.cn-gallery__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.cn-gallery__play span {
  width: 26px; height: 26px;
  border-radius: var(--cn-radius-badge);
  background: rgba(14, 17, 22, .72);
  display: flex;
  align-items: center;
  justify-content: center;
}
.cn-gallery__caption { margin-top: var(--cn-space-3); }

@media (max-width: 600px) {
  .cn-gallery__thumbs { grid-template-columns: repeat(4, 1fr); }
}

/* Buy box, sticky on desktop, unsticks at the tablet breakpoint */
.cn-buybox { position: sticky; top: calc(var(--cn-header) + var(--cn-space-6)); }
@media (max-width: 900px) { .cn-buybox { position: static; } }

.cn-buybox h1 {
  font-size: var(--cn-fs-44);
  line-height: 1.08;
  margin: 0 0 var(--cn-space-4);
}
.cn-buybox__signals {
  display: flex;
  align-items: center;
  gap: var(--cn-space-3);
  flex-wrap: wrap;
  margin-bottom: var(--cn-space-6);
}

/* The mono strip: file count, formats, size, layered */
.cn-specstrip {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-ink);
  border-top: 1px solid var(--cn-line);
  border-bottom: 1px solid var(--cn-line);
  padding: 14px 0;
  margin-bottom: var(--cn-space-6);
}

.cn-buybox__price {
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  flex-wrap: wrap;
  margin-bottom: var(--cn-space-2);
}
.cn-buybox__now {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-60);
  line-height: 1;
  letter-spacing: var(--cn-track-tight);
}
.cn-buybox__was {
  font-size: var(--cn-fs-20);
  color: var(--cn-graphite);
  text-decoration: line-through;
}
.cn-buybox__deadline { margin-bottom: var(--cn-space-6); }
.cn-buybox__actions {
  display: flex;
  gap: var(--cn-space-3);
  margin-bottom: var(--cn-space-5);
  flex-wrap: wrap;
}
.cn-buybox__actions .cn-btn { flex: 1; min-width: 160px; height: var(--cn-control-l); }

/*
 * Woo prints Add to cart, and inc/woocommerce.php hooks Buy now in straight
 * after it. Everything from the button down is laid out here as one row so
 * the pair reads as the drawn pair, on simple and variable products alike.
 */
.woocommerce div.product form.cart {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cn-space-3);
  align-items: center;
  margin-bottom: var(--cn-space-5);
}
.woocommerce div.product form.cart > .variations,
.woocommerce div.product form.cart > .woocommerce-variation-add-to-cart,
.woocommerce div.product form.cart > .single_variation_wrap,
.woocommerce div.product form.cart > .woocommerce-variation { flex: 1 0 100%; }

.woocommerce div.product form.cart .single_add_to_cart_button,
.woocommerce div.product form.cart .cn-buynow {
  flex: 1 1 180px;
  height: var(--cn-control-l);
  min-height: var(--cn-control-l);
  margin: 0;
}

/* The variation add to cart row is itself a flex row. */
.woocommerce div.product form.cart .woocommerce-variation-add-to-cart {
  display: flex;
  gap: var(--cn-space-3);
  align-items: center;
  flex-wrap: wrap;
}

/* Quantity is off for downloadable products, so any stray box goes with it. */
/*
 * Downloadable products are sold one at a time, and craftnest_sold_individually
 * already makes WooCommerce emit a hidden input for them -- so this rule was
 * redundant there and wrong everywhere else. On a physical product WooCommerce
 * prints a real number input and this hid it, leaving the buyer able to order
 * exactly one with no explanation. Scoped by a body class instead.
 */
.cn-downloadable-product .woocommerce div.product form.cart .quantity { display: none; }

/*
 * Woo's variation dropdown, hidden only once JavaScript has wired the
 * segmented control to it. The class is added by theme.js, never in markup,
 * so without JavaScript the dropdown is still the way to pick a licence.
 */
.woocommerce div.product form.cart.is-segmented .variations,
.woocommerce div.product form.cart.is-segmented .reset_variations { display: none; }

/* Woo's variation price block duplicates the buy box price. */
/*
 * WooCommerce's live price stays hidden while the buy box is showing the
 * parent's, and takes over the moment a variation resolves -- theme.js adds
 * .is-live. Hiding it unconditionally is what let the page keep advertising
 * the cheapest licence after the customer had chosen a dearer one.
 */
.woocommerce div.product .woocommerce-variation-price { display: none; }
.woocommerce div.product .woocommerce-variation-price.is-live { display: block; }
.woocommerce div.product .woocommerce-variation-price.is-live .price {
  font: var(--cn-font-display-32);
  color: var(--cn-ink);
}
.woocommerce div.product .woocommerce-variation-availability { flex: 1 0 100%; }
.cn-buybox__sample {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: 15px;
  display: inline-flex;
  align-items: center;
  gap: var(--cn-space-2);
  margin-bottom: var(--cn-space-5);
  min-height: var(--cn-tap);
}
.cn-buybox__pay {
  display: flex;
  gap: var(--cn-space-2);
  flex-wrap: wrap;
  border-top: 1px solid var(--cn-line);
  padding-top: var(--cn-space-5);
}
.cn-buybox__pay span {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: 8px 12px;
}

@media (max-width: 600px) {
  .cn-buybox h1 { font-size: var(--cn-fs-32); }
  .cn-buybox__now { font-size: var(--cn-fs-44); }
}

/* ==========================================================================
   Bundle landing — screen 07
   ========================================================================== */

/* The value stack: the one boxed price in the whole system. */
.cn-valuestack {
  border: 1px solid var(--cn-white-a20);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-6);
  background: rgba(255, 255, 255, .04);
  max-width: 520px;
}
.cn-valuestack__price {
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  flex-wrap: wrap;
  margin-bottom: var(--cn-space-2);
}
.cn-valuestack__now {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-76);
  line-height: 1;
  letter-spacing: var(--cn-track-tight);
}
.cn-valuestack__was {
  font-size: 22px;
  color: var(--cn-white-a55);
  text-decoration: line-through;
}
.cn-valuestack__cta {
  height: 56px;
  font-size: 17px;
  margin-bottom: 10px;
}
@media (max-width: 600px) {
  .cn-valuestack { padding: var(--cn-space-5); }
  .cn-valuestack__now { font-size: var(--cn-fs-44); }
}

/* The contents table carries two summary rows: a struck through subtotal and
   the bundle price on an ink band. */
.cn-table--bundle td,
.cn-table--bundle th { padding: 14px 20px; }
.cn-table__mono {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
}
.cn-table__subtotal { background: var(--cn-surface); }
.cn-table__subtotal td {
  padding-block: 18px;
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: 17px;
}
.cn-table__subtotal del { font-size: var(--cn-fs-20); color: var(--cn-graphite); }
.cn-table__grand {
  background: var(--cn-ink);
  color: var(--cn-on-fill);
}
.cn-table__grand td {
  padding: var(--cn-space-5);
  border-bottom: 0;
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-18);
}
.cn-table__grand td:last-child {
  font-size: var(--cn-fs-32);
  letter-spacing: var(--cn-track-tight);
}
.cn-table__grand .cn-save { color: var(--cn-success-ink); }

/* Made by customers */
.cn-ugc figcaption { text-transform: uppercase; }

/* Reviews */
.cn-reviews__summary {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-8);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: var(--cn-space-12);
  align-items: center;
  margin-bottom: var(--cn-space-8);
}
.cn-reviews__score {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-76);
  line-height: 1;
  letter-spacing: var(--cn-track-tight);
}
/* The wall adds a third column of honesty badges beside the distribution. */
.cn-reviews__summary--wall {
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}
.cn-reviews__summary--wall .cn-distribution__count { width: 52px; }

.cn-reviews__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr));
  gap: var(--cn-space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (max-width: 600px) {
  .cn-reviews__list { grid-template-columns: minmax(0, 1fr); }
  .cn-reviews__score { font-size: var(--cn-fs-60); }
}

.cn-review {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-6);
  margin: 0;
}
.cn-review__head {
  display: flex;
  gap: var(--cn-space-3);
  align-items: center;
  margin-bottom: var(--cn-space-4);
  /* The "Verified purchase" pill does not wrap its own text, so at 320px it
     rode straight out of the review, out of the column and off the page --
     the product page was the one screen with a horizontal scrollbar at 320. */
  flex-wrap: wrap;
}
.cn-review__avatar {
  flex: 0 0 40px;
  width: 40px; height: 40px;
  border-radius: var(--cn-radius-badge);
  overflow: hidden;
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, rgba(14, 17, 22, .07) 0 4px, transparent 4px 8px);
}
.cn-review__avatar img { width: 100%; height: 100%; object-fit: cover; }
.cn-review__who { flex: 1; }
.cn-review__name { display: block; font-size: 15px; font-weight: 500; }
.cn-review__title { font-family: var(--cn-font-display); font-weight: 600; font-size: 17px; margin-bottom: var(--cn-space-2); }
.cn-review__body { color: var(--cn-graphite); margin-bottom: var(--cn-space-4); }
.cn-review__photos { display: flex; gap: var(--cn-space-2); margin-bottom: var(--cn-space-4); flex-wrap: wrap; }
.cn-review__photos button,
.cn-review__photos img {
  width: 72px; height: 72px;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: 0;
  cursor: pointer;
  object-fit: cover;
  background: var(--cn-preview);
}
.cn-review__reply {
  background: var(--cn-surface);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-4);
  margin: 0 0 var(--cn-space-4) var(--cn-space-6);
}
.cn-review__reply-head {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-bottom: var(--cn-space-2);
  flex-wrap: wrap;
}
.cn-review__reply-mark {
  width: 28px; height: 28px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-ink);
  color: var(--cn-on-fill);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-12);
}
.cn-review__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-4);
  border-top: 1px solid var(--cn-line);
  padding-top: var(--cn-space-4);
  flex-wrap: wrap;
}

/* ==========================================================================
   Cart drawer
   ========================================================================== */

.cn-cart__item {
  display: flex;
  gap: var(--cn-space-3);
  padding: var(--cn-space-5) 0;
  border-bottom: 1px solid var(--cn-line);
}
.cn-cart__thumb {
  flex: 0 0 72px;
  width: 72px; height: 72px;
  border-radius: 2px;
  overflow: hidden;
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a06) 0 5px, transparent 5px 10px);
}
.cn-cart__thumb img { width: 100%; height: 100%; object-fit: cover; }

/* The cart page has room for a larger preview than the drawer does. This used
   to be an inline style on the element, which beat every media query below and
   left a 120px thumbnail on a 272px row: the title column came out 80px wide
   and broke words down the middle. */
.cn-cart__thumb--lg { flex: 0 0 120px; width: 120px; height: 120px; }

/* A phone cannot spare 120px of a 272px row for a preview, so the cart page
   falls back to the drawer's thumbnail and gives the width to the title. */
@media (max-width: 600px) {
  .cn-cart__thumb--lg { flex: 0 0 72px; width: 72px; height: 72px; }
}

.cn-cart__info { flex: 1; min-width: 0; }
.cn-cart__name { font-size: 15px; font-weight: 500; line-height: 1.35; color: var(--cn-ink); }
.cn-cart__side { text-align: end; }
.cn-cart__price { font-family: var(--cn-font-display); font-weight: 600; font-size: var(--cn-fs-16); }
.cn-cart__remove {
  margin-top: var(--cn-space-2);
  border: 0;
  background: transparent;
  cursor: pointer;
  font-family: var(--cn-font-mono);
  font-size: 11px;
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  padding: 0;
  min-height: 32px;
}
.cn-cart__remove:hover { color: var(--cn-warm-text); }

.cn-cart__block { padding: var(--cn-space-5) 0; border-bottom: 1px solid var(--cn-line); }
.cn-cart__block:last-child { border-bottom: 0; }

/*
 * Thumb, name and an Add button on one row -- until there is no room for one
 * row. The name column carried an inline flex:1;min-width:0, so inside the
 * 320px cart drawer it shrank to 72px and set "Easter Bunny Bundle SVG" one
 * word per line, five lines tall, while the Add button kept its full 101px.
 * Given a sensible basis the button drops to a second row instead, which is
 * what the licence picker already does.
 */
.cn-suggestion {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cn-space-3);
  align-items: center;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-3);
}
.cn-suggestion__body {
  flex: 1 1 130px;
  min-width: 0;
}
.cn-suggestion__name {
  font-size: 14px;
  font-weight: 500;
}
.cn-suggestion .cn-btn { margin-inline-start: auto; }
.cn-suggestion__thumb {
  flex: 0 0 56px;
  width: 56px; height: 56px;
  border-radius: 2px;
  overflow: hidden;
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(45deg, var(--cn-ink-a06) 0 5px, transparent 5px 10px);
}
.cn-suggestion__thumb img { width: 100%; height: 100%; object-fit: cover; }

.cn-coupon { display: flex; gap: var(--cn-space-2); }
.cn-coupon input { flex: 1; height: var(--cn-tap); }
.cn-coupon .cn-btn { height: var(--cn-tap); }

.cn-totals__row {
  display: flex;
  justify-content: space-between;
  gap: var(--cn-space-4);
  font-size: 15px;
  margin-bottom: var(--cn-space-2);
}
.cn-totals__row--grand {
  align-items: baseline;
  border-top: 1px solid var(--cn-line);
  padding-top: var(--cn-space-3);
  margin-top: var(--cn-space-3);
  margin-bottom: var(--cn-space-4);
}
.cn-totals__label { color: var(--cn-graphite); }
.cn-totals__row--grand .cn-totals__label {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-18);
  color: var(--cn-ink);
}
.cn-totals__grand {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-32);
  letter-spacing: var(--cn-track-tight);
}
.cn-totals__discount { color: var(--cn-success); }

/* Full page cart falls back to the same parts in one column */
.cn-cart-page {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  gap: var(--cn-space-12);
  align-items: start;
}
@media (max-width: 900px) {
  .cn-cart-page { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   Checkout
   ========================================================================== */

.cn-checkout {
  background: var(--cn-paper);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  overflow: hidden;
}
.cn-checkout__head {
  border-bottom: 1px solid var(--cn-line);
  padding-inline: var(--cn-space-8);
  height: var(--cn-header);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-6);
}
.cn-checkout__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr));
  gap: var(--cn-space-12);
  padding: var(--cn-space-12) var(--cn-space-8);
  align-items: start;
}
.cn-checkout h2,
.cn-checkout h3 {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: 22px;
  margin: 0 0 var(--cn-space-4);
}
.cn-express {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--cn-space-3);
  margin-bottom: var(--cn-space-6);
}
.cn-express .cn-btn { height: var(--cn-control-l); font-size: 15px; padding-inline: var(--cn-space-3); }
@media (max-width: 600px) {
  .cn-express { grid-template-columns: 1fr; }
  .cn-checkout__grid { padding: var(--cn-space-8) var(--cn-space-4); }
  .cn-checkout__head { padding-inline: var(--cn-space-4); }
}

/*
 * Payment methods. WooCommerce's own list, which the theme had left entirely
 * alone -- so it arrived as a bulleted ul with a 13px radio and a 20px-tall
 * label. Choosing how to pay was the smallest thing to hit on the whole
 * checkout. The label is the control's label, so making it 44px tall makes the
 * target 44px without redrawing the radio.
 */
.woocommerce-checkout #payment ul.payment_methods {
  list-style: none;
  margin: 0 0 var(--cn-space-4);
  padding: 0;
  border-bottom: 1px solid var(--cn-line);
}
.woocommerce-checkout #payment ul.payment_methods > li {
  list-style: none;
  border-top: 1px solid var(--cn-line);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: var(--cn-space-3);
}
.woocommerce-checkout #payment ul.payment_methods > li > input[type="radio"] {
  margin: 0;
  flex: 0 0 auto;
}
.woocommerce-checkout #payment ul.payment_methods > li > label {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  min-height: var(--cn-tap);
  padding-block: var(--cn-space-2);
  margin: 0;
  cursor: pointer;
  font-weight: 500;
}
.woocommerce-checkout #payment .payment_box {
  flex: 0 0 100%;
  margin: 0 0 var(--cn-space-4);
  padding-inline-start: calc(13px + var(--cn-space-3));
  color: var(--cn-graphite);
  /* 15px was a number, not a token, and the only 15px on the page. */
  font-size: var(--cn-fs-14);
  line-height: 1.5;
}
.woocommerce-checkout #payment .payment_box p { margin: 0; }

/*
 * The payment panel, as the gateway actually leaves it.
 *
 * Reading the live checkout: one gateway, presented as a radio list of one,
 * labelled "Stripe" -- the name of the company the shop banks with, offered
 * to the customer as if it were a choice they had to make. Under it a second
 * radio, "Use a new payment method", with no saved methods to be new
 * instead of. Above the lot, a reCAPTCHA badge dropped in by a plugin with a
 * bare <br> for spacing.
 *
 * None of that is the design's doing and all of it is in the design's panel,
 * so the panel tidies up after it.
 */

/* One way to pay is not a choice. Kept in the accessibility tree, and still
   submitted, because it is the field that carries the answer. */
.cn-paybox .wc_payment_methods > li:only-child > input[type="radio"],
.cn-paybox .wc_payment_methods > li:only-child > label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.cn-paybox .wc_payment_methods > li:only-child > .payment_box {
  padding-inline-start: 0;
  margin: 0;
}

/* Nothing saved, so nothing to pick between. */
.cn-paybox .wc-saved-payment-methods[data-count="0"] { display: none; }

/* The plugin's badge, given room instead of a line break. */
.cn-paybox .g-recaptcha { margin-bottom: var(--cn-space-4); }
.cn-paybox > br { display: none; }

/* The gateway's own field frame, matching the inputs beside it. */
.cn-paybox .wc-stripe-upe-element,
.cn-paybox .wc-payment-form { margin-block: var(--cn-space-3); }

/* "Save payment information" is a sentence too, not a field name. Written
   with the same weight as the rule it overrides, or it loses: that rule is
   .woocommerce form .form-row label, and a media query is not the only thing
   that adds no specificity. */
.woocommerce form .form-row.woocommerce-SavedPaymentMethods-saveNew label,
.woocommerce form .form-row label[for="wc-stripe-new-payment-method"] {
  font-family: var(--cn-font-body);
  font-size: var(--cn-fs-14);
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--cn-graphite);
}

.cn-or {
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  margin-bottom: var(--cn-space-8);
}
.cn-or::before,
.cn-or::after { content: ''; flex: 1; height: 1px; background: var(--cn-line); }

/*
 * The pay column: summary, then the card, then the button.
 *
 * The summary used to be sticky, which was right while it was the only thing
 * in this column and wrong the moment the payment box moved under it -- a
 * pinned summary with the card fieldset sliding underneath it is a column
 * fighting itself. The column scrolls as one thing now.
 */
.cn-checkout__pay { display: grid; gap: var(--cn-space-6); align-content: start; }

.cn-paybox {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  background: var(--cn-paper);
  padding: var(--cn-space-6);
}
.cn-paybox h2 { margin-bottom: var(--cn-space-4); }

/* Woo wraps the box in its own div; it carries no styling of its own. */
.cn-paybox #payment { background: transparent; border: 0; padding: 0; }
.cn-paybox #payment ul.payment_methods { border-bottom: 0; margin-bottom: 0; }
.cn-paybox #payment ul.payment_methods > li:first-child { border-top: 0; }
.cn-paybox #payment .form-row.place-order { margin: var(--cn-space-5) 0 0; padding: 0; }
/* Spacing for the consent stack is set once, further down, where both boxes
   are dealt with together. Setting it here as well is how the two of them
   ended up 36px apart with no single rule to blame. */

/*
 * The place-order button is the one thing on the page that has to look like
 * the end of it. Woo prints a bare <button>, which picked up nothing.
 */
.cn-paybox #place_order {
  width: 100%;
  min-height: var(--cn-control-l);
  border: 0;
  border-radius: var(--cn-radius-button);
  background: var(--cn-ink);
  color: var(--cn-paper);
  font-family: var(--cn-font-body);
  font-size: var(--cn-fs-16);
  font-weight: 600;
  cursor: pointer;
}
.cn-paybox #place_order:hover { background: var(--cn-accent); }
.cn-paybox #place_order:disabled { opacity: .6; cursor: default; }

.cn-checkout__summary {
  top: var(--cn-space-6);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  background: var(--cn-surface);
  padding: var(--cn-space-6);
}
.cn-checkout__line {
  display: flex;
  gap: var(--cn-space-3);
  padding-bottom: var(--cn-space-4);
  margin-bottom: var(--cn-space-4);
  border-bottom: 1px solid var(--cn-line);
}
.cn-checkout__line-thumb {
  flex: 0 0 64px;
  width: 64px; height: 64px;
  border-radius: 2px;
  overflow: hidden;
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a06) 0 5px, transparent 5px 10px);
}
.cn-checkout__line-thumb img { width: 100%; height: 100%; object-fit: cover; }
.cn-checkout__note { text-align: center; margin-top: var(--cn-space-4); }

/* The order summary is a card inside a card. At 320px those two sets of
   padding plus a 64px thumbnail left the product name a 60px column, so
   "Christmas" broke across two lines. Give the name the difference.
   This has to sit after the two rules it overrides -- a media query adds no
   specificity, so the same declarations earlier in the file would lose. */
@media (max-width: 600px) {
  .cn-checkout__summary { padding: var(--cn-space-4); }
  .cn-checkout__line-thumb { flex: 0 0 48px; width: 48px; height: 48px; }
}

/*
 * Consent block, required for EU digital goods. Never collapsed by default.
 *
 * The two tick boxes are one list and have to read as one. They did not:
 * WooCommerce's terms row carries a 16px bottom margin, its wrapper another
 * 16, and this block added its own on top, so the two sentences sat 40px
 * apart while the paragraph above the first sat 16px away. The pair looked
 * like two unrelated blocks with a hole between them.
 *
 * Every margin in the stack is zeroed and one rhythm is set here, so the
 * spacing is stated once instead of being the sum of three things.
 */
.woocommerce .woocommerce-terms-and-conditions-wrapper,
.cn-paybox #payment .woocommerce-terms-and-conditions-wrapper,
.woocommerce form .woocommerce-terms-and-conditions-wrapper .form-row,
.woocommerce .cn-consent,
.cn-paybox .cn-consent,
.woocommerce form .cn-consent .form-row { margin-block: 0; }

.woocommerce-terms-and-conditions-wrapper .woocommerce-privacy-policy-text { margin-bottom: var(--cn-space-4); }

/*
 * The spacing between them is the parent's gap, not a margin.
 *
 * Both boxes sit inside <p class="form-row place-order">, which the theme
 * makes a flex column with an 8px gap. A margin here is added to that gap,
 * so asking for 12 produced 20 and the number in the stylesheet matched
 * nothing on the screen. Set the gap and there is one figure to read.
 */
.woocommerce form .form-row.place-order { gap: var(--cn-space-3); }

.woocommerce form .woocommerce-terms-and-conditions-wrapper .form-row + .form-row { margin-top: var(--cn-space-3); }

.woocommerce .cn-consent,
.cn-paybox .cn-consent { margin-bottom: var(--cn-space-6); }
.cn-consent .cn-check { align-items: flex-start; }
.cn-consent .cn-check span { padding-top: 2px; }

/* Card fieldset, mirrors the gateway iframe layout */
.cn-cardbox {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  overflow: hidden;
  margin-bottom: var(--cn-space-6);
}
.cn-cardbox__row {
  display: flex;
  align-items: center;
  gap: var(--cn-space-3);
  min-height: 52px;
  padding-inline: 14px;
  border-bottom: 1px solid var(--cn-line);
}
.cn-cardbox__split { display: flex; }
.cn-cardbox__split > * { flex: 1; border-bottom: 0; }
.cn-cardbox__split > *:first-child { border-inline-end: 1px solid var(--cn-line); }

/* ==========================================================================
   Order received and downloads
   ========================================================================== */

.cn-orderhero {
  background-color: var(--cn-ink);
  color: var(--cn-on-fill);
  background-image:
    linear-gradient(var(--cn-white-a08) 1px, transparent 1px),
    linear-gradient(90deg, var(--cn-white-a08) 1px, transparent 1px);
  background-size: var(--cn-grid-size) var(--cn-grid-size);
}
.cn-orderhero__inner {
  max-width: var(--cn-max);
  margin-inline: auto;
  padding: var(--cn-section) var(--cn-gutter);
}
.cn-orderhero__facts {
  display: flex;
  gap: var(--cn-space-8);
  flex-wrap: wrap;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-white-a72);
}

.cn-download {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-5);
  display: flex;
  gap: var(--cn-space-5);
  align-items: center;
  flex-wrap: wrap;
}
.cn-download__thumb {
  flex: 0 0 120px;
  width: 120px;
  aspect-ratio: 1;
  border-radius: 2px;
  overflow: hidden;
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a06) 0 6px, transparent 6px 12px);
}
.cn-download__thumb img { width: 100%; height: 100%; object-fit: cover; }
.cn-download__info { flex: 1; min-width: 220px; }
.cn-download__name { font-size: var(--cn-fs-18); font-weight: 500; line-height: 1.35; }
.cn-download__action {
  display: flex;
  flex-direction: column;
  gap: var(--cn-space-2);
  min-width: 220px;
}
.cn-download__action .cn-btn { height: var(--cn-control-l); }
.cn-download__file {
  font-family: var(--cn-font-mono);
  font-size: 11px;
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  text-align: center;
  word-break: break-all;
}
@media (max-width: 600px) {
  .cn-download__thumb { flex: 0 0 88px; width: 88px; }
  .cn-download__action { min-width: 100%; }
}

/* Account list rows */
.cn-account-row {
  background: var(--cn-paper);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-4);
  display: flex;
  gap: var(--cn-space-4);
  align-items: center;
  flex-wrap: wrap;
}
.cn-account-row__thumb {
  flex: 0 0 96px;
  width: 96px;
  aspect-ratio: 1;
  border-radius: 2px;
  overflow: hidden;
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a06) 0 6px, transparent 6px 12px);
}
.cn-account-row__thumb img { width: 100%; height: 100%; object-fit: cover; }
.cn-account-row__info { flex: 1; min-width: 200px; }
.cn-account-row__meta {
  min-width: 150px;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  line-height: 1.8;
}
.cn-account-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-4);
  flex-wrap: wrap;
  background: var(--cn-paper);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-4) var(--cn-space-5);
  margin-bottom: var(--cn-space-4);
}

/* ==========================================================================
   WooCommerce core overrides
   ========================================================================== */

.woocommerce-message,
.woocommerce-info,
.woocommerce-error,
.woocommerce-notices-wrapper .woocommerce-message {
  list-style: none;
  border: 1px solid var(--cn-line);
  border-inline-start: 2px solid var(--cn-accent);
  border-radius: var(--cn-radius-card);
  background: var(--cn-surface);
  padding: var(--cn-space-4) var(--cn-space-5);
  margin: 0 0 var(--cn-space-5);
  font-size: 15px;
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  flex-wrap: wrap;

}

/* A WooCommerce error IS the <ul>, and its errors are <li> children -- so
   flex laid six validation messages out side by side as one run-on sentence.
   The list stacks; only a single-message notice gets the row treatment. */
.woocommerce-error { display: block; }
.woocommerce-error li { display: list-item; list-style: none; }
.woocommerce-error li + li { margin-top: 6px; padding-top: 6px; border-top: 1px solid rgba(0,0,0,.08); }
.woocommerce-message { border-inline-start-color: var(--cn-success); }
.woocommerce-error   { border-inline-start-color: var(--cn-warm-text); }
.woocommerce-message .button,
.woocommerce-info .button,
.woocommerce-error .button { margin-inline-start: auto; }

.woocommerce .button,
.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce #respond input#submit,
.wp-element-button {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-16);
  background: var(--cn-accent);
  color: var(--cn-on-fill);
  border: 1px solid var(--cn-accent);
  border-radius: var(--cn-radius-button);
  height: var(--cn-control);
  padding-inline: var(--cn-space-6);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  line-height: 1;
  transition: background var(--cn-ease), border-color var(--cn-ease);
}
.woocommerce .button:hover,
.woocommerce a.button:hover,
.woocommerce button.button:hover,
.woocommerce input.button:hover,
.woocommerce #respond input#submit:hover {
  background: var(--cn-accent-dark);
  border-color: var(--cn-accent-dark);
  color: var(--cn-on-fill);
}
.woocommerce .button.alt { background: var(--cn-accent); border-color: var(--cn-accent); }
.woocommerce .button:disabled,
.woocommerce .button.disabled {
  background: var(--cn-surface);
  border-color: var(--cn-line);
  color: var(--cn-muted);
  cursor: not-allowed;
}

.woocommerce form .form-row { margin: 0 0 var(--cn-space-4); padding: 0; display: flex; flex-direction: column; gap: var(--cn-space-2); }
.woocommerce form .form-row label {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
}

/*
 * A checkbox label is a sentence, not a field name.
 *
 * The rule above is drawn for "EMAIL ADDRESS *": small, mono, tracked out,
 * upper case. Applied to a checkbox it caught the two consent sentences at
 * the bottom of the checkout, which are 120 and 180 characters of plain
 * English, and set them as upper case monospace paragraphs. Sitting directly
 * under the privacy notice, which is Inter at 16px in sentence case, the
 * checkout looked like two different websites.
 *
 * Everything here undoes that one rule and nothing else, so field labels keep
 * the treatment the design drew for them.
 */
.woocommerce form .form-row label.checkbox,
.woocommerce form .form-row label.woocommerce-form__label-checkbox,
.woocommerce form .form-row .cn-check label,
.cn-consent label,
.woocommerce-terms-and-conditions-wrapper label,
.woocommerce-terms-and-conditions-wrapper label span {
  font-family: var(--cn-font-body);
  font-size: var(--cn-fs-14);
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  line-height: 1.5;
  color: var(--cn-graphite);
}

/*
 * The privacy notice above them is the same voice, so it is the same type.
 * It arrived at 16px against the labels' 15 for no reason anyone chose.
 */
.woocommerce-privacy-policy-text p,
.woocommerce-terms-and-conditions-wrapper .woocommerce-privacy-policy-text p {
  font-family: var(--cn-font-body);
  font-size: var(--cn-fs-14);
  line-height: 1.5;
  color: var(--cn-graphite);
  margin: 0 0 var(--cn-space-4);
}
.woocommerce form .form-row .required { color: var(--cn-warm-text); text-decoration: none; border: 0; }
.woocommerce form .form-row-first,
.woocommerce form .form-row-last { width: 100%; float: none; }
.woocommerce-input-wrapper { width: 100%; }
.woocommerce form .form-row.woocommerce-validated input.input-text { border-color: var(--cn-line); }
.woocommerce form .form-row.woocommerce-invalid input.input-text { border-color: var(--cn-warm-text); }

.woocommerce .quantity .qty {
  width: 72px;
  height: var(--cn-tap);
  text-align: center;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-button);
  font-family: var(--cn-font-mono);
}

.woocommerce div.product form.cart { margin: 0; }
.woocommerce div.product .woocommerce-tabs { display: none; }
.woocommerce div.product p.price,
.woocommerce div.product span.price { color: var(--cn-ink); }

.woocommerce-breadcrumb { display: none; }

/*
 * Woo's default result count and ordering form are suppressed where Woo puts
 * them, then shown again inside the theme's own toolbars. Hiding them by
 * class alone also hid the copies this theme places on purpose.
 */
.woocommerce .woocommerce-result-count { display: none; }
.woocommerce .woocommerce-ordering { display: none; }

.cn-shop-toolbar .woocommerce-ordering,
.cn-filterbar .woocommerce-ordering { display: block; margin: 0; }

.cn-shop-toolbar .woocommerce-ordering select { min-width: 190px; }
.cn-filterbar .woocommerce-ordering select { height: var(--cn-tap); font-size: var(--cn-fs-14); }

/* From 900 down the sticky filter bar carries sort, so the toolbar copy goes.
   This has to sit after the rule above or the re-show wins at every width. */
@media (max-width: 900px) {
  .cn-shop-toolbar .woocommerce-ordering { display: none; }
}

/* Woo variation form, restyled into the segmented control */
.woocommerce div.product form.cart .variations { margin-bottom: var(--cn-space-6); border: 0; }
.woocommerce div.product form.cart .variations td,
.woocommerce div.product form.cart .variations th { padding: 0 0 var(--cn-space-3); border: 0; display: block; }
.woocommerce div.product form.cart .variations label {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  font-weight: 400;
}
.woocommerce div.product form.cart .reset_variations {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
}
.woocommerce div.product .woocommerce-variation-price { margin-bottom: var(--cn-space-4); }

/*
 * Woo's own star rating is replaced by craftnest_get_stars() inside the loop
 * and the buy box. It is NOT hidden globally, because the rating filter
 * widget draws its rows with the same class and hiding it leaves the
 * sidebar with a bare "(8)".
 */
.woocommerce ul.products li.product .star-rating,
.woocommerce div.product .woocommerce-product-rating .star-rating { display: none; }

/*
 * The rating filter draws its stars with WooCommerce's icon font, which lives
 * in the stylesheet this theme drops. Rather than pull that sheet back in for
 * one widget, the row is redrawn from a repeated SVG star: an empty row on
 * the wrapper, a filled row on the inner span whose width is the rating.
 */
.cn-filters .star-rating,
.wc-layered-nav-rating .star-rating {
  position: relative;
  display: inline-block;
  width: 80px;
  height: 14px;
  overflow: hidden;
  font-size: 0;
  vertical-align: middle;
  background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='14' viewBox='0 0 12 12'%3E%3Cpath d='M6 1l1.5 3.2 3.5.5-2.5 2.4.6 3.4L6 8.9 2.9 10.5l.6-3.4L1 4.7l3.5-.5z' fill='%23E4E2DD'/%3E%3C/svg%3E") repeat-x left center;
}
.cn-filters .star-rating > span,
.wc-layered-nav-rating .star-rating > span {
  position: absolute;
  top: 0;
  inset-inline-start: 0;
  height: 100%;
  overflow: hidden;
  text-indent: -9999px;
  white-space: nowrap;
  background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='14' viewBox='0 0 12 12'%3E%3Cpath d='M6 1l1.5 3.2 3.5.5-2.5 2.4.6 3.4L6 8.9 2.9 10.5l.6-3.4L1 4.7l3.5-.5z' fill='%23FF7A2F'/%3E%3C/svg%3E") repeat-x left center;
}

/* ==========================================================================
   Filter widgets — Woo's own markup, given the design's rows
   ========================================================================== */

.cn-filters .woocommerce-widget-layered-nav-list,
.cn-filters .product-categories,
.cn-filters ul.wc-layered-nav-rating,
.cn-filters .woocommerce-widget-layered-nav-list li,
.cn-filters .product-categories li {
  list-style: none;
  margin: 0;
  padding: 0;
}

/*
 * Woo puts the count OUTSIDE the link: <li><a>Name</a> <span class="count">.
 * So the row has to be the flex container, not the link, or the count drops
 * onto a line of its own.
 */
.cn-filters .woocommerce-widget-layered-nav-list li,
.cn-filters .product-categories li,
.cn-filters ul.wc-layered-nav-rating li {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--cn-tap);
}

.cn-filters .woocommerce-widget-layered-nav-list li a,
.cn-filters .product-categories li a,
.cn-filters ul.wc-layered-nav-rating li a {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
  font-size: 15px;
  color: var(--cn-ink);
}
.cn-filters .woocommerce-widget-layered-nav-list li a:hover,
.cn-filters .product-categories li a:hover { color: var(--cn-accent); }

/* A square marker standing in for the drawn checkbox, filled when active. */
.cn-filters .woocommerce-widget-layered-nav-list li a::before,
.cn-filters .product-categories li a::before {
  content: '';
  flex: 0 0 18px;
  width: 18px;
  height: 18px;
  border: 1px solid var(--cn-line);
  border-radius: 3px;
  background: var(--cn-paper);
}
.cn-filters .woocommerce-widget-layered-nav-list li.chosen a::before,
.cn-filters .product-categories li.current-cat a::before {
  background: var(--cn-accent) url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4l2.6 2.6L10 3.4' stroke='%23fff' stroke-width='1.8' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center no-repeat;
  border-color: var(--cn-accent);
}

.cn-filters .count,
.cn-filters li .count {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
  margin-inline-start: auto;
}

/* Price filter */
.cn-filters .price_slider_wrapper .ui-slider {
  height: 4px;
  background: var(--cn-line);
  border: 0;
  border-radius: var(--cn-radius-badge);
  margin: var(--cn-space-5) 0 var(--cn-space-4);
  position: relative;
}
.cn-filters .price_slider_wrapper .ui-slider .ui-slider-range {
  background: var(--cn-accent);
  height: 4px;
  border-radius: var(--cn-radius-badge);
  position: absolute;
}
.cn-filters .price_slider_wrapper .ui-slider .ui-slider-handle {
  width: 18px;
  height: 18px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-paper);
  border: 2px solid var(--cn-accent);
  top: -7px;
  margin-inline-start: -9px;
  position: absolute;
  cursor: grab;
}
.cn-filters .price_slider_amount {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-3);
  flex-wrap: wrap;
}
.cn-filters .price_slider_amount .price_label {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
  order: 1;
}
.cn-filters .price_slider_amount .button { order: 2; height: var(--cn-tap); font-size: var(--cn-fs-14); }

/* Downloads table in the account area */
.woocommerce table.shop_table {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  border-collapse: separate;
  border-spacing: 0;
  overflow: hidden;
}
.woocommerce table.shop_table th {
  background: var(--cn-surface);
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  font-weight: 400;
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  padding: 14px 16px;
  border-bottom: 1px solid var(--cn-line);
  text-align: start;
}
.woocommerce table.shop_table td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--cn-line);
  font-size: 15px;
}
.woocommerce table.shop_table tbody tr:last-child td { border-bottom: 0; }

.woocommerce-MyAccount-navigation { display: none; } /* replaced by cn-account-nav */

/* Password strength meter */
.woocommerce-password-strength {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  padding: var(--cn-space-2) 0;
}
.woocommerce-password-strength.strong { color: var(--cn-success); }
.woocommerce-password-strength.short,
.woocommerce-password-strength.bad { color: var(--cn-warm-text); }

/* Cart drawer body reuses the drawer shell from layout.css */
.cn-cartdrawer__title {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: 22px;
  display: flex;
  align-items: baseline;
  gap: var(--cn-space-2);
}

/* ==========================================================================
   Orders table — screen 12a. One table; at 390 the rows become cards.
   ========================================================================== */

.cn-orders-table__go a {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-14);
  white-space: nowrap;
}
.cn-orders-table td { vertical-align: middle; }

@media (max-width: 600px) {
  .cn-orders-table,
  .cn-orders-table tbody,
  .cn-orders-table tr,
  .cn-orders-table td { display: block; width: 100%; }

  .cn-orders-table thead { display: none; }

  .cn-orders-table tr {
    border: 1px solid var(--cn-line);
    border-radius: var(--cn-radius-card);
    padding: var(--cn-space-4);
    margin-bottom: var(--cn-space-3);
  }

  .cn-orders-table td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--cn-space-4);
    border: 0;
    padding: 6px 0;
    text-align: end;
  }

  /* The header the row lost, put back on the cell it belonged to. */
  .cn-orders-table td::before {
    content: attr(data-label);
    font-family: var(--cn-font-mono);
    font-size: var(--cn-fs-12);
    letter-spacing: var(--cn-track-mono);
    text-transform: uppercase;
    color: var(--cn-graphite);
    text-align: start;
  }

  .cn-orders-table td.cn-orders-table__go { justify-content: flex-end; padding-top: var(--cn-space-3); }
  .cn-orders-table td.cn-orders-table__go::before { content: none; }

  /*
   * Once the row is a card these two links are the only way out of it, and a
   * flex item takes the height of its text -- 24px, half a thumb. They get a
   * real target without moving anything else on the card.
   */
  .cn-orders-table td a,
  .cn-orders-table td.cn-orders-table__go a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* The claims under a product description — screen 03 */
.cn-claims {
  margin: 0 0 var(--cn-space-6);
  padding-inline-start: 18px;
  color: var(--cn-graphite);
}
.cn-claims li { margin-bottom: var(--cn-space-1); }
/* 12px to the claims that follow, 24px when there are none. */
.cn-buybox__desc { margin-bottom: var(--cn-space-6); }
.cn-buybox__desc:has( + .cn-claims ) { margin-bottom: var(--cn-space-3); }
.cn-buybox__desc > p:last-child { margin-bottom: 0; }

/* The product a wall review is about — screen 11b */
.cn-review__product {
  display: flex;
  gap: var(--cn-space-3);
  align-items: center;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: 10px;
  margin-bottom: var(--cn-space-4);
  color: var(--cn-ink);
}
.cn-review__product:hover { border-color: var(--cn-ink); }
.cn-review__product-thumb {
  flex: 0 0 56px;
  width: 56px; height: 56px;
  border-radius: 2px;
  overflow: hidden;
  background: var(--cn-preview);
}
.cn-review__product-thumb img { width: 100%; height: 100%; object-fit: cover; }

/* The avatar carries initials unless a real picture is in it, so the hatch
   only applies to the image case — behind letters it is just noise. */
.cn-review__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-14);
  color: var(--cn-graphite);
  background-image: none;
}
.cn-review__avatar:has( img ) { background-image: repeating-linear-gradient(135deg, rgba(14, 17, 22, .07) 0 4px, transparent 4px 8px); }

/* Clear the search, beside the term — screen 10d */
.cn-clear-search {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-badge);
  color: var(--cn-graphite);
  font-size: 20px;
  vertical-align: middle;
  margin-inline-start: var(--cn-space-3);
}
.cn-clear-search:hover { border-color: var(--cn-ink); color: var(--cn-ink); }

/* A grouped kit needs its real add-to-cart table, not a button that links to
   the page it is already on. It sits on the ink hero, so the table WooCommerce
   prints has to read on a dark ground. */
.cn-bundle__form { margin-block: var(--cn-space-5); }
.cn-bundle__form .woocommerce-grouped-product-list { width: 100%; border-collapse: collapse; margin-bottom: var(--cn-space-4); }
.cn-bundle__form .woocommerce-grouped-product-list td { padding: 10px 8px; border-bottom: 1px solid var(--cn-white-a20); vertical-align: middle; }
.cn-bundle__form .woocommerce-grouped-product-list label { color: var(--cn-on-fill); }
.cn-bundle__form .woocommerce-grouped-product-list a { color: var(--cn-on-fill); text-decoration: underline; }
.cn-bundle__form .woocommerce-grouped-product-list .woocommerce-Price-amount { color: var(--cn-on-fill); }
.cn-bundle__form .quantity input { width: 4.5rem; }
.cn-bundle__form .single_add_to_cart_button { width: 100%; }

/* Licence picker on a simple product. The radios carry the choice so the form
   works with JavaScript off; the label is what gets styled. */
.cn-licence-picker { border: 0; padding: 0; margin: 0 0 var(--cn-space-5); }
.cn-licence-picker legend { padding: 0; margin-bottom: 10px; }
.cn-segmented--radio { display: flex; flex-wrap: wrap; gap: 8px; }
.cn-segmented--radio .cn-segmented__option {
  display: flex; flex-direction: column; gap: 2px;
  cursor: pointer; position: relative;
  border: 1px solid var(--cn-line-strong);
  border-radius: var(--cn-radius-card);
  padding: 10px 14px;
  min-height: var(--cn-tap);
  justify-content: center;
}
.cn-segmented--radio .cn-segmented__option:has(input:checked) {
  border-color: var(--cn-ink);
  background: var(--cn-ink);
  color: var(--cn-on-fill);
}
.cn-segmented--radio .cn-segmented__option:has(input:checked) .cn-segmented__price { color: var(--cn-on-fill); }
.cn-segmented--radio .cn-segmented__option:has(input:focus-visible) {
  outline: 2px solid var(--cn-accent);
  outline-offset: 2px;
}
.cn-segmented--radio .cn-segmented__price { font-size: 13px; color: var(--cn-graphite); }

/* The licence upgrade offer, under the line it upgrades. Quiet enough not to
   compete with the product, present enough to be read. */
.cn-upsell {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--cn-space-3);
  margin-top: var(--cn-space-3);
  padding: 10px 12px;
  background: var(--cn-accent-a08);
  border-radius: var(--cn-radius-card);
}
.cn-upsell__text { font-size: 14px; color: var(--cn-ink); flex: 1; min-width: 12rem; }
.cn-upsell .cn-btn { flex: 0 0 auto; }

/* The checkout offer. Dashed edge so it reads as an aside rather than part of
   the order, and a flash that carries the only reason to look at it. */
.cn-bump {
  border: 2px dashed var(--cn-line-strong);
  border-radius: var(--cn-radius-card);
  overflow: hidden;
  margin-bottom: var(--cn-space-6);
  background: var(--cn-paper);
}
.cn-bump.is-taken { border-color: var(--cn-success); border-style: solid; }
.cn-bump__flash {
  background: var(--cn-success);
  color: var(--cn-on-fill);
  font-weight: 600;
  text-align: center;
  padding: 10px var(--cn-space-4);
}
.cn-bump__body { display: flex; gap: var(--cn-space-4); padding: var(--cn-space-4); }
.cn-bump__thumb { flex: 0 0 88px; }
.cn-bump__thumb img { width: 88px; height: auto; border-radius: var(--cn-radius-card); display: block; }
.cn-bump__info { flex: 1; min-width: 0; }
.cn-bump__name { font-weight: 600; line-height: 1.35; margin-bottom: 4px; }
.cn-bump__price { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.cn-bump__price s { color: var(--cn-graphite); }
.cn-bump__price strong { font-size: 18px; }
.cn-bump__why {
  margin: 0; padding: 0 var(--cn-space-4) var(--cn-space-4);
  font-size: 14px; color: var(--cn-graphite); line-height: 1.55;
}
.cn-bump__take {
  display: flex; align-items: center; gap: var(--cn-space-3);
  padding: var(--cn-space-4);
  background: var(--cn-surface);
  border-top: 1px solid var(--cn-line);
  cursor: pointer;
  min-height: var(--cn-tap);
  font-weight: 500;
}

/* The upsell must not hold the cart's name column open. A 12rem floor turned
   the product name into one character per line at 320px and pushed the offer
   itself off screen.
   min-width:0 alone then broke the offer the same way: against `flex: 1` the
   text's base size is 0, so instead of wrapping it shrank to the ~1px the
   91px Upgrade button left it, and "Sell what you make with it" came out one
   letter per line. Keeping a flex-basis makes the line too long to share, so
   the button wraps underneath and the text gets the whole width -- while
   min-width:0 still lets it shrink rather than overflow. */
.cn-upsell__text { flex: 1 1 10rem; min-width: 0; }

/* A native checkbox or radio gets no usable cue from a border colour and a
   15%-alpha halo -- the rule that substitutes those for text inputs was never
   meant to cover them. */
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
  outline: 2px solid var(--cn-accent);
  outline-offset: 2px;
  box-shadow: none;
}

/* The review form's star picker. Its radio is visually hidden, so the rule
   above draws a 2px ring around a 1px box and the control had no keyboard cue
   whatsoever. The label carries it, and the 44px box screen 03 draws. */
.cn-starpick__star {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--cn-tap);
  height: var(--cn-tap);
  border-radius: var(--cn-radius-card);
  cursor: pointer;
}
.cn-starpick__star:has(input:focus-visible) {
  outline: 2px solid var(--cn-accent);
  outline-offset: 2px;
}

/* "Price on request" stood where the price goes and had no rule at all, so it
   rendered at body size in body colour -- the one thing on the buy box that
   did not look deliberate. It is not a price, so it does not get the price
   type; it gets the same mono the rest of the buy box uses for facts. */
.cn-buybox__ask {
  display: block;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-14);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  padding-block: 8px;
}

/* Picking a pack out of a grouped kit was a 13px browser checkbox on a dark
   band -- the smallest control in the theme, on the one screen whose entire
   job is choosing what to buy. WooCommerce gives it a screen-reader-only label
   and puts the visible name in the next cell as a link to that pack, so the
   name cannot double as the control without taking the link away. The control
   itself grows instead.

   The native control, not a redrawn one. I tried appearance:none with a drawn
   tick and could not get a background onto it -- not from a rule, not from a
   late stylesheet, not from an inline style, with no !important anywhere that
   matched it, while an identical checkbox created on the same page took the
   colour immediately. I could not explain that, and shipping a control whose
   checked state I cannot account for is worse than shipping the browser's own,
   which is legible, scales with width/height, and takes accent-color. */
.woocommerce-grouped-product-list-item__quantity { min-height: var(--cn-tap); }

input.wc-grouped-product-add-to-cart-checkbox,
.cn-on-ink input.wc-grouped-product-add-to-cart-checkbox {
  width: 24px;
  height: 24px;
  margin: 0;
  accent-color: var(--cn-accent);
  position: relative;
  cursor: pointer;
  flex: 0 0 auto;
}

/* 24px drawn, 44px pressable, the same trick as the other small controls. */
input.wc-grouped-product-add-to-cart-checkbox::before {
  content: "";
  position: absolute;
  inset: calc((24px - var(--cn-tap)) / 2);
}

/* ==========================================================================
   Category tree — the all categories page
   --------------------------------------------------------------------------
   Rows rather than cards. A catalogue with a hundred and thirty categories
   cannot be browsed as 300px pictures, and the subcategory is usually the
   thing somebody came for, so the parent opens to show them.
   ========================================================================== */

.cn-cattree {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  background: var(--cn-paper);
  overflow: hidden;
}
.cn-cattree__row { display: block; border-bottom: 1px solid var(--cn-line); }
.cn-cattree__row:last-child { border-bottom: 0; }

.cn-cattree__head {
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  padding: var(--cn-space-4) var(--cn-space-5);
  min-height: var(--cn-tap);
  cursor: pointer;
  color: var(--cn-ink);
  list-style: none;
  transition: background var(--cn-ease);
}
.cn-cattree__head::-webkit-details-marker { display: none; }
.cn-cattree__head:hover { background: var(--cn-surface); }
.cn-cattree__head:focus-visible { outline: 2px solid var(--cn-accent); outline-offset: -2px; }

.cn-cattree__icon {
  flex: 0 0 40px;
  width: 40px;
  aspect-ratio: 1;
  border-radius: var(--cn-radius-badge);
  overflow: hidden;
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a06) 0 5px, transparent 5px 10px);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--cn-font-mono);
  font-size: 11px;
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
}
.cn-cattree__icon img { width: 100%; height: 100%; object-fit: cover; display: block; }

.cn-cattree__label { flex: 1; min-width: 0; }
.cn-cattree__name { display: block; font-size: var(--cn-fs-16); font-weight: 500; }
.cn-cattree__meta { display: block; font-size: var(--cn-fs-12); color: var(--cn-graphite); margin-top: 2px; }

.cn-cattree__chevron {
  flex: 0 0 auto;
  font-size: 22px;
  line-height: 1;
  color: var(--cn-graphite);
  transition: transform var(--cn-ease);
}
details[open] > .cn-cattree__head .cn-cattree__chevron { transform: rotate(90deg); }

.cn-cattree__body {
  padding: 0 var(--cn-space-5) var(--cn-space-5) calc(40px + var(--cn-space-4) + var(--cn-space-5));
  background: var(--cn-surface);
}
.cn-cattree__kids {
  list-style: none;
  margin: 0 0 var(--cn-space-4);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr));
  gap: 2px var(--cn-space-4);
}
.cn-cattree__kids li { margin: 0; }
.cn-cattree__kids a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-3);
  min-height: 34px;
  padding-inline: 10px;
  border-radius: var(--cn-radius-badge);
  color: var(--cn-ink);
  font-size: var(--cn-fs-14);
}
.cn-cattree__kids a:hover { background: var(--cn-paper); color: var(--cn-accent); }
.cn-cattree__kidcount { font-size: 11px; color: var(--cn-graphite); }
.cn-cattree__all { display: inline-flex; gap: 6px; align-items: center; }
.cn-cattree__body { max-height: 52vh; overflow-y: auto; overscroll-behavior: contain; }

@media (max-width: 600px) {
  .cn-cattree__head { padding: var(--cn-space-3) var(--cn-space-4); gap: var(--cn-space-3); }
  .cn-cattree__body { padding-inline: var(--cn-space-4); }
}
