/**
 * jensik — Elements
 * ====================
 * Icons, Brand Heart, Buttons, IconButton, Badges, SectionTitle,
 * Cards (generic), Form controls, Chips.
 */

/* =======================================================================
 * ICON  — .nk-icon
 * Always rendered via nk_icon() (inc/icons.php), never inline <svg>.
 * ===================================================================== */

.nk-icon {
  display: inline-block;
  inline-size: var(--nk-icon-md);
  block-size: var(--nk-icon-md);
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: var(--nk-icon-stroke);
  stroke-linecap: round;
  stroke-linejoin: round;
  /* Optically centre the icon against the text baseline. */
  vertical-align: -0.2em;
}

.nk-icon--xs { inline-size: var(--nk-icon-xs); block-size: var(--nk-icon-xs); }
.nk-icon--sm { inline-size: var(--nk-icon-sm); block-size: var(--nk-icon-sm); }
.nk-icon--lg { inline-size: var(--nk-icon-lg); block-size: var(--nk-icon-lg); }
.nk-icon--xl { inline-size: var(--nk-icon-xl); block-size: var(--nk-icon-xl); }
.nk-icon--bold { stroke-width: var(--nk-icon-stroke-bold); }

/* Filled variants — heart on a wishlist that is already saved, filled stars. */
.nk-icon--filled { fill: currentColor; stroke: none; }

/* Social brand marks are filled paths, not strokes. */
.nk-icon--brand { fill: currentColor; stroke: none; }

/* =======================================================================
 * BRAND HEART — .nk-heart
 * The single official implementation of the coral heart motif.
 * Render with nk_brand_heart(). Never hand-write another heart.
 * ===================================================================== */

.nk-heart {
  display: inline-block;
  inline-size: var(--nk-heart-size-md);
  block-size: var(--nk-heart-size-md);
  flex: none;
  color: var(--nk-heart-color);
  fill: currentColor;
  stroke: none;
  vertical-align: -0.08em;
  /* Decorative by default — it carries no meaning a screen reader needs. */
}

.nk-heart--sm { inline-size: var(--nk-heart-size-sm); block-size: var(--nk-heart-size-sm); }
.nk-heart--lg { inline-size: var(--nk-heart-size-lg); block-size: var(--nk-heart-size-lg); }

/* On dark/inverse surfaces the coral still reads — do not recolour it. */
.nk-surface-inverse .nk-heart { color: var(--nk-coral-400); }

/* =======================================================================
 * SECTION TITLE — .nk-section-title
 * Heading + optional Brand Heart + optional "view all" link.
 * ===================================================================== */

.nk-section-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--nk-space-4);
  margin-block-end: var(--nk-space-5);
}

.nk-section-title__text {
  display: flex;
  align-items: center;
  gap: var(--nk-space-2);
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-2xl);
  font-weight: var(--nk-weight-bold);
  color: var(--nk-text-strong);
  line-height: var(--nk-leading-snug);
}

.nk-section-title__sub {
  display: block;
  margin-block-start: var(--nk-space-1);
  font-size: var(--nk-text-base);
  font-weight: var(--nk-weight-regular);
  color: var(--nk-text-muted);
}

.nk-section-title__link {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--nk-space-1);
  font-size: var(--nk-text-base);
  font-weight: var(--nk-weight-medium);
  color: var(--nk-text-accent);
  text-decoration: none;
  min-block-size: var(--nk-touch-target);
  align-content: center;
}
@media (hover: hover) {
  .nk-section-title__link:hover { text-decoration: underline; }
}

@media (min-width: 768px) {
  .nk-section-title__text { font-size: var(--nk-text-3xl); }
  .nk-section-title { margin-block-end: var(--nk-space-8); }
}

/* Centred editorial variant */
.nk-section-title--center {
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* =======================================================================
 * BUTTON — .nk-btn
 * Variants: primary | secondary | ghost | quiet | danger
 * Sizes: sm | (default md) | lg
 * ===================================================================== */

.nk-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--nk-space-2);
  min-block-size: var(--nk-touch-target);
  padding-inline: var(--nk-space-5);
  padding-block: var(--nk-space-3);
  border: var(--nk-border-width) solid transparent;
  border-radius: var(--nk-radius-md);
  font-family: var(--nk-font-ui);
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-semibold);
  line-height: var(--nk-leading-none);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  transition: background-color var(--nk-transition-base),
              border-color var(--nk-transition-base),
              color var(--nk-transition-base),
              box-shadow var(--nk-transition-base),
              transform var(--nk-duration-instant) var(--nk-ease-standard);
}

/* Press feedback is a 1px settle, never a bounce. */
.nk-btn:active { transform: translateY(1px); }

