/* ==========================================================================
   CraftNest — Components
   Screen 01 is the source of truth. Every component here appears unchanged on
   the homepage, shop, product, cart and support pages.
   ========================================================================== */

/* ==========================================================================
   Buttons — Instrument Sans 600, radius 6, 48px tall, five states
   ========================================================================== */

.cn-btn {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-16);
  line-height: 1;
  height: var(--cn-control);
  min-height: var(--cn-tap);
  padding-inline: var(--cn-space-6);
  border-radius: var(--cn-radius-button);
  border: 1px solid transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--cn-space-2);
  cursor: pointer;
  text-align: center;
  white-space: nowrap;
  text-decoration: none;
  transition: background var(--cn-ease), color var(--cn-ease), border-color var(--cn-ease);
  -webkit-appearance: none;
  appearance: none;
}
.cn-btn:hover { text-decoration: none; }

/* Primary — accent fill */
.cn-btn--primary {
  background: var(--cn-accent);
  border-color: var(--cn-accent);
  color: var(--cn-on-fill);
}
.cn-btn--primary:hover,
.cn-btn--primary:focus {
  background: var(--cn-accent-dark);
  border-color: var(--cn-accent-dark);
  color: var(--cn-on-fill);
}

/* Secondary — outlined ink, inverts on hover */
.cn-btn--secondary {
  background: var(--cn-paper);
  border-color: var(--cn-ink);
  color: var(--cn-ink);
}
.cn-btn--secondary:hover,
.cn-btn--secondary:focus {
  background: var(--cn-ink);
  color: var(--cn-on-fill);
}

/* Ink — solid dark, used where accent would fight a warm banner */
.cn-btn--ink {
  background: var(--cn-ink);
  border-color: var(--cn-ink);
  color: var(--cn-on-fill);
}
.cn-btn--ink:hover { background: var(--cn-ink-pressed); border-color: var(--cn-ink-pressed); color: var(--cn-on-fill); }

/* Quiet — hairline only, for tertiary actions inside cards */
.cn-btn--quiet {
  background: var(--cn-paper);
  border-color: var(--cn-line);
  color: var(--cn-ink);
}
.cn-btn--quiet:hover { border-color: var(--cn-ink); color: var(--cn-ink); }

/* Ghost — accent label, tinted wash on hover */
.cn-btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--cn-accent);
  padding-inline: var(--cn-space-4);
}
.cn-btn--ghost:hover { background: var(--cn-accent-a08); color: var(--cn-accent); }

/* On a dark band the outlined button uses a white hairline */
.cn-on-ink .cn-btn--secondary,
.cn-btn--onink {
  background: transparent;
  border-color: var(--cn-white-a30);
  color: var(--cn-on-fill);
}
.cn-on-ink .cn-btn--secondary:hover,
.cn-btn--onink:hover { background: var(--cn-white-a08); color: var(--cn-on-fill); }

/* Disabled */
/*
 * Press feedback. The file documented five button states and defined four --
 * there was no :active rule anywhere in the theme, which matters most on touch,
 * where there is no hover to fall back on.
 */
.cn-btn:not(:disabled):not([aria-disabled="true"]):active { transform: translateY(1px); }
.cn-icon-btn:not(:disabled):active,
.cn-chip:active,
.cn-segmented__option:active { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
  .cn-btn:active, .cn-icon-btn:active, .cn-chip:active, .cn-segmented__option:active { transform: none; }
}

.cn-btn:disabled,
.cn-btn[aria-disabled="true"],
.cn-btn--disabled {
  background: var(--cn-surface);
  border-color: var(--cn-line);
  color: var(--cn-graphite);
  cursor: not-allowed;
  pointer-events: none;
}

/* Loading — pressed fill plus a spinner, cursor wait */
.cn-btn.is-loading {
  background: var(--cn-accent-dark);
  border-color: var(--cn-accent-dark);
  color: var(--cn-on-fill);
  cursor: wait;
  pointer-events: none;
}
.cn-btn.is-loading::before {
  content: '';
  width: 16px; height: 16px;
  border-radius: 999px;
  border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: var(--cn-on-fill);
  animation: cn-spin 700ms linear infinite;
}
@keyframes cn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .cn-btn.is-loading::before { animation: none; }
}

/* Sizes */
.cn-btn--sm    { height: var(--cn-tap); font-size: var(--cn-fs-14); padding-inline: var(--cn-space-4); }
.cn-btn--lg    { height: var(--cn-control-l); }
/*
 * A full-width button has no neighbour to crowd, so let its label wrap. While
 * it inherited the nowrap from .cn-btn, a long label set a min-content floor
 * that the hero grid could not go under: "Get the kit, instant download" on a
 * bundle made the whole product page scroll sideways at 320px.
 */
.cn-btn--block {
  width: 100%;
  display: flex;
  white-space: normal;
  height: auto;
  min-height: var(--cn-control);
  padding-block: var(--cn-space-3);
  line-height: 1.25;
}

/* Text link styled as a button label — used for "View all" */
.cn-link-strong {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-14);
  display: inline-flex;
  align-items: center;
  gap: var(--cn-space-1);
  white-space: nowrap;
}

/* Icon button — 44px, hairline circle */
.cn-icon-btn {
  width: var(--cn-tap);
  height: var(--cn-tap);
  border: 0;
  background: transparent;
  border-radius: var(--cn-radius-badge);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--cn-ink);
  position: relative;
  padding: 0;
  transition: background var(--cn-ease);
}
.cn-icon-btn:hover { background: var(--cn-surface); }
.cn-on-ink .cn-icon-btn { color: var(--cn-on-fill); }
.cn-on-ink .cn-icon-btn:hover { background: var(--cn-white-a08); }

.cn-icon-btn--framed {
  border: 1px solid var(--cn-line);
  background: var(--cn-paper);
  box-shadow: var(--cn-shadow-arrow);
}

/* ==========================================================================
   Badges — Fredoka only, max two per image, one tilted discount
   ========================================================================== */

.cn-badge {
  font-family: var(--cn-font-badge);
  font-weight: 500;
  font-size: 13px;
  line-height: 1;
  border-radius: var(--cn-radius-badge);
  padding: 7px 14px;
  display: inline-flex;
  align-items: center;
  gap: var(--cn-space-1);
  white-space: nowrap;
  background: var(--cn-surface);
  color: var(--cn-graphite);
}
.cn-badge svg { width: 12px; height: 12px; }

.cn-badge--ink     { background: var(--cn-ink);          color: var(--cn-on-fill); }
.cn-badge--accent  { background: var(--cn-accent);       color: var(--cn-on-fill); }
.cn-badge--warm    { background: var(--cn-warm);         color: var(--cn-ink); font-weight: 600; }
.cn-badge--soft    { background: var(--cn-accent-a10);   color: var(--cn-accent-dark); }
.cn-badge--success { background: var(--cn-success-a10);  color: var(--cn-success-text); }
.cn-badge--surface { background: var(--cn-surface);      color: var(--cn-graphite); }
.cn-badge--outline { background: transparent; border: 1px solid var(--cn-line); color: var(--cn-graphite); }

/* On a dark band the neutral pills go translucent white */
.cn-on-ink .cn-badge--surface { background: var(--cn-white-a08); color: var(--cn-white-a80); }
.cn-on-ink .cn-badge--soft    { background: var(--cn-accent-a22); color: var(--cn-accent-pale); }
.cn-on-ink .cn-badge--success { background: var(--cn-success-a22); color: var(--cn-success-ink); }

