/**
 * jensik — Cart
 * ================
 * The mini-cart drawer, the cart page and the checkout.
 *
 * Loaded after `woocommerce.css` and before `motion.css`. That slot is the
 * whole reason this is a separate file: everything here lands on a route
 * carrying `body.woocommerce-page`, where Woo's own stylesheet out-specifies
 * any single class of ours — so several rules below are deliberately written
 * with two classes and must stay that way. `.claude/rules/css.md` § *Five
 * things the cascade will do to you* has the measurements.
 *
 * Component reference: the jensik-ui skill, `components-cart.md`.
 */

/* =======================================================================
 * 1. DRAWER, INLINE-END VARIANT — .nk-drawer--end
 * ===================================================================== */

/**
 * The cart drawer sits at the inline-end edge and hides off *that same* edge.
 *
 * The base `.nk-drawer` is pinned to inline-start for the navigation menu,
 * whose burger is at that edge; the cart button is at the other one. In this
 * RTL document inline-end is the **physical left**, so the panel rests against
 * the left edge and must slide out to the left — «از سمت چپ باز شود و به سمت
 * چپ بسته شود».
 *
 * **`transform` is not direction-aware, so this needs a real RTL override.**
 * `translateX` is always physical: +100% is right in both writing directions.
 * The first version used +100% for both and the panel flew in from the *right*
 * edge, across the whole screen, to land on the left — which reads as a
 * different surface arriving rather than the cart opening. `layout.css` already
 * learned this for the base drawer (`[dir="rtl"] .nk-drawer`); this is its
 * mirror image.
 *
 * Two classes so it beats `[dir="rtl"] .nk-drawer` (0,1,1) on specificity
 * rather than on the load order of two stylesheets.
 */
.nk-drawer--end {
  inset-inline-start: auto;
  inset-inline-end: 0;
  /* LTR: inline-end is the right edge — hide to the right. */
  transform: translateX(100%);
}
/* RTL: inline-end is the left edge — hide to the left. */
[dir="rtl"] .nk-drawer.nk-drawer--end { transform: translateX(-100%); }

.nk-drawer--end[data-open="true"],
[dir="rtl"] .nk-drawer.nk-drawer--end[data-open="true"] { transform: translateX(0); }

/* =======================================================================
 * 2. MINI-CART — .nk-minicart
 * ===================================================================== */

.nk-minicart__title {
  display: flex;
  align-items: center;
  gap: var(--nk-space-2);
  margin: 0;
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-lg);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

/* The count beside the title, not a second badge — the header already has one. */
.nk-minicart__count {
  min-inline-size: var(--nk-space-5);
  padding-inline: var(--nk-space-1);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-surface-sunken);
  color: var(--nk-text-muted);
  font-family: var(--nk-font-numeric);
  font-size: var(--nk-text-xs);
  font-weight: var(--nk-weight-semibold);
  line-height: var(--nk-space-5);
  text-align: center;
}

/* The body is the base drawer's scrolling area; only the padding differs. */
.nk-minicart .nk-minicart__body { padding: var(--nk-space-3) var(--nk-space-4); }

/**
 * The footer is pinned, and sits above the phone's home indicator.
 *
 * `.nk-drawer` already pads for `--nk-safe-bottom`, but the footer is the
 * element with the visible ground, so the inset has to be inside it or the
 * background stops short of the screen edge.
 */
.nk-minicart__foot {
  padding: var(--nk-space-4);
  padding-block-end: calc(var(--nk-space-4) + var(--nk-safe-bottom));
  border-block-start: var(--nk-border-hairline);
  background-color: var(--nk-surface-raised);
}
.nk-minicart__foot:empty { display: none; }

.nk-minicart__actions {
  display: flex;
  flex-direction: column;
  gap: var(--nk-space-2);
  margin-block-start: var(--nk-space-3);
}

/* =======================================================================
 * 3. CART LINE — .nk-cart-line
 * ===================================================================== */

/**
 * Two classes, not one.
 *
 * `base.css` resets `ul[class], ol[class] { margin: 0; padding: 0 }` at
 * (0,1,1), so a single-class rule on a list is served, parsed and ignored.
 * This has caught three components already. Do not reduce it.
 *
 * `.nk-order-review` joined the list on 2026-08-23. The checkout review's `<ul>`
 * is not inside `.nk-cart-page` — it is in the summary column — so it matched
 * neither selector and was never flexed, which made the
 * `.nk-order-review .nk-cart-lines { gap }` rule below inert from the day it was
 * written. The lines stacked as blocks and touched.
 */
.nk-minicart__body .nk-cart-lines,
.nk-order-review .nk-cart-lines,
.nk-cart-page .nk-cart-lines {
  display: flex;
  flex-direction: column;
  gap: var(--nk-space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nk-cart-line {
  position: relative;
  display: grid;
  grid-template-columns: 64px 1fr auto;
  gap: var(--nk-space-3);
  align-items: start;
  padding-block-end: var(--nk-space-3);
  border-block-end: var(--nk-border-hairline);
}
.nk-cart-line:last-child { border-block-end: none; padding-block-end: 0; }

.nk-cart-line__media {
  inline-size: 64px;
  aspect-ratio: var(--nk-ratio-product);
  overflow: hidden;
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-sunken);
}

/**
 * Two classes, because Woo wins otherwise.
 *
 * `woocommerce-layout.css` ships `.woocommerce-page img { height: auto;
 * max-width: 100% }` at (0,1,1), and `body.woocommerce-page` is on every route
 * this component appears on. A single-class `.nk-cart-line__img` loses to it
 * and the thumbnail renders at its intrinsic size.
 */
.nk-cart-line .nk-cart-line__img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
}

.nk-cart-line__body { min-inline-size: 0; }

.nk-cart-line__title {
  margin: 0;
  font-size: var(--nk-text-base);
  font-weight: var(--nk-weight-medium);
  line-height: var(--nk-leading-snug);
  color: var(--nk-text-strong);
  /* Two lines, then ellipsis: a long Persian product name must not push the
     price and stepper out of the drawer. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.nk-cart-line__title a { color: inherit; text-decoration: none; }

/**
 * Stretched link — the whole line opens the product.
 *
 * The title on its own is a 23px-tall inline box, well under the 44px minimum,
 * and `npm run audit` failed it. Rather than padding a line-clamped box into
 * shape, the link covers the row: the same convention `.nk-product-card` and
 * `.nk-bestseller` already use, and it makes the thumbnail clickable too
 * without a second `<a>` to the same place.
 *
 * The controls have to climb back out of it — see below. Anything pressable
 * added to a cart line in future needs the same escape.
 */
.nk-cart-line__title a::after { content: ""; position: absolute; inset: 0; }

.nk-cart-line__controls,
.nk-cart-line__remove {
  position: relative;
  z-index: var(--nk-z-raised);
}

.nk-cart-line__variation {
  margin: var(--nk-space-1) 0 0;
  font-size: var(--nk-text-xs);
  color: var(--nk-text-muted);
  line-height: var(--nk-leading-snug);
}

.nk-cart-line__controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nk-space-2);
  margin-block-start: var(--nk-space-2);
  flex-wrap: wrap;
}

/*
 * The stepper is compact here — a 32px visible box — but still a 44px target.
 *
 * It was shrunk to 32px outright once and `npm run audit` failed it at every
 * viewport, correctly, so it went back to a full 44px box. The shop owner
 * asked for it smaller again (2026-08-23): three 44px squares next to a price
 * are the loudest thing in a drawer whose job is to show what you bought.
 * Both ends are satisfiable at once — **the ground shrinks, the target does
 * not.** Each button carries the transparent `::before` extender
 * `.nk-product-card__wish` already uses, so the hit area stays 44×44 over a
 * 32px mark.
 *
 * Three consequences, all load-bearing:
 *   - `.nk-qty`'s `overflow: hidden` would clip the extender, so it is lifted
 *     here and the corner rounding moves onto the buttons themselves.
 *   - The extenders reach 6px into the input from either side, so the input
 *     is raised above them — otherwise its edges stop taking clicks.
 *   - `getBoundingClientRect()` cannot see a pseudo-element, so
 *     `tools/audit-responsive.js` checks this button by pattern, not by
 *     measurement: `.nk-cart-line .nk-qty__btn` is in its EXTENDED_HIT_AREA
 *     list. Rename either half and the audit stops checking it, silently.
 */
.nk-cart-line .nk-qty { overflow: visible; }

.nk-cart-line .nk-qty__btn {
  position: relative;
  inline-size: var(--nk-space-8);
  block-size: var(--nk-space-8);
  color: var(--nk-text-muted);
}
.nk-cart-line .nk-qty__btn::before {
  content: "";
  position: absolute;
  inset: 50%;
  inline-size: var(--nk-touch-target);
  block-size: var(--nk-touch-target);
  transform: translate(50%, -50%);
}
[dir="ltr"] .nk-cart-line .nk-qty__btn::before { transform: translate(-50%, -50%); }
.nk-cart-line .nk-qty__btn .nk-icon {
  inline-size: var(--nk-icon-xs);
  block-size: var(--nk-icon-xs);
}
/* The rounding the container can no longer clip for them. */
.nk-cart-line .nk-qty__btn:first-child {
  border-start-start-radius: var(--nk-radius-md);
  border-end-start-radius: var(--nk-radius-md);
}
.nk-cart-line .nk-qty__btn:last-child {
  border-start-end-radius: var(--nk-radius-md);
  border-end-end-radius: var(--nk-radius-md);
}

.nk-cart-line .nk-qty__input {
  position: relative;
  z-index: var(--nk-z-raised);
  inline-size: var(--nk-space-8);
  block-size: var(--nk-space-8);
  font-size: var(--nk-text-sm);
}

.nk-cart-line__remove {
  display: grid;
  place-items: center;
  inline-size: var(--nk-touch-target);
  block-size: var(--nk-touch-target);
  margin-block-start: calc(var(--nk-space-1) * -1);
  border-radius: var(--nk-radius-md);
  color: var(--nk-text-subtle);
  transition: color var(--nk-transition-base), background-color var(--nk-transition-base);
}
@media (hover: hover) {
  .nk-cart-line__remove:hover {
    color: var(--nk-status-danger);
    background-color: var(--nk-status-danger-bg);
  }
}
.nk-cart-line__remove:active {
  color: var(--nk-status-danger);
  background-color: var(--nk-status-danger-bg);
}

/**
 * The row while its request is in flight.
 *
 * Dimmed and inert rather than removed: the line is still there until the
 * server says it is not, and a row that vanishes optimistically has to be put
 * back when the request fails, which reads as a glitch.
 */
.nk-cart-line[data-nk-cart-removing],
.nk-cart-line[data-nk-cart-busy] {
  opacity: 0.5;
  pointer-events: none;
}

/* =======================================================================
 * 4. SUMMARY — .nk-cart-summary
 * ===================================================================== */

.nk-cart-summary {
  display: flex;
  flex-direction: column;
  gap: var(--nk-space-2);
}

.nk-cart-summary__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--nk-space-3);
  font-size: var(--nk-text-base);
  color: var(--nk-text-default);
}

.nk-cart-summary__row--total {
  padding-block-start: var(--nk-space-2);
  border-block-start: var(--nk-border-hairline);
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}
.nk-cart-summary--compact .nk-cart-summary__row--total {
  padding-block-start: 0;
  border-block-start: none;
}

.nk-cart-summary__note {
  margin: 0;
  font-size: var(--nk-text-xs);
  color: var(--nk-text-muted);
  line-height: var(--nk-leading-normal);
}

/* A discount reads as money coming back, so it is the one green figure here. */
.nk-cart-summary__row--discount { color: var(--nk-status-success-text); }

/*
 * A figure never breaks across lines. A discount is «−۱۵۹٬۰۰۰ تومان» and was
 * wrapping after the minus sign, leaving a stray «−» hanging on the row above
 * its own number — which on an RTL line reads as a completely different value.
 */
.nk-cart-summary__value { white-space: nowrap; }

/* The label may wrap; it is the half with words in it. */
.nk-cart-summary__row > span:first-child { min-inline-size: 0; }

/* =======================================================================
 * 5. THE CART PAGE — .nk-cart-page
 * ===================================================================== */

/**
 * Let the cart and checkout use the site's own container width.
 *
 * WooCommerce ships `.woocommerce-cart main .woocommerce { max-width: 1000px }`
 * — (0,2,1), and the same rule for checkout and account. It capped the page at
 * 1000px inside a 1280px `alignwide` wrapper, so the two-column layout was
 * 280px narrower than every other page on the site and looked like a mistake.
 *
 * The `body` element takes this to (0,2,2), which wins on specificity rather
 * than on source order — `wc-blocks-style` loads after our sheets and a tie
 * would go to Woo. `.claude/rules/css.md` has the general rule; this is the
 * cart's instance of it. The width itself then comes from `.nk-cart-page`'s own
 * `--nk-container-max`, so there is still exactly one place it is decided.
 */
body.woocommerce-cart main .woocommerce,
body.woocommerce-checkout main .woocommerce {
  max-inline-size: none;
}

/*
 * Tighter than the rest of the site on purpose.
 *
 * Every other page is browsing, where air is what makes a product photograph
 * read. This one is a task, and the measure of it is how much of the cart and
 * how much of the total fit on one 360px screen at once. The gaps below are
 * `--nk-space-4` where a content page would use `-6`, and grow back at 768px
 * where the room exists. Nothing here is a new value — only a different rung of
 * the same scale.
 */
.nk-cart-page {
  display: grid;
  gap: var(--nk-space-4);
  max-inline-size: var(--nk-container-max);
  margin-inline: auto;
  padding-inline: var(--nk-gutter);
  padding-block: var(--nk-space-4) var(--nk-space-10);
}

/**
 * A grid item's default `min-width: auto` lets a wide child push the track.
 *
 * Without this the cross-sell rail — which is deliberately wider than its
 * container, see below — grew the single mobile column to its own width and
 * dragged the form and the totals card out with it, 23px past the viewport.
 * The symptom was a whole page that scrolled sideways, not a wide rail.
 */
.nk-cart-page > * { min-inline-size: 0; }

.nk-cart-page__heading {
  display: flex;
  align-items: center;
  gap: var(--nk-space-2);
  margin: 0 0 var(--nk-space-3);
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-xl);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}
.nk-cart-page__count {
  font-family: var(--nk-font-numeric);
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-regular);
  color: var(--nk-text-muted);
}

.nk-cart-page__items {
  padding: var(--nk-space-3);
  border-radius: var(--nk-radius-lg);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-xs);
}

/* On the page there is room for the unit price the drawer has to leave out. */
.nk-cart-line__unit {
  margin: var(--nk-space-1) 0 0;
  font-size: var(--nk-text-xs);
  color: var(--nk-text-muted);
}

