/*
 * Global chrome: announcement bar, header, navigation drawer, search sheet,
 * footer, sticky add-to-cart, and the shared notice and interior-page styles.
 *
 * Loaded on every page, so it holds only what every page uses. Every colour,
 * size and duration comes from tokens.css; the shared components (.nd-label,
 * .nd-btn, .nd-input, the focus ring) come from base.css and are used here,
 * never redeclared.
 *
 * Hooks assets/js/ui.js depends on, all kept exactly:
 *   [data-nd-drawer] + aria-controls -> #nd-mobile-nav / #nd-search-panel,
 *   .nd-drawer[hidden] + .is-open, [data-nd-drawer-close], body.nd-scroll-locked,
 *   [data-nd-progress], .nd-sticky-atc[hidden] + .is-visible, #nd-live,
 *   span.nd-cart-count, .nd-sr-only inside the toggle buttons.
 */

/* --------------------------------------------------------- announcement -- */

/*
 * One still line, 36px, charcoal on paper. No marquee: the two facts fit on
 * one line at every width from 768 up, and under that only the first shows.
 */
.nd-announce {
  display: flex;
  align-items: center;
  min-height: var(--nd-announce-h);
  background: var(--nd-ink-900);
  color: var(--nd-paper);
  font-size: var(--nd-fs-xs);
  font-weight: var(--nd-fw-semibold);
  line-height: 1.4;
}

.nd-announce__list {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--nd-s-4);
  width: 100%;
  min-width: 0;
  margin: 0;
  padding: 0 var(--nd-gutter);
  list-style: none;
}

.nd-announce__item {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A rule between items, drawn rather than typed so it is not read out. */
.nd-announce__item + .nd-announce__item::before {
  content: "";
  display: inline-block;
  width: 1px;
  height: 12px;
  margin-inline-end: var(--nd-s-4);
  background: var(--nd-stage-rule-strong);
  vertical-align: -1px;
}

@media (max-width: 767px) {
  .nd-announce__item:not(:first-child) { display: none; }
}

/* -------------------------------------------------------------- header --- */

/*
 * Paper, sticky, one hairline under it and a 1px progress line on its bottom
 * edge. No shade, no border: the hairline is drawn by ::before so the bar is
 * the same height for everyone.
 */
.nd-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--nd-header-bg);
  border-bottom: 0;
}

.nd-header::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 100%;
  height: 1px;
  pointer-events: none;
  background: var(--nd-rule);
}

/*
 * The header grid. Under 1024: toggle | wordmark centred | actions, with the
 * outer columns equal so the mark sits on the true centre line. From 1024:
 * wordmark | nav (right-aligned) | actions.
 */
.nd-header__inner {
  display: grid;
  grid-template-columns: minmax(var(--nd-tap-min), 1fr) auto minmax(var(--nd-tap-min), 1fr);
  align-items: center;
  column-gap: var(--nd-s-4);
  min-height: var(--nd-header-h-sm);
}

@media (min-width: 1024px) {
  .nd-header__inner {
    grid-template-columns: auto minmax(0, 1fr) auto;
    column-gap: var(--nd-s-6);
    min-height: var(--nd-header-h);
  }
}

.nd-header__toggle {
  display: inline-grid;
  place-items: center;
  justify-self: start;
  width: var(--nd-tap-min);
  height: var(--nd-tap-min);
  margin-inline-start: calc(-1 * var(--nd-s-3));
  padding: 0;
  border-radius: var(--nd-r-md);
  color: var(--nd-ink-900);
  cursor: pointer;
}

.nd-header__toggle .nd-icon { width: 22px; height: 22px; }

@media (min-width: 1024px) {
  .nd-header__toggle { display: none; }
}

/* ------------------------------------------------------------- logo ------ */

/* The logo wrapper is a div (or, until the helper lands, an h1): it must
   not pick up heading type either way. */
.nd-logo {
  margin: 0;
  justify-self: center;
  font-size: 1rem;
  font-weight: var(--nd-fw-regular);
  line-height: 1;
}

@media (min-width: 1024px) {
  .nd-logo { justify-self: start; }
}

.nd-logo__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--nd-tap-min);
  color: var(--nd-ink-900);
  text-decoration: none;
  letter-spacing: var(--nd-track-mark);
}

.nd-logo__img { max-height: 32px; width: auto; }

@media (min-width: 1024px) {
  .nd-logo__img { max-height: 40px; }
}

/* ---------------------------------------------------------- the lockup -- */

/*
 * The brand lockup: the word in Fraunces with the paw as the tittle of the
 * i, and the descriptor inline after it at label scale.
 *
 *   span.nd-mark > span.nd-mark__word (+ svg.nd-mark__paw) + span.nd-mark__descriptor
 */
.nd-mark {
  display: inline-flex;
  align-items: baseline;
  gap: var(--nd-s-2);
  line-height: 1;
}

.nd-mark__word {
  position: relative;
  display: inline-block;
  font-family: var(--nd-font-display);
  font-weight: var(--nd-fw-medium);
  letter-spacing: var(--nd-track-mark);
  color: var(--nd-ink-900);
}

/* The tittle of the dotless i, sized and placed in em so it follows the word
   at any size. The offsets are tuned to Fraunces. */
.nd-mark__paw {
  position: absolute;
  width: .30em;
  height: .30em;
  left: .56em;
  top: -.04em;
  color: var(--nd-accent);
}

/* The descriptor takes the label recipe (it is printed without the class). */
.nd-mark__descriptor {
  display: inline-block;
  font-family: var(--nd-font);
  font-size: var(--nd-fs-micro);
  font-weight: var(--nd-fw-medium);
  line-height: var(--nd-lh-label);
  letter-spacing: var(--nd-track-micro);
  text-transform: uppercase;
  color: var(--nd-ink-500);
  margin: 0;
  vertical-align: baseline;
}

.nd-mark--header .nd-mark__word { font-size: 1.5rem; }

@media (min-width: 1024px) {
  .nd-mark--header .nd-mark__word { font-size: 1.75rem; }
}

/* ----------------------------------------------------------- actions ----- */

.nd-header__actions {
  display: flex;
  align-items: center;
  justify-self: end;
  gap: var(--nd-s-1);
  margin-inline-end: calc(-1 * var(--nd-s-3));
}

.nd-action {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--nd-s-2);
  width: var(--nd-tap-min);
  min-width: var(--nd-tap-min);
  height: var(--nd-tap-min);
  padding: 0;
  border: 0;
  border-radius: var(--nd-r-md);
  background: none;
  color: var(--nd-ink-900);
  text-decoration: none;
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
  cursor: pointer;
}

.nd-action .nd-icon { width: 22px; height: 22px; }
.nd-action .nd-icon [stroke] { stroke-width: 1.8; }

/* The visible label is off at every width; the .nd-sr-only copy carries the
   accessible name. The drawer foot turns it back on. */
.nd-action__label { display: none; }

/* Under 1024 the account link lives in the drawer, not the bar. */
@media (max-width: 1023px) {
  .nd-header__actions .nd-action--account { display: none; }
}

.nd-action__icon {
  position: relative;
  display: inline-grid;
  place-items: center;
}

.nd-cart-count {
  position: absolute;
  top: -6px;
  right: -10px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  background: var(--nd-ink-900);
  color: var(--nd-paper);
  border-radius: var(--nd-r-pill);
  font-size: 11px;
  font-weight: var(--nd-fw-semibold);
  line-height: 1;
}

.nd-cart-count.is-empty { display: none; }

/* --------------------------------------------------------------- nav ----- */

.nd-nav__list {
  display: flex;
  align-items: center;
  gap: var(--nd-s-6);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nd-nav__item { margin: 0; }

.nd-nav__link,
.nd-nav__list a {
  display: inline-flex;
  align-items: center;
  min-height: var(--nd-tap-min);
  color: var(--nd-ink-900);
  text-decoration: none;
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
  line-height: 1.5;
}

.nd-nav--desktop { display: none; }

@media (min-width: 1024px) {
  .nd-nav--desktop {
    display: flex;
    justify-content: flex-end;
    min-width: 0;
  }
}

/*
 * The current page and the hovered link carry a 1px accent rule under the
 * word that scales in from the left. Colour never changes: the rule is the
 * whole signal.
 */
.nd-nav--desktop .nd-nav__list > li > a { position: relative; }

.nd-nav--desktop .nd-nav__list > li > a::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 9px;
  height: 1px;
  background: var(--nd-accent);
  scale: 0 1;
  transform-origin: left center;
  transition: scale var(--nd-dur-snap) var(--nd-ease-mech);
}

.nd-nav--desktop .nd-nav__list a[aria-current="page"]::after,
.nd-nav--desktop .nd-nav__list .current-menu-item > a::after,
.nd-nav--desktop .nd-nav__list .current-menu-ancestor > a::after { scale: 1 1; }

/* A second level, should a menu carry one: plain text under its parent. */
.nd-nav--desktop .sub-menu {
  display: none;
}

/* --------------------------------------------------------- drawer ------- */

/*
 * The off-canvas layer: a fixed backdrop and, inside it, the panel. The nav
 * panel slides in from the left; the search panel drops from the top. Both
 * are hidden by script once their transition ends, and pointer-events keep
 * the closed overlay from swallowing taps in the meantime.
 */
.nd-drawer {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(31, 31, 29, .4);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--nd-dur-exit) var(--nd-ease-mech);
}

.nd-drawer.is-open {
  opacity: 1;
  pointer-events: auto;
  transition: opacity var(--nd-dur-travel) var(--nd-ease-mech);
}

.nd-drawer__panel {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: min(360px, 88vw);
  padding: var(--nd-s-2) var(--nd-s-5) var(--nd-s-6);
  background: var(--nd-paper);
  overflow-y: auto;
  overscroll-behavior: contain;
  box-shadow: var(--nd-lift);
  transform: translateX(-100%);
  transition: transform var(--nd-dur-exit) var(--nd-ease-mech);
}

.nd-drawer.is-open .nd-drawer__panel {
  transform: translateX(0);
  transition: transform var(--nd-dur-travel) var(--nd-ease-mech);
}

.nd-drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nd-s-4);
  min-height: var(--nd-header-h-sm);
  margin-bottom: var(--nd-s-4);
}

.nd-drawer__head .nd-logo { justify-self: start; }

.nd-drawer__close {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: var(--nd-tap-min);
  height: var(--nd-tap-min);
  margin-inline-end: calc(-1 * var(--nd-s-3));
  padding: 0;
  border-radius: var(--nd-r-md);
  color: var(--nd-ink-900);
  cursor: pointer;
}

.nd-drawer__close .nd-icon { width: 22px; height: 22px; }

/* The menu: serif names, 56px rows, a hairline between each. */
.nd-nav--mobile .nd-nav__list {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  border-top: 1px solid var(--nd-rule);
}

.nd-nav--mobile .nd-nav__list > li { margin: 0; }

.nd-nav--mobile .nd-nav__list a {
  display: flex;
  align-items: center;
  min-height: 56px;
  padding-block: var(--nd-s-2);
  border-bottom: 1px solid var(--nd-rule);
  font-family: var(--nd-font-display);
  font-size: 1.5rem;
  font-weight: var(--nd-fw-regular);
  line-height: var(--nd-lh-snug);
  letter-spacing: var(--nd-track-title);
  color: var(--nd-ink-900);
}

.nd-nav--mobile .sub-menu {
  margin: 0;
  padding: 0 0 0 var(--nd-s-4);
  list-style: none;
}

.nd-nav--mobile .sub-menu a {
  min-height: var(--nd-tap-min);
  font-family: var(--nd-font);
  font-size: var(--nd-fs-base);
  font-weight: var(--nd-fw-medium);
}

