/*
 * Site-theme section styles (issue #103 — phase B0).
 *
 * Loaded by the theme editor canvas, the admin preview page and (from C4) the
 * storefront, so a section looks identical in all three. Every value comes from
 * a --wn-* custom property emitted by tokensToCssVars — no hardcoded colors.
 *
 * Conventions: mobile-first, tap targets >= 44px, images always carry an
 * aspect-ratio so nothing shifts while loading.
 */

.wn-scope {
  font-family: var(--wn-font-body);
  /* `background` followed the token from the start; `color` did not, and a hardcoded near-black on
   * a token-painted background is only invisible while every palette is light. It stopped being
   * invisible the moment a dark-surface palette existed: `bold` paints #1E293B here and declares
   * '#E2E8F0' for its text, and this line overrode that — inside the scope, so the
   * `.wn-themed body` colour could not reach it either.
   *
   * The fallback keeps the exact previous colour for every theme whose tokens have no `colorText`,
   * so nothing that renders correctly today changes. */
  color: var(--wn-color-text, #111827);
  background: var(--wn-color-surface);
}

.wn-section {
  box-sizing: border-box;
  padding: calc(var(--wn-space) * 2) var(--wn-space);
}

.wn-container {
  width: 100%;
  max-width: var(--wn-container);
  margin: 0 auto;
}

.wn-section h2,
.wn-section h3 {
  font-family: var(--wn-font-heading);
  margin: 0;
}

.wn-section-title {
  font-size: calc(1.5rem * var(--wn-font-scale));
  line-height: 1.25;
  text-align: center;
}

.wn-section-subtitle {
  margin-top: calc(var(--wn-space) / 2);
  color: var(--wn-color-muted);
  font-size: calc(0.95rem * var(--wn-font-scale));
  text-align: center;
}

.wn-img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--wn-radius);
  background: #f3f4f6;
}

.wn-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 calc(var(--wn-space) * 1.25);
  border: 0;
  border-radius: var(--wn-radius);
  background: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
  font-family: var(--wn-font-heading);
  font-size: calc(0.95rem * var(--wn-font-scale));
  cursor: pointer;
}

/* ---------- trust badges ---------- */

.wn-trust-badges .wn-trust-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(var(--wn-space) * 1.5);
  margin-top: calc(var(--wn-space) * 1.5);
}

@media (min-width: 768px) {
  .wn-trust-badges .wn-trust-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.wn-trust-item {
  text-align: center;
}

.wn-trust-icon {
  display: block;
  width: 48px;
  height: 48px;
  margin: 0 auto calc(var(--wn-space) * 0.75);
  object-fit: contain;
  aspect-ratio: 1 / 1;
}

.wn-trust-item h3 {
  font-size: calc(1rem * var(--wn-font-scale));
  line-height: 1.3;
}

.wn-trust-item p {
  margin: calc(var(--wn-space) / 4) 0 0;
  color: var(--wn-color-muted);
  font-size: calc(0.875rem * var(--wn-font-scale));
  line-height: 1.5;
}

/* ---------- reviews ---------- */

.wn-reviews-summary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--wn-space) / 2);
  margin-top: var(--wn-space);
  font-size: calc(1rem * var(--wn-font-scale));
}

.wn-reviews-count {
  color: var(--wn-color-muted);
}

.wn-stars {
  color: var(--wn-color-accent);
  letter-spacing: 1px;
  white-space: nowrap;
}

.wn-stars-empty {
  opacity: 0.25;
}

.wn-reviews-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--wn-space);
  margin-top: calc(var(--wn-space) * 1.5);
}

@media (min-width: 640px) {
  .wn-reviews-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .wn-reviews-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.wn-review-card {
  padding: var(--wn-space);
  border: 1px solid var(--wn-color-border);
  border-radius: var(--wn-radius);
  background: var(--wn-color-surface);
}

.wn-review-head {
  display: flex;
  align-items: center;
  gap: calc(var(--wn-space) / 2);
  margin-bottom: calc(var(--wn-space) / 2);
}

/* The token, not a fixed grey. `#f3f4f6` is a cool neutral, and a review section is one of the few
 * places a flat disc of it sits directly on the theme's own colour — six of them, in a row. On a
 * warm palette they read as pasted in from another site. `--wn-color-border` is the same value
 * within a shade or two on the default palette, so nothing shifts for a theme that never set one. */
.wn-review-avatar {
  width: 40px;
  height: 40px;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  object-fit: cover;
  background: var(--wn-color-border);
}

.wn-review-avatar-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--wn-font-heading);
  color: var(--wn-color-muted);
  text-transform: uppercase;
}

.wn-review-name {
  font-family: var(--wn-font-heading);
  font-size: calc(0.95rem * var(--wn-font-scale));
}

.wn-review-verified {
  font-size: calc(0.75rem * var(--wn-font-scale));
  color: var(--wn-color-muted);
}

.wn-review-card p {
  margin: calc(var(--wn-space) / 2) 0 0;
  font-size: calc(0.9rem * var(--wn-font-scale));
  line-height: 1.6;
}

/* ---------- bundle / upsell ---------- */

.wn-bundle-badge {
  margin-top: calc(var(--wn-space) / 2);
  color: var(--wn-color-accent);
  font-size: calc(0.9rem * var(--wn-font-scale));
  text-align: center;
}