.nk-cart-page__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nk-space-2);
  align-items: center;
  margin-block-start: var(--nk-space-3);
  padding-block-start: var(--nk-space-3);
  border-block-start: var(--nk-border-hairline);
}

/**
 * The update button exists for exactly one visitor: the one without JavaScript.
 *
 * `cart.js` posts the cart form itself now, so with the script running there is
 * nothing for anyone to press and the button is only clutter — the shop owner
 * asked for it gone. It cannot simply be deleted: it *is* the no-JS path, the
 * element whose `name="update_cart"` makes `WC_Form_Handler::cart_action()`
 * run, and `CART.md`'s no-JS contract is not optional.
 *
 * So `cart.js` puts `nk-cart-live` on the body as it initialises and the button
 * goes away only then. Script blocked, script still loading, script errored:
 * the button is there and the cart works the old way.
 */
.nk-cart-page__update { margin-inline-start: auto; }
body.nk-cart-live .nk-cart-page__update { display: none; }

/**
 * The cart while a change is in flight.
 *
 * Dimmed and inert, never blanked: the figures on screen are still the last
 * true ones, and replacing them with a spinner throws away information the
 * shopper is in the middle of reading. `pointer-events: none` is what stops a
 * second press landing on a control whose answer is already on its way.
 */
.nk-cart-page[data-nk-cart-updating] {
  /* 0.5, the same value `.nk-cart-line[data-nk-cart-busy]` already uses — one
     in-flight look for this surface. There is no opacity token; if a second
     value ever appears here, that is the moment to add one. */
  opacity: 0.5;
  pointer-events: none;
  transition: opacity var(--nk-transition-base);
}

/*
 * A control that has been pressed and is waiting. The cart page's own busy
 * state above covers the page; this is for the button itself, which the
 * shopper's finger is still on.
 */
.nk-coupon__apply[data-nk-busy],
.nk-cart-page a[data-nk-busy] {
  opacity: 0.5;
  pointer-events: none;
}

/**
 * «محصولات منتخب» — the curated row under the cart and inside an empty one.
 *
 * Was `.nk-cart-page__cross-sells`, and both rules below came over unchanged
 * with the rename, because both are fixes rather than styling.
 *
 * `.nk-product-rail` pulls itself out to the screen edges with a negative
 * `margin-inline`, which is right for a full-width homepage section and wrong
 * inside the cart's padded column — it escaped the card and overflowed the
 * page, and dragged the whole page into scrolling sideways with it. The bleed
 * is contained here rather than the rail replaced: it is still the same
 * component and still the same scroll-snap carousel on a phone.
 *
 * `scroll-padding-inline` has to be reset with the padding or the track scrolls
 * itself off its own start edge on load — `.claude/rules/css.md` § Responsive.
 */
.nk-cart-featured {
  max-inline-size: var(--nk-container-max);
  margin-inline: auto;
  padding-inline: var(--nk-gutter);
  /* A section break, not a page break: `--nk-section-gap` is 40px here and put
     the row a screenful below the total it should be sitting under. */
  margin-block-start: var(--nk-space-8);
}

.nk-cart-featured .nk-product-rail {
  scroll-padding-inline: var(--nk-gutter);
}

/* =======================================================================
 * 5b. FOLDS — <details> as a density tool
 * ===================================================================== */

/**
 * Three things on this surface fold: the coupon field, the order review's item
 * list and the returning customer's address form. All three are native
 * `<details>` and none of them has a line of JavaScript.
 *
 * That is the whole reason for the choice. A fold built from a button and a
 * class has to survive `update_order_review` replacing the block it lives in,
 * has to be re-bound after every fragment swap, and stops working entirely with
 * the script blocked — and this is the one surface in the store where "stops
 * working" means "cannot buy". A `<details>` has no state anyone has to keep.
 *
 * `.nk-fold__chevron` is the shared affordance; the rest is per-fold.
 */

/**
 * A closed fold must actually be closed. **All three needed this.**
 *
 * The user agent hides a closed `<details>`'s content by not rendering the
 * slot — but that is only a default, and **any author `display` on the child
 * beats it**. Every one of these three folds has such a child: `.nk-coupon` is
 * a flex row, `.nk-cart-lines` is a flex column, and `.nk-checkout__section`
 * picks one up on the commerce route. The result was a 44px collapsed
 * `<details>` box with 1206px of address form rendering straight out the bottom
 * of it — measured, on the checkout, with the fold shut.
 *
 * Stating it outright is also better than relying on a UA default: it takes the
 * contents out of the tab order, which is the half a shopper cannot see.
 *
 * **The inverse of this does not work, and it was measured too.** Rendering a
 * fold closed and forcing it open with `display` on the child lays the child
 * out at its full height while the `<details>` box itself stays 0px, so the
 * content paints outside its own container (Chrome 149). That is why the order
 * review's list is rendered `open` and closed by `cart.js` on a phone, rather
 * than the other way round.
 */
.nk-coupon-toggle:not([open]) > .nk-coupon,
.nk-order-review__items:not([open]) > .nk-cart-lines,
.nk-checkout__edit:not([open]) > .nk-checkout__section { display: none; }

/* The default disclosure triangle, in every engine. */
.nk-checkout__edit-toggle::-webkit-details-marker,
.nk-coupon-toggle__summary::-webkit-details-marker,
.nk-order-review__toggle::-webkit-details-marker { display: none; }
.nk-checkout__edit-toggle,
.nk-coupon-toggle__summary,
.nk-order-review__toggle { list-style: none; }

.nk-checkout__edit-toggle,
.nk-coupon-toggle__summary,
.nk-order-review__toggle {
  display: flex;
  align-items: center;
  gap: var(--nk-space-2);
  /* A summary is the control, so it carries the touch target itself — there is
     no inner button to give one to. */
  min-block-size: var(--nk-touch-target);
  padding-inline: var(--nk-space-1);
  font-size: var(--nk-text-base);
  font-weight: var(--nk-weight-medium);
  color: var(--nk-text-strong);
  cursor: pointer;
  border-radius: var(--nk-radius-sm);
  transition: color var(--nk-transition-base), background-color var(--nk-transition-base);
}

@media (hover: hover) {
  .nk-checkout__edit-toggle:hover,
  .nk-coupon-toggle__summary:hover,
  .nk-order-review__toggle:hover { color: var(--nk-text-accent); }
}
.nk-checkout__edit-toggle:active,
.nk-coupon-toggle__summary:active,
.nk-order-review__toggle:active { background-color: var(--nk-action-secondary-subtle); }

/* The focus ring is on the summary, which is the focusable element. */
.nk-checkout__edit-toggle:focus-visible,
.nk-coupon-toggle__summary:focus-visible,
.nk-order-review__toggle:focus-visible {
  outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
  outline-offset: var(--nk-focus-ring-offset);
}

/*
 * The chevron points at where the content will appear, and turns when it does.
 *
 * `chevron-down` is not in `icons.json#directional`, and must not be: it points
 * along the block axis, which RTL does not mirror. Rotating it here is a
 * transform on one element, not a direction-aware decision — `.claude/rules/rtl.md`.
 */
.nk-fold__chevron {
  margin-inline-start: auto;
  color: var(--nk-text-muted);
  transition: transform var(--nk-transition-base);
}
[open] > .nk-checkout__edit-toggle .nk-fold__chevron,
[open] > .nk-coupon-toggle__summary .nk-fold__chevron,
[open] > .nk-order-review__toggle .nk-fold__chevron { transform: rotate(180deg); }

/* The coupon fold sits in the actions row and must not stretch it. */
.nk-coupon-toggle { flex: 1 1 100%; }
.nk-coupon-toggle /**
 * The inline answer to a coupon.
 *
 * Woo's own reply, repeated where the field is. The page's notice area is at
 * the top of the document, which on a phone is a scroll away from the box the
 * shopper just typed into — an error nobody scrolls back to see is an error
 * nobody sees.
 *
 * `role="status"` rather than `alert`: it is announced, but it does not
 * interrupt what a screen reader is in the middle of saying.
 */
.nk-coupon__message {
  flex: 1 1 100%;
  margin: var(--nk-space-2) 0 0;
  padding: var(--nk-space-2) var(--nk-space-3);
  border-radius: var(--nk-radius-sm);
  font-size: var(--nk-text-sm);
  line-height: var(--nk-leading-snug);
}
.nk-coupon__message[hidden] { display: none; }
.nk-coupon__message--error {
  background-color: var(--nk-status-danger-bg);
  color: var(--nk-status-danger-text);
}
.nk-coupon__message--success {
  background-color: var(--nk-status-success-bg);
  color: var(--nk-status-success-text);
}

.nk-coupon { margin-block-start: var(--nk-space-2); }

/* =======================================================================
 * 5c. STICKY ACTION BAR — .nk-sticky-cta--summary
 * ===================================================================== */

/**
 * The cart's and the checkout's mobile bar.
 *
 * **This is the `.nk-sticky-cta` primitive from `commerce.css`, not a new
 * component.** Everything structural is already handled there and in `ui.js` —
 * the safe-area inset, sitting above the bottom nav, leaving the tab order
 * while parked, publishing `--nk-sticky-cta-space` so the back-to-top button
 * and the contact FAB step aside. Only the typography of the label and the
 * figure is new, and only because a total is not a price.
 *
 * It is deliberately two things and no more: what you will pay, and the one
 * button. A bar that also carried an item count, a thumbnail or a coupon link
 * would be a second summary card pinned over the page it is summarising.
 */
.nk-sticky-cta--summary { gap: var(--nk-space-3); }

.nk-sticky-summary {
  display: grid;
  gap: 0;
  min-inline-size: 0;
  /* The figure takes what it needs and the button takes the rest — a total in
     Persian digits with «تومان» after it is the wider of the two at 360px. */
  flex: 0 1 auto;
}

.nk-sticky-summary__label {
  font-size: var(--nk-text-2xs);
  color: var(--nk-text-muted);
  line-height: var(--nk-leading-tight);
}

.nk-sticky-summary__total {
  font-family: var(--nk-font-numeric);
  font-size: var(--nk-text-base);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
  line-height: var(--nk-leading-tight);
  white-space: nowrap;
}

.nk-sticky-cta--summary .nk-sticky-cta__btn { flex: 1 1 auto; }

/*
 * Woo's own price markup inside the bar, matched to the rest of the surface —
 * `wc_price()` emits its currency symbol hard against the digits and an RTL
 * line collapses the `&nbsp;` it uses to nothing visible.
 */
.nk-sticky-summary .woocommerce-Price-currencySymbol {
  margin-inline-start: var(--nk-space-1);
  font-size: var(--nk-text-2xs);
  font-weight: var(--nk-weight-regular);
  color: var(--nk-text-muted);
}

/* =======================================================================
 * 6. COUPON — .nk-coupon
 * ===================================================================== */

.nk-coupon {
  display: flex;
  /*
   * Wrapping is what keeps the field a field. The message below is a *third*
   * flex item in this row, and without a wrap it competed with the input and
   * the button for the same line — at 360px the input collapsed to about 40px
   * of unusable sliver while the message took half the row. It is given a full
   * basis below so it always lands on its own line.
   */
  flex-wrap: wrap;
  gap: var(--nk-space-2);
  flex: 1 1 min(100%, 20rem);
}
/*
 * `.nk-input` is the field, and it was missing.
 *
 * Both coupon inputs carried `.nk-field` — which is `display: block` and
 * nothing else — plus `.nk-coupon__input`, which is only flex sizing. Neither
 * paints a border, a radius, a height or a font size, so the control fell back
 * to the browser default on the cart and to Woo's 13px `.input-text` on the
 * checkout. That is why it read as unfinished next to every other field on the
 * page: it was the one input in the store with no field styling on it at all.
 *
 * `body` prefixes because `body.woocommerce-page` is on both routes and Woo's
 * `.woocommerce-page .input-text` is (0,2,0).
 */
body .nk-coupon .nk-coupon__input { flex: 1; min-inline-size: 0; }
.nk-coupon__apply { flex: 0 0 auto; }

/* The × beside an applied coupon's label in the summary. */
.nk-coupon__remove {
  display: inline-grid;
  place-items: center;
  inline-size: var(--nk-space-5);
  block-size: var(--nk-space-5);
  margin-inline-start: var(--nk-space-1);
  border-radius: var(--nk-radius-circle);
  color: var(--nk-text-subtle);
  vertical-align: middle;
}
@media (hover: hover) {
  .nk-coupon__remove:hover { color: var(--nk-status-danger); background-color: var(--nk-status-danger-bg); }
}
.nk-coupon__remove:active { color: var(--nk-status-danger); background-color: var(--nk-status-danger-bg); }

/* =======================================================================
 * 7. SUMMARY CARD — .nk-cart-summary-card
 * ===================================================================== */

/**
 * Undo WooCommerce's classic two-up collaterals.
 *
 * `woocommerce-layout.css` ships
 * `.woocommerce-page .cart-collaterals .cart_totals { float: right; width: 48% }`
 * — (0,3,0) — and the matching `.cross-sells { width: 48%; float: left }`.
 * That is the 2011 cart layout: totals and cross-sells side by side across the
 * full page width. Ours stacks them in a 352px sidebar, where 48% made the
 * totals card 169px wide and wrapped «ادامه جهت تسویه حساب» one word per line.
 *
 * `body` takes these to (0,3,1) and wins on specificity, not source order —
 * `woocommerce-layout.css` is not the sheet our own load order beats.
 */
body.woocommerce-cart .nk-cart-page__aside .cart_totals,
body.woocommerce-cart .nk-cart-page__aside .cross-sells,
body.woocommerce-cart .nk-cart-page__aside .nk-cart-featured {
  float: none;
  inline-size: 100%;
  width: 100%;
}

.nk-cart-summary-card {
  padding: var(--nk-space-5);
  border-radius: var(--nk-radius-lg);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-sm);
}

.nk-cart-summary-card__title {
  margin: 0 0 var(--nk-space-4);
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-lg);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

.nk-cart-summary-card__actions { margin-block-start: var(--nk-space-4); }

/**
 * Woo prints the checkout button through `woocommerce_proceed_to_checkout`
 * with its own `.checkout-button.button.alt` classes, and there is no template
 * for it — only that action. Restyling it here is cheaper and more robust than
 * unhooking and reprinting, which would drop any plugin that hooks alongside.
 * Two classes, because `body.woocommerce-page` is on this route.
 */