.nk-btn:disabled,
.nk-btn[aria-disabled="true"] {
  background-color: var(--nk-action-disabled-bg);
  border-color: transparent;
  color: var(--nk-action-disabled-text);
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

.nk-btn.nk-btn--primary,
.nk-btn.nk-btn--primary:active {
  color: var(--nk-text-on-accent);
}
@media (hover: hover) {
  .nk-btn.nk-btn--primary:hover {
    color: var(--nk-text-on-accent);
  }
}
.nk-btn--primary {
  background-color: var(--nk-action-primary);
  box-shadow: var(--nk-shadow-accent);
}
@media (hover: hover) {
  .nk-btn--primary:hover:not(:disabled) { background-color: var(--nk-action-primary-hover); }
}
.nk-btn--primary:active:not(:disabled) { background-color: var(--nk-action-primary-active); }

.nk-btn.nk-btn--secondary,
.nk-btn.nk-btn--secondary:active {
  color: var(--nk-text-inverse);
}
@media (hover: hover) {
  .nk-btn.nk-btn--secondary:hover {
    color: var(--nk-text-inverse);
  }
}
.nk-btn--secondary {
  background-color: var(--nk-action-secondary);
}
@media (hover: hover) {
  .nk-btn--secondary:hover:not(:disabled) { background-color: var(--nk-action-secondary-hover); }
}

.nk-btn.nk-btn--ghost,
.nk-btn.nk-btn--ghost:active {
  color: var(--nk-text-strong);
}
@media (hover: hover) {
  .nk-btn.nk-btn--ghost:hover {
    color: var(--nk-text-strong);
  }
}
.nk-btn--ghost {
  background-color: transparent;
  border-color: var(--nk-border-default);
}
@media (hover: hover) {
  .nk-btn--ghost:hover:not(:disabled) {
    border-color: var(--nk-border-strong);
    background-color: var(--nk-navy-50);
  }
}

.nk-btn.nk-btn--quiet,
.nk-btn.nk-btn--quiet:active {
  color: var(--nk-text-accent);
}
@media (hover: hover) {
  .nk-btn.nk-btn--quiet:hover {
    color: var(--nk-text-accent);
  }
}
.nk-btn--quiet {
  background-color: transparent;
  padding-inline: var(--nk-space-2);
}
@media (hover: hover) {
  .nk-btn--quiet:hover:not(:disabled) { background-color: var(--nk-action-primary-subtle); }
}

.nk-btn.nk-btn--danger,
.nk-btn.nk-btn--danger:active {
  color: var(--nk-white);
}
@media (hover: hover) {
  .nk-btn.nk-btn--danger:hover {
    color: var(--nk-white);
  }
}
.nk-btn--danger {
  background-color: var(--nk-status-danger);
}

/* --- sizes --- */
.nk-btn--sm {
  min-block-size: 36px;
  padding-inline: var(--nk-space-3);
  padding-block: var(--nk-space-2);
  font-size: var(--nk-text-base);
  border-radius: var(--nk-radius-sm);
}
/**
 * 36px is a fine visual height with a mouse, but it breaks the 44px touch
 * minimum. On touch devices the small button grows to a legal target rather
 * than existing as a second, non-compliant size.
 */
@media (pointer: coarse) {
  .nk-btn--sm { min-block-size: var(--nk-touch-target); }
}
.nk-btn--lg {
  min-block-size: var(--nk-touch-target-lg);
  padding-inline: var(--nk-space-8);
  padding-block: var(--nk-space-4);
  font-size: var(--nk-text-lg);
}

.nk-btn--block { display: flex; inline-size: 100%; }

/**
 * Icon inside a button.
 * In RTL the icon sits to the RIGHT of the label automatically because the
 * flex row follows the writing direction — no override required. A leading
 * icon is simply the first DOM child.
 */
.nk-btn .nk-icon { inline-size: var(--nk-icon-md); block-size: var(--nk-icon-md); vertical-align: 0; }
.nk-btn--sm .nk-icon { inline-size: var(--nk-icon-sm); block-size: var(--nk-icon-sm); }

/*
 * Loading state — the label stays for width stability, the spinner replaces it.
 *
 * **The ring is positioned, not left to the static position.** It used to carry
 * `position: absolute` and no offsets, which puts it wherever the transparent
 * label happens to leave it: on a flex button that is roughly the centre, but
 * «افزودن به سبد خرید» wraps to two lines at 360px and the button computes
 * `display: block`, so the ring sat in the bottom inline-start corner. Centred
 * here so it is centred on every button, whatever the label does.
 *
 * `inset-inline: 0` + `margin-inline: auto` rather than a 50% offset and a
 * translate: the offset would have to flip with the writing direction.
 *
 * The colour is declared, never `currentColor` — the rule above paints the
 * label transparent and `currentColor` would inherit exactly that, leaving an
 * invisible spinner. Primary and inverse buttons get the on-accent white;
 * anything on a light ground overrides below.
 */
.nk-btn--loading { position: relative; color: transparent !important; pointer-events: none; cursor: progress; }
.nk-btn--loading::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline: 0;
  margin-inline: auto;
  inline-size: var(--nk-icon-md);
  block-size: var(--nk-icon-md);
  translate: 0 -50%;
  border: 2px solid currentColor;
  border-block-start-color: transparent;
  border-radius: var(--nk-radius-circle);
  color: var(--nk-text-on-accent);
  animation: nk-spin 700ms linear infinite;
}