.wn-bundle-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: calc(var(--wn-space) / 2);
  margin-top: calc(var(--wn-space) * 1.5);
}

.wn-bundle-item {
  width: 140px;
  text-align: center;
}

.wn-bundle-thumb-empty {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  border: 1px dashed var(--wn-color-border);
  border-radius: var(--wn-radius);
}

.wn-bundle-name {
  margin-top: calc(var(--wn-space) / 2);
  font-size: calc(0.875rem * var(--wn-font-scale));
  line-height: 1.4;
}

.wn-bundle-price {
  margin-top: calc(var(--wn-space) / 4);
  font-size: calc(0.875rem * var(--wn-font-scale));
}

.wn-bundle-price s {
  margin-left: 6px;
  color: var(--wn-color-muted);
}

.wn-bundle-plus {
  align-self: center;
  color: var(--wn-color-muted);
  font-size: calc(1.25rem * var(--wn-font-scale));
}

.wn-bundle-total {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--wn-space);
  margin-top: calc(var(--wn-space) * 1.5);
  font-size: calc(1rem * var(--wn-font-scale));
}

.wn-bundle-total s {
  margin-left: 6px;
  color: var(--wn-color-muted);
}

.wn-bundle-saving {
  color: var(--wn-color-accent);
}

/* ---------- size chart ---------- */

.wn-size-details {
  max-width: 720px;
  margin: var(--wn-space) auto 0;
  border: 1px solid var(--wn-color-border);
  border-radius: var(--wn-radius);
}

.wn-size-summary {
  min-height: 44px;
  padding: calc(var(--wn-space) * 0.75) var(--wn-space);
  cursor: pointer;
  font-family: var(--wn-font-heading);
  font-size: calc(1rem * var(--wn-font-scale));
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.wn-size-summary::after {
  content: '▾';
  color: var(--wn-color-muted);
}

.wn-size-details[open] .wn-size-summary::after {
  content: '▴';
}

.wn-size-table-wrap {
  overflow-x: auto;
  border-top: 1px solid var(--wn-color-border);
}

.wn-size-table {
  width: 100%;
  border-collapse: collapse;
  font-size: calc(0.875rem * var(--wn-font-scale));
}

.wn-size-table th,
.wn-size-table td {
  padding: calc(var(--wn-space) / 2) calc(var(--wn-space) * 0.75);
  border-bottom: 1px solid var(--wn-color-border);
  text-align: left;
  white-space: nowrap;
}

.wn-size-table thead th {
  font-family: var(--wn-font-heading);
  text-transform: capitalize;
}

.wn-size-info {
  margin: 0;
  padding: calc(var(--wn-space) * 0.75) var(--wn-space);
  color: var(--wn-color-muted);
  font-size: calc(0.8125rem * var(--wn-font-scale));
}

/* ---------- product detail (POD) ---------- */

.wn-pdp-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: calc(var(--wn-space) * 1.5);
}

@media (min-width: 900px) {
  .wn-pdp-layout {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    align-items: start;
  }
}

.wn-pdp-main {
  aspect-ratio: 1 / 1;
}

.wn-pdp-thumbs {
  display: flex;
  gap: calc(var(--wn-space) / 2);
  margin-top: calc(var(--wn-space) / 2);
  overflow-x: auto;
}

.wn-pdp-thumb {
  flex: 0 0 auto;
  width: 72px;
  padding: 0;
  border: 1px solid var(--wn-color-border);
  border-radius: var(--wn-radius);
  background: none;
  cursor: pointer;
}

.wn-pdp--thumbs-left .wn-pdp-gallery {
  display: flex;
  flex-direction: row-reverse;
  gap: calc(var(--wn-space) / 2);
}

.wn-pdp--thumbs-left .wn-pdp-thumbs {
  flex-direction: column;
  margin-top: 0;
  overflow-x: visible;
}

.wn-pdp--grid .wn-pdp-thumbs {
  flex-wrap: wrap;
}

.wn-pdp--grid .wn-pdp-thumb {
  width: calc(33.333% - var(--wn-space) / 3);
}

.wn-pdp-title {
  margin: 0;
  font-family: var(--wn-font-heading);
  font-size: calc(1.75rem * var(--wn-font-scale));
  line-height: 1.2;
}

.wn-pdp-price {
  display: flex;
  align-items: baseline;
  gap: calc(var(--wn-space) / 2);
  margin-top: var(--wn-space);
  font-size: calc(1.25rem * var(--wn-font-scale));
}

.wn-pdp-sale {
  color: var(--wn-color-accent);
}

.wn-pdp-price s {
  color: var(--wn-color-muted);
  font-size: calc(1rem * var(--wn-font-scale));
}

.wn-pdp-badge {
  padding: 2px 8px;
  border-radius: calc(var(--wn-radius) / 2);
  background: var(--wn-color-accent);
  color: var(--wn-color-on-primary);
  font-size: calc(0.75rem * var(--wn-font-scale));
}

.wn-pdp-block {
  margin-top: calc(var(--wn-space) * 1.25);
}

.wn-pdp-label {
  margin-bottom: calc(var(--wn-space) / 2);
  font-family: var(--wn-font-heading);
  font-size: calc(0.9375rem * var(--wn-font-scale));
}

.wn-pdp-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--wn-space) / 2);
}

.wn-swatch {
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--wn-color-border);
  border-radius: 50%;
  background: #f3f4f6;
  cursor: pointer;
}