/*
 * **Three selectors, and every one of them is needed.** Measured, not guessed.
 *
 * This rule was `.nk-cart-summary-card .checkout-button` — (0,2,0) — and lost
 * two declarations it never mentioned:
 *
 *   `.woocommerce-cart .wc-proceed-to-checkout a.checkout-button`  (0,2,1)
 *       → `font-size: 1.25em` and `padding: 1em`
 *   `:root :where(.wp-element-button, …)`  — Twenty Twenty-Five
 *       → `line-height: inherit`
 *
 * The result was a 75px-tall CTA in 20px type, half again the size of every
 * other primary button in the store, on the one page where the button is
 * supposed to look like the rest of the site. `body` takes this to (0,3,1) and
 * wins on specificity rather than on the load order of two stylesheets, which
 * is the rule for this whole file.
 *
 * `padding-block` and `line-height` are stated outright for the same reason:
 * a value this rule does not set is a value one of those two sets for it.
 */
body.woocommerce-cart .nk-cart-summary-card .checkout-button {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 100%;
  min-block-size: var(--nk-touch-target-lg);
  padding-block: var(--nk-space-3);
  padding-inline: var(--nk-space-5);
  border: none;
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-action-primary);
  color: var(--nk-text-on-accent);
  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;
  transition: background-color var(--nk-transition-base);
}
@media (hover: hover) {
  body.woocommerce-cart .nk-cart-summary-card .checkout-button:hover {
    background-color: var(--nk-action-primary-hover);
    color: var(--nk-text-on-accent);
  }
}
body.woocommerce-cart .nk-cart-summary-card .checkout-button:active {
  background-color: var(--nk-action-primary-active);
  color: var(--nk-text-on-accent);
}

/* =======================================================================
 * 8. CHECKOUT — .nk-checkout
 * ===================================================================== */

.nk-checkout {
  display: grid;
  gap: var(--nk-space-4);
  max-inline-size: var(--nk-container-max);
  margin-inline: auto;
  padding-inline: var(--nk-gutter);
  padding-block: var(--nk-space-4) var(--nk-space-10);
  /*
   * Traps WooCommerce's blockUI overlay inside this form.
   *
   * blockUI paints a `z-index: 1000` element over whatever it blocks, which is
   * four rungs above the whole token ladder — it would sit over the header, the
   * drawer, a modal and every toast. It also cannot be restyled: position,
   * size, background and opacity are all written **inline**, and beating an
   * inline style needs `!important`.
   *
   * `isolation: isolate` makes this form a stacking context, so that 1000 is
   * resolved *within* it and can no longer compete with anything outside — the
   * header, the drawer and every toast keep their rung. Woo keeps blocking and
   * unblocking exactly as it always did. One declaration instead of an override
   * war.
   */
  isolation: isolate;
}

.nk-checkout__section {
  padding: var(--nk-space-4);
  border-radius: var(--nk-radius-lg);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-xs);
}

.nk-checkout__summary-inner {
  padding: var(--nk-space-4);
  border-radius: var(--nk-radius-lg);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-sm);
}

.nk-checkout__summary-title {
  margin: 0 0 var(--nk-space-3);
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-lg);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

/**
 * The review's item list folds on a phone and is forced open from 1024px.
 *
 * `open` is an attribute and no stylesheet can clear one, so the template
 * renders it closed and this opens it — `details:not([open]) > *` overriding the
 * user agent's hiding of the closed slot. It reads like a hack and is ordinary
 * cascade; it was checked in a browser rather than assumed.
 *
 * Only the *list* folds. The totals, the shipping choice, the payment box and
 * «ثبت سفارش» are siblings of this `<details>`, never inside it: folding those
 * would hide the interactions the page exists for.
 */
.nk-order-review__items { margin-block-end: var(--nk-space-2); }

.nk-order-review__toggle {
  padding-block: var(--nk-space-1);
  font-size: var(--nk-text-sm);
  color: var(--nk-text-muted);
}

/* The review's lines are tighter than the cart page's — this is a summary. */
.nk-order-review .nk-cart-lines { gap: var(--nk-space-2); }
.nk-cart-line--review { grid-template-columns: 48px 1fr; padding-block-end: var(--nk-space-2); }
.nk-cart-line--review .nk-cart-line__media { inline-size: 48px; }
.nk-cart-line--review .nk-cart-line__title { font-size: var(--nk-text-sm); }
.nk-cart-line__total {
  font-family: var(--nk-font-numeric);
  font-size: var(--nk-text-sm);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
  white-space: nowrap;
}
.nk-cart-line__qty {
  font-family: var(--nk-font-numeric);
  font-size: var(--nk-text-sm);
  color: var(--nk-text-muted);
}

.nk-order-review .nk-cart-summary {
  margin-block-start: var(--nk-space-4);
  padding-block-start: var(--nk-space-3);
  border-block-start: var(--nk-border-hairline);
}

/* -----------------------------------------------------------------
 * Woo's own checkout markup.
 *
 * Everything below styles HTML WooCommerce prints itself — the billing
 * fields, the payment box, the place-order button. There is no template
 * worth overriding for most of it: forking `form-billing.php` would mean
 * owning every field type Woo and its plugins can emit, and an Iranian
 * shipping or gateway plugin adding a field would land unstyled. Mapping the
 * classes is the smaller, more durable surface.
 *
 * Nearly every rule here needs two selectors' worth of specificity, because
 * `body.woocommerce-page` is on this route and Woo's own sheet is (0,1,1).
 * -------------------------------------------------------------- */

/* Woo's field rows. `.form-row` is its wrapper for every input it renders. */
.nk-checkout .form-row {
  display: flex;
  flex-direction: column;
  gap: var(--nk-space-1);
  margin: 0 0 var(--nk-space-3);
  padding: 0;
}

/*
 * Woo's own two-up pairs, side by side once there is room for them.
 *
 * `.form-row-first` / `.form-row-last` is what `WC_Checkout` puts on a field
 * declared with `class => array( 'form-row-first' )` — first and last name are
 * the pair every locale has, and an Iranian address plugin adding «استان» and
 * «شهر» gets the same treatment with no change here. Woo's own stylesheet
 * floats them at 47%, which is the 2011 layout and collapses badly in RTL; this
 * is a two-column grid on the *container*, so `float` never enters into it.
 *
 * 480px, not 768: two short fields fit side by side on a large phone, and the
 * pair is what makes the top of this form one screen instead of two.
 */
@media (min-width: 480px) {
  .nk-checkout .woocommerce-billing-fields__field-wrapper,
  .nk-checkout .woocommerce-shipping-fields__field-wrapper,
  .nk-checkout .woocommerce-additional-fields__field-wrapper {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: var(--nk-space-3);
  }

  /* Everything spans both columns unless it is half of a declared pair —
     an address line or a note beside a postcode reads as a mistake. */
  .nk-checkout .form-row { grid-column: 1 / -1; }
  .nk-checkout .form-row.form-row-first { grid-column: 1; }
  .nk-checkout .form-row.form-row-last { grid-column: 2; }

  /*
   * Woo also ships `float` and a percentage width on these two at (0,1,1), and
   * `body.woocommerce-page` is on this route. A floated grid item is not a
   * float, but the width is real and would leave a 6% gutter inside a grid
   * track that already has one.
   */
  body.woocommerce-checkout .nk-checkout .form-row-first,
  body.woocommerce-checkout .nk-checkout .form-row-last {
    float: none;
    inline-size: auto;
  }
}

/*
 * `woocommerce-general` ships `.woocommerce-page label { margin-bottom: .7em }`
 * — (0,1,1) — which put dead space under every label. The element name brings
 * this to (0,2,1) and wins outright. Same trap `.nk-check` hit in the filter
 * sheet; `.claude/rules/css.md` has the measurement.
 */
.nk-checkout .form-row label {
  margin: 0;
  /* `.nk-label`'s size and weight, so a Woo label and an `nk_label()` one are
     the same label. */
  font-size: var(--nk-text-base);
  font-weight: var(--nk-weight-medium);
  color: var(--nk-text-strong);
}
/*
 * Woo marks a required field with `<abbr class="required" title="required">*`,
 * and a browser's default `abbr[title]` styling gives it a dotted underline and
 * a help cursor — a footnote marker on every second label.
 */
.nk-checkout .form-row .required {
  color: var(--nk-status-danger);
  text-decoration: none;
  border-block-end: none;
  cursor: inherit;
}
/* Woo's «(اختیاری)» suffix should read as the aside it is. */
.nk-checkout .form-row .optional {
  color: var(--nk-text-muted);
  font-weight: var(--nk-weight-regular);
}

/**
 * The controls themselves — the same box as `.nk-input` in `elements.css`.
 *
 * Every value here is copied from that component rather than chosen again:
 * the 48px floor, `--nk-space-4` / `-3` padding, the radius, the border, the
 * snug line height and the transition. Woo renders the markup, so the classes
 * cannot be shared; the geometry can be, and must be, or the checkout drifts
 * into being a second form language.
 *
 * **It takes four classes to say any of it.** Measured on the live checkout:
 * `.woocommerce-page form .form-row input.input-text` is (0,3,2) and sets
 * `font-size: small` and `padding: .9rem 1.1rem`; `.woocommerce form .form-row
 * .input-text` is (0,3,1) and sets `padding: .5em`, `background: #fff` and its
 * own radius. A (0,2,0) rule of ours lost every one of those — the fields were
 * rendering at **13px in a 4px-radius white box** while this block said 16px,
 * cream and `--nk-radius-md`, and looked untouched because it was. The
 * `body … form.nk-checkout .form-row …` form is (0,4,2) and wins outright. The
 * short selectors are kept alongside for anything Woo renders outside a
 * `.form-row`.
 *
 * **One deliberate difference: the ground is `--nk-surface-page`, not
 * `--nk-surface-raised`.** `.nk-input` is white because it normally sits on the
 * cream page. Here it sits inside a white `.nk-checkout__section` card, and
 * white-on-white leaves a 1px border doing all the work of saying "this is a
 * field". The cream ground is the same token the page already uses, one step
 * down instead of one step up.
 */
body.woocommerce-page form.nk-checkout .form-row .input-text,
body.woocommerce-page form.nk-checkout .form-row select,
body.woocommerce-page form.nk-checkout .form-row textarea,
.nk-checkout .input-text,
.nk-checkout select,
.nk-checkout textarea {
  inline-size: 100%;
  /*
   * 48px, not the 44px minimum. This is the one form in the store a shopper is
   * asked to fill in end to end, on a phone, and `--nk-touch-target-lg` is the
   * token for exactly that case — `layout.md` calls it the preferred size for
   * primary actions, and eight address fields in a row are one.
   */
  min-block-size: var(--nk-touch-target-lg);
  padding-inline: var(--nk-space-4);
  padding-block: var(--nk-space-3);
  border: var(--nk-border-width) solid var(--nk-border-default);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-page);
  color: var(--nk-text-strong);
  font-family: var(--nk-font-ui);
  /* 16px or iOS zooms the page on focus mid-checkout — typography.md. */
  font-size: var(--nk-text-md);
  line-height: var(--nk-leading-snug);
  text-align: start;
  transition: border-color var(--nk-transition-base), box-shadow var(--nk-transition-base);
}

/* Woo's placeholders are full sentences; they must not read as filled-in text. */
.nk-checkout .input-text::placeholder,
.nk-checkout textarea::placeholder { color: var(--nk-text-subtle); }

/*
 * The `<select>` keeps its native arrow.
 *
 * `.nk-select` sets `appearance: none` and gets its chevron from a wrapping
 * `.nk-select-wrap` that holds a real `nk_icon()`. Woo emits a bare `<select>`
 * with no wrapper, and the only ways to draw a chevron onto it are a
 * `background-image` data URI or a second mask asset — the first is an inline
 * SVG, which the icon rule forbids, and the second is a build artifact for one
 * control. The native arrow is already direction-aware and already matches the
 * shopper's OS, so it stays and only the box is ours.
 */
/* Three lines, not two: Woo's own «یادداشت‌ها درباره سفارش شما…» placeholder
   is three lines at 360px and was clipped by its own box. */
.nk-checkout textarea { min-block-size: calc(var(--nk-touch-target) * 2.5); resize: vertical; }

@media (hover: hover) {
  body.woocommerce-page form.nk-checkout .form-row .input-text:hover,
  body.woocommerce-page form.nk-checkout .form-row select:hover,
  body.woocommerce-page form.nk-checkout .form-row textarea:hover,
  .nk-checkout .input-text:hover,
  .nk-checkout select:hover,
  .nk-checkout textarea:hover { border-color: var(--nk-border-strong); }
}
/*
 * `outline-offset: 0`, matching `.nk-input`. The ring itself comes from
 * `base.css`'s global `:focus-visible`; offsetting it by 2px on a field this
 * size makes two concentric rounded rectangles a pixel apart.
 */
.nk-checkout .input-text:focus-visible,
.nk-checkout select:focus-visible,
.nk-checkout textarea:focus-visible {
  border-color: var(--nk-border-accent);
  outline-offset: 0;
}
.nk-checkout .input-text:disabled,
.nk-checkout select:disabled,
.nk-checkout textarea:disabled {
  background-color: var(--nk-navy-50);
  color: var(--nk-action-disabled-text);
  cursor: not-allowed;
}


/* The coupon fold in the checkout's summary, under the totals. */
.nk-checkout__coupon {
  margin-block-start: var(--nk-space-3);
  padding-block-start: var(--nk-space-2);
  border-block-start: var(--nk-border-hairline);
}

.nk-checkout .woocommerce-invalid .input-text,
.nk-checkout .woocommerce-invalid select,
.nk-checkout .woocommerce-invalid textarea { border-color: var(--nk-status-danger); }

/*
 * Woo marks a *valid* field too, and green borders down a filled-in form are
 * noise: nothing is wrong, so nothing should be shouting. The state is kept for
 * assistive technology — Woo sets `aria-invalid` — and taken off the paint.
 */
.nk-checkout .woocommerce-validated .input-text,
.nk-checkout .woocommerce-validated select { border-color: var(--nk-border-default); }

/* -----------------------------------------------------------------
 * The returning customer's saved address — .nk-checkout__saved
 *
 * A card showing what WooCommerce already has, with the real form folded
 * behind it. `form-checkout.php` carries the rule that matters: the fields are
 * *collapsed*, never conditionally rendered, so everything Woo validates and
 * saves is still in the submission.
 * -------------------------------------------------------------- */

.nk-checkout__saved {
  padding: var(--nk-space-3) var(--nk-space-4);
  border: var(--nk-border-hairline);
  border-radius: var(--nk-radius-md);
  /* The accent wash, not the raised surface: this is a confirmation, and it has
     to read as different from the form card below it without a second shadow. */
  background-color: var(--nk-surface-accent);
}