/* A white ring on a cream button is not a ring. The two variants that sit on a
   light ground spin in the colour their own label uses; `--secondary` and
   `--danger` are solid grounds and keep the white above. */
.nk-btn--ghost.nk-btn--loading::after { color: var(--nk-text-strong); }
.nk-btn--quiet.nk-btn--loading::after { color: var(--nk-text-accent); }

/* Reduced rather than removed: a still ring reads as a broken button. */
@media (prefers-reduced-motion: reduce) {
  .nk-btn--loading::after { animation-duration: 2s; }
}

/* =======================================================================
 * ICON BUTTON — .nk-icon-btn
 * Square, always has an accessible name via aria-label.
 * ===================================================================== */

.nk-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--nk-touch-target);
  block-size: var(--nk-touch-target);
  border-radius: var(--nk-radius-pill);
  color: var(--nk-text-strong);
  background-color: transparent;
  border: var(--nk-border-width) solid transparent;
  transition: background-color var(--nk-transition-base), color var(--nk-transition-base);
}
@media (hover: hover) {
  .nk-icon-btn:hover { background-color: var(--nk-navy-50); }
}
.nk-icon-btn:active { background-color: var(--nk-navy-100); }
.nk-icon-btn:disabled { color: var(--nk-action-disabled-text); cursor: not-allowed; background: none; }

.nk-icon-btn--solid { background-color: var(--nk-surface-raised); box-shadow: var(--nk-shadow-sm); }
.nk-icon-btn--accent { background-color: var(--nk-action-primary); color: var(--nk-text-on-accent); }
@media (hover: hover) {
  .nk-icon-btn--accent:hover { background-color: var(--nk-action-primary-hover); }
}
.nk-icon-btn--lg { inline-size: var(--nk-touch-target-lg); block-size: var(--nk-touch-target-lg); }

/* Count bubble on cart/wishlist buttons. */
.nk-icon-btn { position: relative; }
.nk-icon-btn__count {
  position: absolute;
  inset-block-start: 4px;
  inset-inline-end: 4px;
  min-inline-size: 18px;
  block-size: 18px;
  padding-inline: 5px;
  display: grid;
  place-items: center;
  background-color: var(--nk-action-primary);
  color: var(--nk-text-on-accent);
  font-size: var(--nk-text-2xs);
  font-weight: var(--nk-weight-bold);
  border-radius: var(--nk-radius-pill);
  border: 2px solid var(--nk-surface-page);
}

/* =======================================================================
 * BADGE — .nk-badge
 * ===================================================================== */

/*
 * The height is a `min-block-size` and the type sits on `leading-none` —
 * deliberately, and this is the part that is easy to undo.
 *
 * It used to derive its height from `padding-block: 3px` over a `snug`
 * line-height, which meant the box was whatever the *font* happened to make
 * it: 22px around 12px of text, and a different 22px in Vazirmatn than in
 * IRANSansX. A badge is a label chip — every one of them on a card, in a
 * toolbar or beside a facet should be the same height as every other, and a
 * single-digit count should be a disc rather than a wide slab. Fixing the box
 * and centring the text in it is what makes «٪۲۰ تخفیف» on a product card and
 * a bare «۲» beside a filter read as the same component.
 *
 * `min-block-size`, not `block-size`, so a two-line badge is still possible;
 * nothing in the theme does that today and nothing should have to.
 */
.nk-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--nk-space-1);
  min-block-size: var(--nk-control-size);
  padding-inline: var(--nk-space-2);
  border-radius: var(--nk-radius-sm);
  font-size: var(--nk-text-xs);
  font-weight: var(--nk-weight-semibold);
  line-height: var(--nk-leading-none);
  background-color: var(--nk-navy-50);
  color: var(--nk-text-default);
  white-space: nowrap;
}
/* Any icon inside a badge tracks the type, never `.nk-icon`'s 20px default —
   a 20px glyph beside 12px text is the badge wearing an icon twice its size. */
.nk-badge > .nk-icon {
  inline-size: var(--nk-icon-xs);
  block-size: var(--nk-icon-xs);
}

.nk-badge--sale    { background-color: var(--nk-action-primary); color: var(--nk-text-on-accent); }
.nk-badge--new     { background-color: var(--nk-navy-800); color: var(--nk-text-inverse); }
.nk-badge--success { background-color: var(--nk-status-success-bg); color: var(--nk-status-success-text); }
.nk-badge--warning { background-color: var(--nk-status-warning-bg); color: var(--nk-status-warning-text); }
.nk-badge--danger  { background-color: var(--nk-status-danger-bg); color: var(--nk-status-danger-text); }
.nk-badge--soft    { background-color: var(--nk-surface-accent); color: var(--nk-text-accent); }
/* Muted is for a *state*, not a promotion — «ناموجود» over a greyed card.
   Solid navy-tinted rather than translucent, because it sits over photography
   where a wash would take the photograph's contrast, not the theme's. */