/* Under the menu: account, the store facts, the operator. */
.nd-drawer__foot {
  display: grid;
  gap: var(--nd-s-4);
  margin-top: var(--nd-s-5);
}

.nd-drawer__foot .nd-action {
  width: auto;
  justify-content: flex-start;
  gap: var(--nd-s-3);
  padding: 0;
}

.nd-drawer__foot .nd-action__label { display: inline; }

.nd-drawer__facts {
  display: grid;
  gap: var(--nd-s-2);
  margin: 0;
  padding: var(--nd-s-4) 0 0;
  list-style: none;
  border-top: 1px solid var(--nd-rule);
  font-size: var(--nd-fs-xs);
  line-height: 1.5;
  color: var(--nd-ink-700);
}

.nd-drawer__facts li { margin: 0; }

.nd-drawer__operator {
  margin: 0;
  font-size: var(--nd-fs-micro);
  line-height: 1.5;
  color: var(--nd-ink-500);
  max-width: none;
}

/* The page must not scroll behind an open drawer. */
body.nd-scroll-locked { overflow: hidden; }

/* ---------------------------------------------------------- search ------- */

/*
 * The search sheet: a white panel dropping from the top edge over the dimmed
 * page, the field across it, the close button where the search button was.
 * Same script, same hooks as the menu drawer; only the panel geometry differs.
 */
.nd-drawer--search .nd-drawer__panel {
  inset: 0 0 auto 0;
  width: auto;
  max-height: 100dvh;
  padding: var(--nd-s-5) var(--nd-gutter) var(--nd-s-6);
  background: var(--nd-white);
  box-shadow: var(--nd-lift);
  transform: translateY(-8px);
  opacity: 0;
  transition: transform var(--nd-dur-exit) var(--nd-ease-mech),
              opacity var(--nd-dur-exit) var(--nd-ease-mech);
}

.nd-drawer--search.is-open .nd-drawer__panel {
  transform: none;
  opacity: 1;
  transition: transform var(--nd-dur-travel) var(--nd-ease-mech),
              opacity var(--nd-dur-travel) var(--nd-ease-mech);
}

.nd-drawer--search .nd-drawer__close {
  position: absolute;
  top: calc((var(--nd-header-h-sm) - var(--nd-tap-min)) / 2);
  inset-inline-end: calc(var(--nd-gutter) - var(--nd-s-3));
  margin: 0;
}

@media (min-width: 1024px) {
  .nd-drawer--search .nd-drawer__close {
    top: calc((var(--nd-header-h) - var(--nd-tap-min)) / 2);
  }
}

/* The field: an underline, not a box. The magnifier sits on the left margin
   and the submit is a charcoal text button on the right. */
.nd-hsearch {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  max-width: var(--nd-narrow);
  margin: 0 auto;
  padding-inline-end: var(--nd-s-7);
}

@media (min-width: 1024px) {
  .nd-hsearch { padding-inline-end: 0; }
}

.nd-hsearch__icon {
  position: absolute;
  inset-inline-start: 0;
  display: grid;
  place-items: center;
  color: var(--nd-ink-500);
  pointer-events: none;
}

.nd-hsearch__icon .nd-icon { width: 20px; height: 20px; }

.nd-hsearch__input {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: var(--nd-control-h-lg);
  padding: 0 5.5rem 0 2rem;
  border: 0;
  border-bottom: 1px solid var(--nd-border-control);
  border-radius: 0;
  background: none;
  color: var(--nd-ink-900);
  /* 18px: never under 16, or iOS zooms the page on focus. */
  font-size: var(--nd-fs-md);
  line-height: 1.5;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color var(--nd-dur-snap) var(--nd-ease-mech);
}

.nd-hsearch__input::placeholder { color: var(--nd-ink-500); opacity: 1; }

.nd-hsearch__input::-webkit-search-decoration,
.nd-hsearch__input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

.nd-hsearch__input:focus { border-bottom-color: var(--nd-ink-900); }

.nd-hsearch__submit {
  position: absolute;
  inset-inline-end: 0;
  min-height: var(--nd-tap-min);
  padding: 0 var(--nd-s-3);
  border: 0;
  border-radius: var(--nd-r-sm);
  background: none;
  color: var(--nd-ink-900);
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
  cursor: pointer;
}

/* Below 1024 the sheet reserves its right padding for the close button, so
   the submit ends at the input's content edge instead of under the ×. */
@media (max-width: 1023px) {
  .nd-hsearch__submit { inset-inline-end: var(--nd-s-7); }
}

/* On the narrowest phones the field keeps the width and the magnifier
   carries the submit: Enter still searches. */
@media (max-width: 379px) {
  .nd-hsearch__submit { display: none; }
  .nd-hsearch__input { padding-inline-end: var(--nd-s-2); }
}

/* -------------------------------------------------------- sticky ATC ---- */

.nd-sticky-atc {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 150;
  background: var(--nd-white);
  border-top: 1px solid var(--nd-rule);
  box-shadow: var(--nd-lift-up);
  padding: var(--nd-s-3) var(--nd-gutter);
  transform: translateY(100%);
  transition: transform var(--nd-dur-travel) var(--nd-ease-mech);
}

.nd-sticky-atc.is-visible { transform: translateY(0); }

.nd-sticky-atc__inner {
  display: flex;
  align-items: center;
  gap: var(--nd-s-3);
  max-width: var(--nd-container);
  margin-inline: auto;
}

.nd-sticky-atc__title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
  color: var(--nd-ink-900);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nd-sticky-atc__price {
  font-size: var(--nd-fs-sm);
  color: var(--nd-ink-700);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.nd-sticky-atc__btn { flex: 0 0 auto; padding-inline: var(--nd-s-5); }

/* ------------------------------------------------------------- promo ----- */

/*
 * The welcome offer (markup from nilosi_dtc_promo_markup(), behaviour from
 * initPromo() in ui.js). Fixed, so opening it moves nothing: 0 CLS. Hidden by
 * attribute until opened, and every rule below that sets `display` restates
 * [hidden] because an author display value beats the browser's own.
 *
 * ui.js picks the shape when it opens, by width: .nd-promo--modal from 768px,
 * .nd-promo--sheet below. The class, not a media query, drives the layout so
 * the look and the behaviour (focus trap, scroll lock) can never disagree.
 *
 * The stack: header 100, sticky bar 150, drawer 200 -- and the owner's chat
 * bubble, which like most chat widgets sits near the top of the z-index range.
 * The offer goes above all of them while it is open; it is always one tap
 * from closed, so it never covers the bubble for long.
 */
.nd-promo {
  position: fixed;
  z-index: 2147483640;
  display: grid;
}

.nd-promo[hidden],
.nd-promo__panel[hidden] { display: none; }

/* The menu drawer wins: a sheet left open under it would sit on its links. */
.nd-scroll-locked .nd-promo--sheet { visibility: hidden; }

.nd-promo__backdrop { display: none; }

.nd-promo__dialog {
  position: relative;
  display: grid;
  background: var(--nd-paper);
  color: var(--nd-ink-700);
}

.nd-promo__media { display: none; }

.nd-promo__body {
  position: relative;
  display: grid;
  align-content: center;
  gap: var(--nd-s-3);
  min-width: 0;
}

.nd-promo__close {
  position: absolute;
  top: var(--nd-s-2);
  inset-inline-end: var(--nd-s-2);
  display: inline-grid;
  place-items: center;
  width: var(--nd-tap-min);
  height: var(--nd-tap-min);
  padding: 0;
  border: 0;
  border-radius: var(--nd-r-md);
  background: transparent;
  color: var(--nd-ink-900);
  cursor: pointer;
}

.nd-promo__close .nd-icon { width: 22px; height: 22px; }

@media (hover: hover) and (pointer: fine) {
  .nd-promo__close:hover { background: var(--nd-tint); }
}

/* Clear of the close button, whichever line comes first. */
.nd-promo__eyebrow,
.nd-promo__title { padding-inline-end: var(--nd-s-7); }

.nd-promo__eyebrow { margin: 0; }

.nd-promo__title {
  margin: 0;
  font-family: var(--nd-font-display);
  font-size: var(--nd-fs-xl);
  font-weight: var(--nd-fw-regular);
  line-height: var(--nd-lh-snug-title);
  letter-spacing: var(--nd-track-title);
  color: var(--nd-ink-900);
}

/* The heading and the result line take focus from script only, to be read
   out; neither is a control, so neither draws a ring. */
.nd-promo__title:focus,
.nd-promo__result:focus { outline: none; box-shadow: none; }

.nd-promo__panel { display: grid; gap: var(--nd-s-4); }

.nd-promo__text,
.nd-promo__result {
  margin: 0;
  max-width: var(--nd-measure-short);
  color: var(--nd-ink-700);
}

.nd-promo__result { color: var(--nd-ink-900); font-weight: var(--nd-fw-medium); }
.nd-promo__result.is-error { color: var(--nd-error); }

.nd-promo__code { margin: 0; font-size: var(--nd-fs-sm); color: var(--nd-ink-700); }

.nd-promo__code-value {
  color: var(--nd-ink-900);
  font-weight: var(--nd-fw-semibold);
  letter-spacing: .04em;
}

.nd-promo__actions { display: flex; flex-wrap: wrap; gap: var(--nd-s-3); }

.nd-promo__fine {
  margin: 0;
  font-size: var(--nd-fs-xs);
  line-height: var(--nd-lh-title);
  color: var(--nd-ink-500);
}

/* ---- desktop: a centred modal over a dimmed, still page --------------- */

.nd-promo--modal {
  inset: 0;
  place-items: center;
  padding: var(--nd-s-5);
}

.nd-promo--modal .nd-promo__backdrop {
  display: block;
  position: absolute;
  inset: 0;
  background: rgba(31, 31, 29, .4);
}

.nd-promo--modal .nd-promo__dialog {
  width: min(480px, 100%);
  max-height: calc(100vh - 2 * var(--nd-s-5));
  max-height: calc(100dvh - 2 * var(--nd-s-5));
  overflow: auto;
  overscroll-behavior: contain;
  border-radius: var(--nd-r-lg);
  box-shadow: var(--nd-lift);
}

/* With a photo: the photo takes the left half, the copy the right. */
.nd-promo--modal .nd-promo__dialog--media {
  width: min(800px, 100%);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.nd-promo--modal .nd-promo__media {
  display: block;
  position: relative;
  min-height: 280px;
  background: var(--nd-tint);
}

/* Absolutely placed so the photo fills whatever height the copy needs
   without its own 1:1 box deciding the dialog's height. */
.nd-promo__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.nd-promo--modal .nd-promo__body { padding: var(--nd-s-7) var(--nd-s-6) var(--nd-s-6); }

/* While the modal is open the page behind does not scroll, and the width the
   scrollbar gave up is handed back as padding so nothing shifts sideways. */
html.nd-promo-locked {
  overflow: hidden;
  padding-inline-end: var(--nd-promo-gap, 0px);
}

/* ---- phones: a sheet at the foot of the screen, page still usable ----- */

/*
 * Not an interstitial: at most 40% of the screen, the page above it scrolls
 * and taps as normal, and the close button is a full 44px target at its top
 * corner, well clear of a chat bubble in the bottom corner.
 */
.nd-promo--sheet {
  inset: auto 0 0 0;
}

.nd-promo--sheet .nd-promo__dialog {
  max-height: 40vh;
  max-height: 40svh;
  overflow-y: auto;
  overscroll-behavior: contain;
  border-top: 1px solid var(--nd-rule);
  border-radius: var(--nd-r-lg) var(--nd-r-lg) 0 0;
  box-shadow: var(--nd-lift-up);
}

.nd-promo--sheet .nd-promo__body {
  gap: var(--nd-s-2);
  padding: var(--nd-s-3) var(--nd-gutter) calc(var(--nd-s-4) + env(safe-area-inset-bottom, 0px));
}

.nd-promo--sheet .nd-promo__close {
  top: var(--nd-s-1);
  inset-inline-end: calc(var(--nd-gutter) - var(--nd-s-3));
}

.nd-promo--sheet .nd-promo__title { font-size: var(--nd-fs-lg); line-height: var(--nd-lh-snug); }
.nd-promo--sheet .nd-promo__panel { gap: var(--nd-s-3); }
.nd-promo--sheet .nd-promo__text,
.nd-promo--sheet .nd-promo__result { font-size: var(--nd-fs-sm); line-height: var(--nd-lh-title); }
.nd-promo--sheet .nd-promo__actions { flex-wrap: nowrap; gap: var(--nd-s-2); }

.nd-promo--sheet .nd-promo__btn {
  flex: 1 1 0;
  min-width: 0;
  min-height: var(--nd-tap-min);
  padding-inline: var(--nd-s-3);
}

.nd-promo--sheet .nd-promo__fine { font-size: var(--nd-fs-micro); }

/* ---- motion: opt-in, and gone entirely under reduced motion ----------- */

@keyframes nd-promo-fade-in { from { opacity: 0; } }
@keyframes nd-promo-fade-out { to { opacity: 0; } }
@keyframes nd-promo-rise { from { opacity: 0; transform: translateY(8px); } }
@keyframes nd-promo-sink { to { opacity: 0; transform: translateY(8px); } }
@keyframes nd-promo-up { from { transform: translateY(100%); } }
@keyframes nd-promo-down { to { transform: translateY(100%); } }

@media (prefers-reduced-motion: no-preference) {
  .nd-promo--modal .nd-promo__backdrop { animation: nd-promo-fade-in var(--nd-dur-travel) var(--nd-ease-mech) both; }
  .nd-promo--modal .nd-promo__dialog { animation: nd-promo-rise var(--nd-dur-travel) var(--nd-ease-out) both; }
  .nd-promo--sheet .nd-promo__dialog { animation: nd-promo-up var(--nd-dur-travel) var(--nd-ease-mech) both; }

  .nd-promo--modal.is-leaving .nd-promo__backdrop { animation: nd-promo-fade-out var(--nd-dur-exit) var(--nd-ease-mech) both; }
  .nd-promo--modal.is-leaving .nd-promo__dialog { animation: nd-promo-sink var(--nd-dur-exit) var(--nd-ease-mech) both; }
  .nd-promo--sheet.is-leaving .nd-promo__dialog { animation: nd-promo-down var(--nd-dur-exit) var(--nd-ease-mech) both; }
}

/* An administrator's ?nd_promo=preview on a page where the offer cannot show. */
.nd-promo-note {
  position: fixed;
  inset-inline-start: var(--nd-s-4);
  bottom: var(--nd-s-4);
  z-index: 2147483640;
  max-width: min(420px, calc(100% - 2 * var(--nd-s-4)));
  margin: 0;
  padding: var(--nd-s-3) var(--nd-s-4);
  border-radius: var(--nd-r-md);
  background: var(--nd-ink-900);
  color: var(--nd-paper);
  font-size: var(--nd-fs-xs);
  line-height: var(--nd-lh-title);
}

/* ------------------------------------------------------ film phone cut -- */

/*
 * A film with a phone cut carries a second ratio, --nd-video-ratio-sm, and
 * the class .nd-video__frame--cut, both set by nilosi_dtc_video(). Below 768px
 * the frame takes that shape: the same breakpoint as the
 * <source media="(max-width: 767px)"> the browser picks the cut by, so a 9:16
 * file lands in a 9:16 box and nothing moves when it arrives. A film without
 * a cut has neither and keeps its one shape at every width.
 *
 * A 9:16 box is as tall as the screen on most phones and far taller on a
 * small tablet, so it stops at the height left under the sticky header. Past
 * that the film is letterboxed on the oat ground (base.css's contain), never
 * cropped, and the whole picture is on screen at once.
 *
 * .nd-video belongs to base.css. These rules are here because they have to
 * reach every page the component can appear on, and chrome.css is the other
 * sheet that loads everywhere.
 */
@media (max-width: 767px) {
  .nd-video__frame--cut {
    aspect-ratio: var(--nd-video-ratio-sm, var(--nd-video-ratio, 16 / 9));
    max-height: calc(100svh - var(--nd-header-h-sm));
  }
}

/* ------------------------------------------------------------ footer ---- */

/*
 * The page ends on its deepest ground: the wordmark set large, the tagline,
 * the operator line, three link columns, then the legal bar.
 */
.nd-footer {
  background: var(--nd-footer-ground);
  color: var(--nd-footer-ink);
  margin-top: 0;
  padding-block: var(--nd-rhythm-band) var(--nd-s-6);
  --nd-heading-ink: var(--nd-footer-ink);
  --nd-focus: var(--nd-footer-ink);
  --nd-focus-halo: var(--nd-footer-ground);
}

.nd-footer a {
  color: var(--nd-footer-ink-2);
  text-decoration-line: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: .22em;
  transition: text-decoration-color var(--nd-dur-snap) var(--nd-ease-mech),
              color var(--nd-dur-snap) var(--nd-ease-mech);
}

/* Under 768 the brand block spans the row and the three link columns share
   a two-column grid beneath it, Shop first. */
.nd-footer__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--nd-s-7) var(--nd-s-5);
  margin-bottom: var(--nd-s-8);
}