.wn-swatch-selected {
  outline: 2px solid var(--wn-color-primary);
  outline-offset: 2px;
}

.wn-pdp-sizes {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--wn-space) / 2);
}

.wn-size-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 44px;
  min-height: 44px;
  padding: 0 calc(var(--wn-space) * 0.75);
  border: 1px solid var(--wn-color-border);
  border-radius: var(--wn-radius);
  background: var(--wn-color-surface);
  font-family: var(--wn-font-body);
  font-size: calc(0.9375rem * var(--wn-font-scale));
  cursor: pointer;
}

.wn-size-pill-selected {
  border-color: var(--wn-color-primary);
  box-shadow: inset 0 0 0 1px var(--wn-color-primary);
}

.wn-size-extra {
  color: var(--wn-color-muted);
  font-size: calc(0.75rem * var(--wn-font-scale));
}

.wn-pdp-cta {
  width: 100%;
  margin-top: calc(var(--wn-space) * 1.5);
}

.wn-pdp-note {
  margin: calc(var(--wn-space) / 2) 0 0;
  color: var(--wn-color-muted);
  font-size: calc(0.875rem * var(--wn-font-scale));
  line-height: 1.5;
}

/* ---------- announcement bar ---------- */

.wn-announcement {
  background: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
  font-size: calc(0.875rem * var(--wn-font-scale));
}

.wn-announcement-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: calc(var(--wn-space) / 2);
  min-height: 44px;
  padding: calc(var(--wn-space) / 2) var(--wn-space);
  text-align: center;
}

.wn-announcement-link {
  color: inherit;
  text-decoration: underline;
}

/* ---------- countdown ---------- */

.wn-countdown-discount {
  margin-top: calc(var(--wn-space) / 2);
  color: var(--wn-color-accent);
  font-family: var(--wn-font-heading);
  text-align: center;
}

.wn-countdown-clock {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: calc(var(--wn-space) / 2);
  margin-top: var(--wn-space);
}

.wn-countdown-part {
  min-width: 64px;
  padding: calc(var(--wn-space) / 2);
  border: 1px solid var(--wn-color-border);
  border-radius: var(--wn-radius);
  text-align: center;
}

.wn-countdown-value {
  display: block;
  font-family: var(--wn-font-heading);
  font-size: calc(1.5rem * var(--wn-font-scale));
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.wn-countdown-label {
  display: block;
  margin-top: 2px;
  color: var(--wn-color-muted);
  font-size: calc(0.6875rem * var(--wn-font-scale));
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* ---------- faq ---------- */

.wn-faq-list {
  max-width: 820px;
  margin: var(--wn-space) auto 0;
}

.wn-faq-item {
  border-bottom: 1px solid var(--wn-color-border);
}

.wn-faq-question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
  padding: calc(var(--wn-space) * 0.75) 0;
  cursor: pointer;
  font-family: var(--wn-font-heading);
  font-size: calc(1rem * var(--wn-font-scale));
  list-style: none;
}

.wn-faq-question::after {
  content: '+';
  margin-left: var(--wn-space);
  color: var(--wn-color-muted);
}

.wn-faq-item[open] .wn-faq-question::after {
  content: '–';
}

.wn-faq-answer {
  padding: 0 0 calc(var(--wn-space) * 0.75);
  color: var(--wn-color-muted);
  font-size: calc(0.9375rem * var(--wn-font-scale));
  line-height: 1.6;
}

.wn-trust-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  margin: 0 auto calc(var(--wn-space) * 0.75);
  border: 1px dashed var(--wn-color-border);
  border-radius: 50%;
  color: var(--wn-color-muted);
  font-size: 0.75rem;
}


/* ==========================================================================
 * Built-in section icons.
 *
 * A trust badge with no artwork used to render the literal word "icon", which is
 * what every seeded theme looked like. These are the fallback: a block sets
 * `icon: 'shield'` and gets a real mark.
 *
 * Drawn with mask-image rather than <img src>, because an image cannot inherit a
 * colour — masked, the shape is cut out of `--wn-color-primary`, so the icons
 * change with the theme like everything else. A badge that has a real `src` still
 * renders as an <img>; this only fills the gap.
 *
 * The SVGs are inline so there is no extra request and nothing to host, and they
 * are stroke-only: the mask reads alpha, so the stroke becomes the visible shape.
 * ========================================================================== */