.nk-badge--muted   { background-color: var(--nk-navy-700); color: var(--nk-text-inverse); }
.nk-badge--pill    { border-radius: var(--nk-radius-pill); padding-inline: var(--nk-space-3); }
/*
 * A number, not a word. Square-ish by default and growing into a pill at two
 * or three digits, because a disc is what a count looks like everywhere else
 * on the web and a 34px-wide slab around a «۲» does not. `tabular-nums` so a
 * column of facet counts does not shuffle as the numbers change under a
 * filter — the same reason `.nk-num` carries it.
 */
.nk-badge--count {
  min-inline-size: var(--nk-control-size);
  padding-inline: var(--nk-space-1);
  border-radius: var(--nk-radius-pill);
  font-variant-numeric: tabular-nums;
}

/* =======================================================================
 * CARD — .nk-card  (generic surface)
 * ===================================================================== */

.nk-card {
  background-color: var(--nk-surface-raised);
  border: var(--nk-border-width) solid var(--nk-border-subtle);
  border-radius: var(--nk-radius-lg);
  overflow: hidden;
}
.nk-card--flat { box-shadow: none; }
.nk-card--raised { box-shadow: var(--nk-shadow-sm); border-color: transparent; }
.nk-card--pad { padding: var(--nk-space-5); }

.nk-card--interactive {
  transition: box-shadow var(--nk-duration-normal) var(--nk-ease-standard),
              transform var(--nk-duration-normal) var(--nk-ease-standard);
}
@media (hover: hover) {
  .nk-card--interactive:hover {
    box-shadow: var(--nk-shadow-md);
    transform: translateY(-2px);
  }
}

/* =======================================================================
 * BENEFIT / TRUST CARD — .nk-benefit
 * Icon + title + short line. Used in the service strip.
 * ===================================================================== */

.nk-benefit {
  display: flex;
  align-items: center;
  gap: var(--nk-space-3);
  padding: var(--nk-space-4);
  background-color: var(--nk-surface-raised);
  border-radius: var(--nk-radius-lg);
  border: var(--nk-border-width) solid var(--nk-border-subtle);
}

.nk-benefit__icon {
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  flex: none;
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-surface-accent);
  color: var(--nk-action-primary);
}
.nk-benefit__title {
  font-size: var(--nk-text-base);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}
.nk-benefit__desc {
  font-size: var(--nk-text-sm);
  color: var(--nk-text-muted);
  line-height: var(--nk-leading-snug);
}