.nd-footer__brand { grid-column: 1 / -1; }

@media (min-width: 768px) {
  .nd-footer__grid {
    grid-template-columns: 2fr 1fr 1fr 1fr;
    gap: var(--nd-s-7);
    align-items: start;
  }

  .nd-footer__brand { grid-column: auto; }
}

/* The wordmark set large is the last image on the page, and it costs nothing
   because it is type the visitor has already downloaded. */
.nd-footer__name {
  margin: 0 0 var(--nd-s-5);
  line-height: 1;
  max-width: none;
}

.nd-mark--footer { align-items: baseline; gap: var(--nd-s-3); }

.nd-mark--footer .nd-mark__word {
  font-size: clamp(3.5rem, 9vw, 7rem);
  font-weight: var(--nd-fw-regular);
  line-height: .9;
  color: var(--nd-footer-ink);
}

.nd-mark--footer .nd-mark__paw { color: var(--nd-stage-accent); }

.nd-mark--footer .nd-mark__descriptor { color: var(--nd-footer-ink-2); }

.nd-footer__tagline {
  font-size: var(--nd-fs-base);
  line-height: var(--nd-lh-base);
  color: var(--nd-footer-ink-2);
  margin: 0 0 var(--nd-s-5);
  max-width: var(--nd-measure-short);
}

.nd-footer__operator,
.nd-footer__address,
.nd-footer__contact {
  font-size: var(--nd-fs-sm);
  line-height: 1.5;
  font-style: normal;
  color: var(--nd-footer-ink-2);
  margin: 0 0 var(--nd-s-2);
  max-width: var(--nd-measure-short);
}

/* The column title carries .nd-label from the helper; the recipe is repeated
   here so the column reads right whichever file lands first. */
.nd-footer__col-title {
  font-family: var(--nd-font);
  font-size: var(--nd-fs-micro);
  font-weight: var(--nd-fw-medium);
  line-height: var(--nd-lh-label);
  letter-spacing: var(--nd-track-micro);
  text-transform: uppercase;
  color: var(--nd-footer-ink-3);
  margin: 0 0 var(--nd-s-4);
}

.nd-footer .nd-footer__col-title.nd-label { color: var(--nd-footer-ink-3); }

.nd-footer__list {
  display: grid;
  row-gap: var(--nd-s-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nd-footer__list li { margin: 0; }

.nd-footer__list a {
  display: inline-block;
  font-size: var(--nd-fs-sm);
  line-height: 1.5;
  color: var(--nd-footer-ink-2);
}

/* An optional widget area above the legal bar. */
.nd-footer__note {
  margin-bottom: var(--nd-s-6);
  font-size: var(--nd-fs-sm);
  color: var(--nd-footer-ink-2);
}

.nd-footer__note p { max-width: var(--nd-measure); }

.nd-footer__widget-title {
  font-family: var(--nd-font);
  font-size: var(--nd-fs-micro);
  font-weight: var(--nd-fw-medium);
  line-height: var(--nd-lh-label);
  letter-spacing: var(--nd-track-micro);
  text-transform: uppercase;
  color: var(--nd-footer-ink-3);
  margin: 0 0 var(--nd-s-3);
}

/* The legal bar: copyright left, "Secure checkout" right. */
.nd-footer__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--nd-s-3) var(--nd-s-4);
  padding-top: var(--nd-s-5);
  border-top: 1px solid var(--nd-stage-rule);
}

@media (max-width: 599px) {
  .nd-footer__bar {
    flex-direction: column;
    align-items: flex-start;
  }
}

.nd-footer__copy {
  margin: 0;
  font-size: var(--nd-fs-micro);
  line-height: 1.5;
  color: var(--nd-footer-ink-3);
  max-width: none;
}

.nd-footer__secure {
  display: flex;
  gap: var(--nd-s-2);
  align-items: center;
  margin: 0;
  font-size: var(--nd-fs-xs);
  line-height: 1.5;
  color: var(--nd-footer-ink-2);
  max-width: none;
}

.nd-footer__secure-icon,
.nd-footer__secure .nd-icon { width: 16px; height: 16px; }

.nd-footer__admin-note {
  font-size: var(--nd-fs-xs);
  line-height: 1.5;
  color: var(--nd-footer-ink-2);
  border: 1px dashed var(--nd-stage-rule-strong);
  border-radius: var(--nd-r-sm);
  padding: var(--nd-s-2) var(--nd-s-3);
  margin: 0 0 var(--nd-s-2);
  max-width: var(--nd-measure-short);
}

/* ------------------------------------------------- notices and helpers -- */

.nd-notice {
  padding: var(--nd-s-3) var(--nd-s-4);
  border-radius: var(--nd-r-md);
  font-size: var(--nd-fs-sm);
  line-height: 1.5;
  max-width: none;
}

.nd-notice--info {
  background: var(--nd-accent-soft);
  color: var(--nd-ink-900);
  border: 1px solid var(--nd-green-line);
}

/*
 * An administrator-only note explaining why a section is empty. Marked out
 * clearly so nobody mistakes it for customer-facing copy.
 */
.nd-admin-note {
  padding: var(--nd-s-4);
  border: 1px dashed var(--nd-border-control);
  border-radius: var(--nd-r-md);
  background: var(--nd-tint);
  color: var(--nd-ink-500);
  font-size: var(--nd-fs-sm);
  max-width: none;
}

/*
 * A placeholder where real media has not been supplied. Deliberately plain
 * and labelled: it reads as "nothing here yet", never as product imagery.
 */
.nd-placeholder {
  display: grid;
  place-items: center;
  aspect-ratio: 1 / 1;
  border-radius: var(--nd-r-lg);
  background: var(--nd-tint);
}

.nd-placeholder__label {
  color: var(--nd-ink-500);
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
}

.nd-empty__actions { display: flex; flex-wrap: wrap; gap: var(--nd-s-3); }

/* ------------------------------------------------------------ pages ----- */

.nd-page__title { margin-bottom: var(--nd-s-4); }
.nd-page__meta { color: var(--nd-ink-500); font-size: var(--nd-fs-sm); }
.nd-page__body > * + * { margin-top: var(--nd-s-4); }

/*
 * Interior pages share one axis: the head is a rail that stays with you
 * while the body scrolls. page.php puts nd-container and nd-section on ONE
 * element, so `.nd-page > .nd-container` is the selector that matches.
 */