.wn-icon {
  display: block;
  width: 40px;
  height: 40px;
  margin: 0 auto calc(var(--wn-space) * 0.75);
  background-color: var(--wn-color-primary);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* Secure checkout / payment safety. */
.wn-icon-shield {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l7.5 3v5.25c0 4.5-3 7.9-7.5 9.5-4.5-1.6-7.5-5-7.5-9.5V6L12 3z"/><path d="M8.75 12.25l2.25 2.25 4.25-4.5"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l7.5 3v5.25c0 4.5-3 7.9-7.5 9.5-4.5-1.6-7.5-5-7.5-9.5V6L12 3z"/><path d="M8.75 12.25l2.25 2.25 4.25-4.5"/></svg>');
}

/* Returns and exchanges. */
.wn-icon-returns {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 15L3.5 9.5 9 4"/><path d="M3.5 9.5H15a5.5 5.5 0 010 11h-3.5"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 15L3.5 9.5 9 4"/><path d="M3.5 9.5H15a5.5 5.5 0 010 11h-3.5"/></svg>');
}

/* Printed / made to order. */
.wn-icon-print {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7 8V3.5h10V8"/><path d="M5.5 8h13a2 2 0 012 2v5.5H17V21H7v-5.5H3.5V10a2 2 0 012-2z"/><path d="M7 15.5h10"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7 8V3.5h10V8"/><path d="M5.5 8h13a2 2 0 012 2v5.5H17V21H7v-5.5H3.5V10a2 2 0 012-2z"/><path d="M7 15.5h10"/></svg>');
}

/* Shipping and tracking. */
.wn-icon-truck {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 6.5h11v9h-11z"/><path d="M13.5 9.5h4l4 3.5v2.5h-8z"/><circle cx="7" cy="18" r="2"/><circle cx="17" cy="18" r="2"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 6.5h11v9h-11z"/><path d="M13.5 9.5h4l4 3.5v2.5h-8z"/><circle cx="7" cy="18" r="2"/><circle cx="17" cy="18" r="2"/></svg>');
}

/* Privacy / data. */
.wn-icon-lock {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7.5 10.5V8a4.5 4.5 0 019 0v2.5"/><rect x="4.5" y="10.5" width="15" height="9.5" rx="2"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7.5 10.5V8a4.5 4.5 0 019 0v2.5"/><rect x="4.5" y="10.5" width="15" height="9.5" rx="2"/></svg>');
}

/* Help / support. */
.wn-icon-support {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 5.5h17v11H9l-5.5 4z"/><path d="M9.5 9.5a2.5 2.5 0 114 2c-.7.5-1 1-1 2"/><path d="M12.5 15h.01"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 5.5h17v11H9l-5.5 4z"/><path d="M9.5 9.5a2.5 2.5 0 114 2c-.7.5-1 1-1 2"/><path d="M12.5 15h.01"/></svg>');
}

/* Speed / fast dispatch. */
.wn-icon-bolt {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2.5L5 13.5h5l-1 8 8-11h-5l1-8z"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2.5L5 13.5h5l-1 8 8-11h-5l1-8z"/></svg>');
}


/* ==========================================================================
 * Section colour bands.
 *
 * `block.background` wraps a section in one of these, so a theme can alternate
 * bands instead of stacking white blocks. Every value comes from the tokens —
 * the alternative, which the demo themes used, is hand-written HTML with inline
 * colours that stop matching the moment the palette changes.
 *
 * Not gated behind .wn-themed: the dash preview renders sections without that
 * class, same as the icons.
 * ========================================================================== */

.wn-band-soft {
  /* Dropped wholesale by a browser without color-mix, which leaves the section
     on the page background — what it looked like before the field existed. */
  background-color: color-mix(in srgb, var(--wn-color-border) 45%, var(--wn-color-surface));
}

.wn-band-surface {
  background-color: var(--wn-color-surface);
}

.wn-band-primary {
  background-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
}

.wn-band-accent {
  background-color: var(--wn-color-accent);
  color: var(--wn-color-on-primary);
}

/* On a full-colour band the muted greys stop being readable, so anything that
   normally dims inherits the band's own ink instead. */
.wn-band-primary .wn-section-subtitle,
.wn-band-accent .wn-section-subtitle,
.wn-band-primary .wn-trust-item p,
.wn-band-accent .wn-trust-item p,
.wn-band-primary .wn-reviews-count,
.wn-band-accent .wn-reviews-count,
.wn-band-primary .wn-faq-answer,
.wn-band-accent .wn-faq-answer {
  color: inherit;
  opacity: 0.85;
}

/* An icon is masked out of --wn-color-primary, which on a primary band is the
   band's own colour: invisible. On any full-colour band it takes the ink. */
.wn-band-primary .wn-icon,
.wn-band-accent .wn-icon {
  background-color: currentColor;
}

.wn-band-primary .wn-review-card,
.wn-band-accent .wn-review-card {
  background: transparent;
  border-color: currentColor;
}

/* ==========================================================================
 * Theme chrome — the page's own controls follow the theme, not just sections.
 *
 * Everything below is gated behind `.wn-themed` on <html>, which root.tsx only
 * sets when the store has theme tokens. Without it these rules never match, so
 * a store with no theme renders exactly as it did before.
 *
 * The targets are the shared classes the storefront already ships (.btn,
 * .btn-outline) plus a few `wn-*` hooks added to shared components, so a single
 * layer covers product, collection, cart and every other page at once. Selector
 * specificity is >= 2 classes, which beats both the compiled `.btn` rule and
 * the Tailwind utilities on those components.
 * ========================================================================== */

.wn-themed body {
  font-family: var(--wn-font-body);
  background-color: var(--wn-color-surface);
  /* The theme's body colour, which had nowhere to go until `colorText` existed. Every element
   * that inherits picks it up, which is most running text; a component setting its own colour
   * still wins, so this changes copy rather than overriding deliberate choices. The token
   * defaults to near-black because `body` carried no `color` at all before this line — a themed
   * page rendered on the browser default. */
  color: var(--wn-color-text);
}

.wn-themed h1,
.wn-themed h2,
.wn-themed h3,
.wn-themed h4 {
  font-family: var(--wn-font-heading);
}

/* Primary action: Add to cart, checkout, newsletter submit. */
.wn-themed .btn {
  background-color: var(--wn-color-primary);
  border-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
  border-radius: var(--wn-radius);
}

/* The shipped .btn:hover inverts to a transparent fill; keep that behaviour. */
.wn-themed .btn:hover {
  background-color: transparent;
  border-color: var(--wn-color-primary);
  color: var(--wn-color-primary);
}

.wn-themed .btn[disabled],
.wn-themed .btn[disabled]:hover {
  background-color: var(--wn-color-muted);
  border-color: var(--wn-color-muted);
  color: var(--wn-color-on-primary);
}

/* The white variant stays light-on-dark-page; only its ink follows the theme. */
.wn-themed .btn.white,
.wn-themed .btn.white:hover {
  color: var(--wn-color-primary);
}

.wn-themed .btn-outline {
  border-color: var(--wn-color-primary);
  color: var(--wn-color-primary);
  border-radius: var(--wn-radius);
}

.wn-themed .btn-outline:hover {
  background-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
}

/* Size / variant picker (components/VariantButton.tsx). */
.wn-themed .wn-variant-btn {
  border-color: var(--wn-color-border);
  border-radius: calc(var(--wn-radius) / 2);
}

.wn-themed .wn-variant-btn:hover,
.wn-themed .wn-variant-btn.is-active {
  background-color: var(--wn-color-primary);
  border-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
}

/* Colour swatch — the selected ring reads as the theme, not a stock red. */
.wn-themed .wn-swatch.is-active {
  border-color: var(--wn-color-primary);
}

/* Price block: sale price and the discount pill share the accent colour. */
.wn-themed .wn-price-sale {
  color: var(--wn-color-accent);
}

.wn-themed .wn-price-badge {
  background-color: var(--wn-color-accent);
  color: #fff;
  border-radius: calc(var(--wn-radius) / 2);
}

/* Product description tabs (routes/products/components/Specifications.tsx). */
.wn-themed .wn-tab.is-active {
  background-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
}

/* Colour chips: the fill is the real product colour, the frame is chrome. */
.wn-themed .wn-color-chip {
  border-color: var(--wn-color-border);
}

.wn-themed .wn-color-chip.is-active {
  border-color: var(--wn-color-primary);
}

/* Counter pills — cart count, the size on a cart line. */
.wn-themed .wn-badge {
  background-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
}

/* Tag pills — "Explore Related Searches", "Other Products", listing tags.
 *
 * Deliberately the same recipe a theme section uses for its own pills (rounded
 * to 999px, 10px/22px, 0.85rem scaled): these sit a few hundred pixels apart on
 * a product page, so two different pill shapes read as a mistake. */
.wn-themed .wn-tag {
  background-color: var(--wn-color-surface);
  border: 1px solid var(--wn-color-border);
  border-radius: 999px;
  padding: 10px 22px;
  font-size: calc(0.85rem * var(--wn-font-scale));
}

.wn-themed .wn-tag:hover {
  background-color: var(--wn-color-primary);
  border-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
}

/* Current page in a pager. */
.wn-themed .wn-page-current {
  background-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
  border-radius: calc(var(--wn-radius) / 2);
}

/* Neutral panels: the spec table on a product, the count strip on a listing. */
.wn-themed .wn-panel,
.wn-themed .wn-listing-banner {
  background-color: var(--wn-color-surface);
  border: 1px solid var(--wn-color-border);
}

.wn-themed .wn-panel {
  border-radius: calc(var(--wn-radius) / 2);
}

/* ==========================================================================
 * The real header and footer, themed.
 *
 * A theme can replace the chrome with its own HTML template, but a hand-written
 * template only reproduces the markup its author remembered — the multi-level
 * menu, the logo URL, the mobile menu, the mini cart, the socials, the footer
 * menus, the currency selector and the payment icons all live in components.
 * So the default is the other way round: keep the components, restyle them.
 *
 * These selectors are the storefront's own semantic classes (.header-container,
 * .menu-item, .submenu, .search), not Tailwind utilities, so no component needs
 * to change for the chrome to follow the theme.
 * ========================================================================== */

/* The wrapper, not `.header-container`. That class is the width-limited
   container: painting it leaves the full-bleed parent white, which only shows
   once the viewport is wider than the container — 230px of white down each edge
   at 1900px, invisible at 1280. */
.wn-themed header,
.wn-themed header > div {
  background-color: var(--wn-color-surface);
}

.wn-themed .menu-item > a {
  color: inherit;
  font-family: var(--wn-font-heading);
}

.wn-themed .menu-item > a:hover {
  color: var(--wn-color-primary);
}

/* Dropdown panel: keep the reveal behaviour, restate only the surface. */
.wn-themed .submenu {
  background-color: var(--wn-color-surface);
  border: 1px solid var(--wn-color-border);
  border-radius: calc(var(--wn-radius) / 2);
  color: inherit;
}

.wn-themed .submenu a:hover {
  color: var(--wn-color-primary);
}

/* Search field. */
.wn-themed .search {
  background-color: var(--wn-color-surface);
  border-color: var(--wn-color-border);
}

.wn-themed footer {
  background-color: var(--wn-color-surface);
  border-top: 1px solid var(--wn-color-border);
}

/* --- chrome typography and bands, so header/footer read as the same design ---
 *
 * The colour bands are derived from the theme with color-mix rather than adding
 * a token: a browser that does not support it drops the declaration and keeps
 * the greys the storefront ships, which is a safe place to land.
 */

.wn-themed header nav > ul {
  justify-content: center;
}

.wn-themed .menu-item > a {
  font-size: calc(0.95rem * var(--wn-font-scale));
  letter-spacing: 0.02em;
}

.wn-themed footer > div:first-child {
  background-color: color-mix(in srgb, var(--wn-color-border) 45%, var(--wn-color-surface));
}

.wn-themed footer > div:last-child {
  background-color: color-mix(in srgb, var(--wn-color-border) 80%, var(--wn-color-surface));
}

.wn-themed .wn-footer-title {
  font-family: var(--wn-font-heading);
  font-size: calc(1.25rem * var(--wn-font-scale));
}

.wn-themed footer a:hover {
  color: var(--wn-color-primary);
}

/* "Phone:", "Email:", "Address:" — labels, not values. */
.wn-themed footer li > span:first-child {
  color: var(--wn-color-muted);
}

/* Search submit and the cart counter carry the theme's accent, so the identity
 * colour appears in the header the way it does on the page. */

.wn-themed .wn-search-submit {
  color: var(--wn-color-primary);
}

.wn-themed .wn-search-submit-filled {
  background-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
}

.wn-themed .mini-cart {
  border-color: var(--wn-color-primary);
  color: var(--wn-color-primary);
}

.wn-themed .mini-cart:hover {
  background-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
}

/* Mobile drawer (#menu in MobileMenuNew) — the same typography and rules as the
 * desktop nav, so the two do not read as different sites. The id outranks
 * Tailwind's `divide-gray-200`, which sets the row borders through a
 * three-class selector. */

/* Set on the nav, not on a/button: the drawer's own title is a plain div, so
 * inheritance covers it without a selector that depends on row order. */
.wn-themed #menu {
  font-family: var(--wn-font-heading);
}