/* Mobile: horizontal scroll strip. Desktop: 4-up grid. */
.nk-benefit-grid {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(240px, 1fr);
  gap: var(--nk-space-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-block-end: var(--nk-space-2);
  scrollbar-width: none;
}
.nk-benefit-grid::-webkit-scrollbar { display: none; }
.nk-benefit-grid > * { scroll-snap-align: start; }

@media (min-width: 768px) {
  .nk-benefit-grid {
    grid-auto-flow: row;
    grid-template-columns: repeat(4, 1fr);
    overflow-x: visible;
  }
}

/* =======================================================================
 * FORM CONTROLS
 * ===================================================================== */

.nk-field { display: block; }
.nk-field + .nk-field { margin-block-start: var(--nk-space-5); }

.nk-label {
  display: block;
  margin-block-end: var(--nk-space-2);
  font-size: var(--nk-text-base);
  font-weight: var(--nk-weight-medium);
  color: var(--nk-text-strong);
}
.nk-label__required { color: var(--nk-status-danger); margin-inline-start: 2px; }

.nk-input,
.nk-textarea,
.nk-select {
  inline-size: 100%;
  min-block-size: var(--nk-touch-target-lg);
  padding-inline: var(--nk-space-4);
  padding-block: var(--nk-space-3);
  background-color: var(--nk-surface-raised);
  border: var(--nk-border-width) solid var(--nk-border-default);
  border-radius: var(--nk-radius-md);
  color: var(--nk-text-strong);
  /* 16px minimum — anything smaller makes iOS Safari zoom on focus. */
  font-size: var(--nk-text-md);
  line-height: var(--nk-leading-snug);
  transition: border-color var(--nk-transition-base), box-shadow var(--nk-transition-base);
}

.nk-input::placeholder,
.nk-textarea::placeholder { color: var(--nk-text-subtle); }

@media (hover: hover) {
  .nk-input:hover,
  .nk-textarea:hover,
  .nk-select:hover { border-color: var(--nk-border-strong); }
}

.nk-input:focus-visible,
.nk-textarea:focus-visible,
.nk-select:focus-visible {
  border-color: var(--nk-border-accent);
  outline-offset: 0;
}

.nk-input:disabled,
.nk-textarea:disabled,
.nk-select:disabled {
  background-color: var(--nk-navy-50);
  color: var(--nk-action-disabled-text);
  cursor: not-allowed;
}

.nk-input[aria-invalid="true"],
.nk-textarea[aria-invalid="true"] { border-color: var(--nk-status-danger); }

.nk-textarea { min-block-size: 120px; resize: vertical; }

.nk-select {
  appearance: none;
  /* Room for the chevron on the inline-end side, direction-aware. */
  padding-inline-end: var(--nk-space-10);
}
.nk-select-wrap { position: relative; }
.nk-select-wrap .nk-icon {
  position: absolute;
  inset-inline-end: var(--nk-space-4);
  inset-block-start: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  color: var(--nk-text-muted);
}

.nk-help  { margin-block-start: var(--nk-space-2); font-size: var(--nk-text-sm); color: var(--nk-text-muted); }
.nk-error { margin-block-start: var(--nk-space-2); font-size: var(--nk-text-sm); color: var(--nk-status-danger-text); display: flex; align-items: center; gap: var(--nk-space-1); }

/* Checkbox / radio — 20px box inside a 44px hit area. */
/* =======================================================================
 * SELECTION CONTROLS — .nk-check / .nk-radio
 *
 * One component in two shapes. They were `accent-color` on a native input,
 * which is the browser's checkbox tinted coral: a different box on every
 * platform, no hover or disabled state of ours, no control at all over the
 * tick, and — since a radio got no styling whatsoever — a visible design gap
 * between a checkbox and a radio standing in the same sheet.
 *
 * Now both are drawn here, and they differ in exactly two declarations: the
 * radius, and what the `::before` paints. Everything else — size, border,
 * checked fill, hover, focus, disabled, the 44px row — is shared, which is
 * the whole point.
 *
 * `appearance: none` on the input itself rather than a hidden input beside a
 * drawn `<span>`: the input stays the control, so the focus ring, the label
 * association and the keyboard behaviour are the platform's and not a
 * reimplementation. Both selectors are `> input`, so a nested control inside a
 * label's own markup is never captured by its parent.
 * ===================================================================== */

/*
 * `label.nk-check`, with the element name, and it is load-bearing.
 *
 * WooCommerce's `woocommerce-general` ships `.woocommerce-page label
 * { margin-bottom: .7em }` — (0,1,1) — and `body.woocommerce-page` is on the
 * shop, the cart, the checkout and the account. Against a plain `.nk-check`
 * (0,1,0) it won, so **every checkbox row in the filter sheet was 44px of
 * control followed by 11.2px of nothing**: eight rows of a facet list cost an
 * extra 90px, and the sheet read as a list with far too much air between its
 * items — which is exactly how the shop owner reported it.
 *
 * The type selector brings this to (0,1,1) and `elements.css` is enqueued
 * after `woocommerce-general`, so the tie goes to us on source order. This is
 * the fourth component the "single class loses" trap has caught; see
 * `.claude/rules/css.md`.
 */
label.nk-check,
label.nk-radio,
.nk-check,
.nk-radio {
  display: flex;
  align-items: center;
  gap: var(--nk-space-3);
  min-block-size: var(--nk-touch-target);
  margin: 0;
  cursor: pointer;
}

.nk-check > input,
.nk-radio > input {
  appearance: none;
  -webkit-appearance: none;
  display: grid;
  place-content: center;
  inline-size: var(--nk-control-size);
  block-size: var(--nk-control-size);
  flex: none;
  margin: 0;
  border: var(--nk-border-width) solid var(--nk-border-strong);
  background-color: var(--nk-surface-raised);
  cursor: pointer;
  transition: background-color var(--nk-transition-base),
              border-color var(--nk-transition-base);
}

.nk-check > input { border-radius: var(--nk-radius-xs); }
.nk-radio > input { border-radius: var(--nk-radius-pill); }

.nk-check > input::before,
.nk-radio > input::before {
  content: "";
  /* Scaled rather than toggled, so the mark grows out of the box instead of
     appearing on top of it. `--nk-duration-instant` is the press timing —
     a selection control should feel like it answered before the finger left. */
  transform: scale(0);
  transition: transform var(--nk-duration-instant) var(--nk-ease-standard);
}

/*
 * The tick is two borders on a rotated box, not an icon.
 *
 * `nk_icon()` cannot reach inside a `::before`, and a `background-image` data
 * URI would be an inlined SVG — which the design system forbids for the same
 * reason it forbids a second icon library. Two border edges at 45° is the
 * shape itself, drawn in CSS, at any size the token says.
 *
 * The physical `border-width` here is deliberate and must stay physical: this
 * is a glyph, not a layout. A checkmark has a fixed handedness in Persian
 * exactly as it does in English, and swapping it to logical properties would
 * mirror it in RTL — which is what an RTL bug looks like, not a localisation.
 */
.nk-check > input::before {
  inline-size: 5px;
  block-size: 9px;
  border: solid var(--nk-text-on-accent);
  border-width: 0 var(--nk-control-tick) var(--nk-control-tick) 0;
  /* The optical centre of a tick sits above and left of the box's centre. */
  transform: scale(0) rotate(45deg) translate(-1px, -1px);
}
.nk-check > input:checked::before { transform: scale(1) rotate(45deg) translate(-1px, -1px); }

.nk-radio > input::before {
  inline-size: var(--nk-control-dot);
  block-size: var(--nk-control-dot);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-text-on-accent);
}
.nk-radio > input:checked::before { transform: scale(1); }