/* The discount pill. The only tilted element in the whole system. */
.cn-badge--discount {
  background: var(--cn-warm);
  color: var(--cn-ink);
  font-weight: 600;
  transform: rotate(-4deg);
}

.cn-badge--sm { font-size: 12px; padding: 4px 10px; }

/* Badge stack sitting over a product image */
.cn-badges {
  position: absolute;
  top: var(--cn-space-3);
  inset-inline-start: var(--cn-space-3);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--cn-space-2);
  z-index: 2;
  pointer-events: none;
}
.cn-badges .cn-badge { padding: 6px 12px; }

/* Trust badge row */
.cn-trust {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cn-space-2);
}

/* ==========================================================================
   Stars
   ========================================================================== */

.cn-stars {
  display: inline-flex;
  gap: 1px;
  line-height: 0;
}
.cn-stars svg { width: 13px; height: 13px; }
.cn-stars--lg svg { width: 16px; height: 16px; }
.cn-stars--xl svg { width: 20px; height: 20px; }

.cn-rating {
  display: flex;
  align-items: center;
  gap: var(--cn-space-1);
  flex-wrap: wrap;
}
.cn-rating__value { font-size: var(--cn-fs-14); font-weight: 500; }
.cn-rating__count {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
}

/* Rating distribution bars */
.cn-distribution { display: flex; flex-direction: column; gap: 10px; }
.cn-distribution__row {
  display: flex;
  align-items: center;
  gap: var(--cn-space-3);
  color: var(--cn-ink);
  min-height: var(--cn-tap);
}
.cn-distribution__label {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  width: 24px;
}
.cn-distribution__track {
  flex: 1;
  height: 8px;
  background: var(--cn-surface);
  border-radius: var(--cn-radius-badge);
  overflow: hidden;
}
.cn-distribution__fill { display: block; height: 100%; background: var(--cn-warm); }
.cn-distribution__count {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
  width: 40px;
  text-align: end;
}

/* ==========================================================================
   Forms — radius 4, 48px tall, 3px accent focus ring at 15 percent
   ========================================================================== */

.cn-field {
  display: flex;
  flex-direction: column;
  gap: var(--cn-space-2);
  /* 16px between one field and the next, as every form in the design is
     drawn. Without it a help line sits straight against the next label. */
  margin-bottom: var(--cn-space-4);
}
.cn-field:last-child { margin-bottom: 0; }
/* Inside a card that already spaces its children, the gap owns the rhythm. */
.cn-authcard .cn-field,
.cn-checkout .cn-field { margin-bottom: 0; }
/*
 * ...unless the field is a direct child of the card. That gap lives on
 * `.cn-authcard form`, and Account details is the one screen whose fields sit
 * on the card itself rather than inside a form of their own, so they lost
 * their spacing and gained nothing back: NEW PASSWORD printed on the bottom
 * border of the current-password box.
 */
.cn-authcard > .cn-field { margin-bottom: var(--cn-space-4); }
.cn-authcard > .cn-field:last-child { margin-bottom: 0; }
/*
 * Two fields side by side live in their own .cn-grid. The last .cn-field in
 * that grid drops its margin, and the grid itself carried none, so the next
 * row started at the exact pixel the previous input ended -- on the contact
 * form the word TOPIC sat on the bottom border of the email box and read as
 * part of it. The grid now owns the same 16px every other field has.
 */
.cn-grid:has(> .cn-field) { margin-bottom: var(--cn-space-4); }
.cn-grid:has(> .cn-field):last-child { margin-bottom: 0; }

.cn-label,
.cn-field > label {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
}

.cn-input,
.cn-select,
.cn-textarea,
input[type="text"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="number"],
input[type="date"],
select,
textarea {
  width: 100%;
  height: var(--cn-control);
  /* 3.02:1 on paper. The shared --cn-line is 1.29:1, which is right for a
     hairline between rows and wrong for the edge of a control somebody has to
     find and click (WCAG 1.4.11). */
  border: 1px solid var(--cn-line-strong);
  border-radius: var(--cn-radius-card);
  padding: 0 14px;
  font-size: var(--cn-fs-16);
  font-family: var(--cn-font-body);
  color: var(--cn-ink);
  background: var(--cn-paper);
  transition: border-color var(--cn-ease), box-shadow var(--cn-ease);
  -webkit-appearance: none;
  appearance: none;
  min-width: 0;
}

textarea,
.cn-textarea {
  height: auto;
  min-height: 120px;
  padding: 12px 14px;
  line-height: var(--cn-lh-body);
  resize: vertical;
}

select,
.cn-select {
  padding-inline-end: 40px;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5l5-5' stroke='%234A5058' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--cn-accent);
  box-shadow: var(--cn-ring);
}

input::placeholder,
textarea::placeholder { color: var(--cn-graphite); opacity: 1; }

input:disabled, select:disabled, textarea:disabled {
  background: var(--cn-surface);
  color: var(--cn-muted);
  cursor: not-allowed;
}

.cn-field__help { font-size: var(--cn-fs-14); color: var(--cn-graphite); }
.cn-field__error { font-size: var(--cn-fs-14); color: var(--cn-warm-text); }
.cn-field.is-invalid input,
.cn-field.is-invalid select,
.cn-field.is-invalid textarea { border-color: var(--cn-warm-text); }

/* On a dark band */
.cn-on-ink input,
.cn-on-ink select,
.cn-on-ink textarea {
  background: var(--cn-white-a06);
  border-color: var(--cn-line-on-ink);
  color: var(--cn-on-fill);
}
.cn-on-ink input::placeholder { color: var(--cn-white-a60); }

/* Check and radio — 18px, accent, 44px row */
.cn-check {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--cn-tap);
  font-size: var(--cn-fs-16);
  cursor: pointer;
  margin: 0;
}
.cn-check--top { align-items: flex-start; }
.cn-check--top input { margin-top: 5px; }
.cn-check input[type="checkbox"],
.cn-check input[type="radio"] {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  accent-color: var(--cn-accent);
  margin: 0;
  padding: 0;
  height: 18px;
  border-radius: 3px;
  -webkit-appearance: auto;
  appearance: auto;
}
.cn-check input[type="radio"] { border-radius: 999px; }
.cn-check__count {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
  margin-inline-start: auto;
}

/* Range */
input[type="range"] {
  width: 100%;
  height: var(--cn-tap);
  accent-color: var(--cn-accent);
  background: transparent;
  border: 0;
  padding: 0;
  -webkit-appearance: auto;
  appearance: auto;
}
.cn-range__scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
}

/* Toggle — warm when on, because it always guards a free filter */
.cn-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--cn-space-3);
  min-height: var(--cn-tap);
  cursor: pointer;
}
.cn-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.cn-toggle__track {
  width: 44px; height: 26px;
  flex: 0 0 44px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-line);
  position: relative;
  transition: background var(--cn-ease);
}
.cn-toggle__track::after {
  content: '';
  position: absolute;
  top: 3px; inset-inline-start: 3px;
  width: 20px; height: 20px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-on-fill);
  transition: transform var(--cn-ease);
}
.cn-toggle input:checked + .cn-toggle__track { background: var(--cn-warm); }
.cn-toggle input:checked + .cn-toggle__track::after { inset-inline-start: 21px; }