.wn-themed #menu li {
  border-color: var(--wn-color-border);
}

/* ---------------------------------------------------------------------------
 * Header chrome that the tokens were not reaching.
 *
 * The header already followed the theme's colours and heading font, which is why
 * the search icon and the cart count came out primary. What it ignored was every
 * hardcoded shape and the two controls that had no hook at all, so a theme asking
 * for `radius: 12` still rendered a pill search box, a cart tab with square top
 * corners, and a history and heart icon in the default ink beside a themed cart.
 *
 * Each rule below overrides a Tailwind utility of lower specificity — `.wn-themed
 * .search` is two classes against `.rounded-full`'s one — so no `!important` is
 * needed and nothing changes for a store without tokens.
 * --------------------------------------------------------------------------- */

/* `rounded-tl-full rounded-bl-full` on the input and `rounded-tr-full
 * rounded-br-full` on the filled button make one pill between them below `lg`.
 * The split is kept so the two still meet flush; only the amount changes. */
.wn-themed .search {
  border-radius: var(--wn-radius) 0 0 var(--wn-radius);
}

.wn-themed .wn-search-submit-filled {
  border-radius: 0 var(--wn-radius) var(--wn-radius) 0;
}

/* The filled button is `lg:hidden`, so from here the input stands on its own. */
@media (min-width: 1024px) {
  .wn-themed .search {
    border-radius: var(--wn-radius);
  }
}