.nd-page__body.nd-narrow { margin-inline: 0; max-width: var(--nd-measure); }

@media (min-width: 1024px) {
  .nd-page > .nd-container {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
    column-gap: var(--nd-s-6);
    align-items: start;
  }

  .nd-page__head {
    position: sticky;
    top: calc(var(--nd-header-h) + var(--nd-s-5));
    align-self: start;
  }

  .nd-page__title { margin-bottom: 0; }
  .nd-page__body { max-width: var(--nd-measure); }
}

/* Chapters, not a continuous ribbon. */
.nd-page__body > :is(h2, h3) { margin-top: clamp(2.25rem, 4vw, 3rem); }
.nd-page__body > :is(h2, h3) + p { margin-top: var(--nd-s-3); }
.nd-page__body > :first-child { margin-top: 0; }

/* The page opens the way a section does: one rule across the full
   container, then the title. A grid row, not a border on the head, because
   the head lives in the 3fr rail. */
.nd-page > .nd-container::before {
  content: "";
  display: block;
  grid-column: 1 / -1;
  height: 1px;
  background: var(--nd-rule-strong);
  margin-bottom: var(--nd-s-5);
}

/* Imported page content can carry fixed widths and wide tables. Nothing
   inside a page body may push the document wider than the viewport. */
.nd-page__body img,
.nd-page__body iframe,
.nd-page__body video,
.nd-page__body table { max-width: 100%; }

.nd-page__body table { display: block; overflow-x: auto; }

.nd-page__body pre { overflow-x: auto; }

/* ------------------------------------------------------- pagination ----- */

.nd-pagination { padding-block: var(--nd-s-6); }

.nd-pagination .page-numbers {
  display: inline-grid;
  place-items: center;
  min-width: var(--nd-control-h-sm);
  min-height: var(--nd-control-h-sm);
  padding-inline: var(--nd-s-2);
  margin-right: var(--nd-s-2);
  border: 1px solid var(--nd-rule);
  border-radius: var(--nd-r-sm);
  color: var(--nd-ink-900);
  font-size: var(--nd-fs-sm);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}

.nd-pagination .page-numbers.current {
  background: var(--nd-accent);
  border-color: var(--nd-accent);
  color: var(--nd-accent-ink);
}

.nd-pagination .page-numbers.dots { border-color: transparent; }

/* ------------------------------------------------------ search results -- */

/* A ruled list, like the FAQ and the closer: the same idea again. */
.nd-results__for { color: var(--nd-ink-500); margin-bottom: var(--nd-s-5); }

.nd-results__for strong { color: var(--nd-ink-900); font-weight: var(--nd-fw-semibold); }

.nd-postlist {
  display: grid;
  margin-top: var(--nd-s-7);
  border-block-start: 1px solid var(--nd-rule-strong);
}

.nd-postcard {
  padding-block: var(--nd-s-5);
  border-block-end: 1px solid var(--nd-rule);
}

.nd-postcard__title {
  font-family: var(--nd-font-display);
  font-size: var(--nd-fs-lg);
  font-weight: var(--nd-fw-medium);
  line-height: var(--nd-lh-snug);
  margin: 0 0 var(--nd-s-2);
}

.nd-postcard__title a { color: var(--nd-ink-900); text-decoration: none; }

.nd-postcard__excerpt p {
  margin: 0;
  color: var(--nd-ink-500);
  max-width: var(--nd-measure);
}

/* The standalone search form on the 404 and the results page. The input
   and button take the base.css recipes; this only lays them out. */
.nd-search { display: flex; gap: var(--nd-s-2); max-width: 32em; }
.nd-search__input { flex: 1 1 auto; min-width: 0; }
.nd-search__submit { flex: 0 0 auto; }

/* --------------------------------------------------- third-party forms -- */

/*
 * Contact Form 7 ships almost no CSS of its own, so its inputs inherit
 * whatever the theme gives them. Giving them the theme's own control recipe
 * fixes the overflow at 360px and makes the form look like the storefront.
 */
.wpcf7 input[type="text"],
.wpcf7 input[type="email"],
.wpcf7 input[type="tel"],
.wpcf7 input[type="url"],
.wpcf7 input[type="number"],
.wpcf7 input[type="date"],
.wpcf7 select,
.wpcf7 textarea {
  width: 100%;
  max-width: 100%;
  min-height: var(--nd-control-h);
  padding: var(--nd-s-3) var(--nd-s-4);
  background: var(--nd-white);
  color: var(--nd-ink-900);
  border: 1px solid var(--nd-border-control);
  border-radius: var(--nd-r-md);
  font-size: var(--nd-fs-base);
}

.wpcf7 textarea { min-height: 140px; }

.wpcf7 p { max-width: none; }

.wpcf7 label { display: block; font-size: var(--nd-fs-sm); font-weight: var(--nd-fw-medium); }

.wpcf7 input[type="submit"],
.wpcf7 button[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--nd-control-h);
  padding-inline: 28px;
  background: var(--nd-accent);
  color: var(--nd-accent-ink);
  border: 1px solid var(--nd-accent);
  border-radius: var(--nd-r-md);
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
  cursor: pointer;
}

/*
 * Form controls inside page content, whoever generated them. Scoped to the
 * page body so it cannot reach WooCommerce's own forms, which have their own
 * styling in checkout.css.
 */
.nd-page__body input[type="text"],
.nd-page__body input[type="email"],
.nd-page__body input[type="tel"],
.nd-page__body input[type="url"],
.nd-page__body input[type="search"],
.nd-page__body input[type="number"],
.nd-page__body input[type="password"],
.nd-page__body input[type="date"],
.nd-page__body select,
.nd-page__body textarea {
  width: 100%;
  max-width: 100%;
  min-height: var(--nd-control-h);
  padding: var(--nd-s-3) var(--nd-s-4);
  background: var(--nd-white);
  color: var(--nd-ink-900);
  border: 1px solid var(--nd-border-control);
  border-radius: var(--nd-r-md);
  font-size: var(--nd-fs-base);
  box-sizing: border-box;
}

.nd-page__body textarea { min-height: 140px; }

.nd-page__body input[type="submit"],
.nd-page__body button[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  min-height: var(--nd-control-h);
  padding-inline: 28px;
  background: var(--nd-accent);
  color: var(--nd-accent-ink);
  border: 1px solid var(--nd-accent);
  border-radius: var(--nd-r-md);
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
  cursor: pointer;
}

/* ------------------------------------------------- scroll progress ------ */

/*
 * One hairline on the bottom edge of the sticky bar, filling left to right.
 * At rest it is scaled to nothing, which is also what a browser without
 * scroll timelines and a visitor who asked for less motion both see. The
 * ui.js fallback drives the same transform where the timeline is missing.
 */
.nd-progress {
  position: absolute;
  inset-inline: 0;
  top: auto;
  bottom: 0;
  z-index: 2;
  height: 1px;
  pointer-events: none;
  background: var(--nd-accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .nd-progress {
      animation: nd-progress linear both;
      animation-timeline: scroll(root block);
    }

    @keyframes nd-progress { to { transform: scaleX(1); } }
  }
}

/* ------------------------------------------------- chrome under hand ---- */

/* Every hover lives inside this query: iOS synthesises a hover on tap and
   holds it until you tap elsewhere. */
@media (hover: hover) and (pointer: fine) {
  .nd-action:hover,
  .nd-header__toggle:hover,
  .nd-drawer__close:hover { background: var(--nd-tint); color: var(--nd-ink-900); }

  .nd-logo__link:hover { color: var(--nd-ink-900); }

  .nd-nav__link:hover,
  .nd-nav__list a:hover { color: var(--nd-ink-900); }

  .nd-nav--desktop .nd-nav__list > li > a:hover::after { scale: 1 1; }

  .nd-nav--mobile .nd-nav__list a:hover { color: var(--nd-accent-deep); }

  .nd-hsearch__input:hover { border-bottom-color: var(--nd-ink-900); }
  .nd-hsearch__submit:hover { background: none; color: var(--nd-ink-900); text-decoration: underline; text-underline-offset: .2em; }

  .nd-footer a:hover { color: var(--nd-footer-ink); text-decoration-color: currentColor; }

  .nd-pagination .page-numbers:hover { border-color: var(--nd-ink-900); color: var(--nd-ink-900); }
  .nd-pagination .page-numbers.current:hover { border-color: var(--nd-accent); color: var(--nd-accent-ink); }

  .nd-postcard__title a:hover { color: var(--nd-accent-deep); }

  .wpcf7 input[type="submit"]:hover,
  .wpcf7 button[type="submit"]:hover,
  .nd-page__body input[type="submit"]:hover,
  .nd-page__body button[type="submit"]:hover { background: var(--nd-accent-deep); border-color: var(--nd-accent-deep); }
}

/*
 * Reduced motion: the durations are zeroed in tokens.css, so every
 * transition above is instant. The drawer and sheet still set hidden through
 * the script's fallback timer. The scale press is nulled in base.css.
 */
@media (prefers-reduced-motion: reduce) {
  .nd-drawer,
  .nd-drawer__panel,
  .nd-sticky-atc { transition: none; }
}

/*
 * The focus ring gets no transition, deliberately. An indicator that fades in
 * delays the one piece of information a keyboard user is actively waiting for.
 * Do not add one.
 */

/* ============================================================ guides ====
 *
 * The guides hub and the guide topic pages (index.php), a single guide
 * (single.php) with its related guides, the buying-guide block under a
 * category grid (woocommerce/archive-product.php), the product cards a guide
 * embeds with the [products] shortcode, and the "From our guides" list on a
 * product page. Everything reuses the tile, card and page-body recipes; only
 * layout lives here.
 */

/* Breadcrumbs on guides. The same rules as shop.css, which is not loaded
   outside the catalogue. */
.nd-crumbs {
  padding-block: var(--nd-s-4) 0;
  font-size: var(--nd-fs-xs);
  line-height: 1.5;
  color: var(--nd-ink-500);
}

.nd-crumbs ol { display: flex; flex-wrap: wrap; gap: var(--nd-s-2); margin: 0; padding: 0; list-style: none; }
.nd-crumbs li { display: inline-flex; align-items: center; gap: var(--nd-s-2); min-width: 0; }
.nd-crumbs a { color: var(--nd-ink-500); text-decoration: none; }
.nd-crumbs [aria-hidden="true"] { color: var(--nd-rule-strong); }

.nd-crumbs [aria-current="page"] {
  color: var(--nd-ink-700);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 60vw;
}

/* Lists written in the editor. The reset in base.css strips every list that
   carries a class, and the block editor gives every list one, so policy pages
   and guides lost their bullets and numbers. */
.nd-page__body :is(ul.wp-block-list, ol.wp-block-list),
.nd-page__body > :is(ul:not([class]), ol:not([class])) {
  list-style: revert;
  padding-left: 1.4em;
}

.nd-page__body :is(ul.wp-block-list, ol.wp-block-list) li + li,
.nd-page__body > :is(ul:not([class]), ol:not([class])) li + li { margin-top: var(--nd-s-2); }

.nd-page__body :is(ul.wp-block-list, ol.wp-block-list) li::marker,
.nd-page__body > :is(ul, ol) li::marker { color: var(--nd-ink-500); }