.nk-check > input:checked,
.nk-radio > input:checked {
  background-color: var(--nk-action-primary);
  border-color: var(--nk-action-primary);
}

@media (hover: hover) {
  .nk-check > input:hover:not(:disabled),
  .nk-radio > input:hover:not(:disabled) { border-color: var(--nk-action-primary); }
}

.nk-check > input:focus-visible,
.nk-radio > input:focus-visible {
  outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
  outline-offset: var(--nk-focus-ring-offset);
}

.nk-check > input:disabled,
.nk-radio > input:disabled { cursor: not-allowed; opacity: 0.45; }
.nk-check:has(> input:disabled),
.nk-radio:has(> input:disabled) { cursor: not-allowed; color: var(--nk-text-subtle); }

/* =======================================================================
 * RANGE — .nk-range  (a two-handle numeric range)
 *
 * **Two native `<input type="range">` stacked on one rail**, not a scripted
 * widget. Each is an ordinary named form field, so the pair submits on a plain
 * GET and keeps working with the script blocked — which is the archive's
 * standing requirement for every control it prints. The script adds only what
 * a native pair cannot do for itself: stop the handles crossing, paint the
 * fill between them, and mirror the two typed fields.
 *
 * The mechanism that makes an overlay work is `pointer-events`. Two inputs at
 * `inset: 0` means the second covers the first entirely and the lower handle
 * becomes unreachable — so the *inputs* take `pointer-events: none` and only
 * the **thumbs** take it back. The rail is a sibling element rather than the
 * inputs' own `::-webkit-slider-runnable-track`, because there are two of them
 * and only one rail should be painted.
 *
 * The row is a full `--nk-touch-target` tall while the thumb is 22px: the
 * finger gets 44px, and the design keeps a handle that does not look like a
 * button. This is the one place that trick is right, because there is nothing
 * behind the control to mistake the padding for.
 * ===================================================================== */

.nk-range {
  display: grid;
  gap: var(--nk-space-1);
}

.nk-range__readout {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--nk-space-2);
  font-family: var(--nk-font-numeric);
  font-size: var(--nk-text-sm);
  font-weight: var(--nk-weight-medium);
  color: var(--nk-text-strong);
}
.nk-range__dash { color: var(--nk-text-subtle); }

.nk-range__track {
  position: relative;
  display: grid;
  align-items: center;
  block-size: var(--nk-touch-target);
}
/* The rail. A pseudo-element so neither input owns it. */
.nk-range__track::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  block-size: var(--nk-range-track);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-surface-sunken);
}

/*
 * The selected span. `--nk-range-from` / `--nk-range-to` are written by
 * archive.js as percentages; with the script blocked they fall back to the
 * whole rail, which is the truthful picture of an unfiltered range.
 *
 * Logical `inset-inline-start` is what makes this correct in RTL for free: the
 * browser already reverses a range input's direction in an RTL document, so
 * "from" is measured from the same edge the handle counts from.
 */
.nk-range__fill {
  position: absolute;
  inset-inline-start: var(--nk-range-from, 0%);
  inline-size: calc(var(--nk-range-to, 100%) - var(--nk-range-from, 0%));
  block-size: var(--nk-range-track);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-action-primary);
}

.nk-range__input {
  position: absolute;
  inset-inline: 0;
  inline-size: 100%;
  block-size: var(--nk-touch-target);
  margin: 0;
  padding: 0;
  appearance: none;
  -webkit-appearance: none;
  background: none;
  /* See the block comment: the input is a transparent sheet, the thumb is the
     only part that answers a pointer, or the lower handle is unreachable. */
  pointer-events: none;
}

/* The two thumb pseudo-elements cannot be combined into one rule — a selector
   list containing a vendor pseudo-element is dropped whole by the engine that
   does not know it, taking the standard half with it. */
.nk-range__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  pointer-events: auto;
  inline-size: var(--nk-range-thumb);
  block-size: var(--nk-range-thumb);
  border: var(--nk-border-width) solid var(--nk-action-primary);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-xs);
  cursor: grab;
}
.nk-range__input::-moz-range-thumb {
  pointer-events: auto;
  inline-size: var(--nk-range-thumb);
  block-size: var(--nk-range-thumb);
  border: var(--nk-border-width) solid var(--nk-action-primary);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-xs);
  cursor: grab;
}
.nk-range__input:active::-webkit-slider-thumb { cursor: grabbing; background-color: var(--nk-action-primary); }
.nk-range__input:active::-moz-range-thumb { cursor: grabbing; background-color: var(--nk-action-primary); }