/*
 * The shop's "Free files only" switch is a link, not a checkbox: one click,
 * no Apply button, and it works with JavaScript off. role="switch" carries
 * the state to a screen reader; aria-checked carries it to the stylesheet.
 */
a.cn-toggle { text-decoration: none; color: inherit; }
a.cn-toggle[aria-checked="true"] .cn-toggle__track { background: var(--cn-warm); }
a.cn-toggle[aria-checked="true"] .cn-toggle__track::after { inset-inline-start: 21px; }
a.cn-toggle:focus-visible .cn-toggle__track { outline: 2px solid var(--cn-accent); outline-offset: 2px; }
.cn-filter-group--free { padding-block-start: var(--cn-space-4); }
.cn-toggle input:focus-visible + .cn-toggle__track { outline: 2px solid var(--cn-accent); outline-offset: 2px; }

/* Segmented control — this is the licence variation swatch, restyled */
.cn-segmented {
  display: flex;
  flex-wrap: wrap;           /* a tier that will not fit moves down, see below */
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-button);
  overflow: hidden;
  background: var(--cn-paper);
}
.cn-segmented__option {
  /*
   * min-content, not zero. Three equal columns in a buy box come out at 99px
   * each, and "Commercial" needs 102 -- so the browser did exactly what it was
   * told and split the word: "Commer / cial". A tier name is never the thing
   * that should give. The row wraps to a second line instead.
   */
  flex: 1 1 auto;
  min-width: min-content;
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-14);
  background: var(--cn-paper);
  color: var(--cn-graphite);
  border: 0;
  border-inline-start: 1px solid var(--cn-line);
  padding: 8px 12px;
  min-height: var(--cn-tap);
  cursor: pointer;
  line-height: 1.3;
  transition: background var(--cn-ease), color var(--cn-ease);
}
.cn-segmented__option:first-child { border-inline-start: 0; }
/* On a wrapped row the divider would sit against the group's own edge. */
.cn-segmented__option { border-block-start: 1px solid var(--cn-line); margin-block-start: -1px; }
.cn-segmented__option:hover { background: var(--cn-surface); }
.cn-segmented__option[aria-pressed="true"],
.cn-segmented__option.is-active {
  background: var(--cn-ink);
  color: var(--cn-on-fill);
}
.cn-segmented__price {
  display: block;
  font-family: var(--cn-font-mono);
  font-size: 11px;
  letter-spacing: var(--cn-track-mono);
  font-weight: 400;
}

/* Search box with an inline icon */
.cn-searchbox {
  display: flex;
  align-items: center;
  gap: 10px;
  height: var(--cn-tap);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: 0 14px;
  background: var(--cn-paper);
  transition: border-color var(--cn-ease), box-shadow var(--cn-ease);
}
.cn-searchbox:focus-within { border-color: var(--cn-accent); box-shadow: var(--cn-ring); }
.cn-searchbox input {
  flex: 1;
  border: 0;
  height: auto;
  padding: 0;
  background: transparent;
  font-size: 15px;
}
.cn-searchbox input:focus { box-shadow: none; }
.cn-searchbox--lg { height: 56px; padding-inline: 18px; }
.cn-searchbox--lg input { font-size: var(--cn-fs-16); }

/* ==========================================================================
   Cards
   ========================================================================== */

.cn-card {
  background: var(--cn-paper);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-6);
}
.cn-card--flush { padding: 0; overflow: hidden; }
.cn-card--pad32 { padding: var(--cn-space-8); }
.cn-card--pad48 { padding: var(--cn-space-12); }
.cn-card--surface { background: var(--cn-surface); }
.cn-card--accent  { border-color: var(--cn-accent); box-shadow: 0 8px 24px var(--cn-accent-a10); }
.cn-card--hover { transition: box-shadow var(--cn-ease); }
.cn-card--hover:hover { box-shadow: var(--cn-shadow-hover); }
.cn-on-ink .cn-card {
  background: rgba(255, 255, 255, .04);
  border-color: var(--cn-white-a16);
  color: var(--cn-on-fill);
}

/* Corner ticks, featured cards only */
.cn-card--ticked { position: relative; }
.cn-card--ticked::before,
.cn-card--ticked::after {
  content: '';
  position: absolute;
  top: 6px;
  width: 14px; height: 14px;
  border-top: 1px solid var(--cn-accent);
  z-index: 3;
  pointer-events: none;
}
.cn-card--ticked::before { inset-inline-start: 6px;  border-inline-start: 1px solid var(--cn-accent); }
.cn-card--ticked::after  { inset-inline-end: 6px; border-inline-end: 1px solid var(--cn-accent); }

/* Stat tile — big Instrument Sans number over a mono caption */
.cn-stat {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-6);
}
.cn-stat__value {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-44);
  letter-spacing: var(--cn-track-tight);
  line-height: 1;
}
.cn-stat__label {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  margin-top: var(--cn-space-2);
}

/* Feature tile — square icon well over a title and one line of copy */
.cn-feature__icon {
  width: 40px; height: 40px;
  border-radius: var(--cn-radius-card);
  background: var(--cn-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--cn-space-4);
}
.cn-feature__icon svg { width: 20px; height: 20px; }

/* Numbered step, used inside Banner A */
.cn-step { position: relative; }
.cn-step__dot {
  width: 48px; height: 48px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-paper);
  border: 1px solid var(--cn-line);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--cn-space-4);
  position: relative;
  z-index: 1;
}
.cn-step__title {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-20);
  margin-bottom: var(--cn-space-2);
}
.cn-step p { margin: 0; color: var(--cn-graphite); max-width: 300px; }

/* ==========================================================================
   Section header — eyebrow, H2, view all link, one hairline underneath
   ========================================================================== */

.cn-section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--cn-space-6);
  flex-wrap: wrap;
  border-bottom: 1px solid var(--cn-line);
  padding-bottom: var(--cn-space-4);
  margin-bottom: var(--cn-space-8);
}
.cn-section-head--baseline { align-items: baseline; }
.cn-section-head h2,
.cn-section-head h3 { margin: 0; }
.cn-on-ink .cn-section-head { border-bottom-color: var(--cn-white-a18); }

/* ==========================================================================
   Accordion — hairline rows, plus and minus in accent
   ========================================================================== */

.cn-accordion { border-top: 1px solid var(--cn-line); }
.cn-accordion__item { border-bottom: 1px solid var(--cn-line); }
.cn-accordion__summary {
  padding: var(--cn-space-5) 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--cn-space-6);
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-18);
  min-height: var(--cn-tap);
}
.cn-accordion__summary::after {
  content: '+';
  color: var(--cn-accent);
  font-size: var(--cn-fs-20);
  line-height: 1;
  flex: 0 0 auto;
}
.cn-accordion__item[open] > .cn-accordion__summary::after { content: '–'; }
/* The split summary carries a mono meta column instead of a plus and minus.
   This has to out-specify the [open] rule above or the glyph comes back. */
.cn-accordion__summary--split::after,
.cn-accordion__item[open] > .cn-accordion__summary--split::after { content: none; }
.cn-accordion__body {
  padding-bottom: var(--cn-space-5);
  color: var(--cn-graphite);
  max-width: 560px;
}
.cn-accordion__body p:last-child { margin-bottom: 0; }
.cn-accordion__summary--split { font-size: 17px; padding-block: 18px; }
.cn-accordion__meta {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
}