.nk-checkout__saved-head {
  display: flex;
  align-items: center;
  gap: var(--nk-space-2);
  margin-block-end: var(--nk-space-2);
  color: var(--nk-text-accent);
}

/*
 * **Beaten by one class, and it showed.** `.nk-checkout__fields h3` is (0,1,1)
 * and styles Woo's own section headings — «جزئیات صورتحساب» — at
 * `--nk-text-xl` in the display face. This is an `h3` inside that column, so a
 * (0,1,0) rule never reached it: the label rendered at 20px display beside a
 * 16px icon that was sized for a 14px label, and the row read as an icon that
 * had been left behind by its own heading. It is a card's label, not a section
 * heading, so the fix is the specificity rather than a bigger glyph.
 */
.nk-checkout__saved .nk-checkout__saved-title {
  margin: 0;
  font-family: var(--nk-font-ui);
  font-size: var(--nk-text-sm);
  font-weight: var(--nk-weight-semibold);
  line-height: var(--nk-leading-snug);
  color: var(--nk-text-accent);
}

/* Pinned to the label's own size, and never shrunk by the flex row. */
.nk-checkout__saved-head .nk-icon {
  flex: none;
  inline-size: var(--nk-icon-sm);
  block-size: var(--nk-icon-sm);
}

.nk-checkout__saved-name {
  margin: 0 0 var(--nk-space-1);
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

.nk-checkout__saved-line {
  margin: 0;
  font-size: var(--nk-text-sm);
  line-height: var(--nk-leading-normal);
  color: var(--nk-text-default);
}

/*
 * The fold is flush with the card above it — they are one control between them,
 * and a gap would read as two unrelated blocks.
 */
.nk-checkout__edit { margin-block-start: var(--nk-space-1); }
.nk-checkout__edit .nk-checkout__section { margin-block-start: var(--nk-space-2); }

/* Woo's section headings — «جزئیات صورتحساب», «توضیحات تکمیلی». */
.nk-checkout__fields h3 {
  margin: 0 0 var(--nk-space-3);
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-xl);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}
.nk-checkout__fields .woocommerce-additional-fields { margin-block-start: var(--nk-space-6); }

/* -----------------------------------------------------------------
 * The payment step — `#payment`, printed by woocommerce_checkout_payment()
 *
 * **Every selector here carries `#payment`, and it has to.** Woo's own skin for
 * this block is written with the id in the selector — `#payment` is a `#ebe9eb`
 * card, `#payment div.payment_box` a `#dfdcde` panel with a CSS-triangle beak
 * pointing at the method above it — which is (1,1,1). A single class of ours
 * loses to that, silently: the first pass here set a `--nk-surface-sunken`
 * background on `.payment_box` and the lavender stayed on the page.
 *
 * What replaces it is the same idea as the shipping choice: one selectable card
 * per method, the description folded into the chosen card rather than floating
 * under the list in a second colour.
 * -------------------------------------------------------------- */

.nk-checkout #payment {
  margin-block-start: var(--nk-space-5);
  padding: 0;
  border: none;
  border-radius: 0;
  background: none;
}

/*
 * Two classes and the element name: this is a `ul[class]`, so `base.css`'s
 * (0,1,1) reset beats a single class on anything touching margin or padding.
 */
.nk-checkout #payment ul.payment_methods {
  display: flex;
  flex-direction: column;
  gap: var(--nk-space-2);
  margin: 0 0 var(--nk-space-4);
  padding: 0;
  list-style: none;
  border: none;
}

.nk-checkout #payment ul.payment_methods > li {
  padding: 0;
  border: var(--nk-border-width) solid var(--nk-border-default);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
  overflow: hidden;
  transition: border-color var(--nk-transition-base), background-color var(--nk-transition-base);
}

/*
 * The whole card is the label, so the touch target is the card and not the
 * eight characters of its title. `:has()` rather than a class, because nothing
 * server-side marks the chosen method: Woo sets `checked` on the input and
 * moves on.
 */
.nk-checkout #payment ul.payment_methods > li:has(input[name="payment_method"]:checked) {
  border-color: var(--nk-action-primary);
  background-color: var(--nk-action-primary-subtle);
}

.nk-checkout #payment ul.payment_methods label {
  display: flex;
  align-items: center;
  gap: var(--nk-space-2);
  min-block-size: var(--nk-touch-target);
  margin: 0;
  padding: var(--nk-space-3) var(--nk-space-4);
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
  cursor: pointer;
}

/*
 * Woo's own radio, wearing the store's coral. It is a real `<input>` and stays
 * one — a hand-built control here would have to be kept in step with
 * `checkout.js`, which reads `:checked` on it from four places.
 *
 * **With one gateway configured Woo prints it `style="display: none"`** and the
 * card is then a statement rather than a choice, which is correct: there is
 * nothing to pick. `accent-color` is all the styling a radio needs and is the
 * one property that does not fight the native control.
 */
.nk-checkout #payment ul.payment_methods input[name="payment_method"] {
  inline-size: var(--nk-icon-md);
  block-size: var(--nk-icon-md);
  margin: 0;
  accent-color: var(--nk-action-primary);
  cursor: pointer;
}

.nk-checkout #payment ul.payment_methods label img {
  max-block-size: var(--nk-icon-lg);
  inline-size: auto;
  margin-inline-start: auto;
}

/*
 * The description, inside the card it belongs to.
 *
 * Woo's version is a separate grey panel with a beak — a tooltip look, in a
 * palette from nowhere on this page. Here it is the same card, separated by the
 * hairline it shares with the list, so a method and what it means read as one
 * thing. `content: none` on the beak, not `display: none`: it is drawn with
 * borders on a `::before` that Woo positions absolutely.
 */
.nk-checkout #payment div.payment_box {
  margin: 0;
  padding: var(--nk-space-3) var(--nk-space-4);
  border-block-start: var(--nk-border-width) solid var(--nk-border-subtle);
  border-radius: 0;
  background-color: transparent;
  font-size: var(--nk-text-sm);
  line-height: var(--nk-leading-normal);
  color: var(--nk-text-muted);
}
.nk-checkout #payment div.payment_box::before { content: none; }
.nk-checkout #payment div.payment_box p { margin-block: 0; }
.nk-checkout #payment div.payment_box p + p { margin-block-start: var(--nk-space-2); }

/*
 * One spinner for one wait.
 *
 * blockUI paints an overlay **per element**, and the pair Woo blocks —
 * `.woocommerce-checkout-review-order-table` and `.woocommerce-checkout-payment`
 * — are two boxes stacked directly on top of each other. So a single quantity
 * change dimmed two adjacent rectangles and spun two loaders in them: measured
 * at 1280px, a 344×164 overlay immediately above a 344×413 one.
 *
 * The overlays themselves stay. Each is cleared by the code that raised it, and
 * Woo unblocks **by fragment key**, so blocking one wrapper instead would leave
 * an overlay nothing ever removes (`cart.js` says the same, from the other
 * side). Only the *glyph* goes, and only on the table: Woo clears that overlay
 * as soon as the review fragment lands and holds the payment box until the
 * whole update finishes, so the spinner left on screen is the one that spans
 * the entire wait rather than the first half of it.
 */
.nk-checkout .woocommerce-checkout-review-order-table > .blockUI.blockOverlay::before {
  content: none;
}

/*
 * The submit spinner follows the viewport, not the form.
 *
 * Placing the order blocks `form.checkout` itself, and blockUI's glyph is
 * `position: absolute; top: 50%` **of the blocked element**. The checkout form
 * at 360px is around 2400px tall, so the middle of it is roughly a screen and a
 * half below where the shopper just pressed «ثبت سفارش»: the page dimmed, and
 * the only sign that anything was happening was off screen unless they scrolled
 * to find it. Reported twice.
 *
 * Only the glyph moves. The overlay stays exactly as it is — `position`,
 * `size`, `background` and `opacity` are all inline styles of Woo's and each is
 * cleared by the code that raised it (see the note above), so it is still one
 * dim over the form and still not something to restyle.
 *
 * The direct-child selector is what keeps this to the form's own overlay: the
 * review table and the payment box raise their own during
 * `update_order_review`, and those are children of *those* boxes, small enough
 * to centre themselves honestly.
 *
 * Centred with `inset-inline: 0` + `margin-inline: auto` rather than a 50%
 * offset and a translate, because the offset would have to flip with the
 * writing direction and this does not.
 *
 * The ring is `.nk-spinner`'s, drawn here rather than reused as a class because
 * the element is a pseudo of Woo's markup and there is nothing to put a class
 * on.
 */
.nk-checkout > .blockUI.blockOverlay::before {
  position: fixed;
  inset-block-start: 50%;
  inset-inline: 0;
  margin: 0 auto;
  /* `--nk-icon-xl`, where the in-page spinners use `lg`: this one is alone in
     the middle of a dimmed screen with no label beside it, and at 24px it read
     as a stray ring between two form fields. */
  inline-size: var(--nk-icon-xl);
  block-size: var(--nk-icon-xl);
  translate: 0 -50%;
  border: 3px solid var(--nk-navy-200);
  border-block-start-color: var(--nk-action-primary);
  border-radius: var(--nk-radius-circle);
  background: none;
  animation: nk-spin 700ms linear infinite;
}

/*
 * The same treatment for the *update* wait, and only on a phone.
 *
 * A quantity change blocks the payment box and the review table (`cart.js`
 * blocks exactly what `checkout.js` does), and the rule above leaves the
 * payment box's glyph as the single spinner. Stacked at 360px that box is most
 * of a screen tall and sits near the bottom of the page, so its own middle is
 * routinely off screen: the totals greyed out and nothing appeared to be
 * happening. Same fix, same reason as the submit spinner.
 *
 * **Phone only.** From 1024px the summary is a narrow sticky column beside the
 * fields, and a spinner floated into the middle of the viewport would be
 * spinning over the address form — a long way from the box that is actually
 * loading. There it stays where the wait is.
 */
@media (max-width: 1023px) {
  .nk-checkout .woocommerce-checkout-payment > .blockUI.blockOverlay::before {
    position: fixed;
    inset-block-start: 50%;
    inset-inline: 0;
    margin: 0 auto;
    inline-size: var(--nk-icon-xl);
    block-size: var(--nk-icon-xl);
    translate: 0 -50%;
    border: 3px solid var(--nk-navy-200);
    border-block-start-color: var(--nk-action-primary);
    border-radius: var(--nk-radius-circle);
    background: none;
    animation: nk-spin 700ms linear infinite;
  }
}

/* The same slow-down the other in-place spinners honour: a still ring reads as
   broken, so the motion is reduced rather than removed. */
@media (prefers-reduced-motion: reduce) {
  .nk-checkout > .blockUI.blockOverlay::before,
  .nk-checkout .woocommerce-checkout-payment > .blockUI.blockOverlay::before {
    animation-duration: 2s;
  }
}

.nk-checkout .woocommerce-privacy-policy-text {
  font-size: var(--nk-text-xs);
  color: var(--nk-text-muted);
  line-height: var(--nk-leading-normal);
}

.nk-checkout .place-order { margin-block-start: var(--nk-space-4); }

/*
 * Woo prints the place-order button from `checkout/payment.php` with its own
 * `.button.alt` classes and no template hook of ours in between, so it is
 * mapped rather than replaced — the same bargain as the cart's checkout button.
 */
.nk-checkout #place_order {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 100%;
  min-block-size: var(--nk-touch-target-lg);
  padding-inline: var(--nk-space-5);
  border: none;
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-action-primary);
  color: var(--nk-text-on-accent);
  font-family: var(--nk-font-ui);
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-semibold);
  cursor: pointer;
  transition: background-color var(--nk-transition-base);
}
@media (hover: hover) {
  .nk-checkout #place_order:hover { background-color: var(--nk-action-primary-hover); }
}
.nk-checkout #place_order:active { background-color: var(--nk-action-primary-active); }
.nk-checkout #place_order:disabled { background-color: var(--nk-action-disabled-bg); color: var(--nk-action-disabled-text); cursor: not-allowed; }

/* The «کد تخفیف دارید؟» strip Woo prints above the form. */
/**
 * The «کد تخفیف دارید؟» strip Woo prints above the checkout form.
 *
 * Woo's `.woocommerce-info` is an *alert*: a 3px accent bar along one edge and
 * a glyph in a filled circle, both from `woocommerce-general.css` and neither
 * declared here, so both survived a rule that only set the background. On this
 * page it announced a coupon field as though something had gone wrong, in the
 * one blue on an otherwise coral-and-cream page, directly above the address
 * form. It is an offer, so it is styled as one — the same quiet row as the cart
 * page's own coupon fold.
 *
 * The `::before` needs `content: none`, not `display: none`: Woo sets the glyph
 * with a font shorthand that a display change does not reach, and the character
 * still reserved its line box.
 */
.woocommerce-form-coupon-toggle .woocommerce-info,
.nk-checkout-notice {
  display: flex;
  align-items: center;
  gap: var(--nk-space-2);
  margin: 0 0 var(--nk-space-3);
  padding: var(--nk-space-3);
  border: var(--nk-border-hairline);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
  font-size: var(--nk-text-sm);
  color: var(--nk-text-default);
}
.woocommerce-form-coupon-toggle .woocommerce-info::before { content: none; }

/* The «اینجا کلیک کنید» link — a text action, not a visited hyperlink. */
.woocommerce-form-coupon-toggle .woocommerce-info a {
  color: var(--nk-text-accent);
  font-weight: var(--nk-weight-medium);
  text-decoration: none;
}
@media (hover: hover) {
  .woocommerce-form-coupon-toggle .woocommerce-info a:hover { text-decoration: underline; }
}

.checkout_coupon.woocommerce-form-coupon {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nk-space-2);
  margin: 0 0 var(--nk-space-5);
  padding: var(--nk-space-4);
  border-radius: var(--nk-radius-lg);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-xs);
}
.checkout_coupon.woocommerce-form-coupon .form-row { flex: 1 1 12rem; margin: 0; }

/* -----------------------------------------------------------------
 * Woo's price markup, matched to `.nk-price`.
 *
 * `wc_price()` emits `<span class="woocommerce-Price-currencySymbol">تومان</span>`
 * directly against the digits. Woo's `right_space` currency position inserts a
 * `&nbsp;`, which an RTL line collapses to nothing visible — «۱٬۵۹۰٬۰۰۰تومان»
 * read as one word. `.nk-price__currency` already solves this for our own
 * component; this gives Woo's the same treatment so the two match wherever
 * they appear on the same screen, which on the cart page is every row.
 * -------------------------------------------------------------- */