/* The ring goes on the thumb, not on the 44px transparent sheet — a ring
   around the whole rail says nothing about which handle has the keyboard. */
.nk-range__input:focus { outline: none; }
.nk-range__input:focus-visible::-webkit-slider-thumb {
  outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
  outline-offset: var(--nk-focus-ring-offset);
}
.nk-range__input:focus-visible::-moz-range-thumb {
  outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
  outline-offset: var(--nk-focus-ring-offset);
}

/* =======================================================================
 * CHIP — .nk-chip  (filter tokens, applied facets, tag lists)
 * ===================================================================== */

.nk-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--nk-space-2);
  min-block-size: 36px;
  padding-inline: var(--nk-space-4);
  border: var(--nk-border-width) solid var(--nk-border-default);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-surface-raised);
  font-size: var(--nk-text-base);
  color: var(--nk-text-default);
  white-space: nowrap;
  transition: all var(--nk-transition-base);
}
/**
 * 36px is the dense pointer size. On a touch device a chip is a primary tap
 * target — it is how every facet in the search and the filter sheet is chosen —
 * so it takes the full 44px minimum, the same way .nk-btn--sm does.
 */
@media (pointer: coarse) {
  .nk-chip { min-block-size: var(--nk-touch-target); }
}

/* A chip is a <button> in the filter sheet and an <a> on the product archive —
   a real link to the toggled state, so the row works with the script blocked.
   Without this the archive's chip rail rendered every label underlined. */
.nk-chip { text-decoration: none; }

@media (hover: hover) {
  .nk-chip:hover { border-color: var(--nk-border-strong); }
}
.nk-chip:active { background-color: var(--nk-navy-50); }
.nk-chip:disabled { opacity: 0.5; cursor: not-allowed; }
.nk-chip[aria-pressed="true"],
.nk-chip--active {
  background-color: var(--nk-navy-800);
  border-color: var(--nk-navy-800);
  color: var(--nk-text-inverse);
}
/* A chip carrying a count: the number is a quieter second rank, and stays
   legible against the navy fill when the chip is selected. */
.nk-chip__count { color: var(--nk-text-subtle); font-size: var(--nk-text-xs); }
.nk-chip[aria-pressed="true"] .nk-chip__count { color: var(--nk-navy-200); }

/**
 * CHIP ROW — horizontal scroller of chips.
 * Scrolls instead of wrapping: a wrapped row of active filters can grow to
 * four lines on a phone and push the results off the screen.
 */
.nk-chip-row {
  display: flex;
  gap: var(--nk-space-2);
  overflow-x: auto;
  scrollbar-width: none;
  /* Room for the focus ring, which would otherwise be clipped by the scroller. */
  padding-block: var(--nk-space-1);
  padding-inline: var(--nk-space-half);
}
.nk-chip-row::-webkit-scrollbar { display: none; }
.nk-chip-row > * { flex: 0 0 auto; }
.nk-chip-row--wrap { flex-wrap: wrap; overflow: visible; }

@keyframes nk-spin { to { transform: rotate(360deg); } }

/* =======================================================================
 * DIVIDER — .nk-divider
 * A graphical break between sections, for the places where a 1px rule is
 * doing enough work to deserve being seen. PHP: nk_divider().
 *
 * Two variants share one skeleton — rule · [mark] · [label] · rule — so the
 * spacing rhythm is identical whichever one a section uses.
 * ===================================================================== */

.nk-divider {
  display: flex;
  align-items: center;
  gap: var(--nk-space-4);
  margin-block: var(--nk-space-8);
  /* Decoration, never a landmark or a separator a screen reader announces —
     the markup carries aria-hidden and this is the visual half of that. */
  pointer-events: none;
}

.nk-divider__rule {
  flex: 1 1 0;
  min-inline-size: 0;
  block-size: 1px;
  /* Fades out towards the page edge so the rule reads as a drawn line rather
     than a table border stopping dead at the gutter. */
  background: linear-gradient(
    to left,
    transparent,
    var(--nk-border-subtle) 18%,
    var(--nk-border-subtle) 82%,
    transparent
  );
}

/**
 * The wave.
 *
 * The asset is black-on-transparent and used as a *mask*, so the colour is a
 * token on `background-color` rather than a hex baked into an SVG that could
 * drift from the palette. One 1.3KB file serves every tone.
 *
 * `repeat-x` on a tile of exactly two periods: the source path is a sampled
 * sine, so the phase and the slope both match at the seam.
 */
.nk-divider--wave .nk-divider__rule {
  block-size: 14px;
  background: var(--nk-border-default);
  -webkit-mask: url("../../images/dividers/wave.svg") repeat-x center / auto 14px;
  mask: url("../../images/dividers/wave.svg") repeat-x center / auto 14px;
}

/* The mark is the brand's own full stop. Sized in the same 28–36px band as a
   section heading so it sits as a peer of the type around it, not a logo
   dropped into the page. */