/* Links inside running text. */
.nd-page__body > :is(p, ul, ol) a:not(.nd-btn):not(.button) {
  color: var(--nd-accent-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .2em;
}

/* Product cards embedded with [products]. */
.nd-page__body > * + .woocommerce[class*="columns-"] { margin-top: var(--nd-s-5); }

.nd-page__body ul.products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 28px 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nd-page__body ul.products > li { list-style: none; margin: 0; padding: 0; min-width: 0; }
.nd-page__body ul.products .nd-plate__title { font-size: var(--nd-fs-sm); }

@media (min-width: 768px) {
  .nd-page__body ul.products { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--nd-s-6) var(--nd-s-4); }
  .nd-page__body ul.products.columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* The hub. */
.nd-guides__head {
  display: grid;
  gap: var(--nd-s-3);
  max-width: var(--nd-measure);
  margin-top: 0;
  margin-bottom: var(--nd-s-7);
}

.nd-guides__head .nd-page__title { margin: 0; }
.nd-guides__intro p { margin: 0; color: var(--nd-ink-700); }
.nd-guides__intro p + p { margin-top: var(--nd-s-3); }

.nd-guides {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--nd-s-7) var(--nd-s-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 768px) {
  .nd-guides { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .nd-guides { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.nd-guide { position: relative; min-width: 0; }
.nd-guide__tile { margin-bottom: var(--nd-s-3); }
.nd-guide__kind { margin: 0 0 6px; color: var(--nd-ink-500); }

.nd-guide__title {
  margin: 0 0 var(--nd-s-2);
  font-size: var(--nd-fs-lg);
  font-weight: var(--nd-fw-medium);
  line-height: var(--nd-lh-snug);
}

.nd-guide__title a { color: var(--nd-ink-900); text-decoration: none; }

/* The title is the card's one real link; it covers the whole card. */
.nd-guide__title a::after { content: ""; position: absolute; inset: 0; }

.nd-guide__excerpt { margin: 0; color: var(--nd-ink-500); font-size: var(--nd-fs-sm); max-width: var(--nd-measure); }

/* A guide: one column at every width. A long title does not fit the 3fr rail
   the policy pages use, and a guide is read top to bottom. */
.nd-article__kind { margin: 0 0 var(--nd-s-2); color: var(--nd-ink-500); }
.nd-article__meta { margin-top: var(--nd-s-3); }
.nd-article__media { margin: 0 0 var(--nd-s-6); }
.nd-article__more { margin-top: var(--nd-s-7); }
.nd-article .nd-page__head { margin-bottom: var(--nd-s-5); }

@media (min-width: 1024px) {
  .nd-article > .nd-container { display: block; }

  .nd-article .nd-page__head {
    position: static;
    max-width: 48rem;
    margin-bottom: var(--nd-s-6);
  }

  .nd-article .nd-page__title { margin-bottom: 0; }
}

/* The buying guide under a category grid. */
.nd-archive__guide {
  margin-top: var(--nd-s-8);
  padding-top: var(--nd-s-6);
  border-top: 1px solid var(--nd-rule-strong);
}

.nd-archive__guide .nd-page__body { max-width: var(--nd-measure); }
.nd-archive__guide .nd-page__body > :is(h2, h3) { margin-top: var(--nd-s-6); }
.nd-archive__guide .nd-page__body > :first-child { margin-top: 0; }

@media (hover: hover) and (pointer: fine) {
  .nd-crumbs a:hover { color: var(--nd-ink-900); text-decoration: underline; text-decoration-color: var(--nd-accent); text-underline-offset: .2em; }
  .nd-guide__title a:hover { color: var(--nd-accent-deep); }
  .nd-guide:hover .nd-tile { background: var(--nd-tint-deep); }
  .nd-page__body > :is(p, ul, ol) a:not(.nd-btn):not(.button):hover { color: var(--nd-ink-900); }
}

/* A topic page's introduction: the topic's own copy, which may carry a
   heading, a list or a link as well as paragraphs. */
.nd-guides__intro > * { margin: 0; }
.nd-guides__intro > * + * { margin-top: var(--nd-s-3); }

.nd-guides__intro > :is(h2, h3) {
  margin-top: var(--nd-s-5);
  font-size: var(--nd-fs-md);
  line-height: var(--nd-lh-snug);
}

.nd-guides__intro > :first-child { margin-top: 0; }
.nd-guides__intro > :is(ul, ol) { list-style: revert; padding-left: 1.4em; color: var(--nd-ink-700); }

.nd-guides__intro a {
  color: var(--nd-accent-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .2em;
}

/* "Browse by topic". The current page is filled, the way the current page
   number is. From 768 the chips wrap; on a phone see the block below. */
.nd-topics { margin: 0 0 var(--nd-s-7); min-width: 0; }
.nd-guides__head + .nd-topics { margin-top: calc(var(--nd-s-5) - var(--nd-s-7)); }
.nd-topics__title { margin: 0 0 var(--nd-s-3); }

.nd-topics__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nd-s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nd-topics__list > li { min-width: 0; max-width: 100%; }

/* position: relative keeps the chip's visually hidden count (absolutely
   positioned) inside the chip, and so inside the scrolling row on a phone;
   without it, the hidden text of off-screen chips widened the whole page. */
.nd-topics__chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--nd-s-2);
  max-width: 100%;
  min-height: var(--nd-control-h-sm);
  padding: 6px var(--nd-s-4);
  border: 1px solid var(--nd-rule-strong);
  border-radius: var(--nd-r-pill);
  color: var(--nd-ink-900);
  font-size: var(--nd-fs-sm);
  line-height: var(--nd-lh-snug);
  text-decoration: none;
  overflow-wrap: anywhere;
  transition: background-color var(--nd-dur-snap) var(--nd-ease-mech), border-color var(--nd-dur-snap) var(--nd-ease-mech);
}

.nd-topics__count {
  color: var(--nd-ink-500);
  font-size: var(--nd-fs-xs);
  font-variant-numeric: tabular-nums;
}

.nd-topics__chip[aria-current="page"] {
  background: var(--nd-accent);
  border-color: var(--nd-accent);
  color: var(--nd-accent-ink);
}

.nd-topics__chip[aria-current="page"] .nd-topics__count { color: var(--nd-accent-ink); }

/*
 * On a phone the row scrolls sideways inside itself instead of wrapping:
 * wrapped, nine topics stacked one or two pills to a line and pushed the first
 * guide some 400px down the screen. The row bleeds to both screen edges so a
 * chip cut by the edge says there is more; the page itself never gets wider
 * than the screen. The block padding is room for the focus ring, which the
 * scrolling box would otherwise clip. ui.js (initTopicChips) scrolls the
 * current topic's chip into view.
 */
@media (max-width: 767px) {
  .nd-topics__list {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--nd-gutter);
    scrollbar-width: thin;
    scrollbar-color: var(--nd-rule-strong) transparent;
    margin: -6px calc(-1 * var(--nd-gutter));
    padding: 6px var(--nd-gutter);
  }

  .nd-topics__list > li { flex: 0 0 auto; max-width: none; scroll-snap-align: start; }
  .nd-topics__chip { white-space: nowrap; }
}

/* A guide's topic, as the eyebrow over its title. The padding gives a 12px
   label a target a thumb can find without moving the title. */
.nd-article__topic {
  display: inline-block;
  padding-block: var(--nd-s-1);
  color: var(--nd-accent-deep);
  text-decoration: none;
}

/* Related guides: the hub's own cards, under a rule after the article. */
.nd-related {
  margin-top: var(--nd-s-8);
  padding-top: var(--nd-s-5);
  border-top: 1px solid var(--nd-rule-strong);
}

.nd-related__title {
  margin: 0 0 var(--nd-s-6);
  font-family: var(--nd-font-display);
  font-size: var(--nd-fs-xl);
  font-weight: var(--nd-fw-regular);
  line-height: var(--nd-lh-tight);
  letter-spacing: var(--nd-track-title);
  color: var(--nd-ink-900);
}

/* "From our guides" on a product page: titles and reading time, ruled like
   the FAQ, under the same heading treatment as the related products below. */
.nd-pguides { margin-block-start: var(--nd-rhythm-band); min-width: 0; }

.nd-pguides__title {
  margin: 0 0 var(--nd-s-6);
  padding-block-start: var(--nd-s-5);
  border-block-start: 1px solid var(--nd-rule-strong);
  font-family: var(--nd-font-display);
  font-size: var(--nd-fs-2xl);
  font-weight: var(--nd-fw-regular);
  line-height: var(--nd-lh-tight);
  letter-spacing: var(--nd-track-title);
  color: var(--nd-ink-900);
}

.nd-pguides__list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  margin: 0;
  padding: 0;
  list-style: none;
  border-block-start: 1px solid var(--nd-rule);
}

.nd-pguides__item {
  display: grid;
  gap: var(--nd-s-1);
  min-width: 0;
  padding-block: var(--nd-s-4);
  border-block-end: 1px solid var(--nd-rule);
}

.nd-pguides__link {
  justify-self: start;
  max-width: 100%;
  font-family: var(--nd-font-display);
  font-size: var(--nd-fs-md);
  font-weight: var(--nd-fw-medium);
  line-height: var(--nd-lh-snug);
  color: var(--nd-ink-900);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.nd-pguides__meta { color: var(--nd-ink-500); font-size: var(--nd-fs-xs); }

@media (min-width: 768px) {
  .nd-pguides__list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: var(--nd-s-5);
    border-block-start: 0;
  }

  .nd-pguides__item { border-block-start: 1px solid var(--nd-rule); }
}

@media (hover: hover) and (pointer: fine) {
  .nd-topics__chip:hover { border-color: var(--nd-ink-900); background: var(--nd-tint); }
  .nd-topics__chip[aria-current="page"]:hover { border-color: var(--nd-accent-deep); background: var(--nd-accent-deep); color: var(--nd-accent-ink); }
  .nd-article__topic:hover,
  .nd-pguides__link:hover { color: var(--nd-ink-900); text-decoration: underline; text-decoration-color: var(--nd-accent); text-underline-offset: .2em; }
}

/* ===================================================== guide formats ====
 *
 * What a guide written in a format adds (specs/theme-formats.md): the format
 * beside the topic, the blocks the text is written with -- short answer, tip,
 * safety note, checklist, steps, comparison table, product picks -- "Our
 * picks at a glance", "On this page", and the checklist's print sheet.
 *
 * Every rule is scoped to the guide's body, its article, or a format class on
 * the body element, so a classic guide (plain paragraphs, headings and lists)
 * renders as it did. Colours are the existing tokens; every text and ground
 * pair below was measured at 4.5:1 or better, and each is noted where it is
 * chosen.
 */

/* The format beside the topic: the label recipe on the accent's soft fill
   (accent-deep on accent-soft, 7.9:1). Inline, so a classic guide's eyebrow,
   which has none, keeps its exact box. */
.nd-article__sep { margin-inline: var(--nd-s-2); color: var(--nd-ink-500); }

.nd-article__format {
  display: inline-block;
  padding: 2px var(--nd-s-2);
  border-radius: var(--nd-r-md);
  background: var(--nd-accent-soft);
  color: var(--nd-accent-deep);
}

/* "Print this checklist" is printed hidden and shown by ui.js once it works.
   Until then it is invisible but keeps its place (visibility, not display),
   so showing it moves nothing: with display:none, the 48px button and its
   16px margin appeared after the first paint, usually, since ui.js is
   deferred, and pushed the whole article 64px down. Invisible, it is neither
   focusable nor announced. Without script the space stays empty. */
.nd-article__print { margin: var(--nd-s-4) 0 0; }
.nd-article__print-btn[hidden] { visibility: hidden; }
.nd-article__print-btn .nd-icon { width: 20px; height: 20px; }

/* A linked heading or card comes to rest clear of the sticky bar, with a
   little air above it rather than flush under the hairline: header + 24px.
   The page already carries scroll-padding-top of header + 16px (base.css),
   and a target's scroll-margin adds to it, so the margin is only the
   difference. With base.css's own header-high margin on top of that padding,
   "On this page" landed each heading about two header heights down. */
.nd-page__body :is(h2, h3)[id],
.nd-page__body .nd-pick[id] { scroll-margin-top: calc(var(--nd-s-5) - var(--nd-s-4)); }

/* ---- the short answer, tips and safety notes ------------------------- */

/*
 * Three boxes, one shape: a tinted ground, a 3px rule on the reading edge and
 * a label printed as text by inc/template-tags.php (nilosi_dtc_callout_labels()).
 *   short answer  oat ground, moss rule, 18px ink-900  (13.4:1; label 7.9:1)
 *   tip           sage ground, moss-mid rule           (ink-700 9.3:1; label 7.9:1)
 *   safety note   clay ground, brick rule and label    (ink-700 9.1:1; label 5.9:1)
 */
.nd-page__body > :is(.nd-answer, .nd-note, .nd-caution) {
  padding: var(--nd-s-4) var(--nd-s-5);
  border-left: 3px solid var(--nd-accent);
  border-radius: 0 var(--nd-r-md) var(--nd-r-md) 0;
  background: var(--nd-tint);
  color: var(--nd-ink-700);
}

.nd-page__body > * + :is(.nd-answer, .nd-note, .nd-caution),
.nd-page__body > :is(.nd-answer, .nd-note, .nd-caution) + :not(h2, h3) { margin-top: var(--nd-s-5); }

.nd-page__body :is(.nd-answer, .nd-note, .nd-caution) > * { margin: 0; }
.nd-page__body :is(.nd-answer, .nd-note, .nd-caution) > * + * { margin-top: var(--nd-s-3); }
.nd-page__body :is(.nd-answer, .nd-note, .nd-caution) > .nd-callout__label + * { margin-top: var(--nd-s-2); }

.nd-callout__label {
  font-family: var(--nd-font);
  font-size: var(--nd-fs-micro);
  font-weight: var(--nd-fw-semibold);
  line-height: var(--nd-lh-label);
  letter-spacing: var(--nd-track-micro);
  text-transform: uppercase;
  color: var(--nd-accent-deep);
}

.nd-page__body .nd-answer > p:not(.nd-callout__label) {
  font-size: var(--nd-fs-md);
  line-height: var(--nd-lh-title);
  color: var(--nd-ink-900);
}

.nd-page__body > .nd-note { background: var(--nd-tint-sage); border-left-color: var(--nd-g-500); }

.nd-page__body > .nd-caution { background: var(--nd-tint-clay); border-left-color: var(--nd-error); }
.nd-page__body .nd-caution > .nd-callout__label { color: var(--nd-error); }

/* Links inside a box read like links in running text. */
.nd-page__body :is(.nd-answer, .nd-note, .nd-caution) a:not(.nd-btn) {
  color: var(--nd-accent-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .2em;
}

/* ---- checklists --------------------------------------------------------- */

/*
 * A square mark at the start of each item: a moss tick in a soft-filled box
 * on screen, an empty box on paper (see the print sheet) so the list can be
 * ticked by hand. The mark is decoration drawn by CSS; the text is the item.
 * Gaps rather than margins between items, so a long item wraps under its own
 * text and never under the box.
 */
.nd-page__body ul.nd-checklist {
  display: grid;
  gap: var(--nd-s-3);
  padding-left: 0;
  list-style: none;
}

.nd-page__body ul.nd-checklist > li {
  position: relative;
  min-height: 1.6em;
  margin: 0;
  padding-left: 2.25rem;
}

.nd-page__body ul.nd-checklist > li + li { margin-top: 0; }

.nd-page__body ul.nd-checklist > li::before {
  content: "";
  position: absolute;
  top: .18em;
  left: 0;
  width: 1.25rem;
  height: 1.25rem;
  border: 2px solid var(--nd-accent);
  border-radius: var(--nd-r-sm);
  background: var(--nd-accent-soft) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.6 8.4l2.9 2.9 5.9-6.6' fill='none' stroke='%232F5F4E' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / .9rem no-repeat;
}

/* Lists nested in an item keep ordinary bullets. */
.nd-page__body ul.nd-checklist li :is(ul, ol) { margin-top: var(--nd-s-2); }

/* Grouped checklists: each group sits close under its own heading. */
.nd-page__body > :is(h2, h3) + :is(.nd-checklist, .nd-steps) { margin-top: var(--nd-s-3); }

/* ---- numbered steps ----------------------------------------------------- */

/*
 * The number is the mark: a Fraunces numeral on an oat tile (accent-deep on
 * oat, 7.9:1), with a hairline thread down to the next step so the sequence
 * reads at a glance. CSS counters, so the numbers survive any list styling
 * and are not announced twice (the list itself is still an ordered list).
 */
.nd-page__body ol.nd-steps {
  display: grid;
  gap: var(--nd-s-5);
  padding-left: 0;
  list-style: none;
  counter-reset: nd-step;
}

.nd-page__body ol.nd-steps > li {
  position: relative;
  min-height: 2.75rem;
  margin: 0;
  padding-left: 3.75rem;
  counter-increment: nd-step;
}

.nd-page__body ol.nd-steps > li + li { margin-top: 0; }

.nd-page__body ol.nd-steps > li::before {
  content: counter(nd-step);
  position: absolute;
  top: -.2em;
  left: 0;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--nd-r-md);
  background: var(--nd-tint);
  color: var(--nd-accent-deep);
  font-family: var(--nd-font-display);
  font-size: var(--nd-fs-lg);
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
}

.nd-page__body ol.nd-steps > li:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 2.85rem;
  bottom: calc(-1 * var(--nd-s-5) + 4px);
  left: calc(1.375rem - .5px);
  width: 1px;
  background: var(--nd-rule-strong);
}