.nk-cart-summary .woocommerce-Price-currencySymbol,
.nk-cart-line .woocommerce-Price-currencySymbol,
.nk-cart-summary-card .woocommerce-Price-currencySymbol,
.nk-order-review .woocommerce-Price-currencySymbol {
  margin-inline-start: var(--nk-space-half);
  font-size: var(--nk-text-xs);
  font-weight: var(--nk-weight-medium);
  color: var(--nk-text-muted);
}

/* Woo's amounts use the numeric face, like every other figure on the site. */
.nk-cart-summary .woocommerce-Price-amount,
.nk-cart-line .woocommerce-Price-amount,
.nk-order-review .woocommerce-Price-amount {
  font-family: var(--nk-font-numeric);
  font-variant-numeric: tabular-nums;
}


/* -----------------------------------------------------------------
 * 8b. THE VALIDATION NOTICE — .woocommerce-NoticeGroup-checkout
 *
 * **This is a grid item, and nothing told it so.** When validation fails,
 * `checkout.js` does
 * `$checkout_form.prepend( '<div class="woocommerce-NoticeGroup …">' )` — it
 * inserts the error block as the *first child of `form.checkout`*, which on
 * this theme is the two-column grid. Auto-placement then handed the notice
 * column 1, the fields column 2 and the summary the whole of row 2: the form
 * shrank to the sidebar's width, the sidebar stretched to the form's, and the
 * page looked broken at exactly the moment the shopper had made a mistake.
 * Measured at 1280px: fields 384px wide, summary 776px, the two swapped.
 *
 * One declaration fixes it, and it has to be `1 / -1` rather than a column
 * number so the single-column layout below 1024px is unaffected. `order: -1`
 * pins it above both — `prepend` already puts it first in the DOM, and the
 * order keeps it there if Woo ever appends instead.
 *
 * Do not "fix" this by taking the grid off `form.checkout`: the form *is* the
 * layout, because Woo's markup gives us nothing else to hang two columns on.
 * -------------------------------------------------------------- */

.nk-checkout > .woocommerce-NoticeGroup {
  grid-column: 1 / -1;
  order: -1;
  margin-block-end: 0;
}

/* The banner inside it already has `.nk-alert`'s look from `feedback.css`;
   only the scroll target needs marking out. */
.nk-checkout > .woocommerce-NoticeGroup:focus { outline: none; }

/* -----------------------------------------------------------------
 * 8c. THE STATE DROPDOWN — selectWoo, wearing .nk-input
 *
 * WooCommerce enhances «استان» with selectWoo (its fork of Select2) and loads
 * `select2.css` for it. That sheet is the library's default skin: a 4px
 * radius, a `rgba(32,7,7,.8)` border and a 47px box, sitting in a column of
 * 12px-radius, 48px, cream-backed `.nk-input`s. It was the one control on the
 * page that looked like it came from somewhere else.
 *
 * **The enhancement is kept, not removed.** Iran has 31 provinces; a native
 * `<select>` of 31 options is a worse control on a phone than a searchable
 * one, and `country-select.js` re-initialises it after every locale change
 * anyway — dequeuing the script would leave the field working but unsearchable
 * and would fight Woo on every update. So the container is restyled to *be*
 * `.nk-input`, and the real `<select>` underneath is untouched: it still holds
 * the value, still posts it, and still fails validation the same way.
 *
 * Select2 renders the panel in a `.select2-container--open` appended to
 * `<body>`, outside `.nk-checkout` — hence the unscoped selectors below.
 * -------------------------------------------------------------- */

body.woocommerce-page .nk-checkout .select2-container { inline-size: 100% !important; }

body.woocommerce-page .select2-container--default .select2-selection--single {
  display: flex;
  align-items: center;
  /* `.nk-input`'s recipe exactly — `min-block-size` plus vertical padding, not
     a fixed height. Select2's own `height: 28px` produced a 48px box beside a
     51px text input, and three pixels of difference on adjacent controls is
     the kind of thing that reads as sloppy without being nameable. */
  min-block-size: var(--nk-touch-target-lg);
  block-size: auto;
  /* Select2 hangs a -4px bottom margin off this to make its own 28px box line
     up with a 2em container. Ours is a different box; the margin just pulled
     the next field 4px up the column. */
  margin: 0;
  padding-inline: var(--nk-space-4);
  padding-block: var(--nk-space-3);
  border: var(--nk-border-width) solid var(--nk-border-default);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
  font-family: var(--nk-font-ui);
  font-size: var(--nk-text-md);
  line-height: var(--nk-leading-snug);
  color: var(--nk-text-strong);
  transition: border-color var(--nk-transition-base), box-shadow var(--nk-transition-base);
}

/*
 * The inner span carries the padding, and out-specifying it takes five
 * classes: `woocommerce-blocktheme.css` ships
 * `.woocommerce-page form .form-row .select2-container .select2-selection--single
 *  .select2-selection__rendered { padding: .9rem 1.1rem }` at (0,5,1), which is
 * *inside* the box this file has already padded. Left alone it stacked its own
 * 14px on ours and the province control came out 83px tall beside a 51px text
 * input. `body … --default …` is (0,5,2). The comment is here because "why
 * does this selector have six parts" is the first question anyone will have.
 */
body.woocommerce-page form .form-row .select2-container--default .select2-selection--single .select2-selection__rendered,
body.woocommerce-page .select2-container--default .select2-selection--single .select2-selection__rendered {
  padding: 0;
  font-size: var(--nk-text-md);
  line-height: var(--nk-leading-snug);
  color: inherit;
}
body.woocommerce-page .select2-container--default .select2-selection--single .select2-selection__placeholder {
  color: var(--nk-text-subtle);
}

/*
 * Select2 absolutely positions its arrow at `right: 1px` — a physical edge, so
 * in RTL it lands on top of the text. Logical placement instead, and the
 * library's CSS triangle swapped for a chevron drawn the same way the rest of
 * the system draws one.
 */
body.woocommerce-page .select2-container--default .select2-selection--single .select2-selection__arrow {
  position: static;
  inset: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  margin-inline-start: auto;
  inline-size: var(--nk-icon-sm);
  block-size: var(--nk-icon-sm);
}
/*
 * Select2 draws its arrow as a CSS triangle out of four borders. There is no
 * markup to hang an `nk_icon()` on — the library owns this `<b>` and rebuilds
 * it — so the triangle is turned off and the same chevron is drawn with two
 * borders and a rotation, exactly as `.nk-fold__chevron` is. This is geometry,
 * not an icon set: `brand-and-icons.md`'s rule is about which *library* may be
 * used, and no library is involved either way.
 */
body.woocommerce-page .select2-container--default .select2-selection--single .select2-selection__arrow b {
  position: static;
  inline-size: 0.5em;
  block-size: 0.5em;
  margin: 0 0 0.15em;
  border: 0;
  /*
   * **Physical `right`/`bottom`, and that is not an RTL slip.** A chevron
   * pointing *down* means "this opens downwards" in both directions — it is not
   * a directional glyph like a back arrow, and it must not mirror. Logical
   * properties here would flip the L in RTL and rotate it into a `‹`, which is
   * exactly what happened the first time. `rtl.md`'s rule is about content that
   * has a start and an end; a disclosure caret has neither.
   */
  border-right: 2px solid var(--nk-text-muted);
  border-bottom: 2px solid var(--nk-text-muted);
  transform: rotate(45deg);
}

/* The clear «×» Woo shows once a province is picked. */
body.woocommerce-page .select2-container--default .select2-selection--single .select2-selection__clear {
  margin: 0 0 0 var(--nk-space-2);
  color: var(--nk-text-subtle);
}

@media (hover: hover) {
  body.woocommerce-page .select2-container--default .select2-selection--single:hover {
    border-color: var(--nk-border-strong);
  }
}

/* `.select2-container--focus` is what the library sets; the real `<select>` is
   `aria-hidden` and never takes focus itself, so `:focus-visible` cannot be
   used here. Same ring as every other field. */
body.woocommerce-page .select2-container--default.select2-container--focus .select2-selection--single,
body.woocommerce-page .select2-container--default.select2-container--open .select2-selection--single {
  border-color: var(--nk-border-accent);
  outline: var(--nk-focus-ring-width) solid var(--nk-focus-ring-color);
  outline-offset: 0;
}

/* The row is invalid → so is its control, matching `.woocommerce-invalid`. */
body.woocommerce-page .woocommerce-invalid .select2-container--default .select2-selection--single {
  border-color: var(--nk-status-danger);
}

/* The panel. Appended to <body>, so no `.nk-checkout` ancestor to lean on. */
body.woocommerce-page .select2-container--default .select2-dropdown {
  border: var(--nk-border-width) solid var(--nk-border-default);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-md);
  overflow: hidden;
}
body.woocommerce-page .select2-container--default .select2-search--dropdown {
  padding: var(--nk-space-2);
}
body.woocommerce-page .select2-container--default .select2-search--dropdown .select2-search__field {
  min-block-size: var(--nk-touch-target);
  padding-inline: var(--nk-space-3);
  border: var(--nk-border-width) solid var(--nk-border-default);
  border-radius: var(--nk-radius-sm);
  background-color: var(--nk-surface-raised);
  /* 16px, not the library's 14: anything smaller zooms the page on iOS the
     moment the search box takes focus. `typography.md` § the 16px floor —
     which is `--nk-text-md`, not `--nk-text-base` (15px). */
  font-size: var(--nk-text-md);
  font-family: var(--nk-font-ui);
}
body.woocommerce-page .select2-container--default .select2-results__option {
  min-block-size: var(--nk-touch-target);
  display: flex;
  align-items: center;
  padding: var(--nk-space-2) var(--nk-space-4);
  font-size: var(--nk-text-md);
  color: var(--nk-text-default);
}
body.woocommerce-page .select2-container--default .select2-results__option--highlighted[aria-selected],
body.woocommerce-page .select2-container--default .select2-results__option--highlighted[data-selected] {
  background-color: var(--nk-surface-accent);
  color: var(--nk-text-accent);
}
body.woocommerce-page .select2-container--default .select2-results__option[aria-selected="true"],
body.woocommerce-page .select2-container--default .select2-results__option[data-selected="true"] {
  background-color: var(--nk-surface-sunken);
  color: var(--nk-text-strong);
  font-weight: var(--nk-weight-medium);
}

/* =======================================================================
 * 9. RESPONSIVE
 * ===================================================================== */

@media (min-width: 768px) {
  .nk-cart-line { grid-template-columns: 80px 1fr auto; }
  .nk-cart-line__media { inline-size: 80px; }

  /*
   * The air comes back where there is room for it. Below this width every one
   * of these is a rung lower on the same scale — see the note on
   * `.nk-cart-page`.
   */
  .nk-cart-page,
  .nk-checkout {
    gap: var(--nk-space-6);
    padding-block: var(--nk-space-6) var(--nk-section-gap);
  }
  .nk-cart-page__heading { font-size: var(--nk-text-2xl); }
  .nk-cart-page__items { padding: var(--nk-space-4); }
  .nk-checkout__section,
  .nk-checkout__summary-inner { padding: var(--nk-space-5); }
  .nk-cart-featured { margin-block-start: var(--nk-section-gap); }
}

@media (min-width: 1024px) {
  /* Items lead, summary beside them. `minmax(0,…)` or a long product name
     refuses to shrink and the grid overflows. */
  .nk-cart-page {
    grid-template-columns: minmax(0, 1fr) 22rem;
    align-items: start;
  }
  .nk-cart-page--empty { grid-template-columns: minmax(0, 1fr); }

  .nk-checkout {
    grid-template-columns: minmax(0, 1fr) 24rem;
    align-items: start;
  }

  /*
   * The summary follows the reader down a long address form, and it now has
   * two things above it to clear, not one.
   *
   * `--nk-header-stuck` is the header's measured height (`initHeader()` in
   * `ui.js`) and `--nk-steps-stuck` is the journey rail's, published the same
   * way by `initStepsOffset()` in `cart.js`. Both fall back to a sane constant
   * so a blocked script leaves the column usable rather than correct.
   *
   * **Two sticky boxes competing for the same top edge is the whole reason
   * this is measured rather than guessed.** Offset by the header alone and the
   * summary slides under the rail — and it wins the paint, because it comes
   * later in the document and neither box is in a stacking context the other
   * can beat. The rail carries `--nk-z-sticky` for the same collision.
   */
  /*
   * **The sticky summary had zero travel and never once stuck.**
   *
   * `.nk-checkout` is a grid with `align-items: start`, so the aside is exactly
   * as tall as its own content — and `.nk-checkout__summary-inner` is sticky
   * *inside* that aside, whose padding box is its constraint rectangle. Equal
   * heights mean nowhere to travel: measured at 1440px, aside 739px, inner
   * 739px, against a 1160px field column with 421px of scrolling going to
   * waste. It was written, served, and did nothing, on a rule that has claimed
   * in three documents to follow the reader down the address form.
   *
   * `align-self: stretch` gives the aside the row's full height back. It is a
   * bare wrapper — the card is the inner — so nothing paints differently.
   *
   * The cart page never had this: `.nk-cart-page__aside` *is* the sticky
   * element, and a sticky grid item is constrained by the grid container, not
   * by its own shrunk area.
   */
  .nk-checkout__summary { align-self: stretch; }

  .nk-cart-page__aside,
  .nk-checkout__summary-inner {
    position: sticky;
    inset-block-start: calc(
      var(--nk-header-stuck, var(--nk-header-height-lg)) +
      var(--nk-steps-stuck, 0px) +
      var(--nk-space-4)
    );
  }

  /*
   * The order review's item list stays open here and loses its toggle — there
   * is nothing worth folding in a sticky column with room to spare, and a
   * control that cannot change anything is worse than no control.
   *
   * Nothing has to force it open: the template renders it `open` and `cart.js`
   * only closes it below this width.
   */
  .nk-order-review__toggle { display: none; }
}

/* =======================================================================
 * 10. THE CHECKOUT JOURNEY RAIL — .nk-steps
 *
 * Printed by `nk_checkout_progress()` in `inc/checkout-steps.php` on the
 * cart, the checkout, `order-pay` and the order-received page. The visual
 * reference is the skill's `components-checkout.md`; `CART.md` has the
 * architecture.
 *
 * It lives here rather than in a stylesheet of its own because this file is
 * already enqueued in the one slot a commerce-route component needs — after
 * `woocommerce.css`, before `motion.css` — and a new file would mean getting
 * that cascade position right a second time for no gain.
 *
 * Two custom properties carry every number, both set inline by the renderer:
 *   --nk-steps-count  how many nodes (3 or 4)
 *   --nk-steps-fill   0…1, how far the coral fill runs
 * Nothing below knows which journey it is drawing, which is why three steps
 * and four need no variant between them.
 * ===================================================================== */