.nk-divider__mark {
  flex: 0 0 auto;
  display: inline-flex;
}
.nk-divider .nk-divider__mark img {
  block-size: 30px;
  inline-size: auto;
  /* Two classes deep: Woo ships `.woocommerce-page img { height: auto }`,
     which out-specifies a single-class rule on every commerce route. */
}

/* An optional short line between the rules. Display font, because a divider
   that speaks should use the same voice as a heading. */
.nk-divider__label {
  flex: 0 0 auto;
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-sm);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-muted);
}

/* On the navy footer. The rule tone lifts to the inverse border and the wave
   with it; the mark swaps to its cream cut in PHP, not here. */
.nk-divider--inverse .nk-divider__rule {
  background: linear-gradient(
    to left,
    transparent,
    var(--nk-border-inverse) 18%,
    var(--nk-border-inverse) 82%,
    transparent
  );
}
.nk-divider--inverse.nk-divider--wave .nk-divider__rule {
  background: var(--nk-navy-600);
}
.nk-divider--inverse .nk-divider__label { color: var(--nk-navy-200); }

@media (min-width: 768px) {
  .nk-divider { margin-block: var(--nk-space-10); gap: var(--nk-space-6); }
  .nk-divider .nk-divider__mark img { block-size: 36px; }
}

/* =======================================================================
 * HEART LIST — .nk-heart-list
 *
 * A bulleted list whose marker is the Brand Heart. It exists because a
 * feature list is the one place on a product page where the eye is scanning
 * for "what do I get", and a generic disc or a check icon says nothing about
 * whose shop this is. The heart is the storefront's one piece of ornament,
 * and this is a deliberate, documented second placement for it — see
 * DESIGN_SYSTEM.md and the jensik-ui skill's brand-and-icons topic.
 *
 * The marker is a real <svg class="nk-heart"> printed by nk_brand_heart(),
 * not a ::marker or a background image: the Brand Heart has exactly one
 * renderer, and a CSS copy of it is how a motif drifts.
 *
 * Two classes on the selector, not one: base.css resets `ul[class]` margin
 * and padding to 0 at (0,1,1), which a single-class rule cannot beat.
 * ===================================================================== */

ul.nk-heart-list,
ol.nk-heart-list {
  display: grid;
  gap: var(--nk-space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nk-heart-list > li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--nk-space-2);
  color: var(--nk-text-default);
  line-height: var(--nk-leading-normal);
}

/* Nudged down to sit on the text's optical centre rather than its cap line. */
.nk-heart-list > li > .nk-heart {
  margin-block-start: 0.35em;
  flex: none;
}

/* =======================================================================
 * SORT LIST — .nk-sort-list / .nk-sort-option
 *
 * A radio group presented as a list of rows: the row is the control, and the
 * choice is marked with a tick rather than a dot. Promoted out of
 * `archive.css` on 2026-08-22 when the product page's review sort became the
 * second consumer — `archive.css` is enqueued on archive routes only, and a
 * second copy of a list of radio rows is how two sort menus start looking
 * like two different products.
 *
 * Whoever selects the radio decides what happens; this file only paints it.
 * The archive submits a GET form, the review sort reorders the list in place.
 * ===================================================================== */

.nk-sort-list { display: grid; }

.nk-sort-option {
  display: flex;
  align-items: center;
  gap: var(--nk-space-3);
  min-block-size: var(--nk-touch-target-lg);
  padding-inline: var(--nk-space-2);
  border-radius: var(--nk-radius-md);
  cursor: pointer;
  transition: background-color var(--nk-transition-base);
}
/* The radio itself is hidden from sight but not from the accessibility tree or
   the keyboard — the row is the control, and a 20px dot beside a 48px row is
   a second, smaller target for the same thing. */
.nk-sort-option input {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.nk-sort-option__label {
  flex: 1 1 auto;
  font-size: var(--nk-text-md);
  color: var(--nk-text-default);
}
.nk-sort-option__check {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--nk-action-primary);
  opacity: 0;
  transform: scale(0.8);
  transition: opacity var(--nk-transition-base), transform var(--nk-transition-base);
}
.nk-sort-option:has(input:checked) {
  background-color: var(--nk-action-primary-subtle);
}
.nk-sort-option:has(input:checked) .nk-sort-option__label {
  color: var(--nk-text-strong);
  font-weight: var(--nk-weight-semibold);
}
.nk-sort-option:has(input:checked) .nk-sort-option__check {
  opacity: 1;
  transform: scale(1);
}
@media (hover: hover) {
  .nk-sort-option:hover { background-color: var(--nk-action-secondary-subtle); }
}
/* :has() is what carries the checked state, so the focus ring has to be stated
   on the row too or a keyboard user moving through the radios sees nothing. */
.nk-sort-option:has(input:focus-visible) {
  outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
  outline-offset: calc(var(--nk-focus-ring-offset) * -1);
}