/* `.mini-cart` is a shopping bag drawn in CSS, not a box with an icon in it: the element
 * is the bag body and `::before` is the handle, a 12x7 strip sitting at `top: -7px`. That
 * is why only the bottom corners are rounded — the top edge has to stay flat for the
 * handle to meet it. Rounding all four at `var(--wn-radius)` lifted the handle off a
 * curve and, at 12px on a 22px-wide body, read as a pill rather than a bag.
 *
 * So the shape is kept and only its amount follows the token. `/ 3` lands on 4px for a
 * radius of 12, which is what the hardcoded `.25rem` was. */
.wn-themed .mini-cart {
  border-radius: 0 0 calc(var(--wn-radius) / 3) calc(var(--wn-radius) / 3);
}

/* The handle carries its own 2px border, and the rule on the body does not reach a
 * pseudo-element — which left it black beside an otherwise primary-coloured bag. */
.wn-themed .mini-cart::before {
  border-color: var(--wn-color-primary);
}

/* The wordmark is the brand name in text when a store has no logo image, and it
 * was rendering in the body font while every heading around it used the theme's. */
.wn-themed .wn-logo {
  font-family: var(--wn-font-heading);
}

/* Recently-viewed and favourites sat in the default ink next to a primary-coloured
 * cart, which read as two of the three icons having been missed. Tabler icons
 * stroke with `currentColor`, so setting colour on the link is enough.
 *
 * Named `wn-header-icon` rather than with the `wn-icon` prefix: that prefix is the
 * mask-image icon family used inside sections, deliberately left ungated so the dash
 * preview — which renders without the themed class — still shows them.
 * check-theme-sections.mjs asserts that no themed selector reaches that family, and
 * it caught the collision when this rule was first written with that prefix. */
.wn-themed .wn-header-icon {
  color: var(--wn-color-primary);
}

/* `.container-fluid` caps at a hardcoded 1440px while themed sections use
 * `.wn-container` — so the header and footer sat wider than the content between
 * them on any theme whose `containerWidth` is not 1440. */
.wn-themed .container-fluid {
  max-width: var(--wn-container);
}