/* File tree — the accordion built from the downloadable file repeater */
.cn-filetree__label {
  display: flex;
  align-items: center;
  gap: var(--cn-space-3);
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: 17px;
}
.cn-filetree__files {
  padding: 0 0 18px 30px;
  display: flex;
  flex-direction: column;
  gap: var(--cn-space-2);
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
}

/* ==========================================================================
   Chips — mono, pill, hairline. Filters, categories, review sorters.
   ========================================================================== */

.cn-chip {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  background: var(--cn-paper);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-badge);
  height: 40px;
  padding: 0 16px;
  display: inline-flex;
  align-items: center;
  gap: var(--cn-space-2);
  cursor: pointer;
  transition: border-color var(--cn-ease), color var(--cn-ease), background var(--cn-ease);
}
.cn-chip:hover { border-color: var(--cn-ink); color: var(--cn-ink); }
.cn-chip--active,
.cn-chip[aria-current="true"] {
  background: var(--cn-ink);
  border-color: var(--cn-ink);
  color: var(--cn-on-fill);
}
/* Two active looks, and the design uses both: a solid ink pill for the blog
   category chips, an accent outline for the sort chips on the reviews wall.
   The second selector is here so an explicit accent chip is not overridden by
   the aria-current rule above. */
.cn-chip--accent,
.cn-chip--accent[aria-current="true"] {
  background: var(--cn-accent-a08);
  border-color: var(--cn-accent);
  color: var(--cn-accent);
}
.cn-chip--warm { border-color: var(--cn-warm-text); color: var(--cn-warm-text); }
.cn-chip--tall { height: var(--cn-tap); padding-inline: 18px; }
.cn-chip--sm   { height: 36px; padding-inline: 14px; }
.cn-chip__remove {
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  padding: 0;
  font-size: 14px;
  line-height: 1;
}
.cn-chips { display: flex; gap: var(--cn-space-2); flex-wrap: wrap; align-items: center; }

/* ==========================================================================
   Breadcrumb and pagination
   ========================================================================== */

.cn-breadcrumb {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  display: flex;
  gap: var(--cn-space-2);
  flex-wrap: wrap;
}
.cn-breadcrumb__current { color: var(--cn-ink); }

.cn-pagination {
  display: flex;
  gap: var(--cn-space-2);
  align-items: center;
  flex-wrap: wrap;
}
.cn-pagination a,
.cn-pagination span.page-numbers {
  min-width: var(--cn-tap);
  height: var(--cn-tap);
  padding-inline: var(--cn-space-2);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--cn-ink);
  font-weight: 500;
  transition: border-color var(--cn-ease), background var(--cn-ease);
}
.cn-pagination a:hover { border-color: var(--cn-ink); }
/* .page-numbers has to be in this selector too. Without it the rule above,
   `.cn-pagination span.page-numbers`, is the more specific of the two and the
   current page rendered ink on accent blue: 3.7:1, and not what screen 04
   draws either, which is white on blue. */
.cn-pagination .page-numbers.current {
  background: var(--cn-accent);
  border-color: var(--cn-accent);
  color: var(--cn-on-fill);
}
.cn-pagination .dots {
  border: 0;
  color: var(--cn-graphite);
  min-width: auto;
}
/* Same specificity trap as .current above: `.cn-pagination span.page-numbers`
   would otherwise keep the arrow in ink and it would read as live. Screen 04
   greys it to #C6C4BF. It is an inactive control and aria-hidden, so it is
   outside 1.4.3 and 1.4.11. */
.cn-pagination .page-numbers.cn-pagination__disabled { color: var(--cn-disabled-line); }

/* ==========================================================================
   Toast
   ========================================================================== */

.cn-toast {
  position: fixed;
  left: 50%;
  bottom: var(--cn-space-6);
  transform: translateX(-50%);
  z-index: var(--cn-z-toast);
  display: inline-flex;
  align-items: center;
  gap: var(--cn-space-4);
  background: var(--cn-ink);
  color: var(--cn-on-fill);
  border-radius: var(--cn-radius-button);
  padding: 14px 18px;
  box-shadow: var(--cn-shadow-toast);
  font-size: 15px;
  max-width: calc(100vw - 32px);
}
.cn-toast a { color: var(--cn-on-fill); text-decoration: underline; font-family: var(--cn-font-display); font-weight: 600; font-size: var(--cn-fs-14); }
.cn-toast[hidden] { display: none; }

/* ==========================================================================
   Tables — mono body, surface header row, hairline rows, horizontal scroll
   ========================================================================== */

.cn-table-wrap {
  /*
   * Positioned so that absolutely positioned descendants are clipped here
   * rather than by the page. The licence table's tick marks each carry a 1px
   * screen-reader span; with no positioned ancestor inside the scroller, those
   * spans took their containing block from far up the tree, escaped this box
   * and stretched the document 262px wide at 390. A page that scrolls sideways
   * on a phone because of a hidden pixel is the hardest kind of bug to see.
   */
  position: relative;
  overflow-x: auto;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  -webkit-overflow-scrolling: touch;
}
.cn-table { width: 100%; border-collapse: collapse; min-width: 720px; }
.cn-table thead tr { background: var(--cn-surface); }
.cn-table th {
  text-align: start;
  padding: 14px 16px;
  border-bottom: 1px solid var(--cn-line);
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  font-weight: 400;
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  white-space: nowrap;
}
.cn-table td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--cn-line);
  font-size: 15px;
}
.cn-table tbody tr:last-child td { border-bottom: 0; }
.cn-table--mono tbody {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
}
.cn-table td.is-yes { color: var(--cn-success); }
.cn-table td.is-no  { color: var(--cn-graphite); }

/* The cookie table lives inside a 680px reading column, so it is allowed to
   wrap rather than forcing a horizontal scroller onto a legal page.
   The name column is the exception. A cookie name is an identifier, not prose,
   and letting it break anywhere squeezed the column to 76px on a phone, which
   sliced every name into four-letter pieces -- WOOC / OMME / RCE_ / CART /
   _HAS / H. It now keeps enough width for the longest name the shop sets and
   breaks only at the underscores; the wrapper scrolls if the rest no longer
   fits beside it. */
.cn-table--cookies { min-width: 0; }
.cn-table--cookies td,
.cn-table--cookies th { padding: 12px 14px; vertical-align: top; }
.cn-table--cookies td:first-child,
.cn-table--cookies th:first-child {
  min-width: 190px;
  word-break: normal;
  overflow-wrap: normal;
}

/* ==========================================================================
   Marquee — one helper, four variants, pauses on hover, stops when reduced
   ========================================================================== */

.cn-marquee {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 80px, #000 calc(100% - 80px), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 80px, #000 calc(100% - 80px), transparent);
}
.cn-marquee__track {
  display: flex;
  gap: var(--cn-space-6);
  padding-inline-end: var(--cn-space-6);
  width: max-content;
  animation: cn-marquee var(--cn-marquee-duration, 60s) linear infinite;
}
.cn-marquee__track--reverse { animation-name: cn-marquee-reverse; }
.cn-marquee:hover .cn-marquee__track,
.cn-marquee:focus-within .cn-marquee__track { animation-play-state: paused; }

/*
 * The shift is one set, not half the track: the script repeats the set as many
 * times as the frame needs and writes the matching percentage into
 * --cn-marquee-shift. 50% stays the fallback for the two-copy case.
 */
@keyframes cn-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-1 * var(--cn-marquee-shift, 50%))); }
}
@keyframes cn-marquee-reverse {
  from { transform: translateX(calc(-1 * var(--cn-marquee-shift, 50%))); }
  to   { transform: translateX(0); }
}