.nk-steps {
  /*
   * The node's drawn size. A component-scoped alias for a spacing token, not
   * a new value — it is referenced from four rules (the box, the track's
   * vertical centre, the halo and the check) and they must not drift apart.
   */
  --nk-steps-node: var(--nk-space-8);

  position: sticky;
  /*
   * `--nk-header-stuck` is the header's *measured* height, published by
   * `initHeader()` in `ui.js` — never `--nk-header-height`, which is only the
   * bar. The announcement strip is inside the sticky header, it is
   * dismissible, and its sentence wraps at 360px, so the real offset runs from
   * 56px to ~147px. `.nk-cat-rail` in `archive.css` learned this first; the
   * fallback keeps the no-JS case sane rather than exact.
   */
  inset-block-start: var(--nk-header-stuck, var(--nk-header-height));
  z-index: var(--nk-z-sticky);

  /*
   * A bleed and its cancellation, and both halves are load-bearing: the
   * negative margin takes the band to the screen edge so the stuck ground
   * spans it, and the padding hands that width straight back so the nodes
   * still line up with the gutter everything else on the page uses. Same
   * pattern, same reason, as `.nk-cat-rail`.
   */
  margin-inline: calc(var(--nk-gutter) * -1);
  padding-inline: var(--nk-gutter);
  padding-block: var(--nk-space-2);
  margin-block-end: var(--nk-space-4);

  background-color: var(--nk-surface-page);
  border-block-end: var(--nk-border-hairline);
}

/*
 * **Two classes, and that is the whole reason this rule works.**
 * `base.css` ships `ul[class], ol[class] { margin: 0; padding: 0 }` at (0,1,1),
 * so a single-class rule for this `<ol>`'s padding loses silently — the
 * declaration is written, served and ignored, and the nodes sit flush against
 * the band. `.nk-cat-rail__track` hit exactly this and it is worth the second
 * class here rather than the debugging session again.
 */
.nk-steps__list.nk-steps__list--track {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--nk-steps-count), minmax(0, 1fr));
  align-items: start;
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * The track and the fill, as two pseudo-elements on the same box.
 *
 * Both run node-*centre* to node-centre rather than edge to edge: with N equal
 * columns the first centre is at 100%/(2N) and the last is the same distance
 * in from the other side, so the line spans 100% − 100%/N. A track that ran
 * the full width would stick out past the outer nodes like a loose thread.
 *
 * `inset-inline-start` and `inline-size` are logical, so in RTL the line is
 * anchored at the right edge and the fill grows leftward with no [dir]
 * override. That is the entire RTL story for this component.
 */
.nk-steps__list--track::before,
.nk-steps__list--track::after {
  content: "";
  position: absolute;
  inset-block-start: calc(var(--nk-steps-node) / 2 - var(--nk-border-width));
  inset-inline-start: calc(100% / (var(--nk-steps-count) * 2));
  block-size: var(--nk-border-width-thick);
  border-radius: var(--nk-radius-pill);
}

.nk-steps__list--track::before {
  inline-size: calc(100% - 100% / var(--nk-steps-count));
  background-color: var(--nk-border-subtle);
}

.nk-steps__list--track::after {
  inline-size: calc((100% - 100% / var(--nk-steps-count)) * var(--nk-steps-fill));
  background-color: var(--nk-action-primary);
  transition: inline-size var(--nk-duration-slow) var(--nk-ease-out);
}

/* --- one step ------------------------------------------------------- */

.nk-steps__step {
  /* Above the track, or the line paints straight through every node. */
  position: relative;
  z-index: var(--nk-z-raised);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nk-space-1);
  min-inline-size: 0;
  text-align: center;
}

.nk-steps__node {
  display: grid;
  place-items: center;
  inline-size: var(--nk-steps-node);
  block-size: var(--nk-steps-node);
  border-radius: var(--nk-radius-circle);
  /* Opaque, so the track cannot show through the disc. */
  background-color: var(--nk-surface-page);
  border: var(--nk-border-width-thick) solid var(--nk-border-subtle);
  color: var(--nk-text-subtle);
  font-size: var(--nk-text-xs);
  font-weight: var(--nk-weight-semibold);
  font-family: var(--nk-font-numeric);
  line-height: var(--nk-leading-none);
  transition:
    background-color var(--nk-duration-normal) var(--nk-ease-standard),
    border-color var(--nk-duration-normal) var(--nk-ease-standard),
    box-shadow var(--nk-duration-normal) var(--nk-ease-standard),
    color var(--nk-duration-normal) var(--nk-ease-standard);
}

/*
 * The numeral and the check occupy the same grid cell and swap by state, so
 * neither the box nor the row it sits on moves when a step completes. Both
 * are rendered by PHP — see the note in `nk_checkout_progress()` on why a
 * script must not be the thing that draws an icon.
 */
.nk-steps__num,
.nk-steps__check {
  grid-area: 1 / 1;
}

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

.nk-steps__label {
  font-size: var(--nk-text-xs);
  line-height: var(--nk-leading-snug);
  color: var(--nk-text-muted);
  transition: color var(--nk-duration-normal) var(--nk-ease-standard);
}

/* --- the three states ------------------------------------------------ */

.nk-steps__step[data-state="upcoming"] .nk-steps__check { display: none; }

.nk-steps__step[data-state="done"] .nk-steps__num { display: none; }
.nk-steps__step[data-state="done"] .nk-steps__node {
  background-color: var(--nk-action-primary-subtle);
  border-color: var(--nk-action-primary);
  color: var(--nk-text-accent);
}
.nk-steps__step[data-state="done"] .nk-steps__label { color: var(--nk-text-default); }

.nk-steps__step[data-state="current"] .nk-steps__check { display: none; }
.nk-steps__step[data-state="current"] .nk-steps__node {
  background-color: var(--nk-action-primary);
  border-color: var(--nk-action-primary);
  color: var(--nk-text-on-accent);
  /*
   * The halo is a spread shadow, not a second element and not an outline: an
   * element would need its own box in the grid, and an outline cannot be
   * tinted independently of the border. It reads as a soft ring on cream and
   * costs nothing to animate.
   */
  box-shadow: 0 0 0 var(--nk-focus-ring-width) var(--nk-coral-100);
}
.nk-steps__step[data-state="current"] .nk-steps__label {
  color: var(--nk-text-strong);
  font-weight: var(--nk-weight-semibold);
}

/*
 * Back from a gateway that did not complete (`order-pay`). The shopper is not
 * finished and must not be told they are, so the node holds its position and
 * only its colour changes — the rail reports a state, it does not move a step.
 */
.nk-steps--failed .nk-steps__step[data-state="current"] .nk-steps__node {
  background-color: var(--nk-status-danger);
  border-color: var(--nk-status-danger);
  box-shadow: 0 0 0 var(--nk-focus-ring-width) var(--nk-red-50);
}
.nk-steps--failed .nk-steps__list--track::after { background-color: var(--nk-status-danger); }

/* --- the mobile "you are here" line ---------------------------------- */

/*
 * Below 480px four Persian labels do not fit under four nodes at a size worth
 * reading, and shrinking them until they do is exactly what makes a progress
 * bar look generic. So the nodes carry the shape and this line carries the
 * meaning. `aria-hidden` in the markup: every word of it is already on the
 * steps themselves for assistive technology, and reading it twice is noise.
 *
 * **It stays under the track, and it is labelled and ruled off.** Bare, its
 * title sat directly under the first node and was read as that node's label —
 * the confirmation page appeared to say «نهایی‌سازی سفارش» about «سبد خرید»,
 * reported from a phone screenshot. Printing it *above* the nodes fixed that
 * and the shop owner did not want the rail rearranged, so the fix is in the
 * line itself: «مرحله فعلی:» is a label no node carries, and the hairline
 * makes the band read as nodes *and then* a caption rather than as one column
 * of text hanging off a circle.
 */
.nk-steps__now {
  display: flex;
  align-items: baseline;
  gap: var(--nk-space-2);
  margin: var(--nk-space-2) 0 0;
  padding-block-start: var(--nk-space-2);
  border-block-start: var(--nk-border-hairline);
  font-size: var(--nk-text-xs);
  line-height: var(--nk-leading-snug);
}

.nk-steps__now-label {
  flex: none;
  color: var(--nk-text-muted);
}

.nk-steps__now-title {
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

/*
 * `margin-inline-start: auto` rather than `justify-content: space-between`:
 * with the label, the title and the count that would space *three* children
 * and park the title in the middle of the band, under whichever node happens
 * to be there. The pair reads as one phrase at the start; only the count is
 * pushed away.
 */
.nk-steps__now-count {
  flex: none;
  margin-inline-start: auto;
  color: var(--nk-text-muted);
}

.nk-steps__label { display: none; }

@media (min-width: 480px) {
  /* Room for every label under its own node; the summary line is redundant. */
  .nk-steps__label { display: block; }
  .nk-steps__now { display: none; }
}

@media (min-width: 768px) {
  .nk-steps {
    --nk-steps-node: var(--nk-space-10);
    padding-block: var(--nk-space-3);
    margin-block-end: var(--nk-space-6);
  }
  .nk-steps__node { font-size: var(--nk-text-base); }
  .nk-steps__check {
    inline-size: var(--nk-icon-sm);
    block-size: var(--nk-icon-sm);
  }
  .nk-steps__label { font-size: var(--nk-text-base); }
}

/*
 * The fill is the one thing here that animates, and it is the one thing a
 * shopper who has asked for less motion does not need: the rail is already
 * correct in the first paint, and the transition only exists to make a
 * *change* legible on a page that has just navigated anyway.
 */
@media (prefers-reduced-motion: reduce) {
  .nk-steps__list--track::after,
  .nk-steps__node,
  .nk-steps__label { transition: none; }
}

/* =======================================================================
 * 11. THE CONFIRMATION PAGE — .nk-confirm / .nk-confirm-next
 *
 * Step 4. Printed by `inc/checkout-steps.php` §4 into the child
 * `templates/order-confirmation.html`, around WooCommerce's own
 * `order-confirmation-*` blocks — which are kept, not replaced, because the
 * status block carries the guest email-verification gate. So this section has
 * two halves: our two components, and a map of Woo's markup onto the same
 * design language.
 * ===================================================================== */

.nk-confirm {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nk-space-3);
  margin-block: var(--nk-space-4) var(--nk-space-6);
  padding: var(--nk-space-6) var(--nk-space-4);
  border-radius: var(--nk-radius-lg);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-sm);
  text-align: center;
}

/*
 * The mark carries the whole tone of the page, so it is the one place here
 * that is allowed to be large. It is a tinted disc rather than a coral one:
 * `#place_order` was the last coral thing the shopper pressed, and repeating
 * the CTA colour on a page with no action to take reads as another button.
 */
.nk-confirm__mark {
  display: grid;
  place-items: center;
  /*
   * 48px on a phone and 64 from 768. The mark is the page's one large element
   * and every pixel of it pushes the four facts below it — which are what the
   * shopper actually screenshots — further down a 740px screen.
   */
  inline-size: var(--nk-space-12);
  block-size: var(--nk-space-12);
  border-radius: var(--nk-radius-circle);
  background-color: var(--nk-status-success-bg);
  color: var(--nk-status-success);
}

.nk-confirm[data-tone="pending"] .nk-confirm__mark {
  background-color: var(--nk-status-warning-bg);
  color: var(--nk-status-warning);
}

.nk-confirm[data-tone="danger"] .nk-confirm__mark {
  background-color: var(--nk-status-danger-bg);
  color: var(--nk-status-danger);
}

.nk-confirm__title {
  margin: 0;
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-2xl);
  font-weight: var(--nk-weight-bold);
  line-height: var(--nk-leading-tight);
  color: var(--nk-text-strong);
}

.nk-confirm__text {
  max-inline-size: 44ch;
  margin: 0;
  font-size: var(--nk-text-base);
  line-height: var(--nk-leading-normal);
  color: var(--nk-text-muted);
}

/*
 * The facts, as an inset panel of labelled rows — **the receipt**.
 *
 * It was a grid of label-over-value pairs on the reasoning that a label and a
 * value cannot share a 360px row. They can: the card's content box is 328px
 * there and the longest pair on this store, «روش پرداخت» / «کارت به کارت», is
 * under 160px of it. What the auto-fit grid actually did with three facts on a
 * phone was fit two columns and leave the third centred underneath on its own,
 * which is what a shopper's screenshot showed.
 *
 * Rows fix that, and they read as a receipt rather than as a stat strip, which
 * is what this is: one label, one value, one per line, in the order support
 * asks for them. The cream ground separates the panel from the white card
 * without a second shadow — the same move `.nk-checkout__saved` makes.
 */
.nk-confirm__facts {
  display: grid;
  inline-size: 100%;
  margin-block-start: var(--nk-space-2);
  padding-inline: var(--nk-space-4);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-page);
  text-align: start;
}

.nk-confirm__fact {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nk-space-4);
  min-block-size: var(--nk-touch-target);
  padding-block: var(--nk-space-2);
  border-block-end: var(--nk-border-hairline);
}

.nk-confirm__fact:last-child { border-block-end: 0; }

.nk-confirm__fact dt {
  flex: none;
  font-size: var(--nk-text-base);
  color: var(--nk-text-muted);
}

.nk-confirm__fact dd {
  margin: 0;
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
  text-align: end;
  /* A long gateway title must wrap rather than widen its column. */
  overflow-wrap: anywhere;
}

/*
 * The two a shopper photographs the page for. The order number is what support
 * asks for first and the amount is what the transfer has to match, so they are
 * the two rows that read from across a room.
 */
.nk-confirm__fact--number dd,
.nk-confirm__fact--amount dd {
  font-size: var(--nk-text-lg);
}

/* The badge brings its own type; the row must not override it. */
.nk-confirm__fact--status dd { font-size: inherit; }

.nk-confirm__retry { margin: var(--nk-space-2) 0 0; }

/* --- «مراحل بعدی» ---------------------------------------------------- */

.nk-confirm-next { margin-block: var(--nk-space-6) var(--nk-section-gap); }

.nk-confirm-next__title {
  margin: 0 0 var(--nk-space-3);
  font-size: var(--nk-text-xl);
  font-weight: var(--nk-weight-bold);
  color: var(--nk-text-strong);
}