/* ---------------------------------------------------------------------------
 * Chrome variants — the header and footer as part of the design.
 *
 * The rules above make one header follow the theme's colours. Every theme therefore got the
 * *same* header: logo left, search centre, nav centred on its own row below, drop shadow, two
 * tinted footer bands. Recoloured, but one layout — the chrome half of "themes only differ by
 * colour".
 *
 * The alternative was letting a theme supply its own header markup, which the storefront already
 * supports through `theme.page_templates`. That trade is bad: a hand-written template only
 * reproduces what its author remembered, so it silently drops the multi-level menu, the mobile
 * drawer, the mini cart, the currency selector and the payment icons — and the template renderer
 * cannot express a submenu at all, because its `{{#each}}` pattern is non-greedy and a nested each
 * matches only as far as the inner `{{/each}}`. So this goes the same way section variants did:
 * keep every component, restyle it.
 *
 * A theme names one of these in `settings.chrome` and the API sends it beside `tokens`; no value
 * means the centred bar above, unchanged. Written `.wn-themed.wn-chrome-x` rather than the reverse
 * so the layer stays visibly gated — an unthemed store matches none of it.
 *
 * Each is a different KIND of change, not a shade of one: alignment, row order, weight, removal.
 * Keep in sync with CHROME_VARIANTS in themeChrome.ts.
 * --------------------------------------------------------------------------- */

/* `left` — the nav sits under the logo instead of centred, so the header reads as
   editorial rather than catalogue. */
.wn-themed.wn-chrome-left header nav > ul {
  justify-content: flex-start;
}

/* `split` — the nav becomes a strip ABOVE the logo row. The two rows are siblings
   inside `header > div`, so reversing the column swaps them without touching a
   component; both keep full width because a column flex stretches its children,
   and `.container-fluid` keeps centring itself inside that width.
   `div:last-child` is the nav row in the DOM, which column-reverse paints first —
   so this border falls between the two rows. */
.wn-themed.wn-chrome-split header > div {
  display: flex;
  flex-direction: column-reverse;
}

.wn-themed.wn-chrome-split header > div > div:last-child {
  border-bottom: 1px solid var(--wn-color-border);
}

/* `bold` — the header carries the brand colour instead of the page surface. */
.wn-themed.wn-chrome-bold header,
.wn-themed.wn-chrome-bold header > div {
  background-color: var(--wn-color-primary);
  color: var(--wn-color-on-primary);
  box-shadow: none;
}

.wn-themed.wn-chrome-bold .menu-item > a,
.wn-themed.wn-chrome-bold .wn-logo,
.wn-themed.wn-chrome-bold .wn-header-icon,
.wn-themed.wn-chrome-bold .wn-search-submit {
  color: var(--wn-color-on-primary);
}

/* Hover cannot go to the primary colour here — that is the background. */
.wn-themed.wn-chrome-bold .menu-item > a:hover {
  color: var(--wn-color-on-primary);
  opacity: 0.7;
}

.wn-themed.wn-chrome-bold .mini-cart,
.wn-themed.wn-chrome-bold .mini-cart::before {
  border-color: var(--wn-color-on-primary);
}

.wn-themed.wn-chrome-bold .mini-cart {
  color: var(--wn-color-on-primary);
}

/* Everything that sits ON the header but paints its own surface: the dropdown panel,
 * the search input, the mobile drawer. Each keeps `--wn-color-surface` from the rules
 * above, so inheriting `on-primary` ink would put light text on a light panel — light
 * ink on a light panel is how a "bold header" theme becomes an unreadable menu. Stated
 * for each, because `color: inherit` on `.submenu` is what carries it down. */
.wn-themed.wn-chrome-bold .submenu,
.wn-themed.wn-chrome-bold .search,
.wn-themed.wn-chrome-bold #menu {
  color: var(--wn-color-text);
}

/* `quiet` — nothing but a hairline. No shadow, no footer bands, small tracked caps. */
.wn-themed.wn-chrome-quiet header {
  box-shadow: none;
  border-bottom: 1px solid var(--wn-color-border);
}

.wn-themed.wn-chrome-quiet .menu-item > a {
  text-transform: uppercase;
  font-size: calc(0.8rem * var(--wn-font-scale));
  letter-spacing: 0.12em;
}

.wn-themed.wn-chrome-quiet footer > div:first-child,
.wn-themed.wn-chrome-quiet footer > div:last-child {
  background-color: transparent;
}

/* ---------------------------------------------------------------------------
 * Section variants (issue: "themes only differ by colour").
 *
 * A theme could vary its palette and the order of its sections and nothing else — every section
 * rendered one way, titles centred, cards bordered, container at --wn-container. These four give a
 * theme a second axis without a new component or a field per section type: the renderer puts
 * `wn-variant wn-variant-<name>` on the wrapper it already builds for colour bands, and the rules
 * below do the rest.
 *
 * Each is a different KIND of change rather than a shade of the same one, which is what makes two
 * themes read as different designs instead of the same design tinted.
 *
 * Keep in sync with the other copy of this file and with SECTION_VARIANTS in
 * backgrounds.js / backgrounds.ts.
 * --------------------------------------------------------------------------- */

/* Everything is centred by default, which is most of why themes look alike. */
.wn-variant-align-left .wn-section-title,
.wn-variant-align-left .wn-section-subtitle {
  text-align: left;
}