/* Two review rows stack with nothing between them, so they touched. */
.cn-marquee--second { margin-top: var(--cn-space-6); }

/* Reduced motion, and the mobile fallback, both become a snap scroller. */
@media (prefers-reduced-motion: reduce) {
  .cn-marquee { -webkit-mask-image: none; mask-image: none; overflow-x: auto; scroll-snap-type: x mandatory; }
  .cn-marquee__track { animation: none !important; width: auto; }
  .cn-marquee__track > * { scroll-snap-align: start; }
  .cn-marquee__track > .cn-marquee__clone { display: none; }
}
/*
 * On a phone the strips keep moving, so this block no longer turns them into
 * a swipe-only scroller -- it only tightens the spacing and drops the edge
 * mask, which at 390px ate a fifth of the row. A finger can still drag the
 * strip; the animation pauses on touch through the pointer rules above.
 */
@media (max-width: 780px) {
  .cn-marquee { -webkit-mask-image: none; mask-image: none; padding-inline: var(--cn-gutter); }
  .cn-marquee__track { gap: var(--cn-space-3); }
  .cn-marquee__arrow { display: none; }
}

/* Variant 1 — announcement ticker */
.cn-ticker {
  background: var(--cn-ink);
  color: var(--cn-on-fill);
  position: relative;
}
/*
 * The headlines scroll all the way to the edge and pass behind the dismiss,
 * which sliced words in half against the button -- "COMMER x L". Fading the
 * last stretch into the band lets a headline leave the screen instead of being
 * cut by a control sitting on top of it. Under the button, so the cross stays
 * on its own disc.
 */
.cn-ticker::after {
  content: '';
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  width: 96px;
  background: linear-gradient(to right, rgba(14, 17, 22, 0), var(--cn-ink) 70%);
  pointer-events: none;
  z-index: 1;
}
.cn-ticker__dismiss { z-index: 2; }
[dir="rtl"] .cn-ticker::after {
  background: linear-gradient(to left, rgba(14, 17, 22, 0), var(--cn-ink) 70%);
}
.cn-ticker .cn-marquee {
  height: 40px;
  display: flex;
  align-items: center;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 60px, #000 calc(100% - 60px), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 60px, #000 calc(100% - 60px), transparent);
}
.cn-ticker .cn-marquee__track {
  gap: 64px;
  padding-inline-end: 64px;
  white-space: nowrap;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
}
.cn-ticker__dismiss {
  position: absolute;
  inset-inline-end: var(--cn-space-4);
  top: 8px;
  width: 24px; height: 24px;
  border: 0;
  /*
   * A disc behind it on every screen, not only the small ones. The ticker
   * scrolls underneath this button, so with a transparent background the
   * cross landed on top of moving words -- "COMMERCIA×L" -- and read as a
   * rendering fault rather than a control. The band is one flat colour, so
   * the disc is invisible where there is no text and hides the text where
   * there is.
   */
  background: var(--cn-ink);
  border-radius: 50%;
  color: var(--cn-on-fill);
  cursor: pointer;
  line-height: 1;
}
/*
 * The disc stays 24px, which is all the band's height allows without the
 * cross looking like a button on a shelf. The area you can hit is larger than
 * the area you can see: a thumb aiming at a 24px cross on a moving strip
 * misses often enough to be annoying, and nothing else is under here to catch
 * by accident.
 */
.cn-ticker__dismiss::after {
  content: '';
  position: absolute;
  inset: -8px;
  border-radius: 50%;
}
/*
 * The disc stays 24px because a bigger one would swallow the headline behind
 * it, but 24px is half a thumb. An invisible pad around it brings the target
 * to 44px without changing anything anyone can see.
 */
.cn-ticker__dismiss::before {
  content: '';
  position: absolute;
  inset: -10px;
}
@media (max-width: 780px) {
  .cn-ticker .cn-marquee { padding-inline: var(--cn-space-4); }
  .cn-ticker .cn-marquee__track { gap: 32px; }
}

/* Variant 2 — category strip with arrows */
.cn-catstrip {
  position: relative;
  border-top: 1px solid var(--cn-line);
  border-bottom: 1px solid var(--cn-line);
  padding-block: var(--cn-space-5);
}
.cn-catstrip .cn-marquee__track { gap: var(--cn-space-4); padding-inline-end: var(--cn-space-4); }

/* Two rows: the same gap between them as between the cards along them. */
.cn-catstrip--stacked { display: grid; gap: var(--cn-space-4); }
.cn-cat-card {
  flex: 0 0 230px;
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-4);
  display: flex;
  gap: var(--cn-space-3);
  align-items: center;
  background: var(--cn-paper);
  color: var(--cn-ink);
  transition: box-shadow var(--cn-ease);
}
.cn-cat-card:hover { box-shadow: var(--cn-shadow-hover); color: var(--cn-ink); }
.cn-cat-card__icon {
  flex: 0 0 48px;
  width: 48px; height: 48px;
  border-radius: var(--cn-radius-card);
  background: var(--cn-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-accent);
  overflow: hidden;
}
.cn-cat-card__icon img { width: 100%; height: 100%; object-fit: cover; }
.cn-cat-card__name { display: block; font-weight: 500; font-size: 15px; }
.cn-cat-card__count {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
}

.cn-marquee__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: var(--cn-tap);
  height: var(--cn-tap);
  border-radius: var(--cn-radius-badge);
  border: 1px solid var(--cn-line);
  background: var(--cn-paper);
  box-shadow: var(--cn-shadow-arrow);
  cursor: pointer;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--cn-ink);
  font-size: 18px;
  line-height: 1;
}
.cn-marquee__arrow--prev { inset-inline-start: var(--cn-space-4); }
.cn-marquee__arrow--next { inset-inline-end: var(--cn-space-4); }

/* The arrows are declared after the mobile block above, so the hide has to be
   repeated here or the later base rule wins on specificity ties. */
@media (max-width: 780px) {
  .cn-marquee__arrow { display: none; }
}

/* Variant 3 — product row, cards are 260px */
.cn-marquee--products .cn-marquee__track > * { flex: 0 0 260px; }

/* Variant 4 — testimonial row, cards are 380px */
.cn-marquee--reviews .cn-marquee__track > * { flex: 0 0 380px; }
@media (max-width: 600px) {
  .cn-marquee--reviews .cn-marquee__track > * { flex: 0 0 300px; }
  .cn-marquee--products .cn-marquee__track > * { flex: 0 0 220px; }
}

/* Testimonial card */
.cn-quote {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-6);
  background: var(--cn-paper);
  transition: box-shadow var(--cn-ease);
}
.cn-quote:hover { box-shadow: var(--cn-shadow-card); }
.cn-quote__text { margin: var(--cn-space-3) 0 var(--cn-space-4); font-size: var(--cn-fs-16); }
.cn-quote__who { display: flex; gap: var(--cn-space-3); align-items: center; }
.cn-quote__avatar {
  width: 36px; height: 36px;
  flex: 0 0 36px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, rgba(14, 17, 22, .07) 0 4px, transparent 4px 8px);
  overflow: hidden;
}
.cn-quote__avatar img { width: 100%; height: 100%; object-fit: cover; }
.cn-quote__name { display: block; font-size: var(--cn-fs-14); font-weight: 500; }
.cn-quote__shot {
  flex: 0 0 44px;
  width: 44px;
  aspect-ratio: 1;
  border-radius: 2px;
  overflow: hidden;
  background: var(--cn-preview);
  background-image: repeating-linear-gradient(135deg, var(--cn-ink-a06) 0 5px, transparent 5px 10px);
}
.cn-quote__shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cn-quote__bought-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cn-quote__bought:hover { color: var(--cn-ink); }
.cn-quote__bought {
  display: flex;
  align-items: center;
  gap: var(--cn-space-3);
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  margin-top: var(--cn-space-3);
  border-top: 1px solid var(--cn-line);
  padding-top: var(--cn-space-3);
}