.nd-page__body ol.nd-steps > li > strong:first-child { color: var(--nd-ink-900); }

@media (min-width: 768px) {
  .nd-page__body ol.nd-steps > li { padding-left: 4.25rem; }
}

/* ---- comparison tables -------------------------------------------------- */

/*
 * The figure is the scroller: a five-column table is wider than a phone, so
 * it scrolls sideways inside its own rounded box and the page never does.
 * The figure takes keyboard focus (tabindex, role and name are added by
 * nilosi_dtc_compare_tables()), so the base focus ring shows on it. The first
 * column -- the option being compared -- stays put while the rest scroll.
 *
 * border-collapse is separate because collapsed borders do not travel with a
 * sticky cell. Every cell paints its own ground for the same reason: a sticky
 * cell must cover what scrolls under it. Zebra rows alternate white and paper
 * (ink-700 on either, 10.4:1 or better); the header row is accent-soft with
 * ink-900 (13.3:1).
 */
.nd-page__body .nd-compare {
  max-width: 100%;
  margin-inline: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border: 1px solid var(--nd-rule);
  border-radius: var(--nd-r-lg);
  background: var(--nd-white);
  scrollbar-width: thin;
  scrollbar-color: var(--nd-rule-strong) transparent;
}

.nd-page__body > * + .nd-compare,
.nd-page__body > .nd-compare + :not(h2, h3) { margin-top: var(--nd-s-5); }

.nd-page__body .nd-compare table {
  display: table;
  width: 100%;
  max-width: none;
  margin: 0;
  overflow: visible;
  border: 0;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--nd-fs-base);
  line-height: var(--nd-lh-title);
}

.nd-page__body .nd-compare :is(thead, tbody, tfoot) { border: 0; }

/* On a phone the sticky first column is held to 7rem and every other column
   is 11rem, so one compared column at a time sits beside it and a long cell
   wraps to a few lines rather than a tall ribbon of single words. */
.nd-page__body .nd-compare :is(th, td) {
  min-width: 11rem;
  padding: var(--nd-s-3) var(--nd-s-4);
  border: 0;
  border-bottom: 1px solid var(--nd-rule);
  background: var(--nd-white);
  color: var(--nd-ink-700);
  text-align: left;
  vertical-align: top;
  font-variant-numeric: tabular-nums lining-nums;
}

.nd-page__body .nd-compare tbody tr:nth-child(even) > * { background: var(--nd-paper); }
.nd-page__body .nd-compare tbody tr:last-child > * { border-bottom: 0; }

.nd-page__body .nd-compare thead th {
  border-bottom-color: var(--nd-g-200);
  background: var(--nd-accent-soft);
  color: var(--nd-ink-900);
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-semibold);
  vertical-align: bottom;
}

.nd-page__body .nd-compare tbody th { color: var(--nd-ink-900); font-weight: var(--nd-fw-medium); }

.nd-page__body .nd-compare tr > :first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  width: 7rem;
  min-width: 7rem;
  box-shadow: inset -1px 0 0 var(--nd-rule);
  overflow-wrap: anywhere;
  hyphens: auto;
}

.nd-page__body .nd-compare thead tr > :first-child { z-index: 2; }

@media (min-width: 768px) {
  .nd-page__body .nd-compare :is(th, td) { min-width: 10rem; }
  .nd-page__body .nd-compare tr > :first-child { width: 9rem; min-width: 9rem; }
}

/* ---- product picks ------------------------------------------------------ */

/*
 * The cards [nilosi_picks] prints (inc/woocommerce.php). Under 600px a card is
 * a row -- photo left, text right -- so six picks do not make six screens of
 * photographs; from 600px two cards to a row, photo on top; on a comparison
 * page, whose measure is wider, three from 1024px. Cards in a row share a
 * height and their calls to action a baseline. A card that would be left
 * alone in its row -- a block of one, the last of three or five -- takes the
 * whole row instead of leaving half of it empty (below).
 *
 * The name link is stretched over the whole card (one tab stop, a large
 * target); the focus ring moves to the card for the same reason the shop
 * cards do it.
 */
.nd-page__body .nd-picks {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--nd-s-4);
  margin-bottom: 0;
  padding: 0;
  list-style: none;
}

.nd-page__body > * + .nd-picks { margin-top: var(--nd-s-5); }
.nd-page__body > .nd-picks + :not(h2, h3) { margin-top: var(--nd-s-6); }

.nd-pick {
  position: relative;
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  column-gap: var(--nd-s-4);
  align-items: start;
  min-width: 0;
  margin: 0;
  padding: var(--nd-s-3);
  border: 1px solid var(--nd-rule);
  border-radius: var(--nd-r-lg);
  background: var(--nd-white);
  transition: border-color var(--nd-dur-snap) var(--nd-ease-mech);
}

.nd-pick__tile { border-radius: var(--nd-r-md); }

.nd-pick__body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  height: 100%;
}

.nd-pick__title {
  margin: 0;
  font-family: var(--nd-font);
  font-size: var(--nd-fs-base);
  font-weight: var(--nd-fw-semibold);
  line-height: var(--nd-lh-snug);
  letter-spacing: 0;
  color: var(--nd-ink-900);
  text-wrap: pretty;
}

.nd-pick__title a { color: inherit; text-decoration: none; }

/* The picks list is a direct child of the body, so the running-text link
   rule above (.nd-page__body > ul a) would colour and underline the card's
   name; a card is not running text. */
.nd-page__body > .nd-picks a:not(.nd-btn):not(.button) { color: inherit; text-decoration: none; }

.nd-pick__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: var(--nd-r-lg);
}

.nd-pick__price {
  margin: 0;
  font-size: var(--nd-fs-sm);
  line-height: 1.5;
  color: var(--nd-ink-700);
  font-variant-numeric: tabular-nums;
}

.nd-pick__price del { color: var(--nd-ink-500); text-decoration: line-through; }
.nd-pick__price ins { color: var(--nd-ink-900); text-decoration: none; }

.nd-pick__why {
  margin: var(--nd-s-1) 0 0;
  font-size: var(--nd-fs-base);
  line-height: var(--nd-lh-title);
  color: var(--nd-ink-700);
}