/* Edge to edge, for a band meant to read as a break in the page.
 *
 * `!important` because it has to outrank an inline style, which is the only thing it can lose to:
 * the image section's renderer emits `style="max-width:820px;text-align:center"` on this very
 * element, so the variant matched, applied, and was overridden — a hero asking to be full-bleed
 * rendered as an 820px box and the variant looked like it did nothing. Nothing in the cascade below
 * `!important` beats an inline declaration, so the alternative was changing two copies of the
 * renderer. Found by dumping the element's own `style` attribute after the rule itself measured as
 * matching. */
.wn-variant-full .wn-container {
  max-width: none !important;
}

/* Boxes become a list. Borders and card padding are what make a section feel like a widget.
 *
 * The surface has to go with them, and it did not: `.wn-review-card` paints
 * `background: var(--wn-color-surface)` and nothing here removed it, so a "plain" review section
 * kept a white rectangle per review — still a box, and now a box whose text runs into its own left
 * and right edges because the side padding *was* removed. Strictly worse than the bordered card it
 * replaced, and only obvious on a band: on the page background the white is invisible, which is why
 * this survived until a theme put plain reviews on `soft`. */
.wn-variant-plain .wn-review-card,
.wn-variant-plain .wn-faq-item {
  border: 0;
  padding-left: 0;
  padding-right: 0;
  background: transparent;
}

/* With no box there is nothing for the vertical padding to sit inside, so it stopped being padding
 * and became a second gap: 24px of it above and below each card, on top of the grid's own 24px, put
 * 72px between rows against 24px between columns. A grid whose rows are three times further apart
 * than its columns stops reading as a grid. The row gap is set here instead, once, where it can be
 * seen. */
.wn-variant-plain .wn-review-card {
  padding-top: 0;
  padding-bottom: 0;
}

.wn-variant-plain .wn-reviews-grid {
  row-gap: calc(var(--wn-space) * 2);
}

/* Except the line that makes a FAQ read as a list at all. `border: 0` above takes `border-bottom`
 * with it, and questions with nothing between them run together as one column of text — for a FAQ
 * the rule IS the affordance, not decoration. Reviews do not need it back: the grid gap already
 * separates them. */
.wn-variant-plain .wn-faq-item {
  border-bottom: 1px solid var(--wn-color-border);
}

/* Trust items read as rows — icon beside the words instead of above them. */
.wn-variant-stacked .wn-trust-item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: calc(var(--wn-space) / 2);
  align-items: start;
  text-align: left;
}

/* The paragraph is the item's THIRD grid child, so with two columns it wrapped to row 2 column 1 —
 * under the icon, 195px to the left of the heading it belongs to. Only visible once a stacked trust
 * section carried descriptions, which the store's footer strip was the first to do. */
.wn-variant-stacked .wn-trust-item p {
  text-align: left;
  grid-column: 2;
}

/* And the icon spans both rows, or it sets row 1 to its own height and the description starts 86px
 * below a 21px title — the words stop reading as one block beside one icon.
 *
 * Both icon flavours, because a trust row renders either one: `.wn-trust-icon` is the <img> a row
 * with a `src` gets, `.wn-icon` the masked <span> a row with only an `icon` name gets. The first
 * attempt named just the image and changed nothing at all — the store's footer rows carry icon
 * names, so every one of them was a span. */
.wn-variant-stacked .wn-trust-item > .wn-icon,
.wn-variant-stacked .wn-trust-icon {
  grid-row: 1 / span 2;
  margin: 0;
}

/* ---------------------------------------------------------------------------
 * Type scale and vertical rhythm (issue: "themes only differ by colour").
 *
 * `--wn-font-scale` multiplied every size at once, so a theme could be uniformly larger or smaller
 * and never "large display type over modest body copy" — the ratio is what makes type read as
 * designed rather than resized. `--wn-space` had the same problem for rhythm: it drives padding,
 * gaps and margins together, so a theme could not breathe between sections without loosening
 * everything inside them.
 *
 * Both new variables carry a `, 1` fallback, so a theme whose tokens predate them is unchanged.
 * --------------------------------------------------------------------------- */

.wn-section {
  padding: calc(var(--wn-space) * 2 * var(--wn-section-space, 1)) var(--wn-space);
}

.wn-section-title {
  font-size: calc(1.5rem * var(--wn-font-scale) * var(--wn-font-scale-heading, 1));
}

/**
 * The page's own headings, for the ones that carry no class of their own.
 *
 * `:where()` contributes nothing to specificity, so this whole selector weighs (0,0,1) — a
 * DEFAULT rather than an override. Written as `.wn-themed h3` it weighed (0,1,1), which ties with
 * `.wn-trust-item h3` and, being later in the file, won: every component heading was dragged to
 * 1.5rem, so a trust badge title rendered at 27.6px beside a page title at the same size and the
 * size hierarchy the rest of the stylesheet builds was flattened. Measured on the store's footer
 * strip, not spotted by reading.
 *
 * A browser without `:where()` drops the rule and headings fall back to their component sizes,
 * which is what they had before the heading scale existed.
 */
:where(.wn-themed) h1,
:where(.wn-themed) h2,
:where(.wn-themed) h3 {
  font-size: calc(1.5rem * var(--wn-font-scale) * var(--wn-font-scale-heading, 1));
}

.wn-pdp-title {
  font-size: calc(1.5rem * var(--wn-font-scale) * var(--wn-font-scale-heading, 1));
}