/* ==========================================================================
   Banner shells A to E — three colour variants each, interchangeable slots
   ========================================================================== */

.cn-banner {
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-12);
}
.cn-banner h2,
.cn-banner h3 { margin-top: 0; }

/* Colour variants */
.cn-banner--surface {
  background: var(--cn-surface);
  border: 1px solid var(--cn-line);
}
.cn-banner--ink {
  background-color: var(--cn-ink);
  color: var(--cn-on-fill);
  background-image:
    linear-gradient(var(--cn-white-a08) 1px, transparent 1px),
    linear-gradient(90deg, var(--cn-white-a08) 1px, transparent 1px);
  background-size: var(--cn-grid-size) var(--cn-grid-size);
}
.cn-banner--warm {
  background: var(--cn-warm-a10);
  border: 1px solid var(--cn-warm-a35);
}
.cn-banner--ink p,
.cn-banner--ink ul,
.cn-banner--ink ol,
.cn-banner--ink .cn-muted { color: var(--cn-white-a72); }
/* The placeholder tile has to darken with the band, or an ink banner ends up
   with a bright grey hole in the middle of it. */
.cn-banner--ink .cn-placeholder {
  background-color: var(--cn-ink-100);
  background-image: repeating-linear-gradient(135deg, var(--cn-white-a06) 0 8px, transparent 8px 16px);
}
.cn-banner--ink .cn-step__dot { background: var(--cn-white-a06); border-color: var(--cn-white-a20); }
.cn-banner--ink .cn-step__dot svg [stroke] { stroke: var(--cn-on-fill); }
.cn-banner--warm .cn-step__dot { background: var(--cn-warm); border-color: var(--cn-warm); }
.cn-banner--warm .cn-step__dot svg [stroke] { stroke: var(--cn-on-fill); }
.cn-banner--warm .cn-placeholder {
  background-color: var(--cn-preview-warm);
  background-image: repeating-linear-gradient(135deg, var(--cn-warm-a16) 0 8px, transparent 8px 16px);
}
.cn-banner--warm .cn-card { border-color: var(--cn-warm-a30); }

/* Banner A — the three step explainer, joined by one hairline */
.cn-banner-a__steps { position: relative; }
.cn-banner-a__steps::before {
  content: '';
  position: absolute;
  top: 24px;
  left: 16%;
  right: 16%;
  height: 1px;
  background: var(--cn-line);
}
.cn-banner--ink  .cn-banner-a__steps::before { background: var(--cn-white-a18); }
.cn-banner--warm .cn-banner-a__steps::before { background: rgba(255, 122, 47, .4); }
@media (max-width: 780px) {
  .cn-banner-a__steps::before { display: none; }
  .cn-banner-a__steps { display: flex; flex-direction: column; gap: var(--cn-space-5); }
  .cn-step { display: flex; gap: var(--cn-space-4); }
  .cn-step__dot { flex: 0 0 44px; width: 44px; height: 44px; margin-bottom: 0; }
}

/* Banner B — bundle upsell, media left, value stack right */
.cn-banner-b {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: var(--cn-space-12);
  align-items: center;
}
.cn-banner-b__price {
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  flex-wrap: wrap;
}
.cn-banner-b__now {
  font-family: var(--cn-font-display);
  font-weight: 600;
  font-size: var(--cn-fs-44);
  letter-spacing: var(--cn-track-tight);
}
.cn-banner-b__was {
  font-size: var(--cn-fs-20);
  color: var(--cn-graphite);
  text-decoration: line-through;
}
.cn-banner--ink .cn-banner-b__was { color: var(--cn-white-a55); }

/* Banner C — licence explainer, three tiers, the middle one lifted */
.cn-banner-c__tiers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: var(--cn-space-4);
}
.cn-tier {
  background: var(--cn-paper);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-6);
  position: relative;
}
.cn-tier__name { font-family: var(--cn-font-display); font-weight: 600; font-size: var(--cn-fs-20); }
.cn-tier__meta {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
  color: var(--cn-graphite);
  margin: var(--cn-space-2) 0 var(--cn-space-3);
}
.cn-tier p { margin: 0; color: var(--cn-graphite); }
.cn-tier--featured {
  border-color: var(--cn-accent);
  box-shadow: 0 8px 24px var(--cn-accent-a10);
}
.cn-tier__flag {
  position: absolute;
  top: -12px;
  inset-inline-start: var(--cn-space-6);
  padding: 5px 12px;
}
.cn-banner--ink .cn-tier {
  background: rgba(255, 255, 255, .04);
  border-color: var(--cn-white-a16);
}
.cn-banner--ink .cn-tier--featured { background: var(--cn-accent-a16); border-color: var(--cn-accent); }
.cn-banner--ink .cn-tier p { color: var(--cn-white-a72); }
.cn-banner--ink .cn-tier__meta { color: var(--cn-white-a60); }
.cn-banner--warm .cn-tier--featured { border-color: var(--cn-warm); box-shadow: none; }
.cn-banner--warm .cn-tier--featured .cn-tier__flag { background: var(--cn-warm); color: var(--cn-on-fill); font-weight: 600; }

/* Banner D — formats and compatibility */
.cn-banner-d {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-12);
  flex-wrap: wrap;
}
.cn-format-list {
  display: flex;
  gap: var(--cn-space-3);
  flex-wrap: wrap;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  text-transform: uppercase;
}
.cn-format {
  border: 1px solid var(--cn-line);
  background: var(--cn-paper);
  border-radius: var(--cn-radius-card);
  padding: 14px 18px;
  color: var(--cn-ink);
}
.cn-banner--ink .cn-format { background: transparent; border-color: var(--cn-white-a20); color: var(--cn-on-fill); }
.cn-banner--warm .cn-format { border-color: var(--cn-warm-a30); }

/* Banner E — free sample capture */
.cn-banner-e {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: var(--cn-space-12);
  align-items: center;
}
.cn-banner-e__form { display: flex; gap: var(--cn-space-3); flex-wrap: wrap; }
.cn-banner-e__form input { flex: 1; min-width: 240px; }
.cn-banner-e__tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--cn-space-3); }
.cn-banner-e__tiles > * { aspect-ratio: 1; }

@media (max-width: 600px) {
  .cn-banner { padding: var(--cn-space-8) var(--cn-space-4); }
}

/* ==========================================================================
   Modal, lightbox and drawer scaffolding
   ========================================================================== */

.cn-overlay {
  position: fixed;
  inset: 0;
  background: var(--cn-ink-a60);
  z-index: var(--cn-z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--cn-space-6);
}
.cn-overlay[hidden] { display: none; }
.cn-overlay--dark { background: var(--cn-ink-a92); z-index: var(--cn-z-lightbox); padding: var(--cn-space-12); }