.nd-pick__why-label { display: block; margin-bottom: 2px; }

/* Drawn like the secondary button, but not a link of its own: the stretched
   name link is what takes the tap. */
.nd-pick__cta {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  min-height: var(--nd-tap-min);
  margin: auto 0 0;
  padding: 0 var(--nd-s-4);
  border: 1px solid var(--nd-border-control);
  border-radius: var(--nd-r-md);
  color: var(--nd-ink-900);
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
  line-height: 1.2;
  transition: border-color var(--nd-dur-snap) var(--nd-ease-mech);
}

.nd-pick__stock {
  margin: auto 0 0;
  padding-top: var(--nd-s-2);
  color: var(--nd-ink-500);
  font-size: var(--nd-fs-sm);
  font-weight: var(--nd-fw-medium);
}

.nd-pick:has(a:focus-visible) {
  outline: var(--nd-focus-width) solid var(--nd-focus);
  outline-offset: var(--nd-focus-offset);
}

.nd-pick:has(a:focus-visible) a:focus-visible { outline: none; box-shadow: none; }

@media (min-width: 600px) {
  .nd-page__body .nd-picks { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .nd-pick {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    row-gap: var(--nd-s-3);
    padding: var(--nd-s-3) var(--nd-s-3) var(--nd-s-4);
  }

  .nd-pick__body { padding-inline: var(--nd-s-1); }

  /*
   * The card left over. Two to a row, a block of one or the last card of
   * three or five would sit in half a row with nothing beside it, so it takes
   * the whole row as one wide card: the photo in the first half, the text in
   * the second. Its own two columns are cut exactly like the row above -- its
   * gap is the list's gap plus both cards' padding and borders -- so the
   * photo is as wide as the photos above it and lines up under the first,
   * and the text starts under the second card's text. Equal padding all
   * round frames the photo; the call to action still sits at the bottom of
   * the text, level with the bottom of the photo when the text is shorter.
   */
  .nd-page__body .nd-picks > .nd-pick:nth-child(odd):last-child {
    grid-column: 1 / -1;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto;
    column-gap: calc(var(--nd-s-4) + 2 * (var(--nd-s-3) + 1px));
    padding-bottom: var(--nd-s-3);
  }
}

/* A block of one on a phone. A row keeps six picks from becoming six
   screens of photographs; with one pick there is nothing to keep short, so
   the card stands up as it does from 600px -- the photo across the card,
   the text under it. The photo stays square on a phone held upright (up to
   a 384px tile, about a 450px screen); on a wider screen under 600px the
   tile keeps the card's width but stops growing taller, so the card does
   not fill the screen. A cut-out photo is contained in its tile, so it is
   never cut; a tile-cover photo is cropped to fill, as on every tile.
   (inc/woocommerce.php gives such a card's photo a phone-width sizes
   value, so the larger file is the one fetched.) */
@media not all and (min-width: 600px) {
  .nd-page__body .nd-picks > .nd-pick:only-child {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--nd-s-3);
    padding-bottom: var(--nd-s-4);
  }

  .nd-page__body .nd-picks > .nd-pick:only-child :is(.nd-tile__media, .nd-tile__plate) { max-height: 24rem; }

  .nd-page__body .nd-picks > .nd-pick:only-child > .nd-pick__body { padding-inline: var(--nd-s-1); }
}

/*
 * Three to a row on a comparison page, laid on six tracks of which a card
 * takes two, so a short last row can be placed instead of left ragged:
 *
 * - every card is a standing card two tracks wide, including the last of
 *   three or five, which the two-column rule above would make wide;
 * - a last pair (two or five picks) is centred, half a column in from each
 *   side, the cards as wide as those above;
 * - a last card alone (one or four picks) takes the row as a wide card, its
 *   photo as wide as a column and its text across the other two, cut like
 *   the row above as in the two-column case.
 */
@media (min-width: 1024px) {
  .nd-format-comparison .nd-page__body .nd-picks { grid-template-columns: repeat(6, minmax(0, 1fr)); }

  .nd-format-comparison .nd-page__body .nd-picks > .nd-pick,
  .nd-format-comparison .nd-page__body .nd-picks > .nd-pick:nth-child(odd):last-child {
    grid-column: span 2;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    padding-bottom: var(--nd-s-4);
  }

  .nd-format-comparison .nd-page__body .nd-picks > .nd-pick:nth-child(3n+1):nth-last-child(2) { grid-column: 2 / span 2; }

  .nd-format-comparison .nd-page__body .nd-picks > .nd-pick:nth-child(3n+1):last-child {
    grid-column: 1 / -1;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: auto;
    column-gap: calc(var(--nd-s-4) + 2 * (var(--nd-s-3) + 1px));
    padding-bottom: var(--nd-s-3);
  }

  .nd-format-comparison .nd-page__body .nd-picks > .nd-pick:nth-child(3n+1):last-child > .nd-pick__body { grid-column: 2 / -1; }
}

@media (hover: hover) and (pointer: fine) {
  .nd-pick:hover { border-color: var(--nd-rule-strong); }
  .nd-pick:hover .nd-tile { background: var(--nd-tint-deep); }
  .nd-pick:hover .nd-pick__cta { border-color: var(--nd-ink-900); }
  .nd-page__body > .nd-picks .nd-pick:hover .nd-pick__title a { text-decoration: underline; text-decoration-color: var(--nd-accent); text-underline-offset: .2em; }
}

/* ---- our picks at a glance ---------------------------------------------- */

/* A ruled list on white: each name links to its card, its first clause in
   ink-500 under it (6.4:1). The heading is real (h2) but set as a label.

   Every row follows one rule at every width -- the name, then its clause on
   the next line -- so the rows keep one rhythm whatever the length of a
   name. (Beside the name, a clause jumped between beside and under from one
   row to the next, as the names got longer.) The 44px target is the link's
   own padding around one 24px line, 12px above and 8px below, not a 44px box
   the name is centred in: a one-line name used to float in the middle of
   that box with empty space under it, and a two-line name had none, so no two
   rows had the same gap between name and clause. Now the gap is the same 8px
   in every row. */
.nd-page__body > .nd-glance {
  padding: var(--nd-s-3) var(--nd-s-5) var(--nd-s-2);
  border: 1px solid var(--nd-rule);
  border-radius: var(--nd-r-lg);
  background: var(--nd-white);
}

.nd-page__body > * + .nd-glance,
.nd-page__body > .nd-glance + :not(h2, h3) { margin-top: var(--nd-s-5); }

.nd-glance__title {
  margin: 0 0 var(--nd-s-1);
  font-family: var(--nd-font);
  font-size: var(--nd-fs-micro);
  font-weight: var(--nd-fw-semibold);
  line-height: var(--nd-lh-label);
  letter-spacing: var(--nd-track-micro);
  text-transform: uppercase;
  color: var(--nd-ink-500);
  text-wrap: initial;
}

.nd-glance__list { display: grid; margin: 0; padding: 0; list-style: none; }

.nd-glance__item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-bottom: var(--nd-s-3);
  border-top: 1px solid var(--nd-rule);
}

.nd-glance__item:first-child { border-top: 0; }