.nk-confirm-next__list.nk-confirm-next__list {
  /* Two classes: `base.css`'s `ul[class] { padding: 0 }` is (0,1,1). */
  display: grid;
  gap: var(--nk-space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nk-confirm-next__link {
  display: flex;
  align-items: center;
  gap: var(--nk-space-3);
  min-block-size: var(--nk-touch-target-lg);
  padding: var(--nk-space-4);
  border: var(--nk-border-width) solid var(--nk-border-subtle);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
  color: inherit;
  text-decoration: none;
  transition:
    border-color var(--nk-transition-base),
    box-shadow var(--nk-transition-base);
}

/*
 * Split, not wrapped wholesale — `.claude/rules/css.md` § *Hover is a pointer
 * state*. Guarding the pair together would take the focus ring away from
 * keyboard users on a touch device, which is the opposite of the point. And it
 * stays **above** `:active`: the two have equal specificity, so source order
 * decides which wins while the pointer is held down, and moving this below
 * would silently swap them.
 */
.nk-confirm-next__link:focus-visible {
  border-color: var(--nk-border-accent);
  box-shadow: var(--nk-shadow-sm);
}

@media (hover: hover) {
  .nk-confirm-next__link:hover {
    border-color: var(--nk-border-accent);
    box-shadow: var(--nk-shadow-sm);
  }
}

.nk-confirm-next__link:active { box-shadow: none; }

.nk-confirm-next__icon {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: var(--nk-space-10);
  block-size: var(--nk-space-10);
  border-radius: var(--nk-radius-circle);
  background-color: var(--nk-action-primary-subtle);
  color: var(--nk-text-accent);
}

.nk-confirm-next__body {
  display: flex;
  flex-direction: column;
  gap: var(--nk-space-1);
  min-inline-size: 0;
}

.nk-confirm-next__label {
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

.nk-confirm-next__text {
  font-size: var(--nk-text-sm);
  line-height: var(--nk-leading-snug);
  color: var(--nk-text-muted);
}

/* Pushed to the far edge, and mirrored in RTL by `.nk-icon--directional`. */
.nk-confirm-next__chevron {
  flex: none;
  margin-inline-start: auto;
  color: var(--nk-text-subtle);
}

/* --- WooCommerce's own confirmation blocks --------------------------- */

/*
 * Mapped, not replaced. Every rule here is `body`-prefixed for the reason the
 * top of this file gives: `body.woocommerce-page` is on this route and Woo's
 * own sheets are (0,1,1) or higher, so a single-class rule of ours loses in a
 * tie decided by source order — and `wc-blocks-style` loads after us.
 */
body .wc-block-order-confirmation-status,
body .wc-block-order-confirmation-summary,
body .wc-block-order-confirmation-totals,
body .wc-block-order-confirmation-shipping-address,
body .wc-block-order-confirmation-billing-address,
body .wc-block-order-confirmation-additional-information {
  font-family: var(--nk-font-ui);
  font-size: var(--nk-text-base);
  line-height: var(--nk-leading-normal);
  color: var(--nk-text-default);
}

/*
 * Woo's status paragraph repeats what `.nk-confirm` has already said in a
 * larger voice, so it is demoted to a footnote rather than hidden: when the
 * email-verification gate is up, *this* element is the form and the
 * explanation, and hiding it would leave a guest with no way through.
 */
body .wc-block-order-confirmation-status {
  margin-block: 0 var(--nk-space-6);
  font-size: var(--nk-text-sm);
  color: var(--nk-text-muted);
  /* Centred under the card it is a footnote to, rather than a sentence adrift
     at the RTL start of a page whose next element is a panel. */
  text-align: center;
}

/*
 * Except when the email-verification gate is up: that state turns this block
 * into a form, and a centred one with a centred label reads as a newsletter
 * sign-up rather than as the way into your own order.
 */
body .wc-block-order-confirmation-status:has(form) {
  text-align: start;
  font-size: var(--nk-text-base);
}

body .wc-block-order-confirmation-status a { color: var(--nk-text-accent); }

/*
 * Woo's status block prints a heading — «سفارش دریافت شد» — directly under the
 * confirmation card's own «سفارش شما ثبت شد», in a larger voice, saying the
 * same thing. The card states a title in every access state and every status
 * tone, so the heading is always the second one.
 *
 * **Only the heading is hidden, never the block.** Everything else it renders
 * is load-bearing: the description, and — for a guest past the ten-minute
 * grace period — the email-verification form that is the only way into their
 * own order. `remove_block` here would take that with it.
 */
body .wc-block-order-confirmation-status > h1,
body .wc-block-order-confirmation-status > h2,
body .wc-block-order-confirmation-status > h3 { display: none; }

/*
 * Woo tags its status blocks `alignwide`, and in a constrained block layout
 * that is a *wider* measure than everything around them — so the one paragraph
 * on the page nobody needs to study ran the full 1408px at desktop and to both
 * screen edges at 360px, while the confirmation card beside it sat at 768.
 * Pinned to the same measure as the rest of the column; `margin-inline: auto`
 * because `alignwide` supplies its own and dropping the max-width alone would
 * leave it left-hugging.
 */
body.woocommerce-order-received main .alignwide {
  max-inline-size: var(--nk-container-narrow);
  margin-inline: auto;
}

body .wc-block-order-confirmation-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--nk-space-4);
  margin-block-end: var(--nk-space-6);
  padding: var(--nk-space-4);
  border: var(--nk-border-width) solid var(--nk-border-subtle);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
  list-style: none;
}

body .wc-block-order-confirmation-summary li { margin: 0; }

/*
 * The line items. Woo prints a bare two-column table; it is given the same
 * raised card as the addresses below it so the page reads as a stack of
 * panels rather than as a card followed by loose HTML.
 */
body .wc-block-order-confirmation-totals {
  padding: var(--nk-space-2) var(--nk-space-4);
  border: var(--nk-border-width) solid var(--nk-border-subtle);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
}

body .wc-block-order-confirmation-totals__table {
  inline-size: 100%;
  border-collapse: collapse;
  /*
   * Twenty Twenty-Five draws a full 1px grid on any `<table>` — a border on the
   * table and one on every cell — and that grid was what made the receipt look
   * like a spreadsheet: a boxed cell around each name, each figure and one
   * empty box where the hidden column headings had been. It is the parent's,
   * not Woo's (the block's own inline `<style>` for these selectors is empty on
   * this store), so it is trimmed here rather than out-specified.
   */
  border: 0;
}

/*
 * **The line items are not a table at any width, and that is the design.**
 *
 * Woo gives us name-and-figure in two columns. What a receipt for children's
 * clothes has to answer is «کدام لباس», and a name in a column answers it worse
 * than a photograph does — so each row becomes the product line this store
 * already uses in the cart and the order review: thumbnail, title, a quiet
 * count chip, and the line total beside it.
 *
 * The grid lives on the `<tr>` and the product cell is `display: contents`, so
 * the image, the name, the count and the figure are all placed on **one** grid
 * rather than nested in a cell that would trap them in a column. Every part is
 * placed explicitly; nothing here relies on auto-placement, because Woo appends
 * item meta and a purchase note into the same cell and those must fall below
 * the line rather than into whichever slot is free.
 *
 * `display: contents` drops the cell from the box tree — acceptable precisely
 * because the table semantics are already gone here: the headings are
 * `display: none` (two column labels over a photograph say nothing) and the
 * rows read in source order, name then count then price, which is the order
 * they are spoken in.
 *
 * The foot stays a row of label-and-figure pairs, which is the one thing on
 * this table that genuinely is two columns.
 */
body .wc-block-order-confirmation-totals__table,
body .wc-block-order-confirmation-totals__table tbody,
body .wc-block-order-confirmation-totals__table tfoot,
body .wc-block-order-confirmation-totals__table th,
body .wc-block-order-confirmation-totals__table td { display: block; }

body .wc-block-order-confirmation-totals__table thead { display: none; }

body .wc-block-order-confirmation-totals__table th,
body .wc-block-order-confirmation-totals__table td {
  padding: 0;
  border: 0;
  text-align: start;
}

body .wc-block-order-confirmation-totals__table tbody tr {
  display: grid;
  /* `auto` for the photograph: the media box below carries the one width, so
     the track cannot drift out of step with it. */
  grid-template-columns: auto 1fr auto;
  column-gap: var(--nk-space-3);
  /*
   * No `row-gap`, deliberately — the count and the figure carry their own
   * margin instead. Woo separates the name from the count with a literal
   * `&nbsp;`, and a non-breaking space is *rendered* text, so grid wraps it in
   * an anonymous item that auto-places into a third row. Zeroed by the
   * `font-size` below, that row is 0px tall — but a `row-gap` would still be
   * drawn on both sides of it, and 8px of nothing under every line is exactly
   * the loose, unfinished spacing this row was rebuilt to fix.
   */
  align-items: center;
  padding-block: var(--nk-space-4);
  border-block-end: var(--nk-border-hairline);
  /*
   * Collapses that `&nbsp;`. It has to sit on the **grid container**, not on
   * the cell: `display: contents` means the cell generates no box, so the
   * anonymous item wrapping the space inherits from this `<tr>` and a
   * `font-size` on the cell never reached it. Every child placed below sets its
   * own size back — and anything new put into this row must do the same.
   */
  font-size: 0;
}

body .wc-block-order-confirmation-totals__table tbody tr:last-child { border-block-end: 0; }

body .wc-block-order-confirmation-totals__table .wc-block-order-confirmation-totals__product {
  display: contents;
}

/*
 * The photograph — the same box as `.nk-cart-line__media`, deliberately: the
 * cart, the order review and this receipt show the same product and must show
 * it at the same size and crop. Its width is also the grid's first track.
 */
body .wc-block-order-confirmation-totals .nk-order-line__media {
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: start;
  display: block;
  inline-size: 64px;
  aspect-ratio: var(--nk-ratio-product);
  overflow: hidden;
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-sunken);
}

body .wc-block-order-confirmation-totals .nk-order-line__img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

body .wc-block-order-confirmation-totals .nk-order-line__name {
  grid-column: 2 / -1;
  grid-row: 1;
  align-self: end;
  min-inline-size: 0;
  font-size: var(--nk-text-base);
}

/*
 * The product title is a link, and on this page it is the only one inside a
 * block of text — Woo's own underline plus our accent colour made an order
 * line look like a validation error. It is body text that happens to be
 * clickable; the underline is kept for hover and focus, where it means
 * something.
 */
body .wc-block-order-confirmation-totals__table .wc-block-order-confirmation-totals__product a {
  /*
   * A **touch target**: one line of Persian is 23px tall and the audit fails it
   * at every viewport. `align-items: center` inside the link rather than
   * vertical padding, because padding here has to grow the row as well — which
   * is what left a two-line gap under every title when the min-height and the
   * padding were both on the link.
   */
  display: flex;
  align-items: center;
  min-block-size: var(--nk-touch-target);
  color: var(--nk-text-strong);
  font-weight: var(--nk-weight-semibold);
  line-height: var(--nk-leading-snug);
  text-decoration: none;
  /* A DEMO — … title with no space in it must break rather than widen. */
  overflow-wrap: anywhere;
}

body .wc-block-order-confirmation-totals__table .wc-block-order-confirmation-totals__product a:focus-visible {
  color: var(--nk-text-accent);
  text-decoration: underline;
}

/* Split from the rule above, in place — `.claude/rules/css.md` § *Hover is a
   pointer state*: guarded together, a tapped link on a phone would keep the
   accent colour until something else was tapped. */
@media (hover: hover) {
  body .wc-block-order-confirmation-totals__table .wc-block-order-confirmation-totals__product a:hover {
    color: var(--nk-text-accent);
    text-decoration: underline;
  }
}

/*
 * «تعداد: ۴» — a quiet chip under the title, not bold body text beside it.
 * It is metadata about the row, and at Woo's own weight it competed with the
 * product it was counting.
 */
body .wc-block-order-confirmation-totals__table .product-quantity {
  grid-column: 2;
  grid-row: 2;
  justify-self: start;
  margin-block-start: var(--nk-space-2);
  padding: var(--nk-space-half) var(--nk-space-2);
  border-radius: var(--nk-radius-pill);
  background-color: var(--nk-surface-page);
  color: var(--nk-text-muted);
  font-size: var(--nk-text-sm);
  font-weight: var(--nk-weight-medium);
}

/* The figure sits beside the count, on the title's baseline row. It never wraps
   mid-number; the title column is what gives up width. */
body .wc-block-order-confirmation-totals__table tbody .wc-block-order-confirmation-totals__total {
  grid-column: 3;
  grid-row: 2;
  margin-block-start: var(--nk-space-2);
  font-size: var(--nk-text-base);
  text-align: end;
  white-space: nowrap;
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

/* Anything else Woo appends into the product cell — variation meta, a purchase
   note — belongs under the whole line, never in a column beside it. */
body .wc-block-order-confirmation-totals__table .wc-item-meta,
body .wc-block-order-confirmation-totals__table .product-purchase-note {
  grid-column: 2 / -1;
  margin: var(--nk-space-2) 0 0;
  font-size: var(--nk-text-sm);
  color: var(--nk-text-muted);
}

body .wc-block-order-confirmation-totals__table .wc-item-meta { padding-inline-start: 0; list-style: none; }

/* One rule separates the lines from the sums: the last line drops its own
   hairline (above) and the foot carries it, so a table with one item and a
   table with six both end on exactly one divider. */
body .wc-block-order-confirmation-totals__table tfoot {
  border-block-start: var(--nk-border-hairline);
  padding-block-start: var(--nk-space-2);
}

body .wc-block-order-confirmation-totals__table tfoot tr {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--nk-space-3);
  padding-block: var(--nk-space-3);
  border-block-end: var(--nk-border-hairline);
}

body .wc-block-order-confirmation-totals__table tfoot .wc-block-order-confirmation-totals__total {
  text-align: end;
  white-space: nowrap;
}

/*
 * The totals rows. Woo puts shipping, tax and the final figure in `tfoot`, so
 * the rule has to hold for one row and for four: every row keeps the hairline
 * the generic rule gives it, the last one drops it, and only the last one is
 * given the weight — it is the number the shopper is transferring.
 */
body .wc-block-order-confirmation-totals__table tfoot th,
body .wc-block-order-confirmation-totals__table tfoot td {
  color: var(--nk-text-default);
}

body .wc-block-order-confirmation-totals__table tfoot tr:last-child {
  border-block-end: 0;
  padding-block-end: var(--nk-space-2);
}

body .wc-block-order-confirmation-totals__table tfoot tr:last-child th,
body .wc-block-order-confirmation-totals__table tfoot tr:last-child td {
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-bold);
  color: var(--nk-text-strong);
}