.cn-modal {
  /*
   * Positioned so it paints above the transparent scrim button that precedes
   * it. Without this the scrim -- absolutely positioned, inset 0 -- sat over
   * the whole dialog, and every click on the stars, the textarea or Submit
   * closed the modal instead. .cn-drawer__panel and .cn-sheet are positioned
   * already, which is why only this one had it.
   */
  position: relative;
  background: var(--cn-paper);
  border-radius: var(--cn-radius-card);
  max-width: 560px;
  width: 100%;
  max-height: 90vh;
  overflow: auto;
}
.cn-modal__head,
.cn-modal__foot {
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  padding: var(--cn-space-6);
}
.cn-modal__head { justify-content: space-between; border-bottom: 1px solid var(--cn-line); }
.cn-modal__foot { justify-content: flex-end; border-top: 1px solid var(--cn-line); flex-wrap: wrap; }
.cn-modal__body { padding: var(--cn-space-6); display: flex; flex-direction: column; gap: var(--cn-space-5); }
.cn-modal__close {
  width: var(--cn-tap); height: var(--cn-tap);
  border: 0; background: transparent;
  cursor: pointer; font-size: var(--cn-fs-20);
  color: var(--cn-graphite);
}

.cn-dropzone {
  border: 1px dashed var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-6);
  text-align: center;
  color: var(--cn-graphite);
  font-size: 15px;
}

/* Bottom sheet, mobile filters. The wrapper carries the scrim so the grid
   behind dims the way it is drawn, and a tap outside closes the sheet. */
.cn-sheet-wrap {
  position: fixed;
  inset: 0;
  z-index: var(--cn-z-modal);
}
.cn-sheet-wrap[hidden] { display: none; }

.cn-sheet {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  background: var(--cn-paper);
  border-top: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-sheet) var(--cn-radius-sheet) 0 0;
  padding: var(--cn-space-4);
  box-shadow: var(--cn-shadow-sheet);
  max-height: 85vh;
  overflow: auto;
}
.cn-sheet__handle {
  width: 40px; height: 4px;
  background: var(--cn-line);
  border-radius: var(--cn-radius-badge);
  margin: 0 auto var(--cn-space-4);
}

/* ==========================================================================
   Cookie consent bar — screen 13c
   A hairline band, not a modal: it never blocks the page or the shop.
   ========================================================================== */

.cn-consent-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  /*
   * Under the modal layer, not over it. At toast level the bar covered the
   * cart drawer's Checkout button on a 390px screen -- a first-time visitor
   * could not check out until they answered it -- and painted over the lower
   * half of an aria-modal dialog.
   */
  z-index: calc(var(--cn-z-modal) - 1); background: var(--cn-paper);
  border-top: 1px solid var(--cn-line);
  box-shadow: var(--cn-shadow-sticky);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  /*
   * Never more than a third of the screen. On a 320x568 phone this bar stood
   * 310px tall, and with the ticker, the header and the sticky buy bar the
   * page itself was left about ninety pixels -- a first-time visitor saw the
   * breadcrumb and nothing else. Capping it in viewport units means it stays
   * proportionate whatever the shop writes in it, and the copy scrolls inside
   * the bar rather than pushing the page off the screen. svh, so a phone
   * browser's collapsing address bar does not change the answer mid-scroll.
   */
  max-height: 34svh;
  display: flex;
  overscroll-behavior: contain;
}

@supports not (height: 1svh) {
  .cn-consent-bar { max-height: 34vh; }
}

/*
 * The words scroll, the buttons do not. Capping the whole bar pushed Accept
 * below its own fold, so answering the cookie question needed a scroll inside
 * a strip a third of the screen tall.
 */
.cn-consent-bar__inner {
  min-height: 0;
  /*
   * A column once the copy no longer shares a line with the buttons. As a
   * wrapping row the buttons became a second line that the capped bar simply
   * cut off -- present, painted, and not reachable at 320.
   */
  flex-direction: column;
  align-items: stretch;
  gap: var(--cn-space-4);
}
.cn-consent-bar__copy { overflow-y: auto; min-height: 0; }
.cn-consent-bar__actions { flex-shrink: 0; }

@media (min-width: 900px) {
  .cn-consent-bar__inner { flex-direction: row; align-items: center; gap: var(--cn-space-6); }
}
.cn-consent-bar__inner {
  max-width: var(--cn-max);
  margin-inline: auto;
  padding: var(--cn-space-5) var(--cn-gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-6);
  flex-wrap: wrap;
}
.cn-consent-bar__copy { flex: 1; min-width: 280px; }
.cn-consent-bar__copy p {
  margin: 0;
  color: var(--cn-graphite);
  max-width: 720px;
  font-size: 15px;
}
.cn-consent-bar__actions {
  display: flex;
  gap: var(--cn-space-3);
  flex-wrap: wrap;
}

@media (max-width: 600px) {
  .cn-consent-bar__inner { padding: var(--cn-space-4); gap: var(--cn-space-3); }
  .cn-consent-bar__actions { width: 100%; }
  .cn-consent-bar__actions .cn-btn { flex: 1; }
}

/* The sticky product bar and the consent bar can both be present, so the
   product bar steps up out of the way rather than sitting underneath.
   The step is the bar's measured height, published as --cn-consent-h by
   theme.js: 84px is only true of the one-row desktop bar, and on a phone the
   bar is 226px to 310px tall, which left Add to cart entirely covered. The
   84px stays as the fallback for the moment before the script runs. */
.cn-consent-bar ~ .cn-stickybar,
body:has(.cn-consent-bar) .cn-stickybar { bottom: var(--cn-consent-h, 84px); }

/* ==========================================================================
   Empty state
   ========================================================================== */

.cn-empty {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-16) var(--cn-space-8);
  text-align: center;
}
.cn-empty__icon {
  width: 48px; height: 48px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto var(--cn-space-5);
}
.cn-empty p { margin: 0 auto var(--cn-space-6); color: var(--cn-graphite); max-width: 420px; }

/* ==========================================================================
   Numbered step list — the compact aside version, screen 16b
   ========================================================================== */

.cn-steplist { display: flex; flex-direction: column; gap: var(--cn-space-4); }
.cn-steplist__item { display: flex; gap: 14px; }
.cn-steplist__n {
  flex: 0 0 32px;
  width: 32px; height: 32px;
  border-radius: var(--cn-radius-badge);
  background: var(--cn-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  color: var(--cn-accent);
}
.cn-steplist__title { display: block; font-weight: 500; }
.cn-steplist__body { font-size: 15px; color: var(--cn-graphite); }

/* Dropzone. The input sits inside the label, so the whole panel is the
   control and a keyboard reaches it without any script. */
.cn-dropzone {
  display: block;
  cursor: pointer;
  /* It is a <label>, so the field label styling would make it mono caps.
     The design draws it as a plain sentence. */
  font-family: var(--cn-font-body);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--cn-graphite);
}
.cn-dropzone:focus-within { border-color: var(--cn-accent); outline: 2px solid var(--cn-accent); outline-offset: 2px; }
.cn-dropzone input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.cn-dropzone__names { display: block; margin-top: var(--cn-space-2); color: var(--cn-ink); font-size: 14px; }