.nd-glance__link {
  padding-block: var(--nd-s-3) var(--nd-s-2);
  color: var(--nd-ink-900);
  font-weight: var(--nd-fw-medium);
  line-height: 1.5;
  text-decoration: underline;
  text-decoration-color: var(--nd-rule-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: .2em;
}

.nd-glance__why { color: var(--nd-ink-500); font-size: var(--nd-fs-sm); line-height: var(--nd-lh-title); }

/* ---- on this page ------------------------------------------------------- */

/*
 * Under 1100px: a closed <details> block after the short answer, so it costs
 * one line until it is wanted. From 1100px, on an article that has the
 * column (nd-article--toc, set by single.php): the block goes and a sticky
 * column beside the text takes over; the reading column keeps its measure.
 * The current section is marked by ui.js (initToc) with .is-current.
 */
.nd-toc__list { margin: 0; padding: 0; list-style: none; }

.nd-toc__link {
  display: flex;
  align-items: center;
  min-height: var(--nd-tap-min);
  padding-block: var(--nd-s-2);
  color: var(--nd-ink-900);
  line-height: var(--nd-lh-snug);
  text-decoration: none;
}

.nd-toc__link.is-current { color: var(--nd-accent-deep); font-weight: var(--nd-fw-medium); }

.nd-page__body > * + .nd-toc--inline { margin-top: var(--nd-s-5); }

/* The room under the block only while it is there. From 1100px the block is
   display:none, but sibling selectors follow the document, not the screen,
   so this rule would still reach past it: in a classic guide that opens with
   two paragraphs, the second would sit 24px under the first instead of the
   16px it has today. See the 1100px block for what follows it there. The
   query is that block's exact complement rather than max-width: 1099px, so a
   fractional width between the two (a 1099.2px window at 125% scaling) does
   not show the block without its spacing. */
@media not all and (min-width: 1100px) {
  .nd-page__body > .nd-toc--inline + :not(h2, h3) { margin-top: var(--nd-s-5); }
}

.nd-toc__box {
  border: 1px solid var(--nd-rule);
  border-radius: var(--nd-r-lg);
  background: var(--nd-white);
}

.nd-toc__summary {
  display: flex;
  align-items: center;
  gap: var(--nd-s-3);
  min-height: var(--nd-control-h);
  padding: var(--nd-s-2) var(--nd-s-4);
  border-radius: var(--nd-r-lg);
  color: var(--nd-ink-900);
  font-weight: var(--nd-fw-medium);
  list-style: none;
  cursor: pointer;
}

.nd-toc__summary::-webkit-details-marker { display: none; }

.nd-toc__count { margin-left: auto; color: var(--nd-ink-500); font-size: var(--nd-fs-xs); font-weight: var(--nd-fw-regular); }

.nd-toc__summary::after {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  margin: -4px 4px 0 0;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  rotate: 45deg;
  transition: rotate var(--nd-dur-snap) var(--nd-ease-mech);
}

.nd-toc__box[open] > .nd-toc__summary::after { margin-top: 4px; rotate: -135deg; }

.nd-toc__box .nd-toc__list { padding: 0 var(--nd-s-4) var(--nd-s-2); }
.nd-toc__box .nd-toc__item { border-top: 1px solid var(--nd-rule); }

/* The column, until it is wanted, is not there at all. */
.nd-toc--rail { display: none; }

@media (min-width: 1100px) {
  .nd-article--toc .nd-toc--inline { display: none; }

  /* With the block gone, what follows it keeps the gap it would have beside
     the block's own neighbour. After a classic guide's first paragraph that
     is the base rhythm, which needs no rule. After the short answer or the
     picks at a glance -- the only other places nilosi_dtc_lead_end() puts
     the block -- it is their 24px, which a sibling rule of theirs cannot
     reach across the hidden block. */
  .nd-article--toc .nd-page__body > :is(.nd-answer, .nd-glance) + .nd-toc--inline + :not(h2, h3) { margin-top: var(--nd-s-5); }

  /* Text, a gutter track, the column, and an empty track that takes what is
     left, so the rule and the related guides keep the full width they have
     without the column. The gutter is a track rather than a column-gap so
     the empty track does not cost a second gutter's worth of text width. */
  .nd-article--toc > .nd-container {
    display: grid;
    grid-template-columns: minmax(0, var(--nd-article-measure, var(--nd-measure))) clamp(2.5rem, 5vw, 5rem) minmax(12rem, 16rem) minmax(0, 1fr);
    grid-template-areas:
      "rule rule rule rule"
      "head head head head"
      "body . toc ."
      "more more more more";
    align-items: start;
    column-gap: 0;
  }

  .nd-article--toc > .nd-container::before { grid-area: rule; }
  .nd-article--toc .nd-page__head { grid-area: head; }
  .nd-article--toc .nd-page__body { grid-area: body; }
  .nd-article--toc .nd-related { grid-area: more; }

  /* The column fills its row and the panel inside it sticks. A sticky grid
     item is held inside the whole grid container, and this container also
     holds the related guides, so a sticky column kept riding down over those
     cards after the text had ended. A panel sticking inside a column the
     height of the text stops where the text stops. The padding is room for
     the focus ring inside the scrolling panel. */
  .nd-article--toc .nd-toc--rail {
    grid-area: toc;
    align-self: stretch;
    display: block;
  }

  .nd-toc--rail .nd-toc__panel {
    position: sticky;
    top: calc(var(--nd-header-h) + var(--nd-s-5));
    max-height: calc(100vh - var(--nd-header-h) - var(--nd-s-7));
    overflow-y: auto;
    padding: 6px;
    scrollbar-width: thin;
  }

  .nd-toc--rail .nd-toc__title { margin: 0 0 var(--nd-s-2); padding-left: var(--nd-s-4); }
  .nd-toc--rail .nd-toc__list { border-left: 1px solid var(--nd-rule); }

  .nd-toc--rail .nd-toc__link {
    margin-left: -1px;
    padding: var(--nd-s-2) 0 var(--nd-s-2) var(--nd-s-4);
    border-left: 2px solid transparent;
    color: var(--nd-ink-700);
    font-size: var(--nd-fs-sm);
  }

  .nd-toc--rail .nd-toc__link.is-current { border-left-color: var(--nd-accent); color: var(--nd-ink-900); }
}

@media (hover: hover) and (pointer: fine) {
  .nd-toc__link:hover,
  .nd-glance__link:hover { color: var(--nd-ink-900); text-decoration: underline; text-decoration-color: var(--nd-accent); text-underline-offset: .2em; }
  .nd-toc__summary:hover { background: var(--nd-tint); }
}

/* ---- comparison: the wider measure -------------------------------------- */

/*
 * A comparison carries tables, so its body widens to 52rem; everything that
 * is read as text keeps the usual measure, and only the tables and the picks
 * use the extra width. With the contents column the same width is the first
 * column's maximum.
 */
.nd-format-comparison .nd-article { --nd-article-measure: 52rem; }

.nd-format-comparison .nd-article .nd-page__body.nd-narrow { max-width: var(--nd-article-measure); }

.nd-format-comparison .nd-article .nd-page__body > :not(.nd-compare):not(.nd-picks) { max-width: var(--nd-measure); }

/*
 * A comparison table in any other format -- a buying guide's summary, a how-to's
 * timings -- gets the same room. single.php marks such an article
 * nd-article--wide. In the 36em reading column a four-column table
 * (9rem + 3 x 10rem, about 624px) lost its last column behind a sideways
 * scroll even at 1440px. Here the body may widen to 52rem where the screen has
 * it, and only the tables use the extra width:
 *
 * - Everything else keeps exactly the width it has without a table. That is
 *   min(36em, 36rem, 100%): 36em in the element's own type, as base.css gives
 *   a paragraph; 36rem, which is the 36em of the 1rem body text that the
 *   column itself measured (--nd-measure alone would be read in each child's
 *   own size and let a 32px heading or the 18px short answer run wider); and
 *   100% so an image never outgrows a phone. Picks keep their two columns.
 * - A table takes the width its cells ask for (fit-content), never less than
 *   the reading column and never more than the body: a short two-column
 *   table stays flush with the text, one with longer cells or more columns
 *   widens past it, as on a comparison page. On a phone the figure is still
 *   the scroller, with the sticky first column.
 *
 * Screen only: the checklist print sheet sets its own widths.
 */
@media screen {
  .nd-article--wide { --nd-article-measure: 52rem; }

  .nd-article--wide .nd-page__body.nd-narrow { max-width: var(--nd-article-measure); }

  .nd-article--wide .nd-page__body > :not(.nd-compare) { max-width: min(var(--nd-measure), 36rem, 100%); }

  .nd-article--wide .nd-page__body > .nd-compare {
    width: fit-content;
    min-width: min(100%, 36rem);
  }
}

/* The wider text pushes the contents column to the right edge of the
   container, so up to about 1360px it runs down into the corner where the
   owner's chat bubble sits (about 60px, 20px in from the bottom right). Its
   sticky panel could end 24px above the bottom of the window, with its last
   links -- the ones a reader scrolls the panel to reach -- under the bubble.
   Here a stuck panel reaches no lower than 96px above the bottom: clear of
   the bubble with 16px to spare. Wider, the column ends well left of the bubble, and on every
   other format its 36em text keeps it there at any width. An article widened
   for its table (nd-article--wide) puts the column in the same place. */
@media (min-width: 1100px) and (max-width: 1359px) {
  .nd-format-comparison .nd-toc--rail .nd-toc__panel,
  .nd-article--wide .nd-toc--rail .nd-toc__panel { max-height: calc(100vh - var(--nd-header-h) - var(--nd-s-5) - var(--nd-s-9)); }
}

/* ---- the checklist on paper --------------------------------------------- */

/*
 * "Print this checklist" prints the article and nothing else: the header,
 * footer, promo sheet and any chat widget (all children of body other than
 * main), the breadcrumbs, the contents, related guides and the buttons go.
 * The boxes print empty, ready to tick, and an item never splits across two
 * pages.
 *
 * A comparison table stops being a scroller: paper cannot scroll, and a page
 * is only about 720px wide, under the 768px from which the screen columns
 * narrow, so a five-column table (7rem + 4 x 11rem = 816px) lost its last
 * column at the figure's edge. On paper the cells give up their minimum
 * widths and the sticky first column, and the table fits the page.
 */
@media print {
  body.nd-format-checklist { display: block; background: #fff; color: #000; }
  body.nd-format-checklist > :not(.nd-main) { display: none !important; }

  .nd-format-checklist :is(.nd-crumbs, .nd-topics, .nd-related, .nd-article__more, .nd-article__print, .nd-toc, .nd-glance, .nd-article__media, .nd-pick__tile, .nd-pick__cta) { display: none !important; }

  .nd-format-checklist .nd-article > .nd-container { display: block; max-width: none; padding: 0; }
  .nd-format-checklist .nd-article > .nd-container::before { display: none; }
  .nd-format-checklist .nd-section { padding-block: 0; }
  .nd-format-checklist .nd-page__body.nd-narrow { max-width: none; }
  .nd-format-checklist .nd-page__head { margin-bottom: 12pt; }

  .nd-format-checklist :is(h1, h2, h3, p, li) { color: #000; }
  .nd-format-checklist :is(h2, h3) { break-after: avoid; }
  .nd-format-checklist .nd-page__body a { color: inherit; text-decoration: none; }

  .nd-format-checklist ul.nd-checklist > li { break-inside: avoid; }
  .nd-format-checklist ul.nd-checklist > li::before { background: #fff; border: 1.5pt solid #000; }

  .nd-format-checklist .nd-page__body > :is(.nd-answer, .nd-note, .nd-caution) {
    break-inside: avoid;
    background: none;
    border: 1pt solid #999;
    border-left: 3pt solid #000;
  }

  .nd-format-checklist .nd-callout__label { color: #000; }
  .nd-format-checklist .nd-pick { break-inside: avoid; border-color: #999; grid-template-columns: minmax(0, 1fr); }
  /* The wide card keeps the whole row, but its photo is hidden on paper, so
     its text takes the row too instead of the photo's half. */
  .nd-format-checklist .nd-page__body .nd-picks > .nd-pick:nth-child(odd):last-child { grid-template-columns: minmax(0, 1fr); }

  .nd-format-checklist .nd-page__body .nd-compare { overflow: visible; border: 1pt solid #999; }
  .nd-format-checklist .nd-page__body .nd-compare :is(th, td) { min-width: 0; position: static; box-shadow: none; color: #000; }
  .nd-format-checklist .nd-page__body .nd-compare tr { break-inside: avoid; }
}


/* =================================================== guide discovery ====
 *
 * How a reader finds the next guide (specs/theme-formats.md §5-§7): "Search
 * the guides" on the hub and the topic pages, the "Filter by format" chips
 * under the topic chips, guide search results, and the compact guide lists on
 * product pages ("From our guides") and category pages ("Guides for ...").
 * The related guides under an article keep the hub's cards; only which
 * guides they show changed (inc/template-tags.php).
 *
 * Text and ground pairs are the existing ones: ink-900 or ink-700 on paper
 * (15.9:1 / 10.4:1), the ink-500 label and meta line on paper (5.9:1), white
 * on the accent for the current chip (7.4:1).
 */

/* "Search the guides": a visible label over a field and a button, inside the
   hub head under the introduction. The field is the base recipe (16px text,
   48px tall, so iOS does not zoom); the button is the secondary one. */
.nd-gsearch {
  display: grid;
  gap: var(--nd-s-2);
  width: 100%;
  max-width: 32rem;
  margin: var(--nd-s-2) 0 0;
}

.nd-gsearch__row { display: flex; gap: var(--nd-s-2); min-width: 0; }
.nd-gsearch__input { flex: 1 1 auto; min-width: 0; }
.nd-gsearch__submit { flex: 0 0 auto; padding-inline: var(--nd-s-5); }

/* Results of a guide search: the hub's head and cards. */
.nd-results--guides .nd-results__for { margin: 0; }
.nd-results--guides .nd-guides { margin-top: var(--nd-s-2); }

/* A chip is a tap target in its own right: 44px tall on every row of chips,
   the topic row included (it was 40). The page links under the guides get the
   same 44px; the catalogue keeps its own 40px copy of that rule in shop.css,
   which loads after this file. */
.nd-topics__chip { min-height: var(--nd-tap-min); }

.nd-pagination .page-numbers { min-width: var(--nd-tap-min); min-height: var(--nd-tap-min); }

/* "Filter by format" sits close under "Browse by topic", as one block of
   navigation, and takes the topic chips' recipe: outlined, the current
   view filled. */
.nd-topics + .nd-topics--formats { margin-top: calc(var(--nd-s-5) - var(--nd-s-7)); }

/* The compact guide list: the row is the target. The title is its one link,
   stretched over the whole row, and the focus ring is drawn inside the row so
   no scrolling or clipping parent (the category page clips its overflow) can
   cut it off. */
.nd-pguides__item { position: relative; }

.nd-pguides__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.nd-pguides__meta {
  display: flex;
  flex-wrap: wrap;
  margin: 0;
  max-width: none;
  line-height: 1.5;
}

.nd-pguides__topic { font-weight: var(--nd-fw-medium); }
.nd-pguides__sep { white-space: pre; }

.nd-pguides__item:has(.nd-pguides__link:focus-visible) {
  outline: var(--nd-focus-width) solid var(--nd-focus);
  outline-offset: calc(-1 * var(--nd-focus-width));
  border-radius: var(--nd-r-sm);
}

.nd-pguides__item:has(.nd-pguides__link:focus-visible) .nd-pguides__link:focus-visible { outline: none; box-shadow: none; }

/* Two to a row from 768, three from 1024; four on a product page that has
   four, so they share one row instead of leaving the fourth alone. */
@media (min-width: 768px) {
  .nd-pguides__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .nd-pguides__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .nd-pguides__list:has(> :nth-child(4):last-child) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* On a category page the block follows the product grid and leads into the
   category's buying guide: the same gap as that guide, and a heading one step
   below the page title. */
.nd-pguides--archive { margin-block-start: var(--nd-s-8); }
.nd-pguides--archive .nd-pguides__title { font-size: var(--nd-fs-xl); }