/* Woo's headings on this page are `<h2>`/`<h3>` from patterns we do not own. */
body .wc-block-order-confirmation-totals-wrapper h2,
body .wc-block-order-confirmation-totals-wrapper h3,
body .wc-block-order-confirmation-shipping-wrapper h2,
body .wc-block-order-confirmation-shipping-wrapper h3,
body .wc-block-order-confirmation-billing-wrapper h2,
body .wc-block-order-confirmation-billing-wrapper h3 {
  margin-block: 0 var(--nk-space-3);
  font-size: var(--nk-text-lg);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

body .wc-block-order-confirmation-shipping-address,
body .wc-block-order-confirmation-billing-address {
  padding: var(--nk-space-4);
  border: var(--nk-border-width) solid var(--nk-border-subtle);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
}

body .wc-block-order-confirmation-shipping-address address,
body .wc-block-order-confirmation-billing-address address {
  font-style: normal;
  line-height: var(--nk-leading-normal);
}

/*
 * The phone line, and it is a bidi bug rather than a style: a stored
 * `+989121234567` is a neutral `+` followed by a digit run, so the RTL
 * paragraph direction moves the plus to the far end and an Iranian shopper
 * reads «۹۸۹۱۲۱۲۳۴۵۶۷+». `plaintext` lets the line take its own direction from
 * its first strong character while the paragraph stays anchored at the RTL
 * start — the same job `.nk-num` does for a price, in the one place here that
 * cannot be given a class because Woo prints the markup.
 */
body .wc-block-order-confirmation-shipping-address .woocommerce-customer-details--phone,
body .wc-block-order-confirmation-billing-address .woocommerce-customer-details--phone,
body .wc-block-order-confirmation-shipping-address .woocommerce-customer-details--email,
body .wc-block-order-confirmation-billing-address .woocommerce-customer-details--email {
  margin-block: var(--nk-space-2) 0;
  unicode-bidi: plaintext;
  font-family: var(--nk-font-numeric);
  color: var(--nk-text-muted);
}

/*
 * A store with no shipping address — every product here is shipped, but a
 * virtual line item or a local-pickup method leaves the block empty — renders
 * an empty column, and an empty flex column still takes half the row and a
 * heading's worth of gap. `:empty` cannot see it: the column holds whitespace
 * text nodes from the template. `:has()` is already relied on in
 * `commerce.css` for the product card's focus ring.
 */
body .wc-block-order-confirmation-address-wrapper .wp-block-column:not(:has(*)) {
  display: none;
}

/*
 * The gateway's own instructions — on this store, BACS's «کارت به کارت»
 * account details. It is the one thing on the page a shopper may still have to
 * *act* on, so it is the one block given an accent ground.
 */
body .wc-block-order-confirmation-additional-information {
  margin-block: 0 var(--nk-space-6);
  padding: var(--nk-space-4);
  border: var(--nk-border-width) solid var(--nk-border-subtle);
  border-inline-start: var(--nk-border-width-thick) solid var(--nk-action-primary);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-accent);
}

body .wc-block-order-confirmation-additional-information h2,
body .wc-block-order-confirmation-additional-information h3 {
  margin-block: 0 var(--nk-space-2);
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-semibold);
  color: var(--nk-text-strong);
}

body .wc-block-order-confirmation-additional-information p {
  margin-block: 0 var(--nk-space-3);
  font-size: var(--nk-text-base);
  line-height: var(--nk-leading-relaxed);
}

body .wc-block-order-confirmation-additional-information > :last-child { margin-block-end: 0; }

/* The bank details themselves, inside that block: a panel within a panel. */
body .woocommerce-bacs-bank-details {
  margin-block-start: var(--nk-space-4);
  padding: var(--nk-space-3) var(--nk-space-4);
  border-radius: var(--nk-radius-md);
  background-color: var(--nk-surface-raised);
}

body .woocommerce-bacs-bank-details .wc-bacs-bank-details-account-name {
  font-size: var(--nk-text-base);
  color: var(--nk-text-muted);
  font-weight: var(--nk-weight-medium);
}

/*
 * Two classes: `base.css` ships `ul[class] { margin: 0; padding: 0 }` at
 * (0,1,1) and this is Woo's `ul.wc-bacs-bank-details.order_details` — the same
 * trap `.nk-steps__list--track` documents, reached here through `body`.
 */
body .woocommerce-bacs-bank-details .wc-bacs-bank-details {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

body .woocommerce-bacs-bank-details .wc-bacs-bank-details li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--nk-space-1) var(--nk-space-3);
  min-block-size: var(--nk-touch-target);
  padding-block: var(--nk-space-2);
  border-block-end: var(--nk-border-hairline);
  font-size: var(--nk-text-base);
  color: var(--nk-text-muted);
}

body .woocommerce-bacs-bank-details .wc-bacs-bank-details li:last-child { border-block-end: 0; }

/*
 * The value of every row, and the card number is why this exists: it is the
 * one string on the page a shopper copies into a banking app digit by digit,
 * off a screenshot, usually one-handed.
 */
body .woocommerce-bacs-bank-details .wc-bacs-bank-details li strong {
  font-family: var(--nk-font-numeric);
  font-size: var(--nk-text-md);
  font-weight: var(--nk-weight-bold);
  color: var(--nk-text-strong);
  /* Latin digits and hyphens in an RTL row: an isolated LTR run, as `.nk-num`. */
  direction: ltr;
  unicode-bidi: isolate;
  text-align: end;
  /*
   * A card number is one token, and «۰۰۰۰-۰۰۰۰-۰۰۰۰-\n۰۰۰۰» is how a shopper
   * copies three groups into their banking app and wonders where the fourth
   * went. It never breaks; the row wraps around it instead, which is what
   * `flex-wrap` on the `li` is for.
   */
  white-space: nowrap;
}

@media (min-width: 768px) {
  .nk-confirm {
    gap: var(--nk-space-4);
    padding: var(--nk-space-10) var(--nk-space-8);
  }
  .nk-confirm__mark {
    inline-size: var(--nk-space-16);
    block-size: var(--nk-space-16);
  }
  .nk-confirm__title { font-size: var(--nk-text-3xl); }
  .nk-confirm__text { font-size: var(--nk-text-md); }
  .nk-confirm__facts { padding-inline: var(--nk-space-6); }
  .nk-confirm__fact { padding-block: var(--nk-space-3); }
  .nk-confirm-next__list.nk-confirm-next__list {
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  }
}

/*
 * **The rail does not stick on the confirmation page**, and that is a decision
 * rather than an oversight.
 *
 * Two reasons, one of them forced. The page is the *end* of the journey: there
 * is nothing left to track, and a band pinned over a «سفارش شما ثبت شد» is
 * chrome for its own sake. And WordPress's constrained block layout hands every
 * child of `<main>` `max-width: 768px` and `margin-inline: auto` at (0,2,0),
 * which beats the rail's own edge bleed — so a stuck band here would be a
 * 768px island with the page scrolling past on both sides of it. Bleeding back
 * out means guessing how much padding the block layout gave us, and that number
 * is 16px at every width while `--nk-gutter` grows to 32px, so the guess
 * overflows the viewport at 1024px and up.
 *
 * `position: static` also drops it out of `--nk-z-sticky`, which is right: it
 * has nothing to sit above here.
 */
body.woocommerce-order-received .nk-steps {
  position: static;
  margin-inline: 0;
  padding-inline: 0;
}

/* =======================================================================
 * 12. THE SIGN-IN PANEL — .nk-auth
 *
 * Step 2 of the guest journey. Printed by `nk_auth_panel()` in `inc/auth.php`,
 * in the fields column where the address form would be, so the order summary
 * stays beside it on desktop — the shopper can see what they are signing in to
 * buy. `AUTH.md` has the architecture.
 * ===================================================================== */

.nk-auth {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nk-space-3);
  /*
   * Not full width on desktop. A single phone field stretched across a
   * 700px column reads as an unfinished form; the measure is the width the
   * content actually needs.
   */
  max-inline-size: 28rem;
  margin-block: var(--nk-space-4) var(--nk-section-gap);
  margin-inline: auto;
  padding: var(--nk-space-6) var(--nk-space-4);
  border-radius: var(--nk-radius-lg);
  background-color: var(--nk-surface-raised);
  box-shadow: var(--nk-shadow-sm);
  text-align: center;
}

.nk-auth__mark {
  display: grid;
  place-items: center;
  inline-size: var(--nk-space-12);
  block-size: var(--nk-space-12);
  border-radius: var(--nk-radius-circle);
  background-color: var(--nk-action-primary-subtle);
  color: var(--nk-text-accent);
}

.nk-auth__title {
  margin: 0;
  font-family: var(--nk-font-display);
  font-size: var(--nk-text-xl);
  font-weight: var(--nk-weight-bold);
  color: var(--nk-text-strong);
}

.nk-auth__text {
  max-inline-size: 34ch;
  margin: 0;
  font-size: var(--nk-text-base);
  line-height: var(--nk-leading-normal);
  color: var(--nk-text-muted);
}

/* --- the two stages -------------------------------------------------- */

/*
 * Both forms are in the document at all times and one is hidden. **Not
 * conditionally rendered** — the no-JS path posts stage 1 and comes back on
 * stage 2, and a browser that never runs the script still has to find both.
 * `display: none` and not `hidden`, because a hidden form's fields are still
 * submitted and an empty `required` one would block the other form's submit.
 */
.nk-auth__form { display: none; }
.nk-auth[data-stage="phone"] [data-nk-auth-form="request"],
.nk-auth[data-stage="code"] [data-nk-auth-form="verify"] {
  display: flex;
  flex-direction: column;
  gap: var(--nk-space-3);
  inline-size: 100%;
  margin-block-start: var(--nk-space-2);
}

.nk-auth__label {
  font-size: var(--nk-text-sm);
  font-weight: var(--nk-weight-medium);
  color: var(--nk-text-default);
  text-align: start;
}

.nk-auth__input.nk-auth__input {
  /*
   * Two classes: `body.woocommerce-page` is on this route and Woo's own sheets
   * out-specify a single class of ours — the trap this file opens with. And
   * 16px is the floor, `--nk-text-md`: anything smaller zooms the page on iOS
   * the moment the field takes focus, mid-checkout.
   */
  inline-size: 100%;
  font-size: var(--nk-text-md);
  text-align: center;
}

/*
 * The code field is the one place in the store that gets letter-spacing, and
 * it is safe here for the reason `.claude/rules/rtl.md` gives: the rule is
 * never to track *Persian* text, which is cursive and breaks at the joins.
 * This field holds digits and nothing else.
 */
.nk-auth__input--code.nk-auth__input--code {
  font-size: var(--nk-text-2xl);
  font-weight: var(--nk-weight-bold);
  letter-spacing: 0.35em;
  /* The tracking is applied after each glyph, including the last, so the run
     sits half a space off centre without this. */
  text-indent: 0.35em;
}

.nk-auth__submit.nk-auth__submit {
  inline-size: 100%;
  min-block-size: var(--nk-touch-target-lg);
}

.nk-auth__form[data-nk-auth-busy] { opacity: 0.7; }

/* --- resend and «ویرایش شماره» --------------------------------------- */

.nk-auth__aux {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--nk-space-2) var(--nk-space-4);
  margin: 0;
}

.nk-auth__link {
  display: inline-flex;
  align-items: center;
  gap: var(--nk-space-1);
  /* A 44px row rather than a 44px box: two text links side by side, each
     padded to a full square, would be a control bar. The row is the target. */
  min-block-size: var(--nk-touch-target);
  padding: var(--nk-space-2);
  border: 0;
  background: none;
  color: var(--nk-text-accent);
  font-family: inherit;
  font-size: var(--nk-text-sm);
  cursor: pointer;
}

@media (hover: hover) {
  .nk-auth__link:hover { color: var(--nk-action-primary-active); }
}

.nk-auth__link:active { color: var(--nk-action-primary-active); }

.nk-auth__link:disabled {
  color: var(--nk-action-disabled-text);
  cursor: default;
}

/* --- the message line ------------------------------------------------ */

.nk-auth__message,
.nk-confirm__message {
  display: flex;
  align-items: center;
  gap: var(--nk-space-2);
  inline-size: 100%;
  margin: 0;
  padding: var(--nk-space-3);
  border-radius: var(--nk-radius-sm);
  background-color: var(--nk-status-danger-bg);
  color: var(--nk-status-danger-text);
  font-size: var(--nk-text-sm);
  line-height: var(--nk-leading-snug);
  text-align: start;
}

.nk-auth__message[data-tone="success"] {
  background-color: var(--nk-status-success-bg);
  color: var(--nk-status-success-text);
}

/*
 * Empty rather than absent. The element carries `role="alert"`, and a live
 * region that is added to the document at the moment it has something to say
 * is not reliably announced — the screen reader has to have been watching it.
 * So it is always there and only its content changes.
 */
.nk-auth__message--empty {
  padding: 0;
  background: none;
}
.nk-auth__message--empty > * { display: none; }

/* --- WooCommerce's own login form, on /my-account/ -------------------- */

/*
 * Hidden, never unhooked. `woocommerce_login_form` is where a security plugin
 * adds its captcha and where Woo prints its nonce, and the form is still the
 * fallback for anyone who reaches it directly — so `remove_action()` would
 * break more than it tidies. It is only hidden while an SMS transport is
 * configured, which is the only state in which it is redundant.
 *
 * `body.nk-auth-sms` comes from `nk_auth_body_class()`.
 */
body.nk-auth-sms .woocommerce-form-login,
body.nk-auth-sms .woocommerce-form-register { display: none; }

@media (min-width: 768px) {
  .nk-auth {
    gap: var(--nk-space-4);
    padding: var(--nk-space-8) var(--nk-space-6);
  }
  .nk-auth__title { font-size: var(--nk-text-2xl); }
}

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

/*
 * One glyph per tone. Both are printed by PHP so no script has to know where
 * the sprite lives; which one shows is a stylesheet decision, which is what
 * makes the swap free when `auth.js` flips `data-tone` after a reply.
 */
.nk-auth__message[data-tone="error"] .nk-auth__message-ok,
.nk-auth__message[data-tone="success"] .nk-auth__message-error { display: none; }

/*
 * The lede asks for a phone number, and on the code stage that has already
 * happened — the message line above the field now says where the code went.
 * Leaving both up makes the panel argue with itself.
 */
.nk-auth[data-stage="code"] [data-nk-auth-lede] { display: none; }

/*
 * «۱٬۲۹۰٬۰۰۰تومان» — `wc_price()` puts the currency symbol in a `<span>`
 * immediately after the figure with no separator, and Persian needs one. The
 * theme's own `nk_price()` has always spaced it; this surface is the first that
 * shows Woo's raw output at a size anyone reads, in the confirmation card and
 * in the totals table right below it, so both are corrected together rather
 * than leaving the two disagreeing three centimetres apart.
 */
.nk-confirm__fact .woocommerce-Price-currencySymbol,
body .wc-block-order-confirmation-totals .woocommerce-Price-currencySymbol {
  margin-inline-start: 0.25em;
}