/* A row of small links inside a card — recent requests, licence documents */
.cn-minirow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cn-space-4);
  min-height: var(--cn-tap);
  padding-block: var(--cn-space-2);
  border-bottom: 1px solid var(--cn-line);
}
.cn-minirow:last-child { border-bottom: 0; }
.cn-minirow,
.cn-minirow:hover { color: var(--cn-ink); }
.cn-minirow:hover .cn-minirow__name { text-decoration: underline; }
.cn-minirow__name { display: block; font-size: 15px; font-weight: 500; }
.cn-minirow__meta { display: block; }
.cn-minirow__price { font-weight: 500; white-space: nowrap; }
.cn-dropzone.is-over { border-color: var(--cn-accent); background: var(--cn-accent-a08); }

/* ==========================================================================
   Print — the receipt, the licence, the order
   ==========================================================================
   A shop selling commercial licences gets printed: a business buyer files the
   licence terms, and somebody claiming the purchase back prints the order.
   Without this the page arrives with the sticky header over the first line,
   the consent bar across the middle, and the ink bands emptying a colour
   cartridge to say something the reader already has on screen.

   Link URLs are printed after the link text inside the article body only.
   Doing it everywhere turns a nav list into a wall of addresses; doing it
   nowhere makes a printed licence reference sources the reader cannot reach.
   ========================================================================== */

@media print {

  .cn-header,
  .cn-footer,
  .cn-consent-bar,
  .cn-drawer,
  .cn-drawer__scrim,
  .cn-sheet-wrap,
  .cn-sheet,
  .cn-toast,
  .cn-marquee,
  .cn-newsletter,
  .cn-skip-link,
  .cn-pagination,
  .cn-account-nav,
  .cn-banner,
  .cn-banner-b,
  /* These three were written against class names the theme does not emit:
     .cn-toc (it is .cn-contents), .cn-btn--wishlist (it is .cn-product__wish
     and .cn-gallery__wish) and .cn-product-row / .cn-share, which match
     nothing at all. A printed licence page carried the sticky contents rail
     down the side of it and every product card printed its heart. */
  .cn-with-sidebar > aside,
  .cn-contents,
  .cn-product__wish,
  .cn-gallery__wish,
  .cn-gallery__zoom,
  .cn-density,
  form.cn-newsletter__form,
  .woocommerce-ordering,
  .cn-filters {
    display: none !important;
  }

  /* Anything that scrolls on screen has to unroll on paper. */
  .cn-table-wrap { overflow: visible !important; border: 0; }
  .cn-table { min-width: 0 !important; }

  html, body {
    background: #fff !important;
    color: #000 !important;
    font-size: 11pt;
  }

  .cn-main { padding: 0 !important; }

  .cn-shell,
  .cn-article-shell,
  .cn-article-shell--legal,
  .cn-with-sidebar {
    display: block !important;
    max-width: none !important;
    width: auto !important;
    padding-inline: 0 !important;
    margin: 0 !important;
    grid-template-columns: none !important;
  }

  /* Ink bands cost a cartridge and say nothing a printed page needs. */
  .cn-band--ink,
  .cn-band--warm,
  .cn-hero,
  [class*="--ink"] {
    background: #fff !important;
    color: #000 !important;
  }

  .cn-card,
  .cn-table th,
  .cn-table td {
    border-color: #bbb !important;
    background: #fff !important;
  }

  /* Keep a row, a card and a heading with what follows them. */
  tr, .cn-card, .cn-download { page-break-inside: avoid; break-inside: avoid; }
  h1, h2, h3 { page-break-after: avoid; break-after: avoid; }

  a { text-decoration: underline; color: #000 !important; }

  .cn-prose a[href^="http"]::after,
  .cn-article a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    word-break: break-all;
  }

  /* A download button on paper is a dead rectangle; its label still reads. */
  .cn-btn {
    border: 1px solid #bbb !important;
    background: #fff !important;
    color: #000 !important;
    padding: 4px 8px !important;
  }

  img { max-width: 100% !important; }
}

/* ==========================================================================
   Touch targets

   The design draws these controls small on purpose and they should stay that
   size. What they should not stay is hard to hit: a 24px dismiss button on a
   phone is roughly half the 44px a fingertip needs, and this one sits directly
   on top of scrolling marquee text, so a miss reads as "the ticker ate my tap".
   Growing the hit area with a pseudo-element leaves every drawn pixel where it
   was and makes the pressable region 44px square.
   ========================================================================== */

@media (pointer: coarse), (max-width: 780px) {

  /*
   * Only the controls that are otherwise statically positioned. The ticker
   * dismiss, both wish hearts and the gallery zoom are already absolute, and
   * restating position here reset them to relative -- which took the ticker's
   * cross out of the band, dropped it onto its own line and pushed it 16px off
   * the left edge of the screen, because `inset-inline-end: 16px` then read as
   * a relative offset rather than a placement. An absolutely positioned
   * element is already a containing block for its ::after, so it needs nothing
   * from this rule.
   */
  .cn-chip,
  .cn-breadcrumb a,
  .cn-footer__list a {
    position: relative;
  }

  .cn-ticker__dismiss::after,
  .cn-product__wish::after,
  .cn-gallery__wish::after,
  .cn-gallery__zoom::after,
  .cn-chip::after,
  .cn-breadcrumb a::after,
  .cn-footer__list a::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    /*
     * min-width/min-height, not max() against a percentage. The percentage
     * resolves against the control's own box, and hit testing a point six
     * pixels above a 32px footer link showed the pad was not there -- it was
     * computing to the control's own size. These two lines say the same thing
     * unambiguously: never smaller than the control, never smaller than 44.
     */
    width: 100%;
    height: 100%;
    min-width: var(--cn-tap);
    min-height: var(--cn-tap);
    transform: translate(-50%, -50%);
    /*
     * Above the neighbours. Without this the pad is painted inside the
     * control's own box order and a later sibling's background sits on top of
     * the part that overhangs, so hit testing six pixels above a footer link
     * still landed on the link above it -- the pad existed and caught nothing.
     */
    z-index: 1;
  }

}

/* Payment marks — see inc/payment-icons.php for what these are and are not. */
.cn-pay {
  display: inline-flex;
  align-items: center;
  line-height: 0;
}
.cn-pay__mark {
  width: 40px;
  height: 25px;
  display: block;
}
.cn-pay--word {
  font-family: var(--cn-font-mono);
  font-size: var(--cn-fs-12);
  letter-spacing: var(--cn-track-mono);
  color: var(--cn-graphite);
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: 6px 10px;
  line-height: 1;
}

/* ==========================================================================
   Editor note
   --------------------------------------------------------------------------
   Only ever shown to somebody who can edit the page: a block from the previous
   theme that could not be drawn. Warm rather than red, because nothing is
   broken -- one block simply has no home here yet.
   ========================================================================== */

.cn-note {
  border: 1px solid var(--cn-line);
  border-radius: var(--cn-radius-card);
  padding: var(--cn-space-4) var(--cn-space-5);
  margin-block: var(--cn-space-5);
  font-size: var(--cn-fs-14);
  color: var(--cn-graphite);
  background: var(--cn-surface);
}
.cn-note strong { color: var(--cn-ink); font-family: var(--cn-font-mono); }
.cn-note--warn {
  background: var(--cn-warm, var(--cn-surface));
  border-color: var(--cn-ink-a06, var(--cn-line));
}

/*
 * Touch targets on a phone.
 *
 * A link inside a sentence is exempt from the minimum target size and left
 * alone. cn-link-strong is not that: it is a standalone call to action at the
 * end of a card or a section, and on a phone it measured under 30px tall.
 */
@media (max-width: 780px) {
  .cn-link-strong {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
  }
}
