@charset "UTF-8";
/*------------------------------------*\
	RESET
\*------------------------------------*/
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
}

body {
  margin: 0;
  min-height: 100vh;
}

body, h1, h2, h3, h4,
p, figure, blockquote, dl, dd {
  margin-block-start: 0;
  margin-block-end: 0;
}

h1, h2, h3, h4 {
  text-wrap: pretty;
}

ul,
ol {
  margin: unset;
  padding: unset;
  list-style: none;
}

a:not([class]) {
  text-decoration-skip-ink: auto;
}

img,
picture {
  display: block;
  max-width: 100%;
  height: auto;
}

input, button,
textarea, select {
  font-family: inherit;
  font-size: inherit;
}

button {
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
}

button:disabled, button[aria-disabled=true],
input:disabled,
input[aria-disabled=true],
select:disabled,
select[aria-disabled=true],
textarea:disabled,
textarea[aria-disabled=true] {
  cursor: not-allowed;
}

a[aria-disabled=true] {
  cursor: not-allowed;
}

fieldset {
  border: none;
  padding: 0;
}

textarea {
  max-width: 100%;
  box-sizing: border-box;
}

textarea:not([rows]) {
  min-height: 10em;
}

:where([popover]) {
  border: none;
  padding: 0;
}

:target {
  scroll-margin-block: 5ex;
}

/*------------------------------------*\
	MEDIA QUERY

	Wraps content in the appropriate media query.

	Usage:
	.block {
		@include media-query('768') { ... }
	}

	Available aliases:
	portrait, landscape
	768, 768-plus
	900, 900-plus
	1024, 1024-plus
	1440, 1440-plus
	1920, 1920-plus
\*------------------------------------*/
/*------------------------------------*\
	GRID
\*------------------------------------*/
.grid {
  display: grid;
  grid-column: 1/-1;
  row-gap: var(--grid-gap, 25px);
  column-gap: var(--grid-gap, 25px);
  width: 100%;
}

.grid--in-cell {
  grid-column: auto;
}

.grid--1 {
  grid-template-columns: 100%;
}

.grid--2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media screen and (max-width: 767px) {
  .grid--2 {
    grid-template-columns: 100%;
  }
}
.grid--3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media screen and (max-width: 767px) {
  .grid--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.grid--4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

@media screen and (max-width: 767px) {
  .grid--4 {
    grid-template-columns: 100%;
  }
}
.grid--5 {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

@media screen and (max-width: 767px) {
  .grid--5 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.grid--6 {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

@media screen and (max-width: 1024px) {
  .grid--6 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media screen and (max-width: 767px) {
  .grid--6 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.grid--split {
  grid-template-columns: var(--grid-columns, 1fr 1fr);
}

.grid--2-1 {
  grid-template-columns: 2fr 1fr;
}

.grid--1-2 {
  grid-template-columns: 1fr 2fr;
}

@media screen and (max-width: 1024px) {
  .grid--split, .grid--2-1, .grid--1-2 {
    grid-template-columns: 100%;
  }
}
.grid--center {
  align-items: center;
}

.grid--align-start {
  align-items: start;
}

/*------------------------------------*\
	BREATHE — vertical-rhythm utility
\*------------------------------------*/
.breathe {
  display: block;
}

.breathe:not([class*=breathe--]) {
  margin-top: 24px;
  margin-bottom: 24px;
}

.breathe[style*="--breathe-top"] {
  margin-top: var(--breathe-top);
}

.breathe[style*="--breathe-bottom"] {
  margin-bottom: var(--breathe-bottom);
}

.breathe--top {
  margin-top: 24px !important;
}

.breathe--top-tiny {
  margin-top: 4px !important;
}

.breathe--top-mini {
  margin-top: 8px !important;
}

.breathe--top-small {
  margin-top: 12px !important;
}

.breathe--top-large {
  margin-top: 40px !important;
}

.breathe--top-huge {
  margin-top: 64px !important;
}

.breathe--top-auto {
  margin-top: auto !important;
}

.breathe--bottom {
  margin-bottom: 24px !important;
}

.breathe--bottom-tiny {
  margin-bottom: 4px !important;
}

.breathe--bottom-mini {
  margin-bottom: 8px !important;
}

.breathe--bottom-small {
  margin-bottom: 12px !important;
}

.breathe--bottom-large {
  margin-bottom: 40px !important;
}

.breathe--bottom-huge {
  margin-bottom: 64px !important;
}

.breathe--bottom-auto {
  margin-bottom: auto !important;
}

/*------------------------------------*\
	IMAGES
\*------------------------------------*/
/*------------------------------------*\
	TRANSITIONS
\*------------------------------------*/
.hover-zoom {
  display: block;
  overflow: hidden;
}

.hover-zoom img {
  transition: all 300ms ease;
  width: 100%;
  height: auto;
}

.hover-zoom:hover img {
  transform: scale(1.08);
}

.img--cover {
  object-fit: cover;
  width: 100%;
  height: 100%;
}

.img--contain {
  object-fit: contain;
  width: 100%;
  height: 100%;
}

/*------------------------------------*\
	VISIBILITY
\*------------------------------------*/
.is-hidden {
  display: none;
}

@media screen and (max-width: 767px) {
  .is-hidden--mobile {
    display: none !important;
  }
}
@media screen and (max-width: 1024px) {
  .is-hidden--tablet {
    display: none !important;
  }
}
@media screen and (min-width: 1025px) {
  .is-hidden--desktop {
    display: none !important;
  }
}
@media (orientation: portrait) {
  .is-hidden--portrait {
    display: none !important;
  }
}
@media (orientation: landscape) {
  .is-hidden--landscape {
    display: none !important;
  }
}
/*------------------------------------*\
	HOVER

	Generates hover, focus, and active states.
	Pass $include-active: true to also include
	:active and .is-active states.
\*------------------------------------*/
/*------------------------------------*\
	BACKGROUND

	Shorthand for rgba background with opacity.

	Usage: @include background($dark-charcoal, 0.8);
\*------------------------------------*/
@font-face {
  font-family: "Ubuntu Local";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  ascent-override: 95.8%;
  descent-override: 19.6%;
  line-gap-override: 0%;
  src: url("../fonts/ubuntu-300-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Ubuntu Local";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  ascent-override: 95.8%;
  descent-override: 19.6%;
  line-gap-override: 0%;
  src: url("../fonts/ubuntu-300-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Ubuntu Local";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  ascent-override: 96.2%;
  descent-override: 18.9%;
  line-gap-override: 0%;
  src: url("../fonts/ubuntu-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Ubuntu Local";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  ascent-override: 96.2%;
  descent-override: 18.9%;
  line-gap-override: 0%;
  src: url("../fonts/ubuntu-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Ubuntu Local";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  ascent-override: 98.8%;
  descent-override: 20.5%;
  line-gap-override: 0%;
  src: url("../fonts/ubuntu-500-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Ubuntu Local";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  ascent-override: 98.8%;
  descent-override: 20.5%;
  line-gap-override: 0%;
  src: url("../fonts/ubuntu-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Ubuntu Local";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  ascent-override: 96.3%;
  descent-override: 22.1%;
  line-gap-override: 0%;
  src: url("../fonts/ubuntu-700-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Ubuntu Local";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  ascent-override: 96.3%;
  descent-override: 22.1%;
  line-gap-override: 0%;
  src: url("../fonts/ubuntu-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins Local";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  ascent-override: 105.3%;
  descent-override: 56.4%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-300-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Poppins Local";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  ascent-override: 105.3%;
  descent-override: 56.4%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-300-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins Local";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  ascent-override: 106.5%;
  descent-override: 57.2%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-400-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Poppins Local";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  ascent-override: 106.5%;
  descent-override: 57.2%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-400-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins Local";
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  ascent-override: 107.7%;
  descent-override: 58.2%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-500-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Poppins Local";
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  ascent-override: 107.7%;
  descent-override: 58.2%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-500-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins Local";
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  ascent-override: 109.1%;
  descent-override: 59.3%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-600-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Poppins Local";
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  ascent-override: 109.1%;
  descent-override: 59.3%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-600-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins Local";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  ascent-override: 105.3%;
  descent-override: 56.4%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-300-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Poppins Local";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  ascent-override: 105.3%;
  descent-override: 56.4%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-300-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins Local";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  ascent-override: 106.5%;
  descent-override: 57.2%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Poppins Local";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  ascent-override: 106.5%;
  descent-override: 57.2%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins Local";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  ascent-override: 107.7%;
  descent-override: 58.2%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-500-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Poppins Local";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  ascent-override: 107.7%;
  descent-override: 58.2%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins Local";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  ascent-override: 109.1%;
  descent-override: 59.3%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-600-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Poppins Local";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  ascent-override: 109.1%;
  descent-override: 59.3%;
  line-gap-override: 0%;
  src: url("../fonts/poppins-600-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
body {
  background-color: var(--bg-page);
  color: var(--text-body);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  interpolate-size: allow-keywords;
}

/*------------------------------------*\
	INTERACTION

	Approved on the product page mockup (MPG9) before being written here.

	Every hover state on this brand changes a COLOUR — text, background or
	border — and nothing moves. No lift, no scale. That follows the shape law:
	a control is a flat square thing, and a control that rises off the page is
	pretending to be a surface.

	So the layer is a fade at --motion-quick, and the one transform the brand
	will use (a disclosure marker turning, once authored) will run at the
	same rate, so the whole page shares one tempo.
\*------------------------------------*/
a,
.button,
button,
summary,
input,
select {
  transition: color var(--motion-quick) var(--motion-ease), background-color var(--motion-quick) var(--motion-ease), border-color var(--motion-quick) var(--motion-ease);
}

details::details-content {
  block-size: 0;
  overflow: hidden;
  transition: block-size var(--motion-quick) var(--motion-ease), content-visibility var(--motion-quick) var(--motion-ease) allow-discrete;
}

details[open]::details-content {
  block-size: auto;
}

a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
select:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-quick: 0ms;
    --motion-standard: 0ms;
  }
}
/* ── Notice bar ─────────────────────────────────────────────────────── */
.site-head__alerts {
  background: var(--bg-notice);
  color: var(--text-on-brand);
}

.site-head__alerts p {
  max-width: var(--site-max-width);
  margin: 0 auto;
  padding: 10px var(--gutter-small);
  color: var(--text-on-brand);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  text-align: center;
}

/* The ticker's words sit optically centred in the band. Their line box is
   centred already; Poppins carries more room above its capitals than below
   the baseline, so the capitals rode 3px high — 16px of band above them, 22px
   below (measured 2026-10-10, desktop and phone alike). The link moves, not
   the item, so the dividers between items stay on the band's centre line. */
.announcement-bar__link {
  position: relative;
  top: 3px;
}

/* ── Header bar ─────────────────────────────────────────────────────── */
.site-head__main {
  background: var(--bg-chrome);
}

.site-head__main__inner {
  display: flex;
  align-items: stretch;
  max-width: var(--site-max-width);
  margin: 0 auto;
  padding-left: var(--gutter-small);
}

.site-nav {
  display: flex;
  flex: 1;
  align-items: center;
  gap: 32px;
}

.site-nav__burger {
  display: none;
}

.site-nav__logo {
  display: flex;
  align-items: center;
  padding: 14px 0;
}

.pg-logo {
  display: block;
  width: auto;
  height: 38px;
}

/* The phone header's mark — the hexagon from the media library (mobile_logo),
   an <img> at its file's 512px unless sized. The wordmark's height, so the
   header bar keeps its depth. */
.site-nav__logo--mobile img {
  display: block;
  width: auto;
  height: 38px;
}

.site-nav__menu {
  display: flex;
  gap: 34px;
  margin-inline: auto;
}

.site-nav__menu__item {
  padding: 0;
  border: 0;
  background: none;
  color: var(--neutral-400);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
  text-transform: uppercase;
  cursor: pointer;
}

/*
 * The chevron is drawn, not an icon — the network markup carries no element for it.
 *
 * Scoped to `button` so it only appears on items that actually open something.
 * header.php renders a <button popovertarget> when a menu item HAS children and
 * a plain <a href> when it does not, so the tag is already the truth about
 * whether there is a panel behind it. Unscoped, every item wore a dropdown arrow
 * and every click just navigated — the arrow promised a menu that did not exist.
 * All three of this site's nav items have zero children today.
 *
 * Correct under both readings of that, which is why it is the tag and not a
 * hand-maintained list: if the design intends those items to be dropdowns, they
 * gain children, header.php emits buttons, and the chevrons come back on their
 * own. Nothing here needs revisiting either way.
 */
button.site-nav__menu__item {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

button.site-nav__menu__item::after {
  display: block;
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-3.5px) rotate(45deg);
  content: "";
}

.site-nav__menu__item:hover {
  color: var(--text-on-brand);
}

/* ── Header actions ─────────────────────────────────────────────────── */
/* The geometry of these controls is the PARENT's — box size, icon size, spacing
 * and the basket count's placement all come from
 * framework-v2/global/scss/layouts/_site-head.scss. This layer sets colour.
 *
 * What used to be here, and why none of it survives: a 66px box (the parent's
 * --action-box is 44px, the WCAG AAA target, and every brand now gets it), an
 * `align-items: stretch` that made the boxes full header height, and a
 * `border: 0; background: none; cursor: pointer` reset that the global `button`
 * reset in core/_reset.scss has always performed.
 *
 * THE SEARCH BOX IS THE EXCEPTION, and on purpose (operator, 2026-11-10: its
 * dark grey is "meant to extend to the top and bottom edge of the nav bar, and be
 * square"). It is a panel of the bar, not a control sitting on it: it stretches
 * to the bar's full height and takes the same width, so it is square at whatever
 * height the bar is. The icon inside keeps the parent's size and centring.
 */
.site-head__actions__search {
  align-self: stretch;
  aspect-ratio: 1;
  background: var(--bg-chrome-deep);
}

/* Shared with .footer__cta .icon below — same size/colour for both inline SVG symbols.
 *
 * ⚠ `.site-head__main`, NOT `.site-head`. The search modal moved inside the
 * header on 2026-09-21 so it could anchor to the header's bottom edge, and it is
 * a SIBLING of `__main`, not a descendant. Scoped one level up, this rule painted
 * the modal's own icons white — and the submit magnifier sits on a white field,
 * so the search button was invisible on every page of the site. Same specificity
 * as the framework's `.search-form__submit .icon`, brand sheet loads second, brand
 * won. Every header icon is inside `__main` (camcom-v2/header.php:39), which is
 * how Nerdworks and ARTSABERS already scope this.
 */
.site-head__main .icon,
.footer__cta .icon {
  fill: var(--text-on-brand);
}

/* Footer keeps its own size; the header's comes from the parent's --icon-size.
 * The 22px this used to set on both, plus a 26px exception for the search
 * magnifier, was this brand routing around --icon-size rather than using it —
 * `.site-head__main .icon` is two classes against the global primitive's one, so
 * it won silently and the lever looked broken. Header icons are 24px now, the
 * same as every other brand. */
.footer__cta .icon {
  width: 22px;
  height: 22px;
}

.site-head__actions__basket__count {
  background: var(--color-brand);
  color: var(--text-on-brand);
  font-family: var(--ff-body);
}

/* ── Footer ─────────────────────────────────────────────────────────── */
.footer {
  background: var(--bg-chrome);
  color: var(--text-on-chrome);
}

.footer__cta {
  background: var(--color-brand);
}

.footer__cta__inner {
  display: flex;
  gap: 18px;
  align-items: center;
  justify-content: center;
  max-width: var(--site-max-width);
  margin: 0 auto;
  padding: 18px var(--gutter-small);
}

.footer__cta__link,
.footer__cta__follow,
.footer__cta__sep,
.footer__cta__social {
  color: var(--text-on-brand);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  text-decoration: none;
}

.footer__cta__link,
.footer__cta__follow {
  font-size: 22px;
}

.footer__cta__social {
  display: inline-flex;
  align-items: center;
}

/* Icon sizing/colour shared with .site-head__main .icon above. */
.footer__inner {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: var(--space-content-gap);
  max-width: var(--site-max-width);
  margin: 0 auto;
  padding: 44px var(--gutter-small);
}

.footer__columns {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-content-gap);
}

.footer__columns__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer__columns__list .title {
  margin: 0 0 12px;
  color: var(--text-on-brand);
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
}

.footer__columns__list .link {
  color: var(--text-on-chrome);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: 2;
  text-decoration: none;
}

.footer__columns__list .link:hover {
  color: var(--text-on-brand);
}

.footer__promo {
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: flex-end;
  text-align: right;
}

.pg-logo--footer {
  height: 32px;
}

.footer__promo__info p,
.footer__legal p {
  margin: 0;
  color: var(--text-on-chrome);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
}

.footer__promo__info .footer__tagline {
  margin-bottom: 4px;
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
}

.footer__legal {
  grid-column: 1/-1;
  padding-top: 24px;
  border-top: 1px solid var(--neutral-400);
}

/* ── Narrow ─────────────────────────────────────────────────────────── */
/*
 * This brand hands over LATER than the global 1024, because its header does not
 * fit at 1024.
 *
 * Measured at 1025: logo 160 + nav gap 32 + menu 622 + actions 228 + 40 of inner
 * padding = 1082px of content in a 1025px viewport. `.site-nav` is `flex: 1` and
 * its menu items are `white-space: nowrap`, so nothing compresses — the actions
 * cluster was pushed to a right edge of 1062 and took the whole document into
 * horizontal scroll. Same failure ARTSABERS hit at 768, one brand and one
 * breakpoint along.
 *
 * 1100 rather than 1082 so a menu label can grow by a word without bringing it
 * back. Move it if the design would rather shrink the type or shorten the
 * labels than collapse earlier — the number is a floor, not a preference.
 *
 * This block also carries the menu hide that used to duplicate global's. That
 * duplication was real and is gone; what remains is a genuine brand override,
 * because global hides the menu at 1024 and this brand needs it hidden to 1100.
 * Global's rule is doubled-class so it beats a brand base — this one beats it
 * back deliberately, by being later and equally specific.
 */
@media (max-width: 1100px) {
  .site-nav__menu {
    display: none;
  }
  .site-nav__burger {
    display: flex;
    align-items: center;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
  }
  .footer__inner,
  .footer__columns {
    grid-template-columns: 1fr;
  }
  .footer__promo {
    align-items: flex-start;
    text-align: left;
  }
}
/* The 480px block that used to sit here is gone. It squeezed the actions to 52px
 * and shaved the inner container's left padding to 12px, because three 66px boxes
 * plus the gutter overran a 390px viewport by a pixel and took the whole page into
 * horizontal scroll. At the parent's 44px — and with only two controls visible
 * below 768 — the cluster is 93px on a 390px screen, so neither workaround has
 * anything left to fix. Verified: no horizontal scroll at 390. */
/* The sheet hangs from `.site-head`, the parent's containing block for exactly
   this (the search modal does the same), so it lands on the header's bottom
   edge whatever sits above the header. */
.mega-menu {
  position: absolute;
  inset-block-start: 100%;
  inset-inline: 0;
  z-index: 40;
  background-color: var(--bg-panel);
  border-block-start: 3px solid var(--border-brand);
}

/* The page under the sheet, dimmed. The sheet's own layer, so a click on it
   arrives at the sheet and closes the menu. */
.mega-menu::after {
  content: "";
  position: absolute;
  inset-block-start: 100%;
  inset-inline: 0;
  height: 100vh;
  background-color: var(--bg-overlay);
}

/* SOFT IN, SOFT OUT (operator, 2026-10-10). The sheet fades and settles
   into place on opening and fades away on closing; a change of panel or of
   range fades its new content in. `display` is transitioned as a discrete
   property so a closing sheet stays painted while it fades, and
   @starting-style gives a newly shown element somewhere to fade in from. A
   browser without either simply shows and hides, as before. */
.mega-menu {
  transition: opacity 0.2s ease-out, transform 0.2s ease-out, display 0.2s allow-discrete;
}

.mega-menu[hidden] {
  display: none;
  opacity: 0;
  transform: translateY(-8px);
}

.mega-menu__panel {
  transition: opacity 0.2s ease-out;
}

/* A range's columns ease in a few pixels as they fade, so a change of range
   reads as the panel turning over rather than a flicker. */
.mega-menu__range > * {
  transition: opacity 0.3s ease-out, transform 0.3s ease-out;
}

.mega-menu__panel[hidden],
.mega-menu__range[hidden] {
  display: none;
}

/* SWITCHING RANGE CROSS-FADES (operator, 2026-10-14), like the third tier: the
   old range, --leaving, fades out on top while the new one fades in beneath it.
   For the moment both are shown they must share grid cells, so every range's
   columns are placed explicitly (row 1, columns 2 and 3) rather than flowing into
   a second row. --swap is set on the panel by main-nav.js once the shopper
   switches; the range shown on opening keeps its slide-in. 150ms, matched by
   SWAP_FADE in main-nav.js. */
.mega-menu__panel--swap .mega-menu__range > * {
  transition: opacity 0.15s ease-out;
}

.mega-menu__range--leaving > * {
  z-index: 2;
  opacity: 0;
  pointer-events: none;
}

@starting-style {
  .mega-menu {
    opacity: 0;
    transform: translateY(-8px);
  }
  .mega-menu__panel {
    opacity: 0;
  }
  .mega-menu__subs {
    opacity: 0;
    transform: translateX(-12px);
  }
  .mega-menu__main--swap > .mega-menu__subs > * {
    opacity: 0;
  }
  .mega-menu__range > * {
    opacity: 0;
    transform: translateX(6px);
  }
  .mega-menu__panel--swap .mega-menu__range > * {
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .mega-menu,
  .mega-menu__panel,
  .mega-menu__range > *,
  .mega-menu__subs,
  .mega-menu__subs > * {
    transition: none;
  }
}
/* The header row's own column, so the sheet's left edge sits under the logo.
   (The mockup's container tokens are not defined in the theme.) */
.mega-menu__inner {
  max-width: var(--site-max-width);
  margin-inline: auto;
  padding: var(--space-8) var(--gutter-small) 0;
}

.mega-menu__grid {
  --mega-menu-photo-width: 340px;
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr) var(--mega-menu-photo-width);
  align-items: start;
  gap: var(--space-content-gap);
  padding-block-end: var(--space-8);
}

.mega-menu__panel--magazine .mega-menu__grid {
  grid-template-columns: 330px minmax(0, 1fr);
}

/* Each range's sub-ranges and photograph are one unit to show and hide, but
   they sit in the grid's second and third columns — so the unit itself makes
   no box. */
.mega-menu__range {
  display: contents;
}

/* The ranges column is divided from the open range by a hairline; the
   selected range's wash runs up to it, so the pointed-at row visibly opens
   into the panel beside it. */
.mega-menu__nav {
  align-self: stretch;
  margin-inline-end: calc(var(--space-content-gap) * -1);
  padding-inline-end: var(--space-content-gap);
  border-inline-end: 1px solid var(--border-default);
}

.mega-menu__main {
  position: relative;
  z-index: 1;
  grid-row: 1;
  grid-column: 2;
  align-self: stretch;
  min-width: 0;
}

.mega-menu__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
  padding-inline: var(--space-6);
  padding-block-end: var(--space-4);
  border-block-end: 1px solid var(--border-default);
}

.mega-menu__eyebrow {
  display: block;
  margin-block-end: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.mega-menu__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h3);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.mega-menu__head .section-link,
.mega-menu__subs-head .section-link {
  margin-block-start: 0;
}

.mega-menu__columns {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--space-6);
  padding-block-start: var(--space-2);
}

.mega-menu__extra {
  margin-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

.mega-menu__extra .term-chips {
  padding-inline: var(--space-6);
}

/* The picture column stretches to the grid row, so the --fill tile inside it
   stands exactly as tall as the ranges column beside it. */
.mega-menu__aside {
  grid-row: 1;
  grid-column: 3;
  display: grid;
  align-self: stretch;
}

/* THE THIRD TIER (operator, 2026-10-13/14): a sub-range's own categories slide
   out from the right-hand edge of the row's own column, over whatever is to its
   right, so the mouse moves straight across into the list without crossing
   another row. Full height of the open range; a long list (Games by Genre: 17)
   scrolls inside it rather than growing the sheet. Flat like the sheet — a
   hairline, not a shadow, lifts it off what it covers.
   - --over-columns: from the left column, over the right one.
   - --over-photo: from the right column, over the content gap and the
     photograph (the grid's 340px third track). It starts flush at the column's
     edge: a list starting past the gap left the pointer outside both the
     columns and the list while it crossed, and leaving closes the list. */
.mega-menu__subs {
  position: absolute;
  inset-block: 0;
  display: flex;
  flex-direction: column;
  padding: var(--space-6);
  background-color: var(--bg-panel-alt);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  overflow-y: auto;
  transition: opacity 0.2s ease-out, transform 0.2s ease-out;
}

.mega-menu__subs[hidden] {
  display: none;
}

/* Moving from one sub-range to another swaps the open list in place, the panel
   still and only the TEXT cross-fading (operator, 2026-10-14: "stop the flash…
   fade the text in and out"). main-nav.js sets --swap while one is open: the new
   panel appears at once and its contents fade in, while the old one, on top as
   --leaving, fades out whole — the two panels are identical behind the text, so
   only the text is seen to change. 150ms, matched by SWAP_FADE in main-nav.js.
   Only the first list of a visit to the area fades in as a whole. */
.mega-menu__main--swap > .mega-menu__subs {
  transition: none;
}

.mega-menu__main--swap > .mega-menu__subs > * {
  transition: opacity 0.15s ease-out;
}

.mega-menu__main--swap > .mega-menu__subs--leaving {
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease-out;
}

/* The row whose list is open keeps its hover wash while the pointer is in the
   list, so it is plain which row the list belongs to — rule lives on
   .count-list__link:hover in components/_count-list.scss, which this chains
   onto rather than restating the colours. */
.mega-menu__subs--over-columns {
  inset-inline-start: calc((100% - var(--space-6)) / 2);
  width: calc((100% + var(--space-6)) / 2);
}

.mega-menu__subs--over-photo {
  inset-inline-start: 100%;
  width: calc(var(--mega-menu-photo-width) + var(--space-content-gap));
}

.mega-menu__subs-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-6);
  padding-block-end: var(--space-4);
  border-block-end: 1px solid var(--border-default);
}

.mega-menu__subs-title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

/* The magazine's latest articles sit in a stripe-grey well so the white
   article cards read as cards on a white sheet. */
.mega-menu__well {
  margin-block-start: var(--space-6);
  padding: var(--space-6);
  background-color: var(--bg-panel-alt);
  border-radius: var(--radius-card);
}

.mega-menu__cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
}

.mega-menu__foot {
  padding-block: var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

/* The header item whose panel is open reads as selected, its chevron turned
   to the sheet below. */
.site-head__main button.site-nav__menu__item[aria-expanded=true] {
  color: var(--text-on-chrome);
}

.site-head__main button.site-nav__menu__item::after {
  transition: transform 0.2s ease-out;
}

.site-head__main button.site-nav__menu__item[aria-expanded=true]::after {
  transform: translateY(1px) rotate(225deg);
}

/* At and below the width where the header's items give way to the burger, the
   phone menu takes over; the sheet must not linger if the window narrows
   while it is open. */
@media (max-width: 1100px) {
  .mega-menu {
    display: none;
  }
}
/* The popover itself: the whole screen. Its UA box (a centred, bordered,
   content-sized dialog) is reset; each screen scrolls inside it, so the bar
   stays put. */
.phone-menu {
  position: fixed;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 0;
  background-color: var(--bg-panel);
  color: var(--text-body);
}

.phone-menu::backdrop {
  background-color: var(--bg-overlay);
}

.phone-menu__screen {
  display: flex;
  flex-direction: column;
  height: 100%;
  animation: phone-menu-forward 0.2s ease-out;
}

.phone-menu__screen[hidden] {
  display: none;
}

/* A screen comes in from the right going deeper, from the left coming back. */
.phone-menu[data-direction=back] .phone-menu__screen {
  animation-name: phone-menu-back;
}

@keyframes phone-menu-forward {
  from {
    transform: translateX(24px);
    opacity: 0;
  }
  to {
    transform: none;
    opacity: 1;
  }
}
@keyframes phone-menu-back {
  from {
    transform: translateX(-24px);
    opacity: 0;
  }
  to {
    transform: none;
    opacity: 1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .phone-menu__screen {
    animation: none;
  }
}
.phone-menu__bar {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  min-height: 56px;
  background-color: var(--bg-chrome);
  border-block-end: 3px solid var(--border-brand);
}

.phone-menu__bar-start,
.phone-menu__bar-end {
  display: flex;
  flex: 1 1 0;
  min-width: 0;
}

.phone-menu__bar-end {
  justify-content: flex-end;
}

.phone-menu__title {
  flex: 0 1 auto;
  min-width: 0;
  margin: 0;
  overflow: hidden;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--text-on-brand);
}

/* The root has no back control, so its title sits at the start of the bar. */
.phone-menu__title--start {
  flex: 1 1 auto;
  padding-inline-start: var(--space-4);
}

.phone-menu__back,
.phone-menu__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-width: 48px;
  min-height: 48px;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-btn);
  background-color: transparent;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  white-space: nowrap;
  color: var(--text-on-chrome);
  cursor: pointer;
}

.phone-menu__back {
  padding-inline-start: var(--space-2);
}

.phone-menu__back:hover,
.phone-menu__close:hover {
  color: var(--text-on-brand);
}

.phone-menu__back svg {
  width: 18px;
  height: 18px;
}

.phone-menu__close {
  color: var(--text-on-brand);
}

.phone-menu__close svg {
  width: 22px;
  height: 22px;
}

.phone-menu__body {
  flex: 1 1 auto;
  padding-block: var(--space-4) var(--space-6);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Searches, banners, chips and wells sit inset; rows run edge to edge so
   their wash and leading rule meet the sheet's edge. */
.phone-menu__inset {
  padding-inline: var(--space-4);
}

.phone-menu__inset + .phone-menu__inset,
.phone-menu__inset + .range-tabs,
.range-tabs + .phone-menu__inset {
  margin-block-start: var(--space-4);
}

.phone-menu__label {
  display: block;
  margin-block: var(--space-6) var(--space-2);
  padding-inline: var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* The magazine's latest article sits in a stripe-grey well, as on desktop. */
.phone-menu__well {
  margin-inline: var(--space-4);
  padding: var(--space-3);
  background-color: var(--bg-panel-alt);
  border-radius: var(--radius-card);
}

/* My Account: a quieter group at the foot of the root. */
.phone-menu__links {
  margin: var(--space-6) 0 0;
  padding: 0;
  list-style: none;
  border-block: 1px solid var(--border-default);
  background-color: var(--bg-panel-alt);
}

.phone-menu__links li + li {
  border-block-start: 1px solid var(--border-default);
}

.phone-menu__link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 52px;
  padding-inline: var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-decoration: none;
}

.phone-menu__link:hover {
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

.phone-menu__link svg {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: var(--text-brand);
}

.phone-menu__foot {
  margin-block-start: var(--space-6);
  padding: var(--space-3) var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

.grid > .grid {
  grid-column: auto;
}

/* ---------------------------------------------------------------------------
   .grid--1-3 — a quarter beside three-quarters. The store front's Best Sellers
   (MPG21): a promo-tile--fill the full height of the band beside product cards
   three across, so the cards keep the width they were approved at in the full
   1400 column. The global grid has --1-2 and --2-1 but no quarter split; it
   collapses with --1-2, at 1100, where the tile becomes a banner above.
   --------------------------------------------------------------------------- */
.grid--1-3 {
  grid-template-columns: minmax(0, 1fr) minmax(0, 3fr);
}

@media (max-width: 1100px) {
  .grid--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .grid--5 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .grid--1-2,
  .grid--1-3 {
    grid-template-columns: minmax(0, 1fr);
  }
}
@media (max-width: 900px) {
  .grid--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
/* ---------------------------------------------------------------------------
   THE STORE COLUMN COLLAPSES EARLIER, because it is 1042px inside a 1400px page.

   MPG1 and MPG8 state different breakpoints for the same primitives, and it is
   not a disagreement about taste — it is the two pages measuring different
   containers. The homepage's grids have the whole page; the funnel's sit in the
   content column beside a 328px rail. A three-up that still reads at 1400 is
   already tight at 1042, so the funnel collapses it at 1100 where the homepage
   waits until 900.

   Scoped to the store column rather than restated page-wide, so both approved
   designs stay correct at once. The honest fix is a container query — the rule
   is genuinely about the column's width and not the window's — but that is a
   change to the global grid under four other brands, and it is not this walk's
   to make. Raised for the operator's review.

   Breakpoints are MPG8's own (design 17955).
   --------------------------------------------------------------------------- */
@media (max-width: 1100px) {
  .store-layout__content .grid--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .store-layout__content .grid--5 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  /* The three-up has to be restated here, and the reason is specificity rather
     than design: `.store-layout__content .grid--3` above is two classes against
     the phone rule's one, so it wins at every width below 1100 no matter which
     media query comes later. Without this line the magazine row sits at two
     columns on a phone, where MPG8 stacks it — and it looks like the phone rule
     is missing when it is present and outranked. */
  .store-layout__content .grid--3 {
    grid-template-columns: minmax(0, 1fr);
  }
}
@media (max-width: 640px) {
  .grid--2,
  .grid--3,
  .grid--4,
  .grid--5 {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* ---------------------------------------------------------------------------
   THE PRODUCT GRID HOLDS THREE-UP LONGER THAN THE COLUMN'S SHARED THREE-UP.

   MPG7 collapses the listing 3 → 2 at 900 and 2 → 1 at 640. MPG8's block above
   collapses `.store-layout__content .grid--3` at 1100. Both pages sit in the
   same 1042px column, so unlike the MPG1/MPG8 case this is not two containers
   being measured — it is two kinds of card. The funnel's three-up carries
   ARTICLE cards, which hold an image, a title and an excerpt; the archive's
   carries PRODUCT cards, which are narrower and still read at 700px of column.

   So the listing composes `.grid` for its display, gap and width and states its
   own columns here, rather than taking `--3` and fighting the column rule for
   specificity between 1100 and 900. Nothing above changes, and the funnel's
   magazine row is untouched.

   Breakpoints are MPG7's own (design 17929). Raised for the operator's review:
   whether the store column should collapse by CONTENT TYPE, as it does now, or
   uniformly, is a brand decision and not this walk's to take.
   --------------------------------------------------------------------------- */
.product-grid {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 900px) {
  .product-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .product-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* ---------------------------------------------------------------------------
   --scroll: A ROW THAT SWIPES ON A PHONE INSTEAD OF STACKING.

   The game hub's product row (MPG14, design 18513): ten products stacked one
   above another on a phone is a very long walk to the news below, so the row
   turns into a horizontal swipe instead, per the build brief. Above 640 the
   grid's own column count applies untouched.

   It bleeds to the viewport edge so the next card peeks in, which is what tells
   a thumb the row scrolls; the padding puts the first card back on the column.
   The bleed is the page's own gutter (`.page__inner`), not the mockup's
   `--space-page-gutter`, which this brand does not declare.

   Declared AFTER the 640 collapse above on purpose: both are one class, so
   source order decides, and the swipe must win over the single-column stack.
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .grid--scroll {
    width: auto;
    position: relative;
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 78%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    margin-inline: calc(-1 * var(--gutter-small));
    padding-inline: var(--gutter-small);
    padding-block-end: var(--space-2);
    scroll-padding-inline: var(--gutter-small);
  }
  .grid--scroll > * {
    scroll-snap-align: start;
  }
}
/*------------------------------------*\
	COMPONENTS
	One @use per authored brand component, alphabetical. The MPG9 product-page
	walk landed 32 (24 ported from the brand's block catalogue, 8 authored from
	the mockup); the MPG1 homepage walk added 8 more, every one a catalogue port.
\*------------------------------------*/
.about-panel {
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.about-panel__title {
  margin: 0 0 var(--space-6);
  font-family: var(--ff-heading);
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.about-panel__body {
  max-width: var(--container-reading);
}

/* --wide — the category page's About band: no reading measure, the category's
   content fills its card (operator, 2026-10-10 — at 680px inside a 1042px
   card it read as a column with a gap beside it). The homepage's panel keeps
   the measure. */
.about-panel--wide .about-panel__body {
  max-width: none;
}

/* Content that opens with its own heading (the band's title is then dropped —
   archive-about.php) starts at the card's padding, not a heading margin below it. */
.about-panel__body > :first-child {
  margin-block-start: 0;
}

.about-panel__body p {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.about-panel__body p + p {
  margin-block-start: var(--space-4);
}

.about-panel__body a {
  color: var(--text-link);
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.about-panel__body a:hover {
  color: var(--text-link-hover);
}

@media (max-width: 900px) {
  .about-panel__title {
    font-size: var(--fs-h3);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — account-login
   The logged-out form: one centred panel at the reading measure — a log-in
   form is two fields and a button, and a panel spanning 1400px would stretch
   it into a banner. The lost-password and reset-password forms take the same
   frame, since they are the same size of task.
   --------------------------------------------------------------------------- */
.account-login {
  max-width: var(--container-reading);
  margin-inline: auto;
}

/* Lost your password? sits on the button's line, inside the actions row. */
.account-login .form-actions > .form-note {
  margin: 0;
}

/* ---------------------------------------------------------------------------
   BLOCK — account-orders  (NEW)
   The customer's orders as a table: Order, Date, Status, Total, Actions. It is
   built the way the brand builds every table — spec-table's construction, a
   Paragon-blue header row with white heading-font labels over rows striped in
   stripe grey and panel white, the whole at the surface radius — widened to
   five columns. Not spec-table itself: that block is a two-column attribute
   list with bold names, and an order row is not an attribute.

   The order number is a link. The total is a price, so it sets in the
   commerce face, bold and slanted, with the item count after it in slate body
   text — WooCommerce's own "£520.81 for 4 items". Actions are link-blue text,
   medium weight, never buttons: five rows of blue buttons would shout louder
   than the orders.

   Phone: each row becomes a stacked card, label beside value, the labels
   read from WooCommerce's own data-title attribute on each cell, so the
   template needs no second markup for the small screen.
   --------------------------------------------------------------------------- */
.account-orders {
  border-radius: var(--radius-card);
  overflow: hidden;
}

.account-orders__table {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
}

.account-orders__heading {
  padding: var(--space-3) var(--space-6);
  background-color: var(--color-brand);
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
  white-space: nowrap;
}

.account-orders__row:nth-child(odd) {
  background-color: var(--bg-panel-alt);
}

.account-orders__row:nth-child(even) {
  background-color: var(--bg-panel);
}

.account-orders__cell {
  padding: var(--space-4) var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  vertical-align: middle;
}

.account-orders__number {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
  white-space: nowrap;
}

.account-orders__number:hover {
  color: var(--text-link-hover);
}

/* Each package's own order number, under the checkout's: order splitting makes one
   order per package and the list shows the checkout once, so these are how a customer
   matches a package to its dispatch email. Not in the mockup, which predates the
   grouping (operator, 2026-09-26). */
.account-orders__packages {
  display: block;
  margin-block-start: var(--space-1);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

/* A link that names something rather than numbering it — a product in the account's
   stock alerts. The order number's link colour and weight, but it WRAPS: a product
   name is long, and the order number's nowrap pushed the row's actions out of the
   table (refinement list, 2026-09-27). */
.account-orders__link {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
}

.account-orders__link:hover {
  color: var(--text-link-hover);
}

.account-orders__price {
  font-family: var(--ff-chrome);
  font-weight: var(--fw-bold);
  font-style: italic;
  color: var(--text-body);
  white-space: nowrap;
}

.account-orders__count {
  font-size: var(--fs-small);
  color: var(--text-muted);
  white-space: nowrap;
}

.account-orders__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
}

.account-orders__action {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
  text-decoration: none;
  white-space: nowrap;
}

.account-orders__action:hover {
  color: var(--text-link-hover);
}

@media (max-width: 640px) {
  .account-orders__table,
  .account-orders__body,
  .account-orders__row,
  .account-orders__cell {
    display: block;
    width: 100%;
  }
  /* The column labels move into each cell; the blue bar would label nothing. */
  .account-orders__head {
    display: none;
  }
  .account-orders__row {
    padding-block: var(--space-3);
  }
  .account-orders__cell {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-2) var(--space-4);
    font-size: var(--fs-small);
    text-align: end;
  }
  .account-orders__cell::before {
    content: attr(data-title);
    flex: 0 0 auto;
    font-family: var(--ff-heading);
    font-weight: var(--fw-medium);
    color: var(--text-heading);
    text-align: start;
  }
  .account-orders__actions {
    justify-content: flex-end;
  }
  .account-orders__action {
    font-size: var(--fs-small);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — account-switch  (NEW)
   The account menu at phone width: one select-style control at the top of the
   content — "Dashboard" with the brand's chevron — instead of nine links
   stacked above every page. It is a real `details` and `summary`, the same
   disclosure store-nav settled, so it works with no script.

   Closed, it is the brand's select exactly: square, hairline border, panel
   white, the endpoint's name in body text and the Paragon-blue chevron at the
   right. Open, the control takes the focus border and the chevron turns up,
   and the nine sections drop beneath it as a panel-white count-list at the
   surface radius — the sidebar's own list, current item marked the same way,
   so the menu is one construction at every width.
   --------------------------------------------------------------------------- */
.account-switch {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* DEPARTURE: the label's 8px bottom margin is the block's gap instead, so the block
   root carries a rule of its own rather than being a name nothing declares. Same
   geometry. */
.account-switch__label {
  display: block;
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.account-switch__control {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  list-style: none;
  cursor: pointer;
}

/* The endpoint's name. Not styled in the mockup, which only ever drew "Dashboard";
   the longest section name has to hold one line beside the chevron at 320px, so it
   truncates rather than wrapping the control to two lines (walk-back, MPG13). */
.account-switch__current {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.account-switch__control::-webkit-details-marker {
  display: none;
}

.account-switch__control::marker {
  content: "";
}

.account-switch__control:focus-visible {
  border-color: var(--border-focus);
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.account-switch__menu[open] .account-switch__control {
  border-color: var(--border-focus);
}

.account-switch__chevron {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--text-brand);
  transform: rotate(90deg);
}

.account-switch__menu[open] .account-switch__chevron {
  transform: rotate(-90deg);
}

.account-switch__panel {
  margin-block-start: var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   BLOCK — account-tile  (NEW)
   The dashboard's way into the account: one plain panel-white tile per
   section that matters most. Nothing in the catalogue fits — category-tile is
   photographic and range-card carries a product count — so this is new.

   A tile is a link on a panel: a Paragon-blue outline icon on the left, the
   section name in the heading font at the small-title size with the brand's
   trailing chevron, and one slate line saying what the section holds. Hover
   is the brand's navigation wash — the same blue tint count-list gives a row —
   and the name takes the link blue. No shadow, no lift: this brand is flat.
   --------------------------------------------------------------------------- */
.account-tile {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  align-items: start;
  gap: var(--space-4);
  height: 100%;
  padding: var(--space-6);
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  text-decoration: none;
}

.account-tile:hover {
  background-color: var(--bg-card-hover);
}

.account-tile:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.account-tile__icon {
  width: 32px;
  height: 32px;
  color: var(--text-brand);
}

.account-tile__icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.account-tile__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.account-tile__name {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.account-tile__chevron {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--text-brand);
}

.account-tile:hover .account-tile__name {
  color: var(--text-link);
}

.account-tile__text {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

@media (max-width: 640px) {
  .account-tile {
    padding: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — address-card  (NEW)
   A postal address read back to the shopper: the name at medium weight as an
   address label leads, then the lines in body text. Not an inset — on this
   page it is the first thing in its labelled panel, not a value sitting inside
   a form. The block carries the gap beneath it, because what follows it (the
   package rows) always needs one.
   --------------------------------------------------------------------------- */
.address-card {
  margin: 0 0 var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-style: normal;
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.address-card__name {
  font-weight: var(--fw-medium);
}

/* ---------------------------------------------------------------------------
   BLOCK — address-lookup  (NEW)
   The delivery address found from the postcode, the default way in. Three
   shapes stacked, all of them the form specimen's own: the Postcode field and
   Find address button as an inline-form; the addresses at that postcode in a
   field select; and, once one is chosen, the address itself as a compact
   filled block with Edit. A quiet form-note link beneath opens the full
   manual fields for an address the lookup does not know.

   The chosen block is an inset rather than a card — stripe grey with the
   hairline at the surface radius — because it is a value the shopper has
   given, sitting inside a card, not a new surface. The name leads at medium
   weight, as an address label does.

   The block owns the gap between its parts, so the inline-form's own top
   margin (set for when it follows a basket's items) is handed back.
   --------------------------------------------------------------------------- */
.address-lookup > * {
  margin-block: 0;
}

.address-lookup > * + * {
  margin-block-start: var(--space-4);
}

/* The Find address button stays level with the postcode box whatever sits under
   the field — the inline row aligns to its bottom edge, which in the error state is
   the error message (operator review of MPG11). Offset by exactly one label's height
   instead; on phones the row stacks and needs no offset. */
.address-lookup .inline-form__row {
  align-items: start;
}

@media (min-width: 641px) {
  .address-lookup .inline-form__action {
    padding-block-start: calc(var(--fs-small) * var(--lh-heading) + var(--space-2));
  }
}
.address-lookup__chosen {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel-alt);
}

.address-lookup__address {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-style: normal;
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.address-lookup__name {
  font-weight: var(--fw-medium);
}

.address-lookup__edit {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-link);
  cursor: pointer;
}

.address-lookup__edit:hover {
  color: var(--text-link-hover);
}

.address-lookup__edit:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

@media (max-width: 640px) {
  .address-lookup__chosen {
    padding: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   IDEAL POSTCODES' ADDRESS FINDER (checkout wiring, MPG11). Autocomplete in the
   plugin's separate-finder mode (operator, 2026-09-25): p.form-row.idpc-finder
   above the address, the street fields hidden until an address is chosen, then
   folded into `address-lookup__chosen` with Edit by the parent's WooCommerce module
   (addressFinderSummary). The finder's label and box take the brand field rules
   (_field.scss); its suggestion list is dressed here. The postcode-and-button
   lookup the mockup drew is off — autocomplete replaces it.
   --------------------------------------------------------------------------- */
.idpc-finder {
  grid-column: 1/-1;
  margin: 0;
}

.idpc-finder .idpc_af {
  z-index: 30;
  margin-block-start: var(--space-1);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}

.idpc-finder .idpc_ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.idpc-finder .idpc_ul li {
  padding: var(--space-3) var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-heading);
  color: var(--text-body);
  cursor: pointer;
}

.idpc-finder .idpc_ul li + li {
  border-block-start: 1px solid var(--border-default);
}

.idpc-finder .idpc_ul li:hover,
.idpc-finder .idpc_ul li[aria-selected=true] {
  background-color: var(--color-brand-soft);
}

.idpc-manual-entry-link {
  grid-column: 1/-1;
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-link);
  cursor: pointer;
}

.idpc-manual-entry-link:hover {
  color: var(--text-link-hover);
}

.address-lookup__chosen {
  grid-column: 1/-1;
}

/* --folded: the address grid once an address is chosen — the street rows fold into
   the chosen block (parent WooCommerce module, addressFinderSummary). The plugin and
   WooCommerce's address script both set these rows' inline display after a pick, so
   the fold holds with !important for as long as the class is on. Edit removes it. */
.address-lookup--folded > .address-field:not([id$=_country_field]),
.address-lookup--folded .idpc-manual-entry-link {
  display: none !important;
}

/* ---------------------------------------------------------------------------
   BLOCK — applied-code  (NEW)
   A discount code that has been accepted, shown as a removable chip beneath the
   code field. A chip is a control, so it is square; it carries the brand's
   outline and wash so it reads as "yours, and live" without borrowing the
   green, which this brand keeps for confirmations.
   --------------------------------------------------------------------------- */
.applied-code {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-4) 0 0;
}

.applied-code__label {
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.applied-code__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-3);
  border: 1px solid var(--border-brand);
  border-radius: var(--radius-btn);
  background-color: var(--bg-card-hover);
}

.applied-code__code {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.06em;
  color: var(--text-body);
}

.applied-code__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-btn);
  background: none;
  color: var(--text-brand);
  cursor: pointer;
}

.applied-code__remove:hover {
  background-color: var(--bg-panel);
}

.applied-code__remove svg {
  width: 12px;
  height: 12px;
}

.archive-flow {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  min-width: 0;
}

.archive-flow__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  margin: 0;
  padding: 0;
}

.archive-flow__phone {
  display: none;
}

@media (max-width: 1100px) {
  .archive-flow__phone {
    display: block;
  }
}
@media (max-width: 640px) {
  .archive-flow,
  .archive-flow__list {
    gap: var(--space-6);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — archive-header  (REUSED, verbatim)
   --------------------------------------------------------------------------- */
.archive-header {
  max-width: var(--container-reading);
}

.archive-header__standfirst {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.archive-header__count {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

/* A content page's standfirst: the first paragraph of the page, carrying this
   class, sits under the page title as it does inside an archive-header — not the
   page flow's band gap below it (the About page, MPG20). */
/* `~` rather than `+`: on the About page the phone's "Help pages" control sits
   between the title and the standfirst (hidden above 1100px, but still a sibling). */
.page__flow > .section-head ~ .archive-header__standfirst {
  max-width: var(--container-reading);
  margin-block-start: var(--space-4);
}

.article-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

.article-card__media {
  display: block;
  width: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
}

.article-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-card-padding);
}

.article-card__kicker {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-brand);
}

.article-card__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-regular);
  font-style: italic;
  line-height: var(--lh-heading);
}

.article-card__title a {
  color: var(--text-brand);
  text-decoration: none;
}

.article-card__title a:hover {
  color: var(--text-link-hover);
}

.article-card__date {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.article-card__score {
  position: absolute;
  inset-block-start: var(--space-4);
  inset-inline-end: var(--space-4);
}

/* ---------------------------------------------------------------------------
   --row — one compact card: the picture as a square thumbnail on the left,
   kicker, title and date beside it. The phone menu's latest article (MPG22).
   --------------------------------------------------------------------------- */
.article-card--row {
  flex-direction: row;
  align-items: stretch;
}

.article-card--row > a {
  position: relative;
  flex: 0 0 112px;
  min-height: 112px;
}

/* Out of flow, so the picture's own proportions cannot set the card's height —
   the card is as tall as its words, and never less than square. */
.article-card--row .article-card__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
}

.article-card--row .article-card__body {
  justify-content: center;
  gap: var(--space-2);
  min-width: 0;
  padding: var(--space-3) var(--space-4);
}

.article-card--row .article-card__title {
  font-size: var(--fs-body);
}

/* ---------------------------------------------------------------------------
   BLOCK — article-doc  (NEW)
   Distinct from description-panel, which carries a product description at one
   uniform gap. An article needs two things a product description does not: its
   own measure — the panel is sized to the styleguide's reading width, not to
   the content column, so the copy inside lands at the reading measure with the
   panel's padding outside it — and heading-aware spacing, because a heading
   has to bind to the text beneath it and be pushed away from the text above.

   Every gap here is a top margin and never a bottom one, so nothing collapses
   unpredictably. The rhythm rule sets the default; the two "what follows a
   heading" rules bring the space beneath a heading down; the two heading rules
   take the space above it up. Source order is load-bearing — the heading rules
   sit last so a heading always wins its own space.

   Note the specificity: `> * + *` counts as one class, because `*` counts as
   nothing. A block dropped in here that states a bare `margin: 0` ties that
   rule and wins on source order, landing flush against its neighbour. Blocks
   written for this document state the rhythm value outright instead — the way
   media-figure and figure-row already do. The four heading rules carry two
   classes and win outright.

   The three depths are the whole point of the block: the title at the h1 size
   set light and italic in the header above, sections at the h2 size set light,
   sub-sections at the h4 size set medium. The h4 size for a third-level
   heading is the setting feature-panel already uses, so the brand carries one
   in-document sub-heading and not two.
   --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   BLOCK — article-doc  (UPDATED — segments)
   With break-out images the article is several article-doc panels in a row,
   and a panel can now open on a heading or an advert. Whatever comes first
   sits flush with the panel's padding rather than carrying the space it
   would take after a paragraph. Last among the article-doc rules, and at the
   same two-class weight, so it wins.
   --------------------------------------------------------------------------- */
.article-doc {
  max-width: calc(var(--container-article) + var(--space-card-padding) * 2);
  margin-inline: auto;
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.article-doc > * {
  margin-block: 0;
}

.article-doc > * + * {
  margin-block-start: var(--space-8);
}

.article-doc__h2 {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.article-doc__h3 {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.article-doc > .article-doc__h2 + * {
  margin-block-start: var(--space-4);
}

.article-doc > .article-doc__h3 + * {
  margin-block-start: var(--space-3);
}

.article-doc > .article-doc__h2 {
  margin-block-start: var(--space-12);
}

.article-doc > .article-doc__h3 {
  margin-block-start: var(--space-8);
}

@media (max-width: 900px) {
  .article-doc__h2 {
    font-size: var(--fs-h3);
  }
}
@media (max-width: 640px) {
  .article-doc {
    padding: var(--space-6);
  }
}
.article-doc > :first-child {
  margin-block-start: 0;
}

.article-doc .prose {
  max-width: none;
}

/* ---------------------------------------------------------------------------
   BLOCK — article-header  (NEW)
   The magazine's masthead. The title sets the heading font light and italic in
   Paragon blue per the design brief — one weight lighter than the store sets
   the same size, because the editorial side speaks more quietly than the shop.
   The byline sits under a hairline so the three facts read as furniture rather
   than as another line of the standfirst.
   --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   BLOCK — article-header  (UPDATED — --on-image)
   The same masthead reversed for the hero. Title in panel white at medium
   weight — the styleguide's legibility exception for any title laid over
   photography — and still italic, so it is recognisably the magazine's.
   The kicker takes light blue, the editorial light accent, because Paragon
   blue is too dark to read on the scrim. Byline in mist over a quiet rule.
   --------------------------------------------------------------------------- */
.article-header {
  display: block;
}

.article-header__kicker {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-brand);
}

.article-header__kicker a {
  color: var(--text-brand);
  text-decoration: none;
}

.article-header__kicker a:hover {
  color: var(--text-link-hover);
}

.article-header__kicker-sep {
  margin-inline: var(--space-2);
  color: var(--neutral-500);
}

.article-header__title {
  margin: var(--space-4) 0 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-light);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-brand);
}

.article-header__standfirst {
  max-width: var(--container-article);
  margin: var(--space-6) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.article-header__byline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-6);
  margin: var(--space-6) 0 0;
  padding: var(--space-4) 0 0;
  border-block-start: 1px solid var(--border-default);
  list-style: none;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.article-header__author {
  font-weight: var(--fw-medium);
  color: var(--text-body);
}

@media (max-width: 900px) {
  .article-header__title {
    font-size: var(--fs-h2);
  }
}
@media (max-width: 640px) {
  .article-header__title {
    font-size: var(--fs-h3);
  }
  .article-header__standfirst {
    font-size: var(--fs-body);
  }
}
.article-header--on-image .article-header__kicker,
.article-header--on-image .article-header__kicker a {
  color: var(--paragon-300);
}

.article-header--on-image .article-header__kicker a:hover {
  color: var(--text-on-brand);
}

.article-header--on-image .article-header__title {
  font-weight: var(--fw-medium);
  color: var(--text-on-brand);
}

.article-header--on-image .article-header__standfirst {
  color: var(--text-on-brand);
}

.article-header--on-image .article-header__byline {
  border-block-start-color: var(--neutral-600);
  color: var(--text-on-chrome);
}

.article-header--on-image .article-header__author {
  color: var(--text-on-brand);
}

/* ---------------------------------------------------------------------------
   BLOCK — article-hero  (NEW, layout)
   The article's key art, edge to edge, and it IS the article's header: 60%
   of the viewport tall, a charcoal scrim rising from the bottom (the chrome
   colour, never a colour cast), and on it — bottom left, on the reading
   column's text edge — the breadcrumbs, the masthead and the byline. On a
   review the score meter sits at the right, over the rail column, with
   "Jump to verdict" beneath it.

   The frame inside is the article-layout's own two columns, so the title
   lands exactly above the first line of the article and the meter exactly
   above the rail's first panel. The bottom padding reserves the overlap the
   reading card pulls up into, plus a gap, so no text is ever under the card.

   Only used when the featured image is at least ~1600px wide. Smaller art
   falls back to the contained layout: header in the card, article-lead
   inside the column.
   --------------------------------------------------------------------------- */
.article-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 60vh;
  overflow: hidden;
  background-color: var(--bg-chrome);
}

.article-hero__media {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 55%;
}

.article-hero__scrim {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(90deg, color-mix(in srgb, var(--bg-chrome) 80%, transparent) 0%, color-mix(in srgb, var(--bg-chrome) 65%, transparent) 35%, color-mix(in srgb, var(--bg-chrome) 25%, transparent) 60%, transparent 80%), linear-gradient(0deg, var(--bg-chrome) 0%, color-mix(in srgb, var(--bg-chrome) 88%, transparent) 22%, color-mix(in srgb, var(--bg-chrome) 55%, transparent) 52%, transparent 82%);
}

.article-hero__inner {
  position: relative;
  width: 100%;
  max-width: calc(var(--site-max-width) + var(--gutter-small) * 2);
  margin-inline: auto;
  padding: var(--space-16) var(--gutter-small) calc(var(--space-16) + var(--space-8) + var(--space-8));
}

.article-hero__frame {
  display: grid;
  grid-template-columns: minmax(0, calc(var(--container-article) + var(--space-card-padding) * 2)) var(--width-sidebar);
  justify-content: center;
  align-items: end;
  gap: var(--space-content-gap) var(--space-16);
}

.article-hero__head {
  min-width: 0;
  padding-inline: var(--space-card-padding);
}

.article-hero__series {
  margin-block-end: var(--space-4);
}

.article-hero__score {
  justify-self: end;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.article-hero__jump {
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-on-brand);
  text-decoration: none;
}

.article-hero__jump:hover {
  color: var(--paragon-300);
}

@media (max-width: 1100px) {
  .article-hero__frame {
    grid-template-columns: minmax(0, calc(var(--container-article) + var(--space-card-padding) * 2));
  }
  .article-hero__score {
    display: none;
  }
}
@media (max-width: 640px) {
  .article-hero {
    min-height: 55vh;
  }
  .article-hero__inner {
    padding: var(--space-12) var(--gutter-small) calc(var(--space-12) + var(--space-6));
  }
  .article-hero__scrim {
    background-image: linear-gradient(0deg, var(--bg-chrome) 0%, color-mix(in srgb, var(--bg-chrome) 85%, transparent) 30%, color-mix(in srgb, var(--bg-chrome) 60%, transparent) 100%);
  }
  .article-hero__head {
    padding-inline: 0;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — article-layout  (NEW, layout)
   The article's two columns inside the content column: the reading column
   (the reading measure plus the panel's padding either side, so the copy
   lands at 680) and the right rail at the styleguide's sidebar width, with a
   wide gutter so the rail never crowds the text. The pair is centred in the
   1400 column. --single spans the same frame as one column, so the bands
   after the article (buy it, tags and author, keep reading) share its edges.

   __rail is offset down by the breadcrumb trail's height so its first panel
   lines up with the top of the article panel, not with the breadcrumbs.
   __sticky is the part of the rail that stays in view: the rail as a whole is
   taller than a laptop window, so the verdict and the game's products scroll
   with the header they sit beside and the house advert pins beneath them.

   Below 1100px the rail is dropped: its panels move into the flow (the score
   strip under the byline, the products into Buy it) and nothing is sticky.
   __inflow carries anything that only appears once the rail has gone.
   --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   BLOCK — article-layout  (UPDATED — --hero and __break)
   --hero lifts the whole frame 96px up into the bottom of the article hero,
   so the reading card and the rail's first panel both start on the key art
   and the page reads as one piece. It stacks above the hero, which is a
   positioned element and would otherwise paint over the overlap. The rail
   loses its breadcrumb offset because the breadcrumbs now live on the hero.

   __break is a row that spans the reading column AND the rail. The grid
   auto-places in source order, so a break between two segments of the
   article ends the rail above it and starts a fresh rail cell below it —
   the rail steps aside for the image rather than sitting under it. A rail
   cell stretches to its row, so a sticky panel in it pins for exactly the
   length of the segment beside it.
   --------------------------------------------------------------------------- */
.article-layout {
  display: grid;
  grid-template-columns: minmax(0, calc(var(--container-article) + var(--space-card-padding) * 2)) var(--width-sidebar);
  justify-content: center;
  gap: var(--space-content-gap) var(--space-16);
}

.article-layout--single {
  grid-template-columns: minmax(0, calc(var(--container-article) + var(--space-card-padding) * 2 + var(--space-16) + var(--width-sidebar)));
}

.article-layout__main {
  min-width: 0;
}

.article-layout__main > .breakout-figure,
.article-layout__main > .article-doc + .grid,
.article-layout__main > .article-doc + .house-ad,
.article-layout__main > .house-ad + .article-doc,
.article-layout__main > .grid + .grid,
.article-layout__main > .breakout-figure + .article-doc,
.article-layout__main > .grid + .article-doc {
  margin-block-start: var(--space-content-gap);
}

.article-layout__after {
  margin-block-start: var(--space-content-gap);
}

.article-layout__rail {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  padding-block-start: calc(var(--fs-small) * var(--lh-heading) + var(--space-4));
}

.article-layout__sticky {
  position: sticky;
  inset-block-start: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
}

.article-layout__inflow {
  display: none;
}

@media (max-width: 1100px) {
  .article-layout {
    grid-template-columns: minmax(0, calc(var(--container-article) + var(--space-card-padding) * 2));
  }
  .article-layout--single {
    grid-template-columns: minmax(0, 1fr);
  }
  .article-layout__rail {
    display: none;
  }
  .article-layout__inflow {
    display: block;
  }
}
.article-layout--hero {
  position: relative;
  z-index: 1;
  margin-block-start: calc(-1 * (var(--space-16) + var(--space-8)));
}

.article-layout--hero .article-layout__rail {
  padding-block-start: 0;
}

.article-layout__break {
  grid-column: 1/-1;
  min-width: 0;
  margin-block: var(--space-6);
}

@media (max-width: 640px) {
  .article-layout--hero {
    margin-block-start: calc(-1 * var(--space-12));
  }
  .article-layout__break {
    margin-block: 0;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — article-lead  (NEW)
   The lead image INSIDE the reading column, replacing the full-bleed
   lead-image on article pages. Its height is set by the fold: at 1440 x 900,
   under the network header, title, standfirst and byline, an 8:3 image at the
   reading measure (255px) is the tallest that still lets the first paragraph
   land above the fold. 16:9 at this measure is 383px and pushes the opening
   paragraph below it. On a phone, where the fold is a different question, it
   returns to 16:9.
   --------------------------------------------------------------------------- */
.article-lead {
  margin: var(--space-6) 0 0;
}

.article-lead__media {
  display: block;
  width: 100%;
  aspect-ratio: 8/3;
  object-fit: cover;
  border-radius: var(--radius-card);
  background-color: var(--neutral-800);
}

.article-lead__caption {
  margin-block-start: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

@media (max-width: 640px) {
  .article-lead__media {
    aspect-ratio: 16/9;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — article-masthead  (NEW)
   Sets the catalogue's article-header beside a compact score badge, so a
   review answers "is it any good?" in the same glance as its title without
   adding a line of height above the fold. The badge column is only as wide
   as the ring; with no badge (news, features) the header takes the width.
   --------------------------------------------------------------------------- */
.article-masthead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-6);
}

@media (max-width: 1100px) {
  .article-masthead {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — assurance-list  (NEW)
   The rows inside the Good to Know group: an outline icon in Paragon blue, a
   statement in the heading font at medium weight — the styleguide gives the
   heading font the trust statements — and one short slate line under it. Rows
   are divided by the hairline, as rows inside a panel are. Contents only: the
   surface is bordered-group, the brand's one labelled-panel treatment, as
   order-totals is for the summary above it.

   Deliberately not trust-strip: that is a row of separate cards on the
   canvas; this is a list inside one panel, at a sidebar's width.
   --------------------------------------------------------------------------- */
.assurance-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.assurance-list__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.assurance-list__item + .assurance-list__item {
  margin-block-start: var(--space-4);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

.assurance-list__icon {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  color: var(--text-brand);
}

.assurance-list__icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.assurance-list__title {
  display: block;
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.assurance-list__text {
  display: block;
  margin-block-start: var(--space-1);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.assurance-list__text a {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
}

.assurance-list__text a:hover {
  color: var(--text-link-hover);
}

.atc__quantity {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
}

.atc__quantity__button {
  width: 36px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-btn);
  background-color: transparent;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-brand);
  cursor: pointer;
}

.atc__quantity__button:hover:not(:disabled) {
  background-color: var(--bg-card-hover);
}

.atc__quantity__button:disabled {
  color: var(--text-muted);
  cursor: default;
}

.atc__quantity__input {
  width: 52px;
  padding: var(--space-2) 0;
  border: 0;
  border-inline: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-align: center;
  -moz-appearance: textfield;
}

.atc__quantity__input::-webkit-outer-spin-button, .atc__quantity__input::-webkit-inner-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

/* ---------------------------------------------------------------------------
   BLOCK — basket  (NEW)
   The one white panel the old store's `cart.php` put every line on, with the
   delivery choice and the discount code inside it rather than in separate
   cards. Its parts are separated by the brand's hairline — rules are allowed
   INSIDE a panel; it is only between bands on the canvas that they are not.

   At phone width the panel dissolves and each of its parts becomes its own
   panel-white card, which is what the build brief means by "items stack as
   cards": the ground shows between them, so a long basket reads as a list of
   things rather than one tall sheet.
   --------------------------------------------------------------------------- */
.basket {
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.basket > * + * {
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

/* The column labels share the line's own track sizes, so the labels sit over
   the things they name whatever the titles do. */
.basket__columns {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr) 140px 120px;
  gap: var(--space-6);
  margin: 0;
  padding-block-end: var(--space-3);
  border-block-end: 1px solid var(--border-default);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.basket__columns + .basket__lines {
  margin-block-start: 0;
  padding-block-start: 0;
  border-block-start: 0;
}

.basket__column--product {
  grid-column: 1/3;
}

.basket__column--total {
  text-align: end;
}

.basket__lines {
  margin: 0;
  padding: 0;
  list-style: none;
}

.basket__item {
  padding-block: var(--space-6);
}

.basket__item + .basket__item {
  border-block-start: 1px solid var(--border-default);
}

.basket__item:last-child {
  padding-block-end: 0;
}

@media (max-width: 900px) {
  .basket__columns {
    display: none;
  }
  .basket__item:first-child {
    padding-block-start: 0;
  }
}
@media (max-width: 640px) {
  .basket {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: 0;
    background-color: transparent;
    border-radius: 0;
  }
  .basket > * + * {
    margin-block-start: 0;
    padding-block-start: 0;
    border-block-start: 0;
  }
  .basket__lines {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
  }
  .basket__item,
  .basket__section,
  .basket__foot {
    padding: var(--space-6);
    background-color: var(--bg-panel);
    border-radius: var(--radius-card);
  }
  .basket__item + .basket__item {
    border-block-start: 0;
  }
  .basket__item:first-child,
  .basket__item:last-child {
    padding-block: var(--space-6);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — basket  (EXTENDED — `basket--package`)
   The basket was one white panel; an order that ships in packages is now one
   panel PER PACKAGE, each opening with a package-head. The panel itself is
   unchanged. Two things the modifier adds:

   - The first line sits straight under the head. The unmodified panel only
     suppressed the line's top padding after its column labels; a package
     panel has no column labels (three sets, one per panel, read as a table
     repeated three times), so the head takes their place.
   - It does NOT dissolve at phone width. The unmodified basket breaks into one
     card per part there — right for a single sheet of lines, wrong for
     packages, which the brief says "stack as cards": a package IS the card,
     and breaking it up would leave its head on the bare canvas and lose which
     lines travel together.
   --------------------------------------------------------------------------- */
/* The lines list's own `margin: 0; padding: 0` comes after the panel's
   `> * + *` rhythm in source and ties it on specificity, so the hairline under
   the head would sit flush on the first line. Stated outright here. */
.basket--package .basket__lines {
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-6);
}

.basket--package .basket__item:first-child {
  padding-block-start: 0;
}

@media (max-width: 640px) {
  .basket--package {
    display: block;
    padding: var(--space-6);
    background-color: var(--bg-panel);
    border-radius: var(--radius-card);
  }
  .basket--package > * + * {
    margin-block-start: var(--space-6);
    padding-block-start: var(--space-6);
    border-block-start: 1px solid var(--border-default);
  }
  .basket--package .basket__lines {
    display: block;
  }
  .basket--package .basket__item,
  .basket--package .basket__section,
  .basket--package .basket__foot {
    padding: 0;
    background-color: transparent;
    border-radius: 0;
  }
  .basket--package .basket__item {
    padding-block: var(--space-6);
  }
  .basket--package .basket__item + .basket__item {
    border-block-start: 1px solid var(--border-default);
  }
  .basket--package .basket__item:first-child {
    padding-block-start: 0;
  }
  .basket--package .basket__item:last-child {
    padding-block-end: 0;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — basket-line  (NEW)
   One line of the basket: the manufacturer shot on a square tile, the title in
   the commerce face at the product card's title size, the SKU and the stock
   state beneath it, the quantity stepper with a quiet Remove, and the line
   total. No per-line update button — changing the quantity updates the basket.

   The four tracks match `basket__columns` exactly, so the labels over them
   stay true. At tablet width the stepper and total drop to a second row under
   the title; at phone width the image shrinks and the same second row holds.
   --------------------------------------------------------------------------- */
.basket-line {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr) 140px 120px;
  align-items: start;
  gap: var(--space-6);
}

.basket-line__media {
  display: block;
  padding: var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background-color: var(--bg-card);
}

.basket-line__media img {
  display: block;
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: contain;
}

.basket-line__info {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.basket-line__title {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  letter-spacing: 0.01em;
}

.basket-line__title a {
  color: var(--text-heading);
  text-decoration: none;
}

.basket-line__title a:hover {
  color: var(--text-link);
}

.basket-line__sku {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

.basket-line__stock {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.basket-line__stock-dot {
  flex: 0 0 auto;
  translate: 0 -1px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background-color: var(--color-positive);
}

.basket-line--out-of-stock .basket-line__stock-dot {
  background-color: var(--color-negative);
}

.basket-line__quantity {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}

.basket-line__remove {
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
  cursor: pointer;
}

.basket-line__remove:hover {
  color: var(--text-link);
}

.basket-line__total {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-align: end;
}

@media (max-width: 900px) {
  .basket-line {
    grid-template-columns: 96px minmax(0, 1fr) auto;
    row-gap: var(--space-4);
  }
  .basket-line__info {
    grid-column: 2/-1;
  }
  .basket-line__quantity {
    grid-column: 2;
    flex-direction: row;
    align-items: center;
    gap: var(--space-4);
  }
  .basket-line__total {
    grid-column: 3;
    align-self: center;
  }
}
@media (max-width: 640px) {
  .basket-line {
    grid-template-columns: 72px minmax(0, 1fr) auto;
    column-gap: var(--space-4);
  }
  .basket-line__title {
    font-size: var(--fs-body);
  }
  .basket-line__quantity {
    grid-column: 1/3;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — basket-line  (EXTENDED — `basket-line--pre-order`)
   A pre-order line reads `Pre-order` where a stocked line reads `In stock`,
   and its dot takes the brand blue: green says "on the shelf", which a
   pre-order is not, and red is reserved for out of stock and errors.
   --------------------------------------------------------------------------- */
.basket-line--pre-order .basket-line__stock-dot {
  background-color: var(--color-brand);
}

/* ---------------------------------------------------------------------------
   BLOCK — basket-notice  (NEW)
   One standing line about the whole basket — that it ships in several
   packages, or the dispatch rule — on its own slim panel-white card, because
   the design brief does not let content sit on the canvas however slight it
   is. An outline icon in Paragon blue, the line at body size, and an optional
   quieter second line for the detail that qualifies it.
   --------------------------------------------------------------------------- */
.basket-notice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.basket-notice__icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  margin-block-start: 0.1em;
  color: var(--text-brand);
}

.basket-notice__icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.basket-notice__text {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.basket-notice__detail {
  display: block;
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  color: var(--text-muted);
}

.basket-notice__text a {
  color: var(--text-link);
  text-decoration: none;
}

.basket-notice__text a:hover {
  color: var(--text-link-hover);
}

/* ---------------------------------------------------------------------------
   BLOCK — bordered-group  (NEW)
   A labelled panel: a full-width title bar over a bordered white body. This is
   the same construction as `widget` — the brand's sidebar furniture — reused
   here on purpose so the brand carries ONE labelled-panel treatment rather
   than two similar ones. Operator, 2026-09-14. Paragon blue by default,
   --negative for a validation summary, --positive for a confirmation; colour
   is the only thing the modifiers change.
   --------------------------------------------------------------------------- */
.bordered-group {
  border: 2px solid var(--border-brand);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
  overflow: hidden;
}

.bordered-group__title {
  margin: 0;
  padding: var(--space-3) var(--space-6);
  background-color: var(--color-brand);
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.bordered-group__body {
  padding: var(--space-6);
}

.bordered-group__text {
  margin: 0;
  max-width: var(--container-reading);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.bordered-group--negative {
  border-color: var(--color-negative);
}

.bordered-group--negative .bordered-group__title {
  background-color: var(--color-negative);
}

/* An error summary carries `role="alert"` and `tabindex="-1"`, and WooCommerce's script
   moves focus to it on load so a screen reader announces it. Nobody tabbed there, so the
   browser's focus ring would only draw a dark line over the red border — the panel IS
   the signal. Scoped to tabindex -1, which the keyboard can never reach (MPG13 wiring). */
.bordered-group[tabindex="-1"]:focus {
  outline: none;
}

.bordered-group--positive {
  border-color: var(--color-positive);
}

.bordered-group--positive .bordered-group__title {
  background-color: var(--color-positive);
}

/* ---------------------------------------------------------------------------
   BLOCK — brand-index  (MPG23, the Brands page)
   Every brand the store carries, A to Z, on one panel: the "I know the name"
   route. With 31 brands most letters hold one name, so it is ONE flowing
   alphabetical run split into four columns (8 / 8 / 8 / 7), not letter
   groups — a letter heading over a single name is furniture, not help. Each
   column is a count-list; the columns are divided by the same hairline the
   rows are, so the panel reads as one table.

   Four across the 1400px column, two on a tablet, one on a phone, where the
   columns join into a single list of touch rows.
   --------------------------------------------------------------------------- */
.brand-index {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  padding-block: var(--space-3);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.brand-index__column {
  min-width: 0;
}

.brand-index__column + .brand-index__column {
  border-inline-start: 1px solid var(--border-default);
}

@media (max-width: 1100px) {
  .brand-index {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .brand-index__column:nth-child(odd) {
    border-inline-start: 0;
  }
  .brand-index__column:nth-child(n+3) {
    border-block-start: 1px solid var(--border-default);
  }
}
@media (max-width: 640px) {
  .brand-index {
    grid-template-columns: minmax(0, 1fr);
    padding-block: var(--space-1);
  }
  .brand-index__column + .brand-index__column {
    border-inline-start: 0;
    border-block-start: 1px solid var(--border-default);
  }
}
.brand-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.brand-list__item {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-decoration: none;
  white-space: nowrap;
}

.brand-list__item:hover {
  color: var(--text-link);
}

@media (max-width: 640px) {
  .brand-list {
    justify-content: flex-start;
    gap: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   --wall — the brands as an EQUAL grid of panel-white tiles rather than names
   in a wrapping row (the store front, MPG21's brand-wall): six across, four
   below 1100, three on a phone — twelve divide evenly at every width, so no
   brand is left alone on a last row. Each tile shows the brand's logo
   (`__mark`, the term's image) at one height when the brand has one, and its
   name when it does not — none do yet, so names are the shipped state.
   Monochrome: muted, link blue on hover; no brand colours.
   --------------------------------------------------------------------------- */
.brand-list--wall {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--space-3);
  padding: 0;
  background-color: transparent;
  box-shadow: none;
}

.brand-list--wall .brand-list__item {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  overflow: hidden;
  padding: var(--space-4);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
  box-shadow: var(--shadow-panel);
  color: var(--text-muted);
  text-align: center;
  white-space: normal;
}

.brand-list--wall .brand-list__item:hover {
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

.brand-list__mark {
  display: block;
  width: auto;
  max-width: 100%;
  height: 24px;
  object-fit: contain;
}

/* THE WALL'S LOGOS FILL THEIR TILES (operator, 2026-10-10). Brand logos are
   square images on their own grounds — white, black or none — so each takes
   the whole tile, edge to edge, and a dark logo paints its tile dark, as on the
   Brands page. The 24px line above was drawn for wide wordmarks, and made a
   square logo a thumbnail. A brand with no logo keeps its padded name. */
.brand-list--wall .brand-list__item:has(.brand-list__mark) {
  padding: 0;
}

.brand-list--wall .brand-list__mark {
  width: 100%;
  max-width: none;
  height: 100%;
}

@media (max-width: 1100px) {
  .brand-list--wall {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .brand-list--wall {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2);
  }
  .brand-list--wall .brand-list__item {
    padding: var(--space-3);
    font-size: var(--fs-small);
  }
}
/* ---------------------------------------------------------------------------
   MODIFIER — brand-list--tiles  (MPG23, the Brands page)
   The leading brands as a confident wall: each brand a panel-white card with
   its LOGO in a square well across the top and its name, product count and
   the two or three ranges it mostly sits in beneath. Six across the 1400px
   column, three on a tablet, two on a phone — twelve divide evenly at every
   width (the tile-grid track), so no brand is left alone on a last row.

   Built as a modifier on brand-list because the job is brand-list's job (the
   shipped tff/brand-list: "the brands carried, from the product_brand
   taxonomy"). --wall stays the quiet logo strip; --tiles is the index page's
   richer card.

   THE WELL TAKES THE LOGO'S OWN GROUND. Brand logos arrive as SQUARE images
   on mixed grounds — white (ASUS, MSI, GIGABYTE, Xbox, HORI, Fractal Design),
   black or charcoal (Razer, Turtle Beach, AMD), transparent (Intel, Cooler
   Master). The image fills the square well edge to edge at object-fit:
   contain, so an opaque logo paints its own ground across the whole well and
   a transparent one sits on panel white. Logos are never tinted, recoloured
   or filtered — they are the brands' marks, not ours. A hairline under the
   well gives a white logo the same edge a black one has.

   No logo (three brands of 173 today): --text on the well sets the brand's
   name in the commerce font, centred on the stripe-grey inset, so the tile
   keeps its shape and takes the logo later without a redesign.
   --------------------------------------------------------------------------- */
.brand-list--tiles {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  align-items: stretch;
  gap: var(--space-content-gap);
  padding: 0;
  background-color: transparent;
  box-shadow: none;
}

.brand-list--tiles .brand-list__item {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--radius-card);
  background-color: var(--bg-card);
  box-shadow: var(--shadow-card);
  white-space: normal;
}

.brand-list--tiles .brand-list__item:hover {
  background-color: var(--bg-card-hover);
}

.brand-list__well {
  display: block;
  aspect-ratio: 1/1;
  background-color: var(--bg-panel);
  border-block-end: 1px solid var(--border-default);
}

.brand-list--tiles .brand-list__mark {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: contain;
}

.brand-list__well--text {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
  background-color: var(--bg-panel-alt);
}

.brand-list__wordmark {
  font-family: var(--ff-chrome);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-heading);
  text-align: center;
  overflow-wrap: anywhere;
}

.brand-list__body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: var(--space-6);
}

.brand-list__name {
  display: block;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.brand-list--tiles .brand-list__item:hover .brand-list__name {
  color: var(--text-link);
}

.brand-list__count {
  display: block;
  margin-block-start: var(--space-1);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.brand-list__ranges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-block-start: var(--space-4);
}

.brand-list__range {
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-btn);
  background-color: var(--bg-panel-alt);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

@media (max-width: 1100px) {
  .brand-list--tiles {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .brand-list--tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
  }
  .brand-list__body {
    padding: var(--space-4);
  }
  .brand-list__name {
    font-size: var(--fs-body-lg);
  }
}
.breadcrumbs {
  margin: 0 0 var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.breadcrumbs p {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
}

.breadcrumbs a {
  color: var(--text-muted);
  text-decoration: none;
}

.breadcrumbs a:hover {
  color: var(--text-link-hover);
}

.breadcrumbs .last {
  color: var(--text-body);
}

.breadcrumbs .separator {
  color: var(--neutral-500);
}

.breadcrumbs--on-image,
.breadcrumbs--on-image a,
.breadcrumbs--on-image .last {
  color: var(--text-on-chrome);
}

.breadcrumbs--on-image .separator {
  color: var(--neutral-600);
}

.breadcrumbs--on-image a:hover {
  color: var(--text-on-brand);
}

/* ---------------------------------------------------------------------------
   BLOCK — breakout-figure  (NEW)
   An in-body image that runs wider than the reading column, so a long
   article does not read as one grey strip. Sits in article-layout__break.

   --wide spans the reading column and the rail: the image inside a panel-
   white frame at the surface radius with its caption on the panel beneath —
   the category banner's construction, so the caption never sits on the
   canvas. --bleed runs edge to edge, like the hero: no radius (it has no
   edge to round), and the caption on a charcoal foot scrim, aligned to the
   reading column's text edge. On a phone both go to the full screen width.
   --------------------------------------------------------------------------- */
.breakout-figure {
  margin: 0;
}

.breakout-figure__media {
  display: block;
  width: 100%;
  object-fit: cover;
  background-color: var(--neutral-800);
}

.breakout-figure__caption {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
}

.breakout-figure--wide {
  overflow: hidden;
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
}

.breakout-figure--wide .breakout-figure__media {
  aspect-ratio: 12/5;
}

.breakout-figure--wide .breakout-figure__caption {
  max-width: calc(var(--container-article) + var(--space-card-padding) * 2);
  padding: var(--space-4) var(--space-card-padding);
  color: var(--text-muted);
}

.breakout-figure--bleed {
  position: relative;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
}

.breakout-figure--bleed .breakout-figure__media {
  aspect-ratio: 3/1;
  min-height: 360px;
  max-height: 80vh;
}

.breakout-figure--bleed .breakout-figure__caption {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding-block: var(--space-16) var(--space-6);
  padding-inline: calc(max(var(--gutter-small), (100% - (var(--container-article) + var(--space-card-padding) * 2 + var(--space-16) + var(--width-sidebar))) / 2) + var(--space-card-padding));
  background-image: linear-gradient(0deg, color-mix(in srgb, var(--bg-chrome) 90%, transparent) 0%, transparent 100%);
  color: var(--text-on-brand);
}

@media (max-width: 1100px) {
  .breakout-figure--bleed .breakout-figure__caption {
    padding-inline: calc(max(var(--gutter-small), (100% - (var(--container-article) + var(--space-card-padding) * 2)) / 2) + var(--space-card-padding));
  }
}
@media (max-width: 640px) {
  .breakout-figure--wide {
    width: 100vw;
    margin-inline: calc(50% - 50vw);
    border-radius: 0;
  }
  .breakout-figure--wide .breakout-figure__media {
    aspect-ratio: 4/3;
  }
  .breakout-figure--wide .breakout-figure__caption {
    padding-inline: var(--gutter-small);
  }
  .breakout-figure--bleed .breakout-figure__media {
    aspect-ratio: 4/3;
    min-height: 0;
  }
  .breakout-figure--bleed .breakout-figure__caption {
    padding: var(--space-12) var(--gutter-small) var(--space-4);
  }
}
.breakout-figure--column {
  overflow: hidden;
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.breakout-figure--column .breakout-figure__media {
  height: auto;
}

.breakout-figure--column .breakout-figure__caption {
  padding: var(--space-4) var(--space-card-padding);
  color: var(--text-muted);
}

.btn, .cart-drawer__checkout, .cart-drawer__empty-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding-block: var(--space-3);
  padding-inline: var(--space-6);
  border: 0;
  border-radius: var(--radius-btn);
  box-shadow: var(--shadow-card);
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.btn--primary, .cart-drawer__empty-cta {
  background-color: var(--btn-primary-bg);
  color: var(--btn-primary-text);
}

.btn--primary:hover, .cart-drawer__empty-cta:hover {
  background-color: var(--btn-primary-bg-hover);
  color: var(--btn-primary-text);
}

.btn--commerce, .cart-drawer__checkout {
  background-color: var(--btn-primary-bg);
  color: var(--btn-primary-text);
  font-family: var(--ff-chrome);
  font-weight: var(--fw-bold);
  font-style: italic;
  font-size: var(--fs-body);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding-inline: var(--space-4);
}

.btn--commerce:hover, .cart-drawer__checkout:hover {
  background-color: var(--btn-primary-bg-hover);
  color: var(--btn-primary-text);
}

.btn--block, .cart-drawer__checkout {
  width: 100%;
}

/* ---------------------------------------------------------------------------
   BLOCK — buy-box  (UPDATED — a delivery line, a was-price, no invented promise)
   The one region that decides whether the store trades.

   THREE CHANGES from the first draft, each of them a fact rather than a taste:

   1. The dispatch line said "Order before 2pm for same-day dispatch". Nothing
      in the migrated data supports it and no operator stated it, so it is
      gone. Its place is taken by a DELIVERY line read from the product's
      shipping class, which is where this brand keeps delivery windows —
      operator-editable term meta, one value per class. All eleven classes are
      currently empty, so the mockup shows the shape with a marked placeholder
      rather than a number nobody has agreed.

      The class names are SUPPLIER names (Spire Technology, Exertis UK, Target
      Components). The shopper sees the window, never the supplier.

   2. A was-price and a saving, for the 348 products of 3,912 that carry a sale
      price. Absent on the other 91%, where the price stands alone.

   3. No rating and no review count anywhere. Every product in the catalogue
      reads zero reviews and zero average rating — not low, nil — so there is
      nothing to show and no empty state worth printing on 3,912 pages.
   --------------------------------------------------------------------------- */
.buy-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.buy-box__prices {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3);
}

.buy-box__price {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  letter-spacing: 0.01em;
  color: var(--text-body);
}

.buy-box__was {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-heading);
  color: var(--text-muted);
  text-decoration: line-through;
}

.buy-box__save {
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background-color: var(--color-brand);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-on-brand);
}

.buy-box__facts {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* Every stock line (buy box, card, basket line, live search, featured product, game
   feature) aligns on the BASELINE, not the centre. An empty dot's baseline is its
   bottom edge, so it sits on the text's baseline and its 8px reaches the middle of the
   lowercase (Poppins' x-height is ~0.55em). Centred, it sat on the middle of the line
   box, which in Poppins is below the middle of the letters (operator, 2026-10-11).
   On the baseline it still read a touch low, so each dot is lifted 1px (operator). */
.buy-box__stock {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.buy-box__stock-dot {
  flex: 0 0 auto;
  translate: 0 -1px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background-color: var(--color-positive);
}

.buy-box--preorder .buy-box__stock-dot,
.buy-box--coming-soon .buy-box__stock-dot {
  background-color: var(--color-brand);
}

.buy-box--out-of-stock .buy-box__stock-dot {
  background-color: var(--color-negative);
}

.buy-box__delivery {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.buy-box__delivery-icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  color: var(--text-brand);
}

.buy-box__delivery-icon svg {
  width: 100%;
  height: 100%;
}

.buy-box__purchase {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.buy-box__quantity {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

/* The stock state qualifies the control beside it rather than the product above
   it, so it rides the quantity row and sits at its end. `auto` rather than
   space-between, so the label and stepper stay together when the row is wide. */
.buy-box__quantity .buy-box__stock {
  margin-inline-start: auto;
}

.buy-box__quantity-label {
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.buy-box__actions {
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
}

.buy-box__actions .btn {
  flex: 1 1 auto;
}

.buy-box__wishlist {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  background-color: var(--bg-card);
  color: var(--text-brand);
  cursor: pointer;
}

.buy-box__wishlist:hover {
  border-color: var(--border-brand);
  background-color: var(--bg-card-hover);
}

.buy-box__wishlist svg {
  width: 26px;
  height: 26px;
}

.buy-box__pay-later {
  display: block;
}

.buy-box__pay-later-label {
  display: block;
  margin: 0 0 var(--space-2);
  font-family: var(--ff-heading);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.buy-box__instalments {
  flex-basis: 100%;
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.buy-box__loyalty {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.buy-box__loyalty-icon {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  color: var(--text-brand);
}

.buy-box__loyalty-icon svg {
  width: 100%;
  height: 100%;
}

.buy-box__figure {
  font-family: var(--ff-body);
  font-weight: var(--fw-medium);
}

/* ---------------------------------------------------------------------------
   PAGE LAYOUT — the shell, the rail and the region grids.

   BUILT 2026-09-15 from six pieces of operator feedback, after three designs
   were rejected. Each of the six is answered in one place and the place is
   named, so a later session can see which choices are load-bearing:

   1. The short description goes BEFORE the buy box    → .buy-region__summary
   2. Loyalty points sit AFTER the buy box             → .buy-region__summary
   3. Stat pills live inside the product description   → .doc-figures
   4. The description takes the live site's column     → .store-layout
   5. Add to Basket never wraps to two lines           → .btn--commerce, .route-row
   6. The navigation rail comes back, desktop only     → .store-layout__sidebar

   THE COLUMN IS 1042px AND THAT IS THE POINT OF (4). It is what the live store
   gives its content: a 1400 page, a 328 rail, a 30 gap. Three drafts put the
   description at 680 or 740 because that is the styleguide's READING measure,
   and all three read as cramped — because the measure was set for editorial
   pages, where prose is alone on the page. A product description is not alone:
   it carries stat blocks, spec tables and feature rows, and it wants the room
   the store already gives it. The 680 measure still governs article pages.
   --------------------------------------------------------------------------- */
.page__inner {
  max-width: calc(var(--site-max-width) + var(--gutter-small) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter-small);
}

/* ---- the buying region ----------------------------------------------------

   TWO PANELS, NOT ONE. The gallery and the summary carry very different
   amounts, and a single panel spanning both would be as tall as the taller and
   show the difference as empty white — the fault that sank the first two
   drafts. Sized separately they each end where their content ends, and what
   shows beneath the shorter one is the page's own ground.
   --------------------------------------------------------------------------- */
.buy-region {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
}

/* The two halves of the one panel. There is no grey between them — the panel's
   own padding is the outer edge and this gap is the only separation, which is
   what makes them read as one card rather than two. */
.buy-region__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: var(--space-content-gap);
}

/* The pay-later and loyalty cards, on the ground beneath, one under each half. */
.buy-region__cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-content-gap);
}

/* (1) and (2) are both this stack's ORDER, and it is the whole of what they
   asked for: title, then the short description, then the buy box, then the
   loyalty panel, then the identity line. The loyalty group used to be nested
   inside the buy box at its foot; it is now its own panel after it, which is
   also why it can keep the labelled-panel treatment without being a box inside
   a box inside a box. */
.buy-region__summary {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

@media (max-width: 900px) {
  .buy-region__grid,
  .buy-region__cards {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* The identity line closes the hero card, running its whole width. Brand, SKU,
   manufacturer part and barcode then sit on ONE line — in a half-width column
   they wrapped to two, which is what made the gallery side the taller half. */
.buy-region .description-panel > .decision__identity {
  margin-block-start: var(--space-6);
}

.card-line {
  display: block;
  margin-block-start: var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

/* ---------------------------------------------------------------------------
   CATEGORY EDITORIAL  (NEW, layout)
   The category's own long-form copy, alternating text and photograph down the
   page. It is what a category page competes on: the grid answers "show me
   controllers", this answers "which controller should I buy", which is the
   query with the volume behind it.

   IT IS NOT THE POLICY BAND IN A BIGGER FORMAT. The band below repeats on
   every archive and stays short on purpose; this is unique per category and is
   the content that carries the page. Source is the category's own
   `bottom_content_page`, which holds real migrated copy on 33 of 284
   categories — Controllers runs to about a thousand words under one h2 and
   three h3s, which is exactly this shape.

   The panels reuse `feature-panel` from the catalogue, alternating with its
   own `--reverse` modifier. No new block.
   --------------------------------------------------------------------------- */
.category-editorial {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.category-editorial__lede {
  margin: 0;
  max-width: var(--container-reading);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-body);
}

/* ---- category-header (reused from the brand catalogue, verbatim) ---- */
/* ---------------------------------------------------------------------------
   BLOCK — category-header  (NEW)
   The hero that heads every category page: a wide photographic banner carrying
   the category name, with the intro and the store's four promises beneath it
   on white. Chosen by the operator 2026-09-14 over a photograph-beside-copy
   treatment, which is kept on record because it is what works when a category
   owns only a cut-out rather than a scene.

   The banner needs a DARK, WIDE image. The one here is real — a controller in
   low light, 2560x1082 — but it is attached to a product, not to the category,
   so the template needs a category banner field of its own rather than a
   photograph picked at random from the catalogue.

   Text over photography is carried by a scrim rising from the foot of the
   banner, which is the same rule the homepage hero already follows.
   --------------------------------------------------------------------------- */
/* ---- shared over-image typography ---- */
.category-header__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

/* ---- H: banner over copy ---- */
.category-header {
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.category-header__banner {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 220px;
  background-color: var(--bg-chrome);
}

.category-header__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.category-header__scrim {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(0deg, var(--bg-overlay) 0 46%, transparent 90%);
}

.category-header__title {
  position: relative;
  padding: var(--space-6) var(--space-card-padding);
}

.category-header__body {
  padding: var(--space-6) var(--space-card-padding);
  padding-block-start: 0;
}

/* The intro's own gap off the banner. The body carries no top padding (the
   promises row sets its own when there is no intro), so without this the text
   sat tight under the photograph — brand pages, which all have one, showed it
   (operator, 2026-10-10). */
.category-header__intro {
  margin: var(--space-6) 0 0;
  max-width: var(--container-reading);
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.category-header__promises {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-8);
  margin: var(--space-3) 0 0;
  padding: var(--space-4) 0 0;
  list-style: none;
}

/* ---- the promise row ---- */
.category-header__promise {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.category-header__promise-icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  color: var(--text-brand);
}

.category-header__promise-icon svg {
  width: 100%;
  height: 100%;
}

.category-header__promise-label {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
  white-space: nowrap;
}

/* White on the photograph. Written as a descendant so it outranks the shared
   promise rule below rather than tying it and losing on source order. */
.category-header__banner .category-header__title {
  color: var(--text-on-brand);
}

.category-tile {
  position: relative;
  display: block;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--neutral-800);
  box-shadow: var(--shadow-card);
  text-decoration: none;
}

.category-tile__media {
  display: block;
  width: 100%;
  aspect-ratio: 3/2;
  object-fit: cover;
}

.category-tile--compact .category-tile__media {
  aspect-ratio: 4/3;
}

.category-tile__scrim {
  position: absolute;
  inset: 0;
  background-color: var(--bg-overlay);
}

.category-tile__title {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding-inline: var(--space-6);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
  text-align: center;
}

.category-tile:hover .category-tile__title {
  color: var(--text-on-brand);
}

/* ---------------------------------------------------------------------------
   BLOCK — checkout-bar  (NEW)
   At phone width the Order Summary has dropped below the items, so the way on
   is pinned to the foot of the viewport with the total beside it — the shopper
   never has to scroll past a long basket to pay. Hidden above phone width,
   where the summary is sticky in its own column. The one place the brand's
   single shadow is used on this page: it is floating UI.

   --specimen pins it in the flow instead, so it can be judged at desktop in
   the approval strip. Not for production.
   --------------------------------------------------------------------------- */
.checkout-bar {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 20;
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--gutter-small);
  background-color: var(--bg-panel);
  border-block-start: 1px solid var(--border-default);
  box-shadow: var(--shadow-1);
}

.checkout-bar__total {
  display: flex;
  flex-direction: column;
}

.checkout-bar__label {
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.checkout-bar__value {
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.checkout-bar .btn {
  flex: 0 0 auto;
}

.checkout-bar--specimen {
  position: static;
  display: flex;
  max-width: 390px;
  border: 1px solid var(--border-default);
}

@media (max-width: 640px) {
  .checkout-bar {
    display: flex;
  }
}
/* DEPARTURE — the page-level rules the mockup kept outside any block, moved here
   because the bar is what creates the need: at phone width the bar replaces the
   summary's own action, and the page leaves room at its foot so the pinned bar
   never covers the last panel. Scoped with :has() so only a page carrying the
   bar is affected. */
@media (max-width: 640px) {
  .page__body:has(.checkout-bar) {
    padding-block-end: calc(var(--space-16) + var(--space-16));
  }
  .page__body:has(.checkout-bar) .order-totals__action {
    display: none;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — checkout-steps  (NEW)
   Where the shopper is in the order funnel: Basket, Details & Payment,
   Confirmation. On its own slim panel-white card, because the design brief
   does not let content sit on the canvas however slight it is.

   A step is a round indicator (round indicators take the pill radius) and a
   label, joined to the next step by the brand's hairline. A finished step is
   a Paragon-blue outline with a tick, its label a link back; the current step
   is filled Paragon blue, its label ink at medium weight; a step still to
   come is the hairline grey with a slate number. The rule out of a finished
   step takes the brand blue, so the line reads as travelled up to "you are
   here". No green: a finished step is not a confirmation.
   --------------------------------------------------------------------------- */
.checkout-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 0;
  padding: var(--space-4) var(--space-6);
  list-style: none;
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.checkout-steps__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

/* The joining rule fills whatever the step's own content leaves. */
.checkout-steps__item:not(:last-child)::after {
  content: "";
  flex: 1 1 auto;
  min-width: var(--space-4);
  margin-inline: var(--space-2) var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

.checkout-steps__item--done:not(:last-child)::after {
  border-block-start-color: var(--border-brand);
}

.checkout-steps__marker {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 2px solid var(--border-default);
  border-radius: var(--radius-pill);
  background-color: var(--bg-panel);
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: 1;
  color: var(--text-muted);
}

.checkout-steps__marker svg {
  width: 14px;
  height: 14px;
}

.checkout-steps__item--done .checkout-steps__marker {
  border-color: var(--border-brand);
  color: var(--text-brand);
}

.checkout-steps__item--current .checkout-steps__marker {
  border-color: var(--border-brand);
  background-color: var(--color-brand);
  color: var(--text-on-brand);
}

.checkout-steps__label {
  flex: 0 1 auto;
  min-width: 0;
}

.checkout-steps__link {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
}

.checkout-steps__link:hover {
  color: var(--text-link-hover);
}

.checkout-steps__item--current .checkout-steps__label {
  font-weight: var(--fw-medium);
  color: var(--text-heading);
}

/* Phone: each step stacks its marker over its label and the joining rules
   stand down — three labels side by side at 390px have no room for them. */
@media (max-width: 640px) {
  .checkout-steps {
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
  }
  .checkout-steps__item {
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-small);
    text-align: center;
  }
  .checkout-steps__item:not(:last-child)::after {
    content: none;
  }
  .checkout-steps__marker {
    width: 28px;
    height: 28px;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — choice  (REUSED, verbatim)
   --------------------------------------------------------------------------- */
.choice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
  cursor: pointer;
}

.choice__control {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin: 0;
  /* Centred on the label's FIRST line, so a long label still wraps beside the
     box rather than around it: half of what the line is taller than the box.
     It was a flat 0.3em, which left the box 1px low on the line's centre and
     lower still to the eye — Poppins sits high in its line (operator,
     2026-10-10, the In stock only filter). */
  margin-block-start: calc((var(--lh-body) * 1em - 20px) / 2 - 1px);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
  background-repeat: no-repeat;
  background-position: center;
  cursor: pointer;
}

.choice__control[type=radio] {
  border-radius: var(--radius-pill);
}

.choice__control:checked {
  border-color: var(--color-brand);
  background-color: var(--color-brand);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.4 L6.4 11.8 L13 4.6' fill='none' stroke='%23FFFFFF' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size: 13px auto;
}

.choice__control[type=radio]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Ccircle cx='4' cy='4' r='4' fill='%23FFFFFF'/%3E%3C/svg%3E");
  background-size: 8px auto;
}

.choice__control:focus,
.choice__control:focus-visible,
.choice__control--focus {
  border-color: var(--border-focus);
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.choice__control:disabled {
  background-color: var(--bg-page);
  border-color: var(--border-default);
  cursor: not-allowed;
}

.choice__control:disabled + .choice__label {
  color: var(--neutral-500);
}

.choice__label {
  min-width: 0;
}

.field--error .choice__control {
  border: 2px solid var(--color-negative);
}

/* ---------------------------------------------------------------------------
   BLOCK — code-disclosure  (NEW)
   "Have a discount code?" folded shut, opening the basket's own inline-form.
   Most shoppers at checkout have no code, and an open empty field at the
   moment of paying reads as "you are missing a discount". A real disclosure —
   `details` and `summary` — so it works with no script.

   Closed, it is one line of link-blue body text with the brand's chevron at
   the far end, pointing down; open, the chevron points up. The same chevron,
   turned the same way, as faq-accordion. Inside a sidebar the inline-form's
   two-track row is too wide, so the field and the button share the column —
   the field takes what the button leaves.
   --------------------------------------------------------------------------- */
.code-disclosure {
  margin: var(--space-4) 0 0;
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

.code-disclosure__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  list-style: none;
  cursor: pointer;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
}

.code-disclosure__summary::-webkit-details-marker {
  display: none;
}

.code-disclosure__summary::marker {
  content: "";
}

.code-disclosure__summary:hover {
  color: var(--text-link-hover);
}

.code-disclosure__summary:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.code-disclosure__marker {
  flex: 0 0 auto;
  display: inline-flex;
  width: 14px;
  height: 14px;
  color: var(--text-brand);
}

.code-disclosure__marker svg {
  width: 100%;
  height: 100%;
  transform: rotate(90deg);
}

.code-disclosure[open] .code-disclosure__marker svg {
  transform: rotate(-90deg);
}

.code-disclosure .inline-form {
  margin-block-start: var(--space-4);
}

.code-disclosure .inline-form__row {
  grid-template-columns: minmax(0, 1fr) auto;
}

/* ---------------------------------------------------------------------------
   BLOCK — confirm-hero  (NEW)
   The success state's opening: a brand photograph, darkened, carrying a green
   check mark, the thank-you title and the order line. The operator asked for
   "a bit more life"; the page still has to show what happens next above the
   fold on a 900px-tall laptop, so this is the compact cousin of the homepage's
   hero-slider rather than a copy of it — hero-slider is 1400 / 520 with a
   380px floor, and overlay-band and cta-band both floor at 300px or more before
   their aspect ratio adds height. None of them can be held to 300px without
   overriding the rule that defines them.

   What it takes from hero-slider, unchanged: the surface (card radius, the
   neutral-800 ground under the photograph, clipped), the leading-edge scrim at
   the same stops, the title in the heading font at medium weight — the
   styleguide's exception for a title over photography — and the lead in the
   body font, light, at the large size, both white. At phone width the scrim
   flips bottom-up and the text sits at the foot, as hero-slider does.

   Height: exactly 300px on desktop. The photograph is absolutely placed, so
   the image's own proportions never add height; the content is centred in
   the fixed box. At phone width the box grows with its text instead, from a
   320px floor, because a wrapped email address must never be clipped.

   The check mark is a round indicator, so it takes the pill radius, filled go
   green — the styleguide's colour for a positive confirmation — with a white
   tick. It is the only green on the hero.
   --------------------------------------------------------------------------- */
.confirm-hero {
  position: relative;
  display: flex;
  align-items: center;
  height: 300px;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--neutral-800);
  box-shadow: var(--shadow-card);
}

.confirm-hero__media {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 55%;
}

.confirm-hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--bg-overlay) 0%, var(--bg-overlay) 40%, transparent 78%);
}

.confirm-hero__content {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  max-width: 720px;
  padding: var(--space-8) var(--space-12);
  text-align: left;
}

.confirm-hero__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  margin-block-end: var(--space-1);
  border-radius: var(--radius-pill);
  background-color: var(--color-positive);
  color: var(--text-on-brand);
}

.confirm-hero__mark svg {
  width: 26px;
  height: 26px;
}

.confirm-hero__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.confirm-hero__lead {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-on-brand);
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .confirm-hero__content {
    padding: var(--space-6) var(--space-8);
    max-width: 75%;
  }
  .confirm-hero__title {
    font-size: var(--fs-h2);
  }
}
@media (max-width: 640px) {
  .confirm-hero {
    align-items: flex-end;
    height: auto;
    min-height: 320px;
  }
  /* The source photograph is square with white letterbox bars; at a near-square
     crop the scale keeps them out of frame. A properly cropped brand image at
     build makes this rule a no-op. */
  .confirm-hero__media {
    transform: scale(1.5);
  }
  .confirm-hero__scrim {
    background: linear-gradient(0deg, var(--bg-overlay) 0%, var(--bg-overlay) 55%, transparent 95%);
  }
  .confirm-hero__content {
    max-width: none;
    padding: var(--space-16) var(--space-6) var(--space-6);
    gap: var(--space-2);
  }
  .confirm-hero__mark {
    width: 40px;
    height: 40px;
  }
  .confirm-hero__mark svg {
    width: 22px;
    height: 22px;
  }
  .confirm-hero__title {
    font-size: var(--fs-h3);
  }
  .confirm-hero__lead {
    font-size: var(--fs-body);
  }
}
/* ---- the banner ------------------------------------------------------------ */
.consent-banner {
  position: fixed;
  inset-inline: var(--space-4);
  inset-block-end: var(--space-4);
  z-index: 9990;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-8);
  max-width: var(--site-max-width);
  margin-inline: auto;
  padding: var(--space-6) var(--space-8);
  border-block-start: 3px solid var(--border-brand);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
  box-shadow: var(--shadow-panel);
}

.consent-banner[hidden],
.consent-panel[hidden] {
  display: none;
}

.consent-banner__text {
  flex: 1 1 28rem;
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.consent-banner__link {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
}

.consent-banner__link:hover {
  color: var(--text-link-hover);
}

.consent-banner__actions,
.consent-panel__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
}

/* "Manage cookies" — the one control that is not a decision. */
.consent-button--link {
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
  cursor: pointer;
}

.consent-button--link:hover {
  color: var(--text-link-hover);
}

/* ---- the Cookie Settings dialog ----------------------------------------- */
.consent-panel {
  position: fixed;
  inset: 0;
  z-index: 9991;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background-color: var(--bg-overlay);
}

.consent-panel__dialog {
  width: 100%;
  max-width: 36rem;
  max-height: 100%;
  overflow-y: auto;
  padding: var(--space-card-padding);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
  box-shadow: var(--shadow-panel);
}

.consent-panel__dialog:focus {
  outline: none;
}

.consent-panel__title {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-heading);
  font-size: var(--fs-h3);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.consent-panel__text,
.consent-panel__description {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.consent-panel__group {
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

.consent-panel__toggle {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-block-end: var(--space-2);
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
  cursor: pointer;
}

.consent-panel__toggle input {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--color-brand);
}

.consent-panel__always {
  margin-inline-start: auto;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.consent-panel__cookies {
  margin-block-start: var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  color: var(--text-body);
}

.consent-panel__cookies summary {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  cursor: pointer;
}

.consent-panel__cookies ul {
  margin: var(--space-2) 0 0;
  padding-inline-start: var(--space-6);
}

.consent-panel__actions {
  justify-content: flex-end;
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

html.consent-panel-open {
  overflow: hidden;
}

/* ---- the cookie table on the Cookie Policy -------------------------------- */
.consent-cookies__group + .consent-cookies__group {
  margin-block-start: var(--space-8);
}

.consent-cookies__title {
  margin: 0 0 var(--space-2);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.consent-cookies__text {
  margin: 0 0 var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.consent-cookies__table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.consent-cookies__table th {
  padding: var(--space-2) var(--space-3);
  border-block-end: 2px solid var(--border-brand);
  font-family: var(--ff-heading);
  font-weight: var(--fw-medium);
  text-align: start;
  color: var(--text-heading);
}

.consent-cookies__table td {
  padding: var(--space-3);
  border-block-end: 1px solid var(--border-default);
  vertical-align: top;
}

/* A cookie name is one token — kept whole, so the column sizes to the longest. */
.consent-cookies__table code {
  font-size: var(--fs-small);
  white-space: nowrap;
}

/* ---- the footer's company line and Cookie settings ----------------------- */
.consent-settings-link {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
}

@media (max-width: 640px) {
  .consent-banner {
    padding: var(--space-4);
  }
  .consent-banner__actions .btn {
    flex: 1 1 auto;
  }
  .consent-cookies__table thead {
    display: none;
  }
  .consent-cookies__table tr {
    display: block;
    padding-block: var(--space-3);
    border-block-end: 1px solid var(--border-default);
  }
  .consent-cookies__table td {
    display: block;
    padding: 0;
    border: 0;
  }
  .consent-cookies__table code {
    white-space: normal;
    overflow-wrap: anywhere;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — contact-layout  (NEW)
   The Contact page's content: the form in the wide track, the ways to reach us
   in a sidebar-width track beside it, About Paragon Gaming across the foot. The
   ways to reach us come FIRST in the markup, so a phone reads them before the
   form — there, the email address or the chat bubble is often the quicker
   answer. The grid areas put the form first on the desktop, where both show.
   --------------------------------------------------------------------------- */
.contact-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--width-sidebar);
  grid-template-areas: "form options" "about about";
  gap: var(--space-content-gap);
  align-items: start;
}

.contact-layout__options {
  grid-area: options;
  min-width: 0;
}

.contact-layout__form {
  grid-area: form;
  min-width: 0;
}

.contact-layout__about {
  grid-area: about;
  min-width: 0;
}

@media (max-width: 900px) {
  .contact-layout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "options" "form" "about";
  }
}
@media (max-width: 640px) {
  .contact-layout {
    gap: var(--space-6);
  }
}
.content {
  width: 100%;
}

.content > :where(* + *) {
  margin-block-start: var(--space-6);
}

.content > .alignfull {
  width: auto;
  margin-inline: calc(var(--space-card-padding) * -1);
}

.content > .alignwide {
  width: auto;
  margin-inline: calc(var(--space-card-padding) * -0.5);
}

.count-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.count-list__item + .count-list__item {
  border-block-start: 1px solid var(--border-default);
}

.count-list__link {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-decoration: none;
}

.count-list__link:hover,
.mega-menu__columns .count-list__link[aria-expanded=true] {
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

/* The category name. The count is fixed and this half takes what is left, so the
   floor decides what happens to a long name in a 328px rail: wrap under itself,
   rather than hold the row open and push the count off the end of the panel.
   Category names here run to 'Gaming Chairs & Accessories' and longer. */
.count-list__label {
  min-width: 0;
}

.count-list__count {
  flex: 0 0 auto;
  font-size: var(--fs-small);
  color: var(--text-muted);
}

/* A row that opens more — the mega menu's sub-ranges with a third tier
   (operator, 2026-10-14) — carries the brand chevron, as the range list does.
   It sits in the row's end padding, out of the flow, so the counts stay in one
   column whether a row has a chevron or not. */
.count-list__chevron {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: var(--space-1);
  width: 14px;
  height: 14px;
  color: var(--neutral-500);
  transform: translateY(-50%);
  transition: color 0.2s ease-out;
}

.count-list__chevron svg {
  display: block;
  width: 100%;
  height: 100%;
}

.count-list__link:hover .count-list__chevron,
.count-list__link[aria-expanded=true] .count-list__chevron {
  color: var(--text-link);
}

.count-list__link:hover .count-list__count,
.mega-menu__columns .count-list__link[aria-expanded=true] .count-list__count {
  color: var(--text-link);
}

.count-list__item--current {
  border-inline-start: 3px solid var(--color-brand);
}

.count-list__item--current .count-list__link {
  padding-inline-start: calc(var(--space-6) - 3px);
  background-color: var(--bg-card-hover);
  font-weight: var(--fw-medium);
  color: var(--text-link);
}

.count-list__more {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  border-block-start: 1px solid var(--border-default);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
  text-decoration: none;
}

.count-list__more:hover {
  background-color: var(--bg-card-hover);
  color: var(--text-link-hover);
}

.count-list__more svg {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
}

/* ---------------------------------------------------------------------------
   MODIFIER — count-list--touch  (MPG23, the Brands page)
   A count-list that is a page's main route rather than a sidebar's, so on a
   phone every row is a 48px touch target. Nothing changes above 640.
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .count-list--touch .count-list__link {
    align-items: center;
    min-height: 48px;
    padding-inline: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — cta-band  (NEW, layout)
   The band that closes a listing. The shopper has browsed and either found
   something or has not, and that is the point at which to offer the next step.

   It is image-led rather than tinted, and that is brand law rather than taste:
   this brand has one ground and bans alternating band tones, which is how most
   stores mark a section break. Here the break is carried by the photograph.

   A band, so it is the full width of the column it closes; a surface, so it
   takes the card radius like every other surface. The scrim is weighted to the
   leading edge on desktop and flipped bottom-up at phone width, the same way
   the brand's other overlaid image behaves. The title sets medium, which is
   the styleguide's legibility exception for a title laid over photography.
   --------------------------------------------------------------------------- */
.cta-band {
  position: relative;
  display: block;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--neutral-800);
}

.cta-band__media {
  display: block;
  width: 100%;
  aspect-ratio: 1400/420;
  min-height: 320px;
  object-fit: cover;
}

.cta-band__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--bg-overlay) 0%, var(--bg-overlay) 50%, transparent 90%);
}

.cta-band__content {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  max-width: 620px;
  padding: var(--space-8) var(--space-12);
}

.cta-band__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h2);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.cta-band__text {
  margin: var(--space-3) 0 var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-on-brand);
}

@media (max-width: 900px) {
  .cta-band__content {
    max-width: 75%;
    padding: var(--space-6) var(--space-8);
  }
  .cta-band__title {
    font-size: var(--fs-h3);
  }
  .cta-band__text {
    font-size: var(--fs-body);
  }
}
@media (max-width: 640px) {
  .cta-band__media {
    aspect-ratio: 3/4;
    min-height: 440px;
  }
  .cta-band__scrim {
    background: linear-gradient(0deg, var(--bg-overlay) 0%, var(--bg-overlay) 62%, transparent 96%);
  }
  .cta-band__content {
    justify-content: flex-end;
    max-width: none;
    padding: var(--space-6);
  }
}
/* ---------------------------------------------------------------------------
   --spotlight — the band as a ROUTING break rather than a listing's close (the
   store front, MPG21's spotlight-band): one range given the whole column on a
   wide photograph, a small eyebrow, its name large, a line of copy, its
   sub-ranges as on-photo chips with their counts (`.term-chips__list--on-media`)
   and the one button into the range. Same construction and the same scrim law
   as the base; what changes is that the copy is in flow and the photograph
   fills behind it, so the band's height follows its content (a floor of 520)
   rather than the image's ratio — the chips make the content taller than a
   close band's one line.
   --------------------------------------------------------------------------- */
.cta-band--spotlight {
  display: flex;
  align-items: center;
  min-height: 520px;
}

.cta-band--spotlight .cta-band__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-height: 0;
  aspect-ratio: auto;
  object-position: right center;
}

.cta-band--spotlight .cta-band__scrim {
  background: linear-gradient(90deg, var(--bg-overlay) 0%, var(--bg-overlay) 40%, transparent 80%);
}

.cta-band--spotlight .cta-band__content {
  position: relative;
  inset: auto;
  /* A flex item sizes to its content by default, and on a phone the chip row
     is one unwrapped swipe line — without this the whole column takes the
     row's width and the title and copy run off the band's edge. */
  min-width: 0;
  width: 100%;
  gap: var(--space-4);
  max-width: 720px;
  padding: var(--space-16) var(--space-12);
}

.cta-band__eyebrow {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-on-brand);
}

.cta-band--spotlight .cta-band__title {
  font-size: var(--fs-h1);
}

.cta-band--spotlight .cta-band__text {
  margin: 0;
}

.cta-band--spotlight .btn {
  margin-block-start: var(--space-2);
}

@media (max-width: 900px) {
  .cta-band--spotlight .cta-band__content {
    max-width: none;
    padding: var(--space-12) var(--space-8);
  }
  .cta-band--spotlight .cta-band__title {
    font-size: var(--fs-h2);
  }
}
@media (max-width: 640px) {
  .cta-band--spotlight {
    min-height: 0;
  }
  .cta-band--spotlight .cta-band__media {
    aspect-ratio: auto;
    min-height: 0;
  }
  .cta-band--spotlight .cta-band__scrim {
    background: var(--bg-overlay);
  }
  .cta-band--spotlight .cta-band__content {
    justify-content: center;
    padding: var(--space-8) var(--space-6);
  }
  .cta-band--spotlight .cta-band__title {
    font-size: var(--fs-h3);
  }
}
/* ---- composed in the editor (the About page, MPG20) -------------------------

   A cta-band written in the block editor is a group: the photograph is a core
   image (a figure holding the img), the scrim an empty group, the content a group
   of heading, paragraph and button link. The figure takes the media class, so the
   img inside it fills the figure; core's restored inner wrapper is taken out of
   the band's layout, as the global `.grid` repair does. */
.cta-band > .wp-block-group__inner-container {
  display: contents;
}

.cta-band figure.cta-band__media,
.cta-band .cta-band__scrim,
.cta-band .cta-band__content {
  margin: 0;
}

figure.cta-band__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cta-band__content > .wp-block-group__inner-container > :last-child {
  margin-block: 0;
}

/* ---------------------------------------------------------------------------
   BLOCK — decision  (NEW)
   The right-hand column of the header panel: who makes it, what it is, what it
   costs, whether it is here, when it arrives, and the basket — in that order,
   because that is the order the questions arrive in.

   It is a stack with a gap rather than a set of margins, so nothing inside it
   can tie the document's own rhythm rule and win on source order.
   --------------------------------------------------------------------------- */
.decision {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* Brand, SKU and manufacturer part, at the foot and deliberately quiet. A
   component buyer cross-references all three against a build list or a
   compatibility checker; the old store buried them in a tab. */
.decision__identity {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

.decision__identity-pair {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.decision__identity-value {
  font-weight: var(--fw-medium);
  color: var(--text-body);
}

/* The identity line closes the hero card, running its whole width. Brand, SKU,
   manufacturer part and barcode then sit on ONE line — in a half-width column
   they wrapped to two, which is what made the gallery side the taller half. */
.buy-region .description-panel > .decision__identity {
  margin-block-start: var(--space-6);
}

/* ---------------------------------------------------------------------------
   BLOCK — delivery-options  (NEW)
   The delivery speeds, chosen in the basket rather than first met at checkout
   — the one thing the old store's basket did that most stores leave to the
   next page. Each method is a `choice` radio with its price set right, in the
   commerce face because it is a price. The selected method takes the brand's
   current-item wash, the same one the store navigation uses. The rows are a
   bordered group of list rows, so the outline takes the surface radius.
   --------------------------------------------------------------------------- */
.delivery-options {
  min-inline-size: 0;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.delivery-options__legend {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.delivery-options__item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background-color: var(--bg-panel);
}

.delivery-options__item + .delivery-options__item {
  border-block-start: 1px solid var(--border-default);
}

.delivery-options__item--selected {
  background-color: var(--bg-card-hover);
  box-shadow: inset 3px 0 0 var(--border-brand);
}

.delivery-options__item .choice {
  flex: 1 1 auto;
}

.delivery-options__detail {
  display: block;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.delivery-options__price {
  flex: 0 0 auto;
  font-family: var(--ff-chrome);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-body);
  color: var(--text-body);
}

.delivery-options__scope {
  margin: 0 0 var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.delivery-options__note {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-4) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.delivery-options__note-icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  color: var(--text-brand);
}

.description-panel {
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.description-panel__doc > * {
  margin-block: 0;
}

.description-panel__doc > * + * {
  margin-block-start: var(--space-8);
}

.description-panel li:empty {
  display: none;
}

/* ---------------------------------------------------------------------------
   BLOCK — difference-card  (NEW)
   One point that sets the store apart, on its own card: an outline icon, a
   heading-font title, a short body line and a trailing link to the page that
   owns the subject. Heavier than trust-row: each point is a claim WITH its
   reason and a way to check it. The link sits at the card foot so a row of
   uneven copy still lines its links up.

   DEPARTURE: composed in the editor from core blocks, so the icon is not markup
   — a modifier names it and the card draws it, a mask over the brand blue, so
   the editor never holds an SVG. The link's chevron is drawn the same way.
   --------------------------------------------------------------------------- */
/* SCOPED UNDER THE BLOCK. The parts are core paragraphs and headings carrying
   these classes, and the theme's core-block rules (`.wp-block-paragraph`,
   `h3.wp-block-heading`, core's flow margins) load later at the same weight —
   so each part is named inside its block to outrank them. */
.difference-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: var(--space-card-padding);
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}

.difference-card::before {
  content: "";
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  background-color: var(--text-brand);
  mask-position: center;
  mask-size: contain;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
  -webkit-mask-repeat: no-repeat;
}

.difference-card .difference-card__title {
  margin: var(--space-6) 0 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.difference-card .difference-card__text {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.difference-card .difference-card__link {
  margin: auto 0 0;
  padding-block-start: var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
}

.difference-card .difference-card__link a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-link);
  text-decoration: none;
}

.difference-card .difference-card__link a:hover {
  color: var(--text-link-hover);
}

.difference-card .difference-card__link a::after {
  content: "";
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  background-color: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 5 16 12 9 19'/%3E%3C/svg%3E") center/contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 5 16 12 9 19'/%3E%3C/svg%3E") center/contain no-repeat;
}

/* The four icons, from the mockup's outline set. */
.difference-card--range::before {
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 7.5 12 3l9 4.5v9L12 21l-9-4.5z'/%3E%3Cpath d='M3 7.5 12 12l9-4.5'/%3E%3Cline x1='12' y1='12' x2='12' y2='21'/%3E%3C/svg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 7.5 12 3l9 4.5v9L12 21l-9-4.5z'/%3E%3Cpath d='M3 7.5 12 12l9-4.5'/%3E%3Cline x1='12' y1='12' x2='12' y2='21'/%3E%3C/svg%3E");
}

.difference-card--points::before {
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='6' rx='7' ry='2.5'/%3E%3Cpath d='M5 6v4c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5V6'/%3E%3Cpath d='M5 10v4c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5v-4'/%3E%3Cpath d='M5 14v4c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5v-4'/%3E%3C/svg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='6' rx='7' ry='2.5'/%3E%3Cpath d='M5 6v4c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5V6'/%3E%3Cpath d='M5 10v4c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5v-4'/%3E%3Cpath d='M5 14v4c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5v-4'/%3E%3C/svg%3E");
}

.difference-card--pay::before {
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='5' width='19' height='14' rx='1'/%3E%3Cline x1='2.5' y1='9.5' x2='21.5' y2='9.5'/%3E%3Cline x1='6' y1='14.5' x2='10' y2='14.5'/%3E%3C/svg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='5' width='19' height='14' rx='1'/%3E%3Cline x1='2.5' y1='9.5' x2='21.5' y2='9.5'/%3E%3Cline x1='6' y1='14.5' x2='10' y2='14.5'/%3E%3C/svg%3E");
}

.difference-card--help::before {
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 14.4a2.6 2.6 0 0 1-2.6 2.6h-7.8L6.4 20.4v-3.4H5.6A2.6 2.6 0 0 1 3 14.4V6.2a2.6 2.6 0 0 1 2.6-2.6h12.8A2.6 2.6 0 0 1 21 6.2z'/%3E%3Cline x1='7.4' y1='8.2' x2='16.6' y2='8.2'/%3E%3Cline x1='7.4' y1='12.2' x2='13.4' y2='12.2'/%3E%3C/svg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 14.4a2.6 2.6 0 0 1-2.6 2.6h-7.8L6.4 20.4v-3.4H5.6A2.6 2.6 0 0 1 3 14.4V6.2a2.6 2.6 0 0 1 2.6-2.6h12.8A2.6 2.6 0 0 1 21 6.2z'/%3E%3Cline x1='7.4' y1='8.2' x2='16.6' y2='8.2'/%3E%3Cline x1='7.4' y1='12.2' x2='13.4' y2='12.2'/%3E%3C/svg%3E");
}

/* COMPOSED IN THE EDITOR. Core restores `.wp-block-group__inner-container` inside
   every group on a site with no theme.json, so the card would lay out one
   wrapper instead of its parts. The wrapper is taken out of the layout — the
   global `.grid` repair, for this component's own flex/grid containers. */
.difference-card > .wp-block-group__inner-container {
  display: contents;
}

@media (max-width: 640px) {
  .difference-card {
    padding: var(--space-6);
  }
  .difference-card::before {
    width: 32px;
    height: 32px;
  }
  .difference-card .difference-card__title {
    margin-block-start: var(--space-4);
  }
}
/* ---- doc-section (reused from the brand catalogue, verbatim) ---- */
/* ---------------------------------------------------------------------------
   BLOCK — doc-section  (NEW)
   A reference page is consulted, not read: a reader arrives from a support
   email at one section and never sees the rest. So a section is a real object
   rather than a heading followed by some paragraphs — it carries the id the
   contents list and the support email point at, and the scroll offset that
   stops the heading landing flush against the top of the viewport.

   Two gaps, and the difference between them is what makes the page scannable:
   a section and its neighbour are a section gap apart, the shapes inside one
   section a document gap apart. The document gap is the same one the brand's
   other documents already use, so a block written for an article or a product
   description states the right value and lands correctly in here too.

   The rhythm value is stated outright rather than reset to zero. The document
   container's `> * + *` rule is a single-class selector, so a bare `margin: 0`
   here would tie it and win on source order, landing every section flush
   against the last — the trap figure-row and pull-quote already document.

   The heading rule hands the space beneath a section title back to the title's
   own margin, so the heading binds to what it introduces instead of floating
   midway between two shapes. It carries two classes and wins outright.
   --------------------------------------------------------------------------- */
.doc-section {
  margin: var(--space-12) 0 0;
  scroll-margin-block-start: var(--space-12);
}

.doc-section > * + * {
  margin-block-start: var(--space-8);
}

.doc-section > .section-head + * {
  margin-block-start: 0;
}

@media (max-width: 640px) {
  .doc-section {
    margin-block-start: var(--space-8);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — embed-frame  (NEW)
   The slot a third-party document fills — Terms & Conditions and Privacy Policy
   are Termly embeds: Termly hosts the text and its script writes an iframe. The
   slot sits inside article-doc, so the document gets the same panel and column
   as every other help page; the iframe brings its own type and contents list, so
   nothing of ours styles inside it. It runs the column's full width with no
   border, so the panel reads as one surface.
   --------------------------------------------------------------------------- */
.embed-frame {
  min-width: 0;
}

.embed-frame iframe {
  display: block;
  width: 100%;
  min-height: 1200px;
  border: 0;
}

.empty-state {
  padding: var(--space-16) var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
  text-align: center;
}

.empty-state__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.empty-state__text {
  max-width: var(--container-reading);
  margin: var(--space-4) auto 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

@media (max-width: 900px) {
  .empty-state {
    padding: var(--space-12) var(--space-6);
  }
  .empty-state__title {
    font-size: var(--fs-h3);
  }
}
/* --compact: an empty state standing in for ONE panel inside a column, not a whole
   result set — titled at card size so it never out-ranks the page title (operator
   review of MPG13). Ported for the account walk, MPG13. */
.empty-state--compact .empty-state__title {
  font-size: var(--fs-h3);
}

@media (max-width: 900px) {
  .empty-state--compact .empty-state__title {
    font-size: var(--fs-h4);
  }
}
/* The brand form specimen's error summary list (catalogue block `error-list`),
   pasted verbatim into MPG11 for the checkout's error state. */
.error-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.error-list__item {
  padding-block: var(--space-2);
}

.error-list__item + .error-list__item {
  border-block-start: 1px solid var(--border-default);
}

.error-list__link {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-link);
  text-decoration: none;
}

.error-list__link:hover {
  color: var(--text-link-hover);
}

/* ---------------------------------------------------------------------------
   BLOCK — express-checkout  (NEW)
   The fastest way through: Apple Pay and Google Pay, above the form, on its
   own slim panel-white card. An express payment supplies the shopper's name,
   email and address, so taking it skips the form entirely — which is why it
   sits first, and why the divider beneath it says what the form below is for.

   The two buttons are the one place on the page that does not wear the brand:
   the platforms require their own black button with a white mark, drawn here
   with the brand's own ink and panel white (the palette has both, so no value
   outside the seventeen is needed). Everything around them — the card, the
   eyebrow, the hairline divider — is the brand's. The buttons take the square
   control corner; Stripe's Express Checkout Element sets its buttons' corner
   from the Appearance API's border radius, so square is buildable.

   The buttons share the row equally in a flex row, so a device offering only
   one of them shows one full-width button with no gap; a device offering
   neither drops the whole card.
   --------------------------------------------------------------------------- */
.express-checkout {
  padding: var(--space-6) var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.express-checkout__title {
  margin: 0 0 var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.express-checkout__buttons {
  display: flex;
  gap: var(--space-4);
}

.express-checkout__button {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  height: 48px;
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-btn);
  background-color: var(--neutral-900);
  color: var(--neutral-50);
  cursor: pointer;
}

.express-checkout__button svg {
  display: block;
  width: auto;
  height: 22px;
}

.express-checkout__button:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.express-checkout__divider {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin: var(--space-6) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
  text-align: center;
}

.express-checkout__divider::before,
.express-checkout__divider::after {
  content: "";
  flex: 1 1 0;
  min-width: var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

@media (max-width: 640px) {
  .express-checkout {
    padding: var(--space-4);
  }
  .express-checkout__buttons {
    gap: var(--space-3);
  }
  .express-checkout__divider {
    gap: var(--space-3);
  }
}
/* Wiring (MPG11): Stripe prints its own "— OR —" inside its button output and shows it
   with an inline `display` from its script; there is no hook to remove it, so the one
   `!important` on this page takes it down. The card's own divider says what the form
   below is for. */
.express-checkout__buttons #wc-stripe-express-checkout-button-separator {
  display: none !important;
}

/* ---- faq-accordion (reused from the brand catalogue, verbatim) ---- */
/* ---------------------------------------------------------------------------
   BLOCK — faq-accordion  (NEW)
   A real disclosure — `details` and `summary` — and not a styled list with a
   script on it. Three things follow from that and all three are requirements
   rather than preferences: it opens with no JavaScript, a search engine and a
   screen reader see every answer whether or not its row is open, and the
   platform's own fragment-reveal opens a closed row when a link points inside
   it.

   THE ID SITS ON THE ANSWER, not on the row and not on the question. The
   reveal only fires for a target inside the disclosure, and a summary is
   already visible so it does not count — an id on the question scrolls to a
   row that is still shut. On the answer it opens, which is the whole point: a
   support email pointing at one question must not land on a closed page. The
   answer then carries a scroll offset a little deeper than the height of the
   row above it, so the question it belongs to lands on screen with it.

   THE CLOSED ROW — the question at the brand's in-document sub-heading
   setting, a chevron at the far end, a hairline to the next row and nothing
   else. No ground, no border, no box: six questions in a row of boxes reads as
   six cards, and these are one list.

   THE MARKER — the brand's own chevron, the one section-link and count-list
   carry, turned to point down. Down is already how this brand says a thing
   opens: it is the mark on every item in the main navigation and on every bar
   in the store sidebar. It sits at the far end of the row rather than in front
   of the question, so the questions stay flush left and scannable as a column
   of sentences; a leading marker would also collide with the dots the nested
   list puts in that same position elsewhere on the page. Open, it points up.

   THE OPEN ROW — the row differs by more than height, because a reader who has
   scrolled past the summary needs to know which question the answer belongs
   to. It takes the brand's current-item marking exactly as the store sidebar
   and count-list already define it: the blue-tint wash across the whole row,
   the three-pixel Paragon-blue rule on the leading edge, and the question in
   Paragon blue. The rule is paid for out of the row's own padding, so an open
   row is the same width as a closed one and nothing shifts as it opens.

   Hover is the same wash without the rule — a row about to be opened,
   previewing the state it is heading for.

   The measure is the reading measure plus the row's padding: a question is a
   sentence and an answer is a paragraph, so both are read along, not across.
   --------------------------------------------------------------------------- */
.faq-accordion {
  max-width: calc(var(--container-reading) + var(--space-4) * 2);
  /* The rhythm value stated outright — see doc-section. */
  margin: var(--space-8) 0 0;
  border-block: 1px solid var(--border-default);
}

.faq-accordion__item + .faq-accordion__item {
  border-block-start: 1px solid var(--border-default);
}

.faq-accordion__summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-4);
  list-style: none;
  cursor: pointer;
}

/* The browser's own disclosure triangle, removed in both dialects. */
.faq-accordion__summary::-webkit-details-marker {
  display: none;
}

.faq-accordion__summary::marker {
  content: "";
}

.faq-accordion__summary:hover {
  background-color: var(--bg-card-hover);
}

.faq-accordion__summary:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

.faq-accordion__question {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.faq-accordion__marker {
  flex: 0 0 auto;
  display: inline-flex;
  width: 16px;
  height: 16px;
  margin-block-start: 0.3em;
  color: var(--text-brand);
}

.faq-accordion__marker svg {
  width: 100%;
  height: 100%;
  transform: rotate(90deg);
}

.faq-accordion__answer {
  padding: 0 var(--space-4) var(--space-6);
  scroll-margin-block-start: var(--space-16);
}

.faq-accordion__item[open] {
  background-color: var(--bg-card-hover);
  border-inline-start: 3px solid var(--color-brand);
}

/* The leading rule is paid for out of the row's own start padding, so an open
   row is exactly the width of a closed one — the trick count-list already uses
   to mark its current item. */
.faq-accordion__item[open] .faq-accordion__summary,
.faq-accordion__item[open] .faq-accordion__answer {
  padding-inline-start: calc(var(--space-4) - 3px);
}

.faq-accordion__item[open] .faq-accordion__question {
  color: var(--text-link);
}

.faq-accordion__item[open] .faq-accordion__marker svg {
  transform: rotate(-90deg);
}

@media (max-width: 640px) {
  .faq-accordion__summary {
    gap: var(--space-4);
    padding-inline: var(--space-3);
  }
  .faq-accordion__item[open] .faq-accordion__summary,
  .faq-accordion__item[open] .faq-accordion__answer {
    padding-inline-start: calc(var(--space-3) - 3px);
  }
  .faq-accordion__question {
    font-size: var(--fs-body);
  }
  .faq-accordion__answer {
    padding-inline: var(--space-3);
  }
}
.feature-panel {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  align-items: center;
  gap: var(--space-8);
}

.feature-panel--reverse {
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
}

.feature-panel__media {
  display: block;
  width: 100%;
  aspect-ratio: 3/2;
  object-fit: contain;
  background-color: var(--bg-panel);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
}

.feature-panel--reverse .feature-panel__media {
  order: 2;
}

/* The text half. Placed by the track, so no layout here either — only the floor
   that stops a long word in migrated category copy from widening the column past
   its share of the panel and squeezing the render beside it. */
.feature-panel__body {
  min-width: 0;
}

.feature-panel__title {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.feature-panel__text {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

@media (max-width: 768px) {
  .feature-panel,
  .feature-panel--reverse {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
  }
  .feature-panel--reverse .feature-panel__media {
    order: 0;
  }
  .feature-panel__media {
    aspect-ratio: 16/9;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — featured-product  (NEW)
   The range's one rotating slot: a single product given the room a band would
   normally give a grid — manufacturer shot on panel white beside a label, the
   name, the price, one line of copy, the stock fact and one action.

   Authored rather than reused, and the two near misses are worth recording.
   promo-tile has the proportions the build brief points at, but it lays its
   copy over a photograph and carries neither a price nor a button — and this
   brand's product imagery is a manufacturer shot on white that is never cropped
   into a scene. product-card carries every field except the line of copy, but a
   product-card at the full width of the column reads as a product grid holding
   one item, which is the one thing this page must not become.

   The label is the whole point of the slot. One day it reads 'Our Best Seller'
   and the copy is about how many have sold; the next it reads 'Worth A Look'
   and the copy is about a product nobody has bought yet. Same block, same
   geometry, different promise — the words carry the difference, so the operator
   can rotate the slot without the page changing shape underneath them.

   Large promotional copy sets the body font at 18px light, per the styleguide.
   --------------------------------------------------------------------------- */
.featured-product {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  align-items: center;
  gap: var(--space-12);
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.featured-product__media {
  display: block;
  background-color: var(--bg-panel);
}

.featured-product__media img {
  display: block;
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: contain;
}

/* The copy half. The track places it; this is the floor that keeps a product name
   inside the column rather than letting it widen past its 3fr share and take the
   manufacturer shot's width with it. */
.featured-product__body {
  min-width: 0;
}

.featured-product__eyebrow {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-brand);
}

.featured-product__title {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  letter-spacing: 0.01em;
}

.featured-product__title a {
  color: var(--text-heading);
  text-decoration: none;
}

.featured-product__title a:hover {
  color: var(--text-link);
}

.featured-product__price {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.featured-product__text {
  margin: var(--space-4) 0 0;
  max-width: var(--container-reading);
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.featured-product__meta {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: var(--space-4) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.featured-product__stock-dot {
  flex: 0 0 auto;
  translate: 0 -1px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background-color: var(--color-positive);
}

.featured-product__stock-dot--out {
  background-color: var(--color-negative);
}

.featured-product__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin-block-start: var(--space-6);
}

/* section-link is built to close a band, so it carries a top margin and sets
   medium. Beside a button it is neither — the margin knocks it out of line with
   the button, and medium competes with the button it sits next to. */
.featured-product__actions .section-link {
  margin-block-start: 0;
  font-weight: var(--fw-regular);
}

@media (max-width: 900px) {
  .featured-product {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-8);
  }
  .featured-product__media img {
    aspect-ratio: 16/9;
  }
}
@media (max-width: 640px) {
  .featured-product {
    padding: var(--space-6);
  }
  .featured-product__title {
    font-size: var(--fs-h4);
  }
  .featured-product__price {
    font-size: var(--fs-h3);
  }
  .featured-product__text {
    font-size: var(--fs-body);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — field  (REUSED, verbatim)
   The price range's two inputs and the toolbar's sort control are both the
   brand's standard control.
   --------------------------------------------------------------------------- */
.field {
  display: block;
  min-width: 0;
}

/* --wide: spans both tracks of a two-column field grid (field-group__fields). No-op
   outside one. Ported from MPG11 for the checkout walk. */
.field--wide {
  grid-column: 1/-1;
}

.field__label,
.idpc-finder > label {
  display: block;
  margin-block-end: var(--space-2);
  padding: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

/* Required carries no mark; optional is marked, and the form says so once at
   the top. The marker is the only thing that distinguishes the two. */
.field__marker {
  margin-inline-start: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-regular);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.field__help,
.field .description {
  margin: 0 0 var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.field__control,
.idpc-finder input {
  display: block;
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.field__control::placeholder {
  color: var(--neutral-500);
  opacity: 1;
}

/* FOCUS — authored, never the browser's own outline, and three signals so it
   survives on panel white and on canvas grey alike: the border takes the brand
   colour, the ground takes the brand's soft wash, and a 2px brand ring sits
   clear of the box. Nothing changes width, so nothing shifts. */
.field__control:focus,
.field__control:focus-visible,
.field__control--focus,
.idpc-finder input:focus {
  border-color: var(--border-focus);
  background-color: var(--color-brand-soft);
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

/* ERROR — the border doubles to the brand's emphatic weight in alert red and
   the padding gives back the pixel, so an errored field is exactly the size of
   a good one. Red appears here and nowhere else. */
.field--error .field__control,
.field.woocommerce-invalid .field__control {
  border: 2px solid var(--color-negative);
  padding: calc(var(--space-3) - 1px);
}

.field--error .field__control:focus,
.field--error .field__control:focus-visible,
.field--error .field__control--focus,
.field.woocommerce-invalid .field__control:focus {
  border-color: var(--color-negative);
  background-color: var(--bg-input);
  outline-color: var(--color-negative);
}

.field__error,
.field .checkout-inline-error-message {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: var(--space-2) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--color-negative);
}

.field__error-icon {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin-block-start: 0.3em;
}

/* DISABLED — unavailable, not merely pale. The control drops off the panel on
   to the page ground, its text and its label to the disabled grey. */
.field__control:disabled,
.field__control--disabled {
  background-color: var(--bg-page);
  border-color: var(--border-default);
  color: var(--neutral-500);
  cursor: not-allowed;
}

.field--disabled .field__label,
.field--disabled .field__help {
  color: var(--neutral-500);
}

.field__control[type=date]::-webkit-calendar-picker-indicator {
  cursor: pointer;
}

.field__choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-8);
}

/* SELECT — square, own chevron in Paragon blue, greyed while it still shows its
   placeholder. The chevron is the token value inlined; a data URI cannot read a custom
   property. Added by walk-back on the checkout walk (MPG11): the form specimen's port
   left the select and textarea rules out, and the checkout's address select rendered
   the browser's own control. */
select.field__control {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: var(--space-12);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 12'%3E%3Cpath d='M1.5 2 L10 9.5 L18.5 2' fill='none' stroke='%231D7DBB' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
  background-size: 14px auto;
  cursor: pointer;
}

select.field__control:required:invalid {
  color: var(--neutral-500);
}

select.field__control option {
  color: var(--text-body);
}

textarea.field__control {
  line-height: var(--lh-body);
  resize: vertical;
}

/* ---------------------------------------------------------------------------
   WOOCOMMERCE'S OWN FIELD MARKUP (checkout wiring, MPG11). woocommerce_form_field()
   draws a field as p.form-row > label + span.woocommerce-input-wrapper > control +
   span.description, and the checkout script validates through that markup, so it is
   kept and dressed rather than replaced. includes/order-funnel.php adds `field`,
   `field__label` and `field__control`; the rules below cover the parts WooCommerce
   names itself — the help line (drawn above the control, as the brand's field does),
   the required mark (none: the form says so once), the optional mark, the invalid
   state and the inline error, which join the brand rules above.
   --------------------------------------------------------------------------- */
.field.form-row {
  margin: 0;
  padding: 0;
}

.field .woocommerce-input-wrapper {
  display: flex;
  flex-direction: column;
}

.field .description {
  order: -1;
}

.field .required {
  display: none;
}

/* WooCommerce writes "(optional)" with its brackets hard-coded, in PHP and again in
   the address script whenever the country loads, so the text cannot be changed at
   source. The brand's marker is drawn in its place. English-only store. */
.field .optional {
  margin-inline-start: var(--space-2);
  font-size: 0;
}

.field .optional::after {
  content: "Optional";
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-regular);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* WooCommerce enhances the country and county selects with selectWoo (select2), which
   hides the real <select> — the one carrying field__control — and draws its own box.
   Only the closed box is dressed, to the brand control; the open list is select2's own
   furniture (the ARTSABERS precedent). */
.field .select2-container .select2-selection--single {
  height: auto;
  padding: var(--space-3);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
}

.field .select2-container .select2-selection__rendered {
  padding: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.field .select2-container .select2-selection__arrow {
  top: 50%;
  right: var(--space-3);
  transform: translateY(-50%);
}

.field .select2-container--focus .select2-selection--single,
.field .select2-container--open .select2-selection--single {
  border-color: var(--border-focus);
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.field-group {
  display: block;
}

.field-group__title {
  margin: 0 0 var(--space-6);
  padding-block-end: var(--space-3);
  border-block-end: 1px solid var(--border-default);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

/* Two tracks at a measure a control is actually read at — a panel spanning the
   full column must not stretch an order number to half of it. A field that
   needs the room takes --wide and spans both tracks. */
.field-group__fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 24rem));
  gap: var(--space-6) var(--space-content-gap);
  align-items: start;
  justify-content: start;
}

@media (max-width: 900px) {
  .field-group__fields {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .field-group__fields {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* On the checkout, WooCommerce's billing and shipping templates wrap their groups in
   their own divs, so the card's `> * + *` rhythm (description-panel__doc) stops at the
   wrapper and Contact / Address / the deliver-elsewhere choice / Delivery Address sat
   against each other. The same step is given inside the wrappers. (Checkout wiring,
   MPG11.) */
.woocommerce-billing-fields > .field-group + .field-group,
.woocommerce-shipping-fields > .field-group + .field-group {
  margin-block-start: var(--space-8);
}

.figure-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-4);
  /* The list reset has to carry its own top margin. A bare `margin: 0` ties
     with the document's `> * + *` rhythm rule on specificity and wins on
     source order, so the row lands flush against the bullets above it. */
  margin: var(--space-8) 0 0;
  padding: 0;
  list-style: none;
}

.figure-row__cell {
  padding: var(--space-6);
  border: 2px solid var(--border-brand);
  border-radius: var(--radius-card);
}

.figure-row__value {
  display: block;
  font-family: var(--ff-heading);
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.figure-row__label {
  display: block;
  margin-block-start: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

@media (max-width: 900px) {
  .figure-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .figure-row__value {
    font-size: var(--fs-h3);
  }
  .figure-row__cell {
    padding: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — filter-chips  (NEW)
   What the listing is filtered by, above the grid, each one removable, with
   'Clear all' beside them. A filtered listing that does not say what it is
   filtered by is the commonest way a shopper concludes the shop has no stock.

   It sits on a panel like everything else on this brand — content never sits
   directly on the canvas. Each chip is a control, so it is square, and it
   carries the facet name above its value so 'Xbox' cannot be read as a brand
   when it was chosen as a platform.
   --------------------------------------------------------------------------- */
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  padding: var(--space-4) var(--space-6);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.filter-chips__label {
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.filter-chips__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.filter-chips__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--border-brand);
  border-radius: var(--radius-btn);
  background-color: var(--bg-card-hover);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-decoration: none;
}

.filter-chips__chip:hover {
  background-color: var(--bg-panel);
}

.filter-chips__group {
  color: var(--text-muted);
}

.filter-chips__value {
  font-weight: var(--fw-medium);
}

.filter-chips__remove {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  color: var(--text-brand);
}

.filter-chips__clear {
  margin-inline-start: auto;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
  text-decoration: none;
}

.filter-chips__clear:hover {
  color: var(--text-link-hover);
  text-decoration: underline;
}

@media (max-width: 640px) {
  .filter-chips__clear {
    margin-inline-start: 0;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — filter-group  (NEW)
   A collapsible filter panel in the store sidebar.

   It is the brand's widget and not a third labelled-panel treatment: the
   markup composes `widget` unchanged and this block adds only what turns a
   panel into a disclosure — the native marker removed, the brand's chevron at
   the far end of the title bar, pointing down closed and up open. Exactly the
   gesture the store navigation above it uses, at the scale of a panel.

   The body holds whatever the facet needs: a flush `count-list` where the
   values carry counts, the standard `field` controls where it is a range, a
   `choice` where it is a single switch.
   --------------------------------------------------------------------------- */
.filter-group__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  list-style: none;
  cursor: pointer;
}

.filter-group__summary::-webkit-details-marker {
  display: none;
}

.filter-group__summary::marker {
  content: "";
}

.filter-group__summary:focus-visible {
  outline: 2px solid var(--neutral-50);
  outline-offset: -3px;
}

.filter-group__marker {
  flex: 0 0 auto;
  display: inline-flex;
  width: 14px;
  height: 14px;
  color: var(--text-on-brand);
}

.filter-group__marker svg {
  width: 100%;
  height: 100%;
  transform: rotate(90deg);
}

.filter-group[open] .filter-group__marker svg {
  transform: rotate(-90deg);
}

.filter-group__range {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}

/* A filter's form: its controls, then the Apply button, a step apart. The
   price form had its gap as a margin on the range; the availability form had
   none, so Apply sat tight against the checkbox (operator, 2026-10-10). One
   gap on the form now serves both. */
.filter-group__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.filter-group__note {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

/* The brand form specimen's closing row (catalogue block `form-actions`), pasted
   verbatim into MPG11 for the checkout's phone foot. */
.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-6);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

.form-actions__cancel {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
  text-decoration: none;
}

.form-actions__cancel:hover {
  color: var(--text-link);
}

@media (max-width: 640px) {
  .form-actions {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-4);
  }
  .form-actions .btn {
    width: 100%;
  }
  .form-actions__cancel {
    text-align: center;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — form-note  (NEW)
   One quiet line that belongs to a form but to none of its fields: that
   optional fields are the marked ones, a way in for a returning customer, the
   consent line under the order button. Body font at the small size in slate;
   a link inside it is Paragon blue, no underline, as links are in this brand.

   The base sets no top margin on purpose: a note that opens a form, or follows
   a group inside a document, takes its container's own rhythm. The two
   trailing modifiers always follow something — the fields above, the payment
   marks above — so they carry the gap themselves, and say which way they
   align.
   --------------------------------------------------------------------------- */
.form-note {
  margin-block-end: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.form-note a {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
}

.form-note a:hover {
  color: var(--text-link-hover);
}

/* --start: a note closing a field group, on the left like the fields above it. It was
   `--end`, right-aligned, until the operator asked for the checkout's "Already have an
   account?" line to sit left (2026-09-26) — `--end` had no other use, so it is replaced
   rather than kept beside it. */
.form-note--start {
  margin-block-start: var(--space-4);
}

.form-note--center {
  margin-block-start: var(--space-4);
  text-align: center;
}

/* ---------------------------------------------------------------------------
   BLOCK — game-feature  (NEW)
   One operator-picked game that is out now, art-led: KEY ART (never a box
   shot) bled to the top of the card, and beneath it on panel white the
   label, the name in the commerce face, the platforms it comes on, the stock
   fact, the price with its action, and the Clearpay line.

   Authored rather than reused. launch-ad lays its words over the art — that
   is the pre-order mosaic's look, and a second band of it would read as a
   copy. featured-product carries the right fields but frames a manufacturer
   shot on white, padded and contained; key art has to run to the card edge.

   Games are sold one product per platform, so the action follows the game:
   one platform -> Add to Basket; several -> Choose Platform, which opens the
   game's platform choice. When the platforms are priced differently the
   price carries __from ("from £54.99") and the Clearpay line is worked out
   on that lowest price.

   --lead is the same card on its side: the art two-thirds wide on the left,
   the panel on the right with a larger name and price and one line of copy.
   Below 900 it stands back up.
   --------------------------------------------------------------------------- */
.game-feature {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

.game-feature__media {
  display: block;
  background-color: var(--neutral-800);
}

.game-feature__media img {
  display: block;
  width: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
}

.game-feature__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
}

.game-feature__eyebrow {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-brand);
}

.game-feature__title {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  letter-spacing: 0.01em;
}

.game-feature__title a {
  color: var(--text-heading);
  text-decoration: none;
}

.game-feature__title a:hover {
  color: var(--text-link);
}

.game-feature__text {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.game-feature__platforms {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.game-feature__platforms li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.game-feature__platforms svg {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  color: var(--text-brand);
}

.game-feature__meta {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.game-feature__stock-dot {
  flex: 0 0 auto;
  translate: 0 -1px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background-color: var(--color-positive);
}

.game-feature__stock-dot--out {
  background-color: var(--color-negative);
}

.game-feature__buy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  margin-block-start: auto;
  padding-block-start: var(--space-2);
}

.game-feature__price {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.game-feature__from {
  margin-inline-end: var(--space-1);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  font-style: normal;
  color: var(--text-muted);
}

.game-feature__instalments {
  margin: calc(-1 * var(--space-1)) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.game-feature--lead {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
}

/* The art fills its two-thirds whatever height the panel beside it needs. */
.game-feature--lead .game-feature__media {
  position: relative;
  min-height: 400px;
}

.game-feature--lead .game-feature__media img {
  position: absolute;
  inset: 0;
  height: 100%;
  aspect-ratio: auto;
}

.game-feature--lead .game-feature__body {
  justify-content: center;
  gap: var(--space-4);
  padding: var(--space-8);
}

.game-feature--lead .game-feature__title {
  font-size: var(--fs-h2);
}

.game-feature--lead .game-feature__price {
  font-size: var(--fs-h2);
}

.game-feature--lead .game-feature__buy {
  margin-block-start: var(--space-2);
}

@media (max-width: 900px) {
  .game-feature--lead {
    display: flex;
  }
  .game-feature--lead .game-feature__media {
    position: static;
    min-height: 0;
  }
  .game-feature--lead .game-feature__media img {
    position: static;
    height: auto;
    aspect-ratio: 16/9;
  }
}
@media (max-width: 640px) {
  .game-feature__body,
  .game-feature--lead .game-feature__body {
    padding: var(--space-4);
  }
  .game-feature--lead .game-feature__title {
    font-size: var(--fs-h3);
  }
  .game-feature--lead .game-feature__price {
    font-size: var(--fs-h3);
  }
  .game-feature__text {
    font-size: var(--fs-body);
  }
}
/* ---------------------------------------------------------------------------
   LAYOUT — game-mosaic  (NEW; replaces the pre-orders release-board)
   The games the store is promoting hard, as an editorial grid of adverts in
   three sizes: one HERO ad at half the column and two rows tall, up to two
   WIDE ads stacked beside it, and up to four SMALL ads in a row beneath.
   Every tile is a launch-ad on its own key art.

   Built for a count nobody can predict:
     1 ad       --single: the hero alone across the column, one big advert.
     2-3 ads    hero + the stack; one wide ad takes the whole stack height.
     4-7 ads    the row beneath shares its width between however many small
                ads there are, so three small ads are three thirds, never a
                row with a hole in it.
     8+ ads     the mosaic caps at seven and the band closes with "See all
                pre-orders".
   Below 900 the hero and the stack go one column; on a phone the small ads
   become a sideways row.
   --------------------------------------------------------------------------- */
.game-mosaic {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
}

.game-mosaic__top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-content-gap);
  min-height: 560px;
}

.game-mosaic__stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  min-width: 0;
}

.game-mosaic__stack > * {
  flex: 1 1 0;
}

.game-mosaic__row {
  display: flex;
  gap: var(--space-content-gap);
  min-height: 280px;
}

.game-mosaic__row > * {
  flex: 1 1 0;
}

.game-mosaic--single .game-mosaic__top {
  grid-template-columns: minmax(0, 1fr);
}

@media (max-width: 900px) {
  .game-mosaic__top {
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
  }
  .game-mosaic__top > .launch-ad {
    min-height: 440px;
  }
  .game-mosaic__stack > .launch-ad {
    min-height: 260px;
  }
}
@media (max-width: 640px) {
  .game-mosaic,
  .game-mosaic__top,
  .game-mosaic__stack {
    gap: var(--space-4);
  }
  .game-mosaic__top > .launch-ad {
    min-height: 400px;
  }
  .game-mosaic__row {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    gap: var(--space-4);
    margin-inline: calc(-1 * var(--gutter-small));
    padding-inline: var(--gutter-small);
    scroll-padding-inline: var(--gutter-small);
  }
  .game-mosaic__row::-webkit-scrollbar {
    display: none;
  }
  .game-mosaic__row > .launch-ad {
    flex: 0 0 78%;
    min-height: 280px;
    scroll-snap-align: start;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — game-routes  (NEW)
   The quick ways into the games range, on one panel so they never become a
   strip of pills: four platform tiles two by two — each the platform's mark
   (drawn monochrome, like the brand wall) over its name, a hairline outline
   at the card radius, blue-tint wash on hover — then one quiet line of genre
   links under a hairline. A platform with no games in stock is left out at
   build, as the store rail already does; the grid takes three as a row.
   --------------------------------------------------------------------------- */
.game-routes {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-width: 0;
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.game-routes__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.game-routes__platforms {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.game-routes__platform {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  height: 100%;
  min-height: 104px;
  padding: var(--space-4);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  color: var(--text-heading);
  text-align: center;
  text-decoration: none;
}

.game-routes__platform:hover {
  border-color: var(--border-brand);
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

.game-routes__mark {
  display: block;
  width: auto;
  height: 22px;
  max-width: 100%;
}

.game-routes__name {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.game-routes__platform:hover .game-routes__name {
  color: var(--text-link);
}

.game-routes__genres {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-3);
  margin: 0;
  padding: var(--space-4) 0 0;
  border-block-start: 1px solid var(--border-default);
  list-style: none;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
}

.game-routes__genres-label {
  font-weight: var(--fw-medium);
  color: var(--text-body);
}

.game-routes__genres a {
  color: var(--text-link);
  text-decoration: none;
}

.game-routes__genres a:hover {
  color: var(--text-link-hover);
}

@media (max-width: 1100px) {
  .game-routes__platforms {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .game-routes {
    gap: var(--space-4);
    padding: var(--space-6);
  }
  .game-routes__platforms {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .game-routes__platform {
    min-height: 88px;
    padding: var(--space-3);
  }
}
/* ---------------------------------------------------------------------------
   --text — the mark as a short platform name (PS5, XBOX, SWITCH) until the store
   has platform logos. Set as a mark rather than a label: the heading face, heavy,
   tracked, at the logo's height. Added in the MPG21 wiring pass — the mockup drew
   the marks as SVG text stand-ins, which is markup a template cannot keep.
   --------------------------------------------------------------------------- */
.game-routes__mark--text {
  height: auto;
  font-family: var(--ff-heading);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-bold);
  line-height: 1;
  letter-spacing: 0.12em;
  color: var(--text-heading);
}

.game-routes__platform:hover .game-routes__mark--text {
  color: var(--text-link);
}

/* ---------------------------------------------------------------------------
   LAYOUT — hardware-board  (NEW; replaces New In)
   New hardware, art-led like the games mosaic but its own shape: one WIDE
   launch across two-thirds of the column, one TALL launch down the last
   third, two launches beneath the wide one — then a row of three product
   cards (the three-column maximum) for the new hardware you can buy now,
   hardware pre-orders included. Where the games mosaic is a wall of key art,
   this is a launch board: fewer, bigger pictures of the kit itself.
   Below 900 the launches stack in one column.
   --------------------------------------------------------------------------- */
.hardware-board {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
}

.hardware-board__launches {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: 320px 280px;
  gap: var(--space-content-gap);
}

.hardware-board__wide {
  grid-column: span 2;
}

.hardware-board__tall {
  grid-column: 3;
  grid-row: 1/span 2;
}

@media (max-width: 900px) {
  .hardware-board__launches {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
  }
  .hardware-board__launches > .launch-ad {
    min-height: 280px;
  }
  .hardware-board__wide,
  .hardware-board__tall {
    grid-column: auto;
    grid-row: auto;
  }
  .hardware-board__launches > .hardware-board__tall {
    min-height: 380px;
  }
}
@media (max-width: 640px) {
  .hardware-board,
  .hardware-board__launches {
    gap: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — help-frame  (NEW)
   The Information Centre's content column, inside store-layout's content track
   (the store-layout rail carries the help-page list). Three parts:

   __head    the page title, on the canvas. The breadcrumbs sit above the whole
             store layout, full width, as on the product and category pages.
   __body    the text column at the reading measure (article-doc's own width,
             reading measure plus the panel's padding) and, beside it, an
             "On This Page" rail. The rail is a widget, so the jump links sit on
             a panel, never on the canvas; it is sticky because a policy is
             consulted in pieces. Below 1366 there is no room for both, so the
             rail goes and the inline page-contents at the top of the document
             takes over — the inline form is page-contents' own default.

   DEPARTURE: the mockup's `__switch` (the phone's "Help pages" control) is
   store-layout's own `__switch`, which already shows a rail's list as one
   control at the width the rail is removed — the account page's construction.

   The text column is a fixed track rather than a fraction so the measure never
   grows with the screen.
   --------------------------------------------------------------------------- */
.help-frame {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  min-width: 0;
}

.help-frame__body {
  display: grid;
  grid-template-columns: calc(var(--container-reading) + var(--space-card-padding) * 2) minmax(0, 1fr);
  gap: var(--space-content-gap);
  align-items: start;
}

.help-frame__main {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  min-width: 0;
}

/* article-doc centres itself with auto inline margins, and an auto margin in a
   flex column switches stretch off — so a short document (a hosted policy still
   loading) would shrink to its content. The document always takes the column. */
.help-frame__main > .article-doc {
  width: 100%;
  max-width: none;
}

.help-frame__aside {
  position: sticky;
  inset-block-start: var(--space-6);
  min-width: 0;
}

/* In the rail the contents list stands upright instead of running as a wrapped
   row — the same treatment the seo-doc rail gives it. */
.help-frame__aside .page-contents {
  padding: 0;
  border: 0;
}

.help-frame__aside .page-contents__list {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-3);
}

.help-frame__aside .page-contents__item::after {
  content: none;
}

.help-frame__aside .page-contents__link {
  font-size: var(--fs-small);
}

/* A sub-section (an h3 in the document) steps in under its section. */
.help-frame__sub {
  padding-inline-start: var(--space-4);
}

.help-frame__sub .page-contents__link {
  font-weight: var(--fw-regular);
}

.help-frame__inline {
  display: none;
}

/* While the inline contents is hidden, the text that follows it opens the
   document and takes no rhythm gap above it. */
@media (min-width: 1366px) {
  .help-frame__inline + * {
    margin-block-start: 0;
  }
}
/* A jump link lands with the heading clear of the top of the viewport. */
.help-frame .article-doc__h2,
.help-frame .article-doc__h3,
.help-frame .bordered-group__title {
  scroll-margin-block-start: var(--space-12);
}

@media (max-width: 1365px) {
  .help-frame__body {
    grid-template-columns: minmax(0, calc(var(--container-reading) + var(--space-card-padding) * 2));
  }
  .help-frame__aside {
    display: none;
  }
  .help-frame__inline {
    display: block;
  }
}
@media (max-width: 640px) {
  .help-frame,
  .help-frame__body,
  .help-frame__main {
    gap: var(--space-6);
  }
}
.hero-slider {
  /* The arrow's geometry, declared once. The arrow rules below consume it, and
     so does the copy's inline padding — the copy has to clear the arrow, and
     before this was a token that clearance was a hand-added 64px that left
     exactly 4px of daylight. Stated from the parts, the copy follows the arrow
     if the arrow ever moves. */
  --hero-arrow-size: 44px;
  --hero-arrow-inset: var(--space-4);
  /* ALL SLIDES OCCUPY ONE CELL, so they can cross-fade. They used to be
     `display: none` / `block`, which cannot transition — a property that jumps
     between two keywords has nothing to interpolate. Stacking them in a single
     grid cell keeps the tallest slide sizing the band, which absolute
     positioning would have given away, and the band keeps its height with no
     slide visible at all. */
  position: relative;
  display: grid;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--neutral-800);
  box-shadow: var(--shadow-card);
}

/* THE SLIDE OWNS THE BOX, NOT ITS IMAGE.

   Until 2026-09-17 the ratio and the floor sat on `.hero-slider__media`, so the
   slide's height came from its picture. That works in a mockup, where every
   slide has one. It does not work in a theme: the scrim and the copy are both
   absolutely positioned, so a slide with no image has NO in-flow child at all
   and collapses to zero — and the whole hero with it. The band did not look
   broken, it looked absent, which is why it read as a missing block rather than
   a sizing rule in the wrong place.

   The brand has no hero photography yet, so this is the normal case rather than
   an edge one. The slide now carries the design's own 1400x520 proportion with a
   floor for narrow viewports, and the image — when one lands — fills that box
   instead of defining it. `.hero-slider` already paints a ground, so an
   image-less slide shows brand colour under the scrim rather than nothing. */
.hero-slider__slide {
  position: relative;
  grid-area: 1/1;
  aspect-ratio: 1400/520;
  min-height: 380px;
  /* Hidden, but still laid out — that is the point of stacking them. `opacity`
     carries the fade; `visibility` is what takes an inactive slide out of the
     accessibility tree and off the tab order, which `opacity: 0` alone does not
     do. Its transition is a zero-length step DELAYED until the fade finishes, so
     the outgoing slide stays visible while it fades and only then stops
     existing. Transitioning visibility as a duration instead makes it flicker
     half way. */
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--motion-standard) var(--motion-ease), visibility 0s linear var(--motion-standard);
}

.hero-slider__slide.is-active {
  /* Above its siblings so that during the fade the OUTGOING slide's scrim is not
     the thing a pointer lands on. The controls sit above both — see the z-index
     on the arrows and dots, which is load-bearing rather than tidy: without it
     this line alone puts the whole slide over them and every click hits the
     scrim instead of the button. The slider is then silently dead, and it still
     looks perfect. */
  z-index: 1;
  opacity: 1;
  visibility: visible;
  transition: opacity var(--motion-standard) var(--motion-ease), visibility 0s linear 0s;
}

/* A slider is decoration a reader did not ask to move. Honour the system
   setting: the slide still changes, it just arrives rather than fades. */
@media (prefers-reduced-motion: reduce) {
  .hero-slider__slide,
  .hero-slider__slide.is-active {
    transition: none;
  }
}
.hero-slider__media {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-slider__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--bg-overlay) 0%, var(--bg-overlay) 40%, transparent 78%);
}

.hero-slider__content {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-6);
  max-width: 680px;
  /* CLEARS THE ARROW WITH ROOM TO SPARE, rather than by four pixels. The old
     value was a flat 64px against an arrow that ends at 60 — technically clear,
     and it read as the copy being jammed against the control. Built from the
     arrow's own geometry plus a gap, so it is 24px of daylight by construction
     and stays right if the arrow moves. Measured before: text at x=84, arrow
     ending at x=80. */
  padding-inline-start: calc(var(--hero-arrow-inset) + var(--hero-arrow-size) + var(--space-6));
  padding-inline-end: var(--space-8);
  padding-block: var(--space-8);
  text-align: left;
}

.hero-slider__eyebrow {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-on-brand);
}

.hero-slider__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.hero-slider__lead {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-on-brand);
}

.hero-slider__arrow {
  position: absolute;
  /* Above the slide stack — see the note on `.is-active`. */
  z-index: 2;
  inset-block-start: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--hero-arrow-size);
  height: var(--hero-arrow-size);
  border: 0;
  border-radius: var(--radius-btn);
  background-color: var(--btn-primary-bg);
  color: var(--btn-primary-text);
  cursor: pointer;
}

.hero-slider__arrow:hover {
  background-color: var(--btn-primary-bg-hover);
}

.hero-slider__arrow--prev {
  inset-inline-start: var(--hero-arrow-inset);
}

.hero-slider__arrow--next {
  inset-inline-end: var(--hero-arrow-inset);
}

.hero-slider__arrow svg {
  width: 22px;
  height: 22px;
}

.hero-slider__dots {
  position: absolute;
  /* Above the slide stack — see the note on `.is-active`. */
  z-index: 2;
  inset-block-end: var(--space-6);
  inset-inline-start: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: var(--space-3);
}

.hero-slider__dot {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: var(--radius-pill);
  background-color: var(--color-surface);
  opacity: 0.55;
  cursor: pointer;
}

.hero-slider__dot.is-current {
  background-color: var(--color-brand);
  opacity: 1;
}

@media (max-width: 1100px) {
  .hero-slider__content {
    /* NOT a flat value here either. The arrow is the same size at this width,
       so the clearance is the same calculation — restating 64px would put the
       copy back against the control below 1100 only, which is the kind of
       fault that survives a desktop check. */
    padding-inline-start: calc(var(--hero-arrow-inset) + var(--hero-arrow-size) + var(--space-6));
    padding-inline-end: var(--space-6);
    max-width: 560px;
  }
}
@media (max-width: 900px) {
  .hero-slider__title {
    font-size: var(--fs-h2);
  }
}
@media (max-width: 640px) {
  /* THE RATIO FOLLOWED THE BOX. When the slide took ownership of its own height
     on 2026-09-17 this override was left pointing at the media, which no longer
     sizes anything — so the phone hero fell back to the 380px floor instead of
     the design's portrait crop, and nothing looked broken enough to notice. */
  .hero-slider__slide {
    aspect-ratio: 4/5;
    min-height: 420px;
  }
  .hero-slider__scrim {
    background: linear-gradient(0deg, var(--bg-overlay) 0%, var(--bg-overlay) 55%, transparent 95%);
  }
  .hero-slider__content {
    justify-content: flex-end;
    padding-inline-start: var(--space-6);
    padding-inline-end: var(--space-6);
    padding-block-end: var(--space-16);
    max-width: none;
    gap: var(--space-4);
  }
  /* THE ARROWS MOVE OFF THE COPY. Below 640 the slide goes portrait and the copy
     moves to the BOTTOM of it, while the arrows stay vertically centred — which
     puts the prev arrow straight through the lead paragraph. Measured at 390:
     arrow 392-436, lead 401-509, a genuine overlap that the title cleared and
     the paragraph did not.

     Pinned to the top of the slide rather than nudged up a percentage, so the
     clearance does not drift when a slide's copy runs to another line. The
     transform goes with the centring it existed to correct. */
  .hero-slider__arrow {
    inset-block-start: var(--space-8);
    transform: none;
  }
  .hero-slider__title {
    font-size: var(--fs-h3);
  }
  .hero-slider__lead {
    font-size: var(--fs-body);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — house-ad  (NEW)
   "From the store": the magazine carries the shop's own adverts, not third-
   party ones. Product-led, labelled plainly, and never louder than the text
   around it — a hairline outline on white rather than a filled band, one
   product, one commerce button, one quiet View link.

   --inline sits once in the body where the old in-article ad marker was: a
   single compact row at the reading-column width. --rail is the portrait
   form for the rail. When the article has no game hub the rail form holds a
   promo-tile from the store's promo pool instead of a product.
   --------------------------------------------------------------------------- */
.house-ad {
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
}

.house-ad__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* The label's store icon — the listing advert carries one (MPG15). */
.house-ad__label svg {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--text-brand);
}

.house-ad__media {
  display: block;
}

.house-ad__media img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
  background-color: var(--bg-card);
}

.house-ad__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.house-ad__title {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
}

.house-ad__title a {
  color: var(--text-heading);
  text-decoration: none;
}

.house-ad__title a:hover {
  color: var(--text-link);
}

.house-ad__price {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.house-ad__meta {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.house-ad__actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.house-ad__view {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
  text-decoration: none;
}

.house-ad__view:hover {
  color: var(--text-link-hover);
}

.house-ad--inline {
  margin: var(--space-8) 0 0;
  display: grid;
  grid-template-columns: 112px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-4) var(--space-6);
  padding: var(--space-4) var(--space-6);
  border: 1px solid var(--border-default);
}

.house-ad--rail {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
}

.house-ad--rail .house-ad__media img {
  aspect-ratio: 4/3;
}

.house-ad--rail .house-ad__actions {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-3);
  text-align: center;
}

@media (max-width: 640px) {
  .house-ad--inline {
    grid-template-columns: 88px minmax(0, 1fr);
    padding: var(--space-4);
  }
  .house-ad--inline .house-ad__actions {
    grid-column: 1/-1;
  }
}
/* ---------------------------------------------------------------------------
   MODIFIER — house-ad--listing  (MPG15, section landing)
   The advert once in a list of articles, after the sixth: a wide row — image,
   text, button — the same height class as the review cards around it, and with
   their card shadow so it sits in the list rather than on it. The mockup named
   the parts __name and __action; they are the base __title and __actions here,
   so one advert partial serves the article and the listing. Its phone rules are
   scoped to the variant — unscoped, they would have resized the article's adverts.
   --------------------------------------------------------------------------- */
.house-ad--listing {
  display: grid;
  overflow: hidden;
  box-shadow: var(--shadow-card);
  grid-template-columns: 160px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-6) var(--space-card-padding);
}

.house-ad--listing .house-ad__body {
  min-width: 0;
  max-width: var(--container-reading);
}

@media (max-width: 640px) {
  .house-ad--listing {
    grid-template-columns: 96px minmax(0, 1fr);
    gap: var(--space-4) var(--space-6);
    padding: var(--space-6);
  }
  .house-ad--listing .house-ad__actions {
    grid-column: 1/-1;
  }
  .house-ad--listing .house-ad__actions .btn {
    width: 100%;
  }
  .house-ad--listing .house-ad__title {
    font-size: var(--fs-body);
  }
  .house-ad--listing .house-ad__price {
    font-size: var(--fs-h4);
  }
}
.hub-header {
  overflow: hidden;
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.hub-header__banner {
  position: relative;
  display: flex;
  align-items: flex-end;
  aspect-ratio: 1400/400;
  min-height: 240px;
  background-color: var(--bg-chrome);
}

.hub-header__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hub-header__scrim {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(0deg, var(--bg-overlay) 0 38%, transparent 85%);
}

.hub-header__heading {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
  width: 100%;
  padding: var(--space-6) var(--space-card-padding);
}

.hub-header__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.hub-header__banner .hub-header__title {
  color: var(--text-on-brand);
}

.hub-header__score {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-decoration: none;
}

.hub-header__score-label {
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.hub-header__banner .hub-header__score-label {
  color: var(--text-on-brand);
}

.hub-header__body {
  padding: var(--space-6) var(--space-card-padding) var(--space-card-padding);
}

.hub-header--plain .hub-header__heading {
  padding-block: var(--space-card-padding) 0;
}

.hub-header__summary {
  max-width: var(--container-reading);
  margin: 0 0 var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.hub-header__contents {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-8);
  margin: 0;
  padding: var(--space-4) 0 0;
  border-block-start: 1px solid var(--border-default);
  list-style: none;
}

.hub-header__contents-link {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
  text-decoration: none;
}

.hub-header__contents-link:hover {
  color: var(--text-link-hover);
}

.hub-header__contents-count {
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  color: var(--text-muted);
}

@media (max-width: 900px) {
  .hub-header__title {
    font-size: var(--fs-h2);
  }
}
@media (max-width: 640px) {
  .hub-header__banner {
    aspect-ratio: 2/1;
    min-height: 180px;
  }
  .hub-header__heading {
    gap: var(--space-4);
    padding: var(--space-4) var(--space-6);
  }
  .hub-header--plain .hub-header__heading {
    padding-block-start: var(--space-6);
  }
  .hub-header__title {
    font-size: var(--fs-h3);
  }
  .hub-header__body {
    padding: var(--space-4) var(--space-6) var(--space-6);
  }
  .hub-header__summary {
    font-size: var(--fs-body);
  }
}
/* ---- the policy band ------------------------------------------------------

   Four short blocks at the foot: delivery, returns, ways to pay, help. Each
   names the product or its category and links to the page that owns the
   subject.

   Four across the content column gives each block about 223px, which is a
   footer column's width and is why the copy is deliberately short. It is also
   the point: this band exists so the product term and the payment or delivery
   term appear in ONE document, which is what a dedicated policy page can never
   do for a compound query. Volume of text would work against it.
   --------------------------------------------------------------------------- */
/* The band carries its own surface rather than being wrapped in a panel, because
   it now has two consumers — the product page and the category archive — and a
   block that needs a wrapper to look right is a block that gets composed wrong
   on the third page. */
.info-band {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-12) var(--space-16);
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

/* The grid item. The track places it, so it declares no layout of its own — this
   is the floor that keeps it inside that track. A grid item's default minimum is
   its own longest word, and this copy names the product it sits on, which arrives
   from the catalogue and can be a single unbroken string. Without the floor one
   such name widens the item past its 459px column and the two-up row goes with it. */
.info-band__block {
  min-width: 0;
}

.info-band__title {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.info-band__text {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.info-band .section-link {
  margin-block-start: var(--space-3);
  font-size: var(--fs-small);
}

@media (max-width: 560px) {
  .info-band {
    grid-template-columns: minmax(0, 1fr);
  }
}
.inline-form {
  margin: var(--space-6) 0 0;
}

.inline-form__row {
  display: grid;
  grid-template-columns: minmax(0, 18rem) minmax(0, 22rem) auto;
  gap: var(--space-4);
  align-items: end;
  justify-content: start;
}

/* --single: one field and its button, the field taking the width — a search box in
   a 328px sidebar (MPG15 walk-back) cannot hold the three-column row. It stands
   alone in its panel, so it takes no top margin. */
.inline-form--single {
  margin: 0;
}

.inline-form--single .inline-form__row {
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-3);
}

/* The button's own padding gives back the two pixels the inputs spend on their
   borders, so the row reads as one height. */
.inline-form__action .btn {
  padding-block: calc(var(--space-3) + 1px);
}

@media (max-width: 900px) {
  .inline-form__row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  }
}
@media (max-width: 640px) {
  .inline-form__row {
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
    gap: var(--space-6);
  }
  .inline-form__action .btn {
    width: 100%;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — launch-ad  (NEW)
   An advert for one product, art-led: KEY ART (never a box shot) filling a
   tile at the card radius, a foot scrim, and over it the platform and
   release date as the eyebrow, the title (medium — the brand's legibility
   rule for type on photography), the price in the commerce face with the
   one action beside it, and the Clearpay line. Size is the layout's
   decision, not the tile's: the same tile is the games mosaic's hero and its
   small ads, and the new-hardware board's launches. --lead adds the room a
   lead tile has: larger title and price, and one line of copy.
   --------------------------------------------------------------------------- */
.launch-ad {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-width: 0;
  min-height: 0;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--neutral-800);
}

.launch-ad__art {
  position: absolute;
  inset: 0;
  display: block;
}

.launch-ad__media {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.launch-ad__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, var(--bg-overlay) 0%, var(--bg-overlay) 30%, transparent 75%);
}

.launch-ad__content {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-6);
}

.launch-ad__eyebrow {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-on-brand);
}

.launch-ad__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
}

.launch-ad__title a {
  color: var(--text-on-brand);
  text-decoration: none;
}

.launch-ad__text {
  margin: 0;
  max-width: 560px;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-on-brand);
}

.launch-ad__buy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  margin-block-start: var(--space-1);
}

.launch-ad__price {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.launch-ad__buy .btn {
  padding-block: var(--space-2);
}

.launch-ad__instalments {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.launch-ad--lead .launch-ad__content {
  gap: var(--space-3);
  padding: var(--space-12);
}

.launch-ad--lead .launch-ad__title {
  font-size: var(--fs-h1);
}

.launch-ad--lead .launch-ad__price {
  font-size: var(--fs-h3);
}

@media (max-width: 640px) {
  .launch-ad__content,
  .launch-ad--lead .launch-ad__content {
    padding: var(--space-4);
  }
  .launch-ad--lead .launch-ad__title {
    font-size: var(--fs-h3);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — lead-story  (REUSED, verbatim — plus one NEW modifier, --split)
   --------------------------------------------------------------------------- */
.lead-story {
  display: flex;
  flex-direction: column;
  height: 100%;
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

.lead-story__media {
  position: relative;
  display: block;
  flex: 1 0 auto;
  aspect-ratio: 16/9;
}

.lead-story__media img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.lead-story__body {
  display: flex;
  flex-direction: column;
  padding: var(--space-card-padding);
}

.lead-story__kicker {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-brand);
}

.lead-story__title {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
  font-style: italic;
  line-height: var(--lh-heading);
}

.lead-story__title a {
  color: var(--text-brand);
  text-decoration: none;
}

.lead-story__title a:hover {
  color: var(--text-link-hover);
}

.lead-story__standfirst {
  max-width: var(--container-reading);
  margin: var(--space-4) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.lead-story__meta {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

.lead-story__byline {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.lead-story__author {
  font-weight: var(--fw-medium);
}

.lead-story__date {
  color: var(--text-muted);
}

@media (max-width: 640px) {
  .lead-story__title {
    font-size: var(--fs-h3);
  }
  .lead-story__standfirst {
    font-size: var(--fs-body);
  }
}
.lead-story--split {
  flex-direction: row;
}

.lead-story--split .lead-story__media {
  flex: 0 0 50%;
  aspect-ratio: auto;
  min-height: 300px;
}

.lead-story--split .lead-story__body {
  flex: 1 1 auto;
  justify-content: center;
}

@media (max-width: 900px) {
  .lead-story--split {
    flex-direction: column;
  }
  .lead-story--split .lead-story__media {
    flex: 1 0 auto;
    aspect-ratio: 16/9;
    min-height: 0;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — listing-toolbar  (NEW)
   The row above the grid: what you are looking at on the left, how it is
   ordered and how it is laid out on the right.

   Beneath it, quiet and left-aligned, the dispatch line. The store's real term
   is 2pm Monday to Friday, so before the cut-off it counts the time left and
   after it reads 'Ordered today, dispatched tomorrow' — the same slot, never
   empty, never a countdown to nothing.

   The sort control is the brand's standard select, given an auto width; the
   view toggle is two square controls with the current one filled, because
   this brand offers both layouts and the shopper chooses.
   --------------------------------------------------------------------------- */
.listing-toolbar {
  padding: var(--space-4) var(--space-6);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.listing-toolbar__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.listing-toolbar__count {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.listing-toolbar__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.listing-toolbar__label {
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

/* The sort control arrives inside WooCommerce's own form, which is what carries
   the active filters through a sort as hidden inputs. The form is the flex item
   and has no appearance of its own — this only stops a margin arriving from the
   platform's stylesheet and pushing the select out of the row. */
.listing-toolbar__ordering {
  margin: 0;
}

.listing-toolbar__select {
  width: auto;
  min-width: 210px;
  padding-block: var(--space-2);
}

.listing-toolbar__views {
  display: flex;
  gap: var(--space-2);
  margin-inline-start: var(--space-2);
}

.listing-toolbar__view {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  background-color: var(--bg-panel);
  color: var(--text-brand);
  cursor: pointer;
}

.listing-toolbar__view svg {
  width: 18px;
  height: 18px;
}

.listing-toolbar__view:hover {
  border-color: var(--border-brand);
  background-color: var(--bg-card-hover);
}

.listing-toolbar__view--current {
  border-color: var(--btn-primary-bg);
  background-color: var(--btn-primary-bg);
  color: var(--btn-primary-text);
}

.listing-toolbar__view--current:hover {
  border-color: var(--btn-primary-bg-hover);
  background-color: var(--btn-primary-bg-hover);
  color: var(--btn-primary-text);
}

.listing-toolbar__dispatch {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-4) 0 0;
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--border-default);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.listing-toolbar__dispatch svg {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  color: var(--text-brand);
}

@media (max-width: 640px) {
  .listing-toolbar__controls {
    width: 100%;
  }
  .listing-toolbar__select {
    flex: 1 1 auto;
    min-width: 0;
  }
  .listing-toolbar__views {
    margin-inline-start: 0;
  }
}
/* The loyalty claim, given the weight the operator asked for. It keeps the
   brand's one labelled-panel treatment rather than inventing a second surface —
   the impact is in the size of the figure, which is set in the commerce face at
   h2, matching the pay-later card opposite so the two are the same height. */
.loyalty-card__body {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.loyalty-card__icon {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  color: var(--text-brand);
}

.loyalty-card__icon svg {
  width: 100%;
  height: 100%;
}

/* The figures beside the icon. A flex item's default minimum is its longest word,
   and the card sits in a 476px half of the hero — the floor lets the wording under
   the figure wrap instead of pushing the icon out of the row. */
.loyalty-card__figures {
  min-width: 0;
}

.loyalty-card__points {
  display: block;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  /* Black, not brand blue — operator, 2026-09-15. The blue read as a link at
     that size and the card already has blue on its title bar. */
  color: var(--text-heading);
}

.loyalty-card__worth {
  display: block;
  margin-block-start: var(--space-1);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

/* Both cards carry a trailing link, which is what makes them the same height —
   and that is the only way two cards bottom-aligned can also line up along the
   top. Bottom-aligning alone put their title bars 36px apart, which reads worse
   than the 14px it was meant to fix, because the eye follows the blue bar and
   not the foot of the card. */
.paylater-card .section-link,
.loyalty-card__status {
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.loyalty-card .section-link {
  margin-block-start: var(--space-4);
}

/* ---------------------------------------------------------------------------
   BLOCK — card-barcode  (NEW)
   A scanner needs a quiet margin either side of the bars and dark bars on a
   light ground, whatever the panel behind it — so the barcode keeps its own card-white
   ground and padding. Capped at 360px: wider bars read no better, and on a
   phone it shrinks with the column.
   --------------------------------------------------------------------------- */
.card-barcode {
  max-width: 360px;
  margin: 0;
  padding: var(--space-4) var(--space-6);
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
}

.card-barcode svg {
  display: block;
  width: 100%;
  height: auto;
}

.card-barcode__number {
  margin-block-start: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  letter-spacing: 0.08em;
  text-align: center;
  color: var(--text-body);
}

/* BLOCK — media-figure (NEW) */
.media-figure {
  margin: var(--space-8) 0 0;
}

.media-figure--bleed {
  margin-inline: calc(-1 * var(--space-card-padding));
}

.media-figure__media {
  display: block;
  width: 100%;
  height: auto;
  border-block: 1px solid var(--border-default);
}

.media-figure__caption {
  margin-block-start: var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.media-figure--bleed .media-figure__caption {
  padding-inline: var(--space-card-padding);
}

/* ---------------------------------------------------------------------------
   BLOCK — message-panel  (NEW)
   The top of the page-not-found page: one calm statement of what happened and
   the search to get past it. A panel, because this brand puts content on a
   panel and never on the canvas.

   The 404 is a small slate label above the title — secondary on purpose: the
   number is for the record, the sentence is for the shopper. The title is a
   page title at h1 size and so sets LIGHT (the band-title rule; this is not a
   hero and not laid over photography). The sentence is large promotional
   copy, so body font at 18px light, held to the reading measure.

   The __search slot carries the search-field component full width — the same
   field the search modal uses, so a lost shopper meets the control they will
   meet again in the header.
   --------------------------------------------------------------------------- */
.message-panel {
  padding: var(--space-12);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.message-panel__label {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.message-panel__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.message-panel__text {
  max-width: var(--container-reading);
  margin: var(--space-4) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.message-panel__search {
  margin-block-start: var(--space-8);
}

@media (max-width: 900px) {
  .message-panel__title {
    font-size: var(--fs-h2);
  }
}
@media (max-width: 640px) {
  .message-panel {
    padding: var(--space-6);
  }
  .message-panel__text {
    font-size: var(--fs-body);
  }
  .message-panel__search {
    margin-block-start: var(--space-6);
  }
}
/* ---- panel (modal only) ---- */
.modal:not(.search) .modal__wrapper {
  position: relative;
  max-width: 680px;
  margin-block-start: var(--space-8);
  padding: 0;
  background-color: transparent;
}

/* ---- close (modal only) ---- */
.modal:not(.search) .modal__close {
  top: 16px;
  right: 16px;
  z-index: 1;
  width: 40px;
  height: 40px;
}

.modal:not(.search) .modal__close .icon {
  fill: var(--text-body);
  transition: fill 200ms ease;
}

.modal:not(.search) .modal__close:hover .icon {
  fill: var(--color-brand);
}

@media (max-width: 767px) {
  .modal:not(.search) .modal__wrapper {
    margin-block-start: var(--space-4);
    padding-inline: var(--space-4);
  }
  .modal:not(.search) .modal__close {
    right: calc(var(--space-4) + 8px);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — order-close  (EXTENDED on the second review, markup only)
   One quiet line of help links — plain section-links, the brand's trailing
   link. The trailing button slot is now optional: on the confirmation,
   Continue Shopping moved to the foot of Complete Your Setup, so the row here
   carries the links alone. The CSS is unchanged; with no button the row's
   space-between simply leaves the links on the left. Not a band and not a panel: the design brief lets
   the canvas carry the small trailing links that follow a band, and this is
   exactly that. The section-link's own top margin is handed back to the row.
   --------------------------------------------------------------------------- */
.order-close {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4) var(--space-8);
}

.order-close__links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-8);
  margin: 0;
  padding: 0;
  list-style: none;
}

.order-close__links .section-link {
  margin-block-start: 0;
}

@media (max-width: 640px) {
  .order-close {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-6);
  }
  .order-close__links {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
  }
  .order-close .btn {
    width: 100%;
  }
}
.order-layout {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  align-items: start;
  gap: var(--gutter-small);
}

.order-layout__main {
  grid-column: span 5;
}

.order-layout__aside {
  position: sticky;
  top: var(--space-6);
  grid-column: span 2;
}

/* Each column stacks its panels with a flex GAP, not a `> * + *` margin (changed for
   the checkout walk, MPG11): the checkout's main column opens with the phone-only
   summary toggle, and hidden above phone width it still counted as "a previous
   sibling", so the first visible panel took the gap and sat 30px below the summary's
   top edge. A gap is only laid between boxes that render. */
.order-layout__main,
.order-layout__aside {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
}

.order-layout__main > *,
.order-layout__aside > * {
  margin-block: 0;
}

/* __stack: a container INSIDE a column that stacks the column's panels — the basket's
   cart form. WooCommerce's cart form wraps every package panel, so the column's own
   spacing reaches only the form, and the panels would touch. Added by walk-back
   during the MPG10 packages composition (2026-09-24). */
.order-layout__stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
}

.order-layout__stack > * {
  margin-block: 0;
}

/* The Smart Coupons plugin reserves a slot at the top of the cart form for its coupon
   messages — a wrapper holding an empty placeholder whenever there is no message. As a
   flex item it still took a line and a gap, dropping the first panel 50px below the
   summary. Hidden only while it holds nothing but the placeholder, so a real coupon
   message still shows. Once a coupon is applied it re-renders with no placeholder at
   all — only whitespace, which :empty does not match — hence the second selector. */
.order-layout__stack > .wc_coupon_message_wrap:has(> .no_wc_coupon_message:only-child),
.order-layout__stack > .wc_coupon_message_wrap:not(:has(*)) {
  display: none;
}

/* WooCommerce's checkout script puts its error summary (and any update notices) at the
   top of the checkout form — which is this grid — so without this it lands in one
   seventh-wide cell and pushes both columns out of place. It spans the grid, above both
   columns. (Checkout wiring, MPG11.) */
.order-layout > .woocommerce-NoticeGroup {
  grid-column: 1/-1;
}

/* --settled: the order confirmation (MPG12). The order is placed and there is no button
   to keep in reach, so nothing sticks; and below 1100 the aside — Delivering To — takes
   the full width rather than the basket's 480px right-hand column. */
.order-layout--settled .order-layout__aside {
  position: static;
}

@media (max-width: 1100px) {
  .order-layout--settled .order-layout__aside {
    max-width: none;
  }
}
/* The checkout's summary panel is a bordered-group, whose `overflow: hidden` crops its
   title to the card radius — and also makes it a scroll container, which silently
   cancels any `position: sticky` inside it: the payment marks pinned to the viewport
   foot (order-totals__action--sticky) sat at the panel's end instead. `clip` crops the
   same without creating a scroll container. */
.order-layout__summary {
  overflow: clip;
}

/* The checkout's phone piece (MPG11): __toggle is the order summary folded into a bar
   above the form. It stands down while the sidebar does its job, and at phone width
   __summary — the sidebar's summary panel — stands down for it. */
.order-layout__toggle {
  display: none;
}

@media (max-width: 1100px) {
  .order-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  .order-layout__main,
  .order-layout__aside {
    grid-column: 1/-1;
  }
  .order-layout__aside {
    position: static;
    max-width: 480px;
    justify-self: end;
    width: 100%;
  }
}
@media (max-width: 640px) {
  .order-layout__aside {
    max-width: none;
  }
  .order-layout__toggle {
    display: block;
  }
  .order-layout__summary {
    display: none;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — order-lines  (NEW)
   What is in the order, compactly, grouped by package — the checkout
   summary's contents above its totals. Each package opens with the basket's
   own package-head and closes with its delivery as an order-totals row, so the
   three parts are the basket's vocabulary at a sidebar's width; this block is
   only the grouping and the compact line.

   A line is a small manufacturer shot on a hairline tile at the surface
   radius, the title in the commerce face at the small size and never more
   than two lines, the quantity, and the line total in the commerce face. A
   pre-order line keeps its marker, with the brand-blue dot the basket gives
   it. The block closes on a hairline, so the grand totals below it start
   clean.
   --------------------------------------------------------------------------- */
.order-lines {
  margin: 0 0 var(--space-4);
  padding: 0 0 var(--space-6);
  list-style: none;
  border-block-end: 1px solid var(--border-default);
}

/* The closing hairline separates the lines from the totals BELOW them. Where nothing
   follows — Track Order lists the packages and stops — it closed the panel on a stray
   line, so it only draws when something comes after (refinement list, 2026-09-27). */
.order-lines:last-child {
  margin-block-end: 0;
  padding-block-end: 0;
  border-block-end: 0;
}

.order-lines__package + .order-lines__package {
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

.order-lines__list {
  margin: var(--space-4) 0 var(--space-2);
  padding: 0;
  list-style: none;
}

.order-lines__item {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-3);
}

.order-lines__item + .order-lines__item {
  margin-block-start: var(--space-3);
}

.order-lines__media {
  display: block;
  padding: var(--space-1);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background-color: var(--bg-card);
}

.order-lines__media img {
  display: block;
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: contain;
}

.order-lines__info {
  min-width: 0;
}

.order-lines__title {
  display: -webkit-box;
  margin: 0;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  font-family: var(--ff-chrome);
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.order-lines__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-3);
  margin: var(--space-1) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.order-lines__marker {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: var(--fw-medium);
  color: var(--text-body);
}

.order-lines__marker::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background-color: var(--color-brand);
}

.order-lines__total {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
  white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   BLOCK — order-status  (NEW)
   An order's status as a small indicator: a round dot — round indicators take
   the pill radius, per the shape law — and the status name in body text at
   medium weight, ink. The colour is only ever the dot; the words stay ink, so
   no status reads as coloured text.

   The modifier is WooCommerce's own status slug, so the template writes
   `order-status--{slug}` from the order and never picks a colour per row.
   Custom statuses registered in camcom-global fall back to the base grey dot
   until they are given one.
     processing, on-hold  Paragon blue — with us, in hand
     completed            go green — the brand's positive confirmation
     pending              slate, hollow — waiting on payment
     failed, cancelled    alert red — an error state, which is red's job
     refunded             mist — closed, nothing more to happen
   --------------------------------------------------------------------------- */
.order-status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
  white-space: nowrap;
}

.order-status::before {
  content: "";
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border: 2px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background-color: var(--border-strong);
}

.order-status--processing::before,
.order-status--on-hold::before {
  border-color: var(--color-brand);
  background-color: var(--color-brand);
}

.order-status--completed::before {
  border-color: var(--color-positive);
  background-color: var(--color-positive);
}

.order-status--pending::before {
  border-color: var(--text-muted);
  background-color: transparent;
}

.order-status--failed::before,
.order-status--cancelled::before {
  border-color: var(--color-negative);
  background-color: var(--color-negative);
}

.order-status--refunded::before {
  border-color: var(--border-strong);
  background-color: var(--border-strong);
}

/* ---------------------------------------------------------------------------
   BLOCK — order-totals  (NEW)
   The contents of the Order Summary: the sum, the delivery, any discount, then
   the total in the commerce face at the size the product page gives a price,
   the VAT it includes, the Clearpay line when the total allows it, and the
   points line. Contents only — the surface is bordered-group, the brand's one
   labelled-panel treatment, exactly as buy-box sits inside it on the product
   page.
   --------------------------------------------------------------------------- */
.order-totals {
  margin: 0;
}

.order-totals__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-2);
}

.order-totals__label {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.order-totals__detail {
  display: block;
  margin-block-start: var(--space-1);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.order-totals__value {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
  white-space: nowrap;
}

.order-totals__total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-block-start: var(--space-3);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

.order-totals__total-label {
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.order-totals__total-value {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  letter-spacing: 0.01em;
  color: var(--text-body);
  white-space: nowrap;
}

.order-totals__vat {
  margin: var(--space-1) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
  text-align: end;
}

.order-totals__line {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-4) 0 0;
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--border-default);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.order-totals__line + .order-totals__line {
  margin-block-start: var(--space-3);
  padding-block-start: 0;
  border-block-start: 0;
}

.order-totals__line strong {
  font-weight: var(--fw-medium);
}

.order-totals__icon {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  color: var(--text-brand);
}

.order-totals__icon svg {
  width: 100%;
  height: 100%;
}

/* The checkout action's wrapper. WooCommerce prints `wc-proceed-to-checkout`;
   this element names it for the brand so the phone checkout bar can stand in
   for it (see _checkout-bar.scss). In the mockup this was a page-level
   `order-summary__action` owned by no block. */
.order-totals__action {
  margin-block-start: var(--space-6);
}

/* Clearpay's "Checkout with Clearpay" button (the Clearpay plugin prints it on
   woocommerce_proceed_to_checkout, straight after ours) sits apart from our
   checkout button rather than touching it (operator, 2026-11-11). The same gap
   the payment marks keep below. */
.order-totals__action .btn-clearpay_express {
  margin-block-start: var(--space-4);
}

/* --sticky: THE PAYMENT MARKS STAY IN VIEW (checkout, MPG11). The checkout summary lists
   every package before its totals, so it is taller than a laptop screen and a sticky
   column alone would carry its foot off the bottom. The accepted-payment marks pin to
   the foot of the viewport inside the pinned column — a trust signal kept above the
   fold (operator, 2026-09-26) — and settle back as the column's end comes into view,
   painted panel white with a hairline above so whatever scrolls beneath is covered
   cleanly. Static once the summary drops below the form. Ported from the mockup's
   `order-summary__action`; Place Order itself moved into the Payment card. */
.order-totals__action--sticky {
  position: sticky;
  bottom: 0;
  z-index: 1;
  padding-block: var(--space-4);
  border-block-start: 1px solid var(--border-default);
  background-color: var(--bg-panel);
}

.order-totals__action--sticky > .payment-marks {
  margin-block-start: 0;
}

@media (max-width: 1100px) {
  .order-totals__action--sticky {
    position: static;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — package-delivery  (EXTENDED on the checkout's second review)
   The checkout's per-package delivery, confirmed rather than chosen again.
   The shopper picked each package's speed in the basket, so here each package
   is ONE read-only line — which package, when it arrives, the speed and its
   price. DEPARTURE: no Change. The mockup offered one at the far end of each
   line; it is gone (operator, 2026-09-24) because the store runs one speed,
   and because the checkout merges the packages into one settled charge so the
   wallets can render (camcom-global camcom-dropship-checkout-merge.php) —
   there is nothing to change and nowhere to change it. The rules for Change
   and its opened row were not ported.

   What changed: the row used to be the basket's package-head beside a select
   holding the speed. The select is gone — it asked the basket's question a
   second time, and at 390px it clipped its own price. The row is now a single
   line that wraps rather than truncates: a Paragon-blue outline icon (a van,
   or a calendar for a pre-order), the package name and arrival at ink and
   medium weight, the speed in slate, the price in the commerce face because
   it is a price, and Change as a link-blue text button. Change opens that
   package's two speeds in place as the basket's own delivery-options, reused
   verbatim; the opened row takes the brand's leading Paragon-blue rule so it
   is clear which package is being changed. Beneath the rows the dispatch
   rule, as before, and a new quieter line for the Highlands & Islands
   surcharge, which the shopper never picks.
   --------------------------------------------------------------------------- */
.package-delivery__rows {
  margin: 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.package-delivery__row {
  padding: var(--space-4) var(--space-6);
  background-color: var(--bg-panel);
}

.package-delivery__row + .package-delivery__row {
  border-block-start: 1px solid var(--border-default);
}

.package-delivery__line {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  align-items: start;
  column-gap: var(--space-3);
  row-gap: var(--space-2);
}

.package-delivery__icon {
  width: 24px;
  height: 24px;
  margin-block-start: 0.15em;
  color: var(--text-brand);
}

.package-delivery__icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.package-delivery__summary {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.package-delivery__package,
.package-delivery__arrival {
  font-weight: var(--fw-medium);
  color: var(--text-body);
}

.package-delivery__price {
  font-family: var(--ff-chrome);
  font-weight: var(--fw-bold);
  font-style: italic;
  color: var(--text-body);
  white-space: nowrap;
}

.package-delivery__note {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-8) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.package-delivery__note-icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  color: var(--text-brand);
}

.package-delivery__note-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.package-delivery__surcharge {
  margin: var(--space-2) 0 0;
  padding-inline-start: calc(24px + var(--space-3));
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

/* Phone: the line keeps every word and wraps, a step smaller. */
@media (max-width: 640px) {
  .package-delivery__row {
    padding: var(--space-4);
  }
  .package-delivery__summary {
    font-size: var(--fs-small);
  }
  .package-delivery__note {
    align-items: flex-start;
    font-size: var(--fs-small);
    line-height: var(--lh-body);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — package-head  (NEW)
   The top of a package panel: `Package 1 of 3` in the heading font at the
   small-title size, then the package's status line. The build brief calls the
   arrival date the most important line in the panel, so it is the one phrase
   set at ink and medium weight — the stock state beside it matches it, the
   dispatch detail between them stays slate. A Paragon-blue outline icon leads
   the line: a van for a stocked package, a calendar for a pre-order.

   The title is optional. A basket that does not split draws the head with the
   status line alone — "Package 1 of 1" would be a label for a fact nobody
   needs told.
   --------------------------------------------------------------------------- */
.package-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.package-head__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.package-head__status {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.package-head__icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  margin-block-start: 0.15em;
  color: var(--text-brand);
}

.package-head__icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.package-head__state,
.package-head__arrival {
  font-weight: var(--fw-medium);
  color: var(--text-body);
}

@media (max-width: 640px) {
  .package-head__status {
    font-size: var(--fs-small);
  }
}
/* ---------------------------------------------------------------------------
   PAGE LAYOUT — the shell, the rail and the region grids.

   BUILT 2026-09-15 from six pieces of operator feedback, after three designs
   were rejected. Each of the six is answered in one place and the place is
   named, so a later session can see which choices are load-bearing:

   1. The short description goes BEFORE the buy box    → .buy-region__summary
   2. Loyalty points sit AFTER the buy box             → .buy-region__summary
   3. Stat pills live inside the product description   → .doc-figures
   4. The description takes the live site's column     → .store-layout
   5. Add to Basket never wraps to two lines           → .btn--commerce, .route-row
   6. The navigation rail comes back, desktop only     → .store-layout__sidebar

   THE COLUMN IS 1042px AND THAT IS THE POINT OF (4). It is what the live store
   gives its content: a 1400 page, a 328 rail, a 30 gap. Three drafts put the
   description at 680 or 740 because that is the styleguide's READING measure,
   and all three read as cramped — because the measure was set for editorial
   pages, where prose is alone on the page. A product description is not alone:
   it carries stat blocks, spec tables and feature rows, and it wants the room
   the store already gives it. The 680 measure still governs article pages.
   --------------------------------------------------------------------------- */
.page__inner {
  max-width: calc(var(--site-max-width) + var(--gutter-small) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter-small);
}

.page__body {
  padding-block: var(--space-6) var(--space-16);
}

.page__flow > * + * {
  margin-block-start: var(--space-12);
}

/* The tight flow — INSIDE a band rather than between bands.

   A band is a head and the thing it introduces, and on a composed page those
   arrive as separate top-level blocks. Left as siblings of the page flow they
   took the 48px that separates one band from the NEXT, so a title sat as far
   from its own grid as from the band above it and nothing read as a unit
   (measured 2026-09-17: every head 48px from its own content).

   So each band is wrapped in a group carrying this, and the page flow's 48px
   falls between those groups. A modifier rather than a second component: the
   mechanism is identical and only the step changes, which is what `--wide`
   already established for the axis. 24px is the value `.section-head` carries
   for the same gap in the PHP templates, so both routes space a band head the
   same way.

   TWO SELECTORS BECAUSE THERE ARE TWO DOM SHAPES. A PHP template puts the
   children directly inside; a `core/group` wraps them in
   `.wp-block-group__inner-container`, which WordPress restores on any site
   without a `theme.json` — every theme in this line, by policy. A `>` rule alone
   therefore lands on the wrapper and spaces nothing. Naming the container is
   normally the thing not to do, but the alternative here is a descendant rule
   that would reach every nesting level of a band. */
.page__flow--tight > * + *,
.page__flow--tight > .wp-block-group__inner-container > * + * {
  margin-block-start: var(--space-6);
}

/* The wide flow — the bands below the product zone. They are not about THIS
   product's purchase decision, they are the routes out of it, so they run the
   full page width rather than the content column's and pass under the rail where
   it ends. A modifier rather than a second container: same vertical rhythm,
   different width. Operator, 2026-09-16. */
.page__flow--wide {
  width: 100%;
  /* The gap between the two zones. Without it the specification band opens
     immediately under the description's last line and reads as part of it —
     which is the opposite of what moving it out here was for. */
  margin-block-start: var(--space-16);
}

/* __band: a full-width band that follows the page's main content — the basket's
   trust row. It stands further off than the flow's panel gap so it reads as the
   page's close rather than one more panel (MPG10). */
.page__flow > .page__band {
  margin-block-start: var(--space-12);
}

/* A WooCommerce page (basket, checkout, account) prints its whole template inside one
   `.woocommerce` wrapper, so the page flow's own spacing never reaches the parts —
   the opening, the steps band, the order layout, the closing band. The wrapper stacks
   them instead, at the order funnel's rhythm (--space-8, as the accepted basket
   draws it). A flex gap, not sibling margins, because WooCommerce always prints a
   notices wrapper that is usually empty: hidden, it takes no gap at all.
   The closing band keeps its further offset (--space-12 in all). Walk-back, MPG10. */
.page__flow > .woocommerce {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.page__flow > .woocommerce > * {
  margin-block: 0;
}

.page__flow > .woocommerce > .woocommerce-notices-wrapper:empty {
  display: none;
}

.page__flow > .woocommerce > .page__band {
  margin-block-start: var(--space-4);
}

/* In the rail the contents list stacks instead of running as a wrapped row. */
.seo-doc__rail .page-contents {
  margin: 0;
  padding: 0;
  border: 0;
}

.seo-doc__rail .page-contents__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.seo-doc__rail .page-contents__item::after {
  content: none;
}

/* ---- page-contents (reused from the brand catalogue, verbatim) ---- */
/* ---------------------------------------------------------------------------
   BLOCK — page-contents  (NEW)
   Inline at the top of the document, not sticky. These pages are consulted
   once from a support email and then left; a rail that follows the reader down
   a page they are not reading is furniture for its own sake, and it would have
   to survive beside the spliced site header.

   Built the way breadcrumbs is built — a wrapping flex row with the separator
   on the item's own ::after — so the brand's two 'where am I' strips read as
   one construction. The separator is the middot the article kicker already
   uses, in the same quiet grey.
   --------------------------------------------------------------------------- */
.page-contents {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3) var(--space-6);
  padding-block-end: var(--space-6);
  border-block-end: 1px solid var(--border-default);
}

/* AS A CORE COLUMN, the rail states its own share here rather than carrying the
   editor's `style="flex-basis:28%"` into a pattern file. The doc beside it takes
   the rest.

   It stands the way the PHP band's rail does (seo-doc): a sticky stacked list
   with its rule down the side facing the document, not the strip's rule along
   the bottom. Until 2026-10-13 none of this applied — core's own
   `.wp-block-columns:not(.is-not-stacked-on-mobile) > .wp-block-column` out-
   ranks a two-class selector, so the rail ran at half the panel, and the strip's
   bottom rule hung under an empty column on every range page (operator). The
   description-panel class lifts this one above core's. Core stacks the columns
   below 782px, and there the strip's own shape is right, so all of it is
   desktop-only. */
@media (min-width: 782px) {
  .wp-block-columns.description-panel > .wp-block-column.page-contents {
    flex: 0 0 28%;
    align-self: flex-start;
    position: sticky;
    inset-block-start: var(--space-6);
    padding-block-end: 0;
    padding-inline-end: var(--space-6);
    border-block-end: 0;
    border-inline-end: 1px solid var(--border-default);
  }
  .wp-block-column.page-contents .page-contents__list {
    flex-direction: column;
    gap: var(--space-3);
  }
  .wp-block-column.page-contents .page-contents__item::after {
    content: none;
  }
}
/* The list is a core/list, which draws the brand's running-copy bullet; a
   contents list has its own separators instead. */
.page-contents .page-contents__list {
  padding-inline-start: 0;
}

.page-contents .page-contents__item {
  margin-block-end: 0;
}

.page-contents .page-contents__item::before {
  content: none;
}

.page-contents__label {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.page-contents__list {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.page-contents__item {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-4);
}

.page-contents__item::after {
  content: "·";
  color: var(--neutral-500);
}

.page-contents__item:last-child::after {
  content: none;
}

.page-contents__link {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
  text-decoration: none;
}

.page-contents__link:hover {
  color: var(--text-link-hover);
}

@media (max-width: 640px) {
  .page-contents__label {
    flex: 0 0 100%;
  }
}
.pagination {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.pagination__list {
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.pagination__page {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  height: 44px;
  padding-inline: var(--space-3);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  background-color: var(--bg-panel);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: 1;
  color: var(--text-body);
  text-decoration: none;
}

.pagination__page:hover {
  border-color: var(--border-brand);
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

.pagination__page--current {
  border-color: var(--btn-primary-bg);
  background-color: var(--btn-primary-bg);
  font-weight: var(--fw-medium);
  color: var(--btn-primary-text);
}

.pagination__gap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 44px;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: 1;
  color: var(--text-muted);
}

.pagination__arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 44px;
  padding-inline: var(--space-4);
  border: 1px solid var(--border-brand);
  border-radius: var(--radius-btn);
  background-color: var(--bg-panel);
  line-height: 1;
  color: var(--text-link);
  text-decoration: none;
  white-space: nowrap;
}

.pagination__arrow[rel=prev] {
  grid-row: 1;
  grid-column: 1;
  justify-self: start;
}

.pagination__arrow[rel=next] {
  grid-row: 1;
  grid-column: 3;
  justify-self: end;
}

.pagination__arrow:hover {
  background-color: var(--bg-card-hover);
  color: var(--text-link-hover);
}

.pagination__arrow svg {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
}

/* The control holds an icon and a word, and only the word has a typeface. Type
   therefore sits here rather than on the control, which owns the box: the icon
   is sized in pixels and inherits nothing, so this is the only element the
   heading face, the small step and the medium weight actually describe. */
.pagination__arrow-label {
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
}

/* Too narrow for one row: the number run takes a row of its own and the two
   arrows sit beneath it, one at each end, where a thumb reaches them. */
@media (max-width: 640px) {
  .pagination {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-4);
    padding: var(--space-4);
  }
  .pagination__list {
    grid-row: 1;
    grid-column: 1/-1;
    justify-content: center;
  }
  .pagination__arrow[rel=prev] {
    grid-row: 2;
    grid-column: 1;
  }
  .pagination__arrow[rel=next] {
    grid-row: 2;
    grid-column: 2;
  }
  .pagination__page,
  .pagination__gap {
    min-width: 38px;
    height: 38px;
    padding-inline: var(--space-2);
  }
  .pagination__arrow {
    height: 38px;
    padding-inline: var(--space-3);
  }
}
/* The pay-later card, under the gallery. Same construction as the loyalty card
   so the two read as a pair either side of the hero, and the figure is set the
   same way — commerce face, black, with the explanation beneath it. */
.paylater-card__body {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.paylater-card__icon {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  color: var(--text-brand);
}

.paylater-card__icon svg {
  width: 100%;
  height: 100%;
}

/* Same floor as the loyalty card's figures, for the same reason: a flex item's
   default minimum is its longest word, so without it the instalment wording pushes
   the icon out of the row rather than wrapping under the figure. */
.paylater-card__figures {
  min-width: 0;
}

/* Matched to the loyalty figure so the two cards are the same height, which is
   the only way they line up along the top as well as the foot. */
.paylater-card__amount {
  display: block;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.paylater-card__note {
  display: block;
  margin-block-start: var(--space-1);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

/* Both cards carry a trailing link, which is what makes them the same height —
   and that is the only way two cards bottom-aligned can also line up along the
   top. Bottom-aligning alone put their title bars 36px apart, which reads worse
   than the 14px it was meant to fix, because the eye follows the blue bar and
   not the foot of the card. */
.paylater-card .section-link,
.loyalty-card .section-link {
  margin-block-start: var(--space-4);
}

/* ---------------------------------------------------------------------------
   BLOCK — payment-marks  (EXTENDED — real marks replace the text labels;
   EXTENDED again on the basket's second review — a Google Pay mark joins the
   row, drawn the same way: a monochrome G and "Pay" in currentColor, in the
   same hairline chip. CSS unchanged; the row is now Visa, Mastercard,
   Apple Pay, Google Pay, Clearpay — the ways Stripe takes payment here.)
   The accepted ways to pay, beneath the checkout button and deliberately quiet
   — a reassurance, not a feature.

   What changed: each mark is now the payment scheme's own drawn mark (Visa,
   Mastercard, Apple Pay, Clearpay) as inline SVG rather than a text label, so
   the shopper recognises it at a glance instead of reading it. The marks are
   drawn in `currentColor` and the chip sets that to the muted text role: the
   schemes' own colours are not in this brand's seventeen, and a row of four
   competing logos beside the one blue button would be exactly the garishness
   the brief rules out. The chip keeps its square control corner and hairline.
   Each SVG carries role="img" and an aria-label, so the list still reads as
   words to a screen reader.
   --------------------------------------------------------------------------- */
.payment-marks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin: var(--space-4) 0 0;
  padding: 0;
  list-style: none;
}

.payment-marks__mark {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 56px;
  height: 34px;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  background-color: var(--bg-panel);
  color: var(--text-muted);
}

.payment-marks__mark svg {
  display: block;
  width: auto;
  height: 18px;
}

/* The two presentation details the marks' SVGs carried inline in the mockup, moved
   here because a theme template carries no inline styles: the Visa wordmark's slant,
   and the Clearpay mark's knocked-out arrow drawn in the panel colour. */
.payment-marks__italic {
  font-style: italic;
}

.payment-marks__knockout {
  stroke: var(--bg-panel);
}

/* ---------------------------------------------------------------------------
   BLOCK — payment-methods  (EXTENDED on the checkout's second review)
   The ways to pay as radio tiles: Card and Clearpay, and nothing else. Each
   tile's head is a `choice` radio with the method's name, an optional slate
   detail line, and the scheme's own marks at the far end — the basket's
   `payment-marks`, reused, so the marks here and under the order button are
   one drawing.

   What changed: markup and copy only, CSS untouched. Payments are Stripe's
   now; Apple Pay and Google Pay have moved up into express-checkout, so the
   Apple Pay tile is gone. The Card tile opens to Stripe's card fields (Card
   number, Expiry, Security code — Stripe's Payment Element collects no name
   on card) and the note under them names Stripe. The block now sits inside a
   bordered-group titled Payment.

   The tiles are list rows inside a hairline outline at the surface radius,
   the construction delivery-options uses, and the selected tile takes the
   same current-item marking: the blue-tint wash and a Paragon-blue rule on
   its leading edge. Only the selected tile opens. Its body keeps the leading
   rule, so the card fields read as belonging to the tile that opened them.

   A method that is not offered — Clearpay over its £1,200 limit — is simply
   absent. The tiles are a stack, so a missing one leaves no gap.
   --------------------------------------------------------------------------- */
.payment-methods {
  min-inline-size: 0;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.payment-methods__legend {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.payment-methods__item + .payment-methods__item {
  border-block-start: 1px solid var(--border-default);
}

.payment-methods__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  padding: var(--space-4) var(--space-6);
  background-color: var(--bg-panel);
}

.payment-methods__item:has(> .payment-methods__head .input-radio:checked) .payment-methods__head {
  background-color: var(--bg-card-hover);
  box-shadow: inset 3px 0 0 var(--border-brand);
}

.payment-methods__head .choice {
  flex: 1 1 auto;
  align-items: center;
}

.payment-methods__head .choice__control {
  margin-block-start: 0;
}

.payment-methods__name {
  display: block;
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.payment-methods__detail {
  display: block;
  margin-block-start: var(--space-1);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.payment-methods__marks {
  flex: 0 0 auto;
}

/* payment-marks sits under a button everywhere else, centred with a gap
   above it. In a tile head it sits beside the method's name, so the head
   takes both back. Nothing else about the marks changes. */
.payment-methods__marks .payment-marks {
  margin: 0;
  justify-content: flex-end;
}

.payment-methods__body {
  padding: var(--space-6);
  border-block-start: 1px solid var(--border-default);
  background-color: var(--bg-panel);
  box-shadow: inset 3px 0 0 var(--border-brand);
}

.payment-methods__note {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-6) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.payment-methods__note-icon {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  color: var(--text-brand);
}

.payment-methods__note-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

@media (max-width: 640px) {
  .payment-methods__head {
    padding: var(--space-4);
  }
  .payment-methods__marks {
    flex-basis: 100%;
    padding-inline-start: calc(20px + var(--space-3));
  }
  .payment-methods__marks .payment-marks {
    justify-content: flex-start;
  }
  .payment-methods__body {
    padding: var(--space-4);
  }
  .payment-methods__note {
    align-items: flex-start;
  }
}
/* The highlight follows the CHECKED RADIO through `:has()` above, and nothing else.
   WooCommerce's checkout script only swaps the open payment box when the shopper picks
   another method, so a class the server sets on the chosen gateway never moves: a
   `--selected` modifier drawn here as well left Card lit beside Klarna or Clearpay
   (operator, 2026-09-26). The server already renders the chosen radio `checked`, so the
   radio alone covers first paint too. The radio itself is the brand choice control
   (WooCommerce's `input-radio` class kept for its script). */
/* PLACE ORDER closes the Payment card (operator, 2026-09-26). It is WooCommerce's
   `#place_order`, whose text checkout.js rewrites on every payment-method change — an
   icon inside it would be wiped on page load — so the padlock is drawn here, from the
   same drawing the other Place Order buttons carry, as a mask in currentColor (a data
   URI cannot read a custom property). */
.place-order #place_order::before {
  content: "";
  width: 16px;
  height: 16px;
  background-color: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='10.5' width='16' height='11'/%3E%3Cpath d='M8 10.5V7a4 4 0 0 1 8 0v3.5'/%3E%3C/svg%3E") center/contain no-repeat;
}

.woocommerce-checkout-payment .form-actions {
  margin-block-start: var(--space-8);
}

.woocommerce-checkout-payment .form-actions + .woocommerce-terms-and-conditions-wrapper {
  margin-block-start: var(--space-4);
}

.product-links {
  display: flex;
  flex-direction: column;
  align-self: stretch;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

.product-links__row {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.product-links__label {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.product-links__options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.product-links__options > li {
  flex: 1 1 96px;
  max-width: 140px;
}

.product-links__option {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 52px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
  text-decoration: none;
  transition: border-color 0.15s ease;
}

.product-links__option:hover {
  border-color: var(--border-brand);
}

.product-links__option--current {
  border-width: 2px;
  border-color: var(--border-brand);
}

.product-links__logo {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 32px;
}

.product-links__name {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.product-links__row--both .product-links__options > li {
  flex-basis: 110px;
  max-width: 160px;
}

.product-links__row--both .product-links__option {
  flex-direction: column;
  gap: var(--space-2);
  height: 100%;
  padding: var(--space-3);
  text-align: center;
}

.product-links__row--both .product-links__logo {
  max-width: 100%;
  max-height: 72px;
}

/* ---------------------------------------------------------------------------
   BLOCK — product-card  (UPDATED — an instalment line and three states)

   Four additive slots, every one of them optional. The card still renders
   correctly with all four absent, which is how the homepage and the editorial
   buy band already use it, and nothing about the base card moved.

     __badge          the sale mark, alert red, on the image. Red is reserved
                      for sale, out of stock and errors, and this is the first
                      time the card has drawn it.
     __price-was      the previous price struck through beside the current one.
                      The current price stays ink: the badge carries the red,
                      so red never becomes decoration.
     __instalments    pay-later messaging belongs beside a price and not only
                      in a trust card. Shown above a threshold only, so it
                      never appears under a £5.99 cable, and never on an item
                      that cannot be bought.
     __stock-note     'Only 2 left'. Set in ink at medium weight rather than
                      red, because low stock is not on the brand's red list.
                      Rare is what makes it credible.

   Out of stock is a state rather than a slot: the stock dot turns red and the
   basket button gives way to 'Notify me', which is not a commerce action and
   so sets its label in the heading font like every other secondary button.
   The card keeps its shape.

   One correction carried in this overwrite: the catalogue's copy of the media
   rule had an escape character in front of the slash in its aspect ratio, which
   no browser parses. It reads plainly here.
   --------------------------------------------------------------------------- */
.product-card {
  display: flex;
  flex-direction: column;
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

.product-card__media {
  position: relative;
  display: block;
  padding: var(--space-6) var(--space-4);
  background-color: var(--bg-card);
}

.product-card__media img {
  display: block;
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: contain;
}

.product-card__badge,
.product-gallery__badge,
.product-list-row__badge {
  position: absolute;
  inset-block-start: var(--space-4);
  inset-inline-start: var(--space-4);
  padding: var(--space-1) var(--space-3);
  background-color: var(--color-negative);
  font-family: var(--ff-chrome);
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-on-brand);
}

.product-card__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
  padding-block-start: 0;
}

.product-card__title {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
  line-height: 1.375;
}

.product-card__title a {
  color: var(--text-heading);
  text-decoration: none;
}

.product-card__title a:hover {
  color: var(--text-link);
}

.product-card__price {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.product-card__price-was {
  margin-inline-start: var(--space-2);
  font-size: var(--fs-h4);
  font-weight: var(--fw-regular);
  color: var(--text-muted);
  text-decoration: line-through;
}

/* The instalment line is pulled back against the price it belongs to, out of
   the body's own gap, so it reads as part of the price and not as a third
   line of meta. */
.product-card__instalments {
  margin: calc(-1 * var(--space-2)) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.product-card__meta {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.product-card__stock-dot {
  flex: 0 0 auto;
  translate: 0 -1px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background-color: var(--color-positive);
}

.product-card__stock-dot--preorder {
  background-color: var(--color-brand);
}

.product-card__stock-dot--out {
  background-color: var(--color-negative);
}

.product-card__stock-note {
  margin: calc(-1 * var(--space-2)) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

/* The actions sit on the card's floor, so a row of cards lines its buttons up
   whatever the titles run to (operator, 2026-09-24). The body fills the card's
   height (above) and `auto` takes up the slack; the 4px the row always had above
   it is kept as padding, so a lone card looks exactly as it did. */
.product-card__actions {
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
  margin-block-start: auto;
  padding-block-start: var(--space-1);
}

.product-card__actions .btn {
  flex: 1 1 auto;
}

.product-card__wishlist {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  background-color: var(--bg-card);
  color: var(--text-brand);
  cursor: pointer;
}

.product-card__wishlist:hover {
  border-color: var(--border-brand);
  background-color: var(--bg-card-hover);
}

.product-card__wishlist svg {
  width: 26px;
  height: 26px;
}

/* EVERY CARD IN THE STRIP IS THE SAME HEIGHT, ACROSS ROWS AS WELL AS ALONG THEM.

   A grid row is as tall as its own tallest item, so a four-card strip laid out
   two-by-two gives two rows that each size independently — and one product title
   wrapping to a second line makes the whole bottom row taller than the top one.
   Within a row the cards already match, which is what makes the difference read
   as a fault rather than as content: two cards of one height beside two of
   another, with nothing visible to explain it.

   `1fr` sizes every row to the tallest, so the strip is one block of equal cards
   whatever any single title does. Safe because the card is a flex column with its
   price pinned to the bottom — a stretched card grows its middle, it does not
   leave a gap under its content.

   Brand-side rather than on `.grid--in-cell`, which is a global modifier four
   brands use: the rule an inner grid needs is "occupy one cell", and equal rows
   is this strip's own decision. */
.wp-block-tff-product-strip {
  grid-auto-rows: 1fr;
  /* AND NOT ONCE IT IS A SINGLE COLUMN. `.grid--2` collapses at 768, and below
     that every card is its own row — so `1fr` stops equalising cards beside each
     other and starts padding every stacked card out to the tallest one in the
     strip. Measured at 390: four cards at 587px each, where their own content
     wanted 563, 563, 587 and 563. Equal height is a rule about a ROW of cards,
     and there are no rows here. */
}

@media (max-width: 768px) {
  .wp-block-tff-product-strip {
    grid-auto-rows: auto;
  }
}
/* ===========================================================================
   NEW BLOCKS — authored here because no catalogue block carries the
   structural purpose.
   =========================================================================== */
/* ---------------------------------------------------------------------------
   THIS PAGE'S OWN BLOCKS
   --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   BLOCK — product-gallery  (UPDATED — the thumbnail rail is vertical)
   Manufacturer shots on white at their natural proportions; the design brief
   forbids cropping them into scenes, so the stage is `object-fit: contain` and
   a square shot and a wide one both sit correctly in it.

   The rail moved from under the stage to beside it. Eight 76px thumbs at an
   8px gap stack to 664px against a 690px stage, so the gallery is exactly as
   tall as its own picture and adds nothing to the column. `auto-fill` on a
   strip underneath could not do that — it added a row's height to whichever
   column was already taller, which is how two earlier attempts ended up with
   white space to fill.

   The current thumbnail is marked with the brand's 2px Paragon-blue border,
   the same weight a bordered group uses, because this brand has no second
   accent to mark a selection with.
   --------------------------------------------------------------------------- */
.product-gallery {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  align-items: start;
  gap: var(--space-4);
}

.product-gallery__thumbs {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.product-gallery__thumb {
  display: block;
  width: 100%;
  padding: var(--space-1);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
  cursor: pointer;
}

.product-gallery__thumb:hover {
  border-color: var(--border-brand);
}

.product-gallery__thumb:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.product-gallery__thumb--active .product-gallery__thumb {
  border: 2px solid var(--border-brand);
  padding: calc(var(--space-1) - 1px);
}

.product-gallery__thumb .product-gallery__img {
  display: block;
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: contain;
}

.product-gallery__main {
  display: block;
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  overflow: hidden;
}

/* `aspect-ratio` holds only because the global reset gives every image
   `height: auto`: `wp_get_attachment_image()` emits width and height ATTRIBUTES, and
   without an author height rule the attribute sets the used height — every thumbnail
   rendered at 300px inside a 66px box. This rule carried its own `height: auto` until
   the reset took it on for every image (2026-09-27). */
.product-gallery__img {
  display: block;
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: contain;
  background-color: var(--bg-panel);
}

@media (max-width: 1180px) {
  .product-gallery {
    grid-template-columns: minmax(0, 1fr);
  }
  .product-gallery__thumbs {
    flex-direction: row;
    flex-wrap: wrap;
    order: 2;
  }
  .product-gallery__thumb {
    flex: 0 0 76px;
  }
}
/* ---------------------------------------------------------------------------
   OVERRIDES THAT MUST OUTRANK THE BLOCKS ABOVE

   Both of these are single-class rules that tie with a block's own single-class
   rule, so they win on SOURCE ORDER and nothing else — which is why they are
   written here, after the blocks, rather than up with the page layout. Placed
   before the blocks they lose silently and the page renders as if they were
   never written; that is exactly what happened to the gallery modifier on the
   first run of this build.
   --------------------------------------------------------------------------- */
/* ---- product-gallery --under ----------------------------------------------

   The thumbnails go UNDER the stage rather than beside it, and at this width
   that is arithmetic rather than taste: the gallery panel's padding leaves
   446px, and a 76px rail down the side would take the picture to 354. Under
   it, the stage keeps the whole 446.
   --------------------------------------------------------------------------- */
.product-gallery--under {
  grid-template-columns: minmax(0, 1fr);
}

/* ONE ROW, SCROLLED — not wrapped.
   Eight thumbs at 76px plus gaps need 700px and the rail has 446, so wrapping put
   them on two rows and the gallery's height then changed with the image count:
   a four-image product and a nine-image one made different-sized panels, which is
   the hero's two halves argued about in a different form.
   Scrolled, the rail is one row whatever the product carries. `scroll-snap` makes
   a drag land on a thumb rather than between two, and the thin scrollbar is left
   VISIBLE deliberately — a scroll area with no scrollbar is a scroll area nobody
   knows about. */
.product-gallery--under .product-gallery__thumbs {
  flex-direction: row;
  flex-wrap: nowrap;
  order: 2;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-block-end: var(--space-2);
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}

.product-gallery--under .product-gallery__thumbs::-webkit-scrollbar {
  height: 6px;
}

.product-gallery--under .product-gallery__thumbs::-webkit-scrollbar-thumb {
  border-radius: var(--radius-pill);
  background-color: var(--border-strong);
}

.product-gallery--under .product-gallery__thumb {
  flex: 0 0 76px;
  scroll-snap-align: start;
}

/* ---------------------------------------------------------------------------
   BLOCK — gallery lightbox  (NEW)
   The stage opens a full-size view. Component buyers inspect port layouts and
   connector positions, and eight photographs at 446px does not let them.

   Driven by `:target`, so the mockup demonstrates the real behaviour with no
   script; the theme's own modal module takes over at wiring time.
   --------------------------------------------------------------------------- */
.product-gallery__zoom {
  position: relative;
  cursor: zoom-in;
}

/* The sale badge on the main photograph, top left, opposite the zoom cue. Its
   look is the product card's badge — one rule, declared with it in
   _product-card.scss — so a sale reads the same on the card and the page. It
   replaces WooCommerce's sale flash, which this theme unhooks (functions.php). */
.product-gallery__badge {
  z-index: 1;
}

.product-gallery__zoom-cue {
  position: absolute;
  inset-block-start: var(--space-3);
  inset-inline-end: var(--space-3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  background-color: var(--bg-panel);
  color: var(--text-brand);
}

.product-gallery__zoom-cue svg {
  width: 20px;
  height: 20px;
}

.product-gallery__zoom:hover .product-gallery__zoom-cue {
  border-color: var(--border-brand);
  background-color: var(--bg-card-hover);
}

/* ---------------------------------------------------------------------------
   BLOCK — product-heading  (UPDATED — it lives in the decision column)
   26px in the commerce face, bold and slanted, over the brand's diagonal-cut
   rule. It used to run across the whole page at 40px; at that size it was the
   loudest thing on a page whose job is a photograph and a price.
   --------------------------------------------------------------------------- */
.product-heading__eyebrow {
  display: inline-block;
  margin: 0 0 var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-link);
  text-decoration: none;
}

.product-heading__eyebrow:hover {
  color: var(--text-link-hover);
}

.product-heading__title {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  letter-spacing: 0.01em;
  color: var(--text-heading);
}

.product-heading__rule {
  display: block;
  width: 100%;
  height: 6px;
  margin-block-start: var(--space-4);
  background-color: var(--color-brand);
  clip-path: polygon(20px 0, 100% 0, 100% 100%, 0 100%);
}

@media (max-width: 640px) {
  .product-heading__title {
    font-size: var(--fs-h4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — product-line  (NEW)
   The compact product row for a rail: a small manufacturer shot on white,
   the name and the price in the commerce font. The whole row is the link —
   no basket button here; the article's Buy it band carries those. Rows run
   edge to edge in a flush widget body, each with a hairline above it.
   --------------------------------------------------------------------------- */
.product-line {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  border-block-start: 1px solid var(--border-default);
  text-decoration: none;
}

.product-line:hover {
  background-color: var(--bg-card-hover);
}

.product-line__media {
  display: block;
  width: 56px;
  aspect-ratio: 1;
  object-fit: contain;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background-color: var(--bg-card);
}

.product-line__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.product-line__title {
  font-family: var(--ff-chrome);
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.product-line:hover .product-line__title {
  color: var(--text-link);
}

.product-line__price {
  font-family: var(--ff-chrome);
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
}

/* ---------------------------------------------------------------------------
   BLOCK — stock-line  (NEW)
   The type-ahead's product rows are the catalogue's product-line — small shot,
   name, price — and the only thing they lacked was stock. Same move as
   card-line: the missing line is its own block, placed inside the host's body,
   so product-line is reused completely unchanged.

   The dot is an indicator, so it is round. Green and red are the brand's two
   status colours and are used for exactly their listed jobs; pre-order is not
   a status the styleguide colours, so it takes the brand blue rather than
   inventing an amber the store does not have.
   --------------------------------------------------------------------------- */
.product-line__stock {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.product-line__stock-dot {
  flex: 0 0 auto;
  translate: 0 -1px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background-color: var(--color-positive);
}

.product-line__stock--out .product-line__stock-dot {
  background-color: var(--color-negative);
}

.product-line__stock--preorder .product-line__stock-dot {
  background-color: var(--color-brand);
}

/* ---------------------------------------------------------------------------
   BLOCK — product-list-row  (NEW)
   The listing's other layout, and a different block from the product card on
   purpose: the card compares products by shape and price, and the row
   compares them by specification.

   Image left; title, three bullet highlights and the three facts a shopper
   asks for — stock, dispatch day, loyalty points — in the middle; price,
   instalment line, wishlist and add to basket in a column on the right, so the
   prices line up down the page whatever the titles do.

   The bullet is the brand's small Paragon-blue dot. The facts are outline
   Paragon-blue icons with a short body-font label each. Loyalty points are
   display-only until the points system exists.
   --------------------------------------------------------------------------- */
.product-list-row {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr) 250px;
  gap: var(--space-6);
  padding: var(--space-6);
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}

.product-list-row__media {
  position: relative;
  display: block;
  align-self: start;
}

/* The Sale badge — the product card's, one rule in _product-card.scss — tucked
   into the corner of the smaller list-view photograph. */
.product-list-row__badge {
  inset-block-start: 0;
  inset-inline-start: 0;
}

.product-list-row__media img {
  display: block;
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: contain;
}

/* The middle column. The track places it — `minmax( 0, 1fr )` between a fixed
   picture and a fixed buy column — so it declares no layout, only the floor that
   keeps a long product name inside the column instead of widening the row past
   its own card. Product names here run to 'Backbone One: PlayStation Gaming
   Controller For iOS Lightning - White'. */
.product-list-row__body {
  min-width: 0;
}

.product-list-row__title {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  letter-spacing: 0.01em;
}

.product-list-row__title a {
  color: var(--text-heading);
  text-decoration: none;
}

.product-list-row__title a:hover {
  color: var(--text-link);
}

.product-list-row__highlights {
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
}

.product-list-row__highlight {
  position: relative;
  padding-inline-start: var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.product-list-row__highlight::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.62em;
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background-color: var(--color-brand);
}

.product-list-row__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin: var(--space-4) 0 0;
  padding: 0;
  list-style: none;
}

.product-list-row__fact {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.product-list-row__fact svg {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  color: var(--text-brand);
}

.product-list-row__buy {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-2);
}

.product-list-row__price {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.product-list-row__instalments {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
  text-align: right;
}

.product-list-row__actions {
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
  width: 100%;
  margin-block-start: var(--space-2);
}

.product-list-row__actions .btn {
  flex: 1 1 auto;
}

.product-list-row__wishlist {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  background-color: var(--bg-card);
  color: var(--text-brand);
  cursor: pointer;
}

.product-list-row__wishlist:hover {
  border-color: var(--border-brand);
  background-color: var(--bg-card-hover);
}

.product-list-row__wishlist svg {
  width: 26px;
  height: 26px;
}

@media (max-width: 900px) {
  .product-list-row {
    grid-template-columns: 150px minmax(0, 1fr);
  }
  .product-list-row__buy {
    grid-column: 1/-1;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
  }
  .product-list-row__actions {
    width: auto;
    margin-block-start: 0;
  }
}
@media (max-width: 640px) {
  .product-list-row {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
  }
  .product-list-row__media img {
    max-width: 200px;
  }
  .product-list-row__actions {
    width: 100%;
  }
}
/* ---- the list view's container --------------------------------------------

   The rows stack; nothing else. It is the grid's counterpart and the two never
   render together — the shopper's view toggle picks one.

   Not in the catalogue row, which stores the ROW. Taken from the MPG7 mockup's
   own stylesheet, where it is declared beside it.
   --------------------------------------------------------------------------- */
.product-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
}

.product-mini {
  display: flex;
  flex-direction: column;
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

.product-mini__media {
  display: block;
  padding: var(--space-3);
  background-color: var(--bg-card);
}

.product-mini__media img {
  display: block;
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: contain;
}

.product-mini__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  padding-block-start: 0;
}

.product-mini__title {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
}

.product-mini__title a {
  color: var(--text-heading);
  text-decoration: none;
}

.product-mini__title a:hover {
  color: var(--text-link);
}

.product-mini__price {
  margin: 0;
  font-family: var(--ff-chrome);
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.promo-tile {
  position: relative;
  display: block;
  aspect-ratio: 1;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--neutral-800);
  box-shadow: var(--shadow-card);
  text-decoration: none;
}

/* THE TILE THAT TAKES ITS HEIGHT FROM A NEIGHBOUR (MPG1 walk, 2026-09-16).

   The square above is right for the rail, where the tile has no neighbour to
   measure against and a fixed ratio is what removes the height breakpoint. The
   homepage's Best Sellers band is the other case: one tall tile beside a 2x2
   product grid, where the tile's job is to stand exactly as tall as the four
   cards next to it. A square there either leaves a gap under it or crops the
   artwork — and the artwork is authored 560x760 for this slot.

   So the ratio is dropped rather than replaced. The grid row supplies the
   height, the media fills it, and nothing here needs to know how tall that is.

   NO `height: 100%` HERE, and that is the working part rather than an omission.
   A percentage height on a grid item resolves against its grid AREA, and an
   `auto`-sized row is indefinite while it is being laid out — so the percentage
   falls back to auto and the tile sizes to its image's own aspect ratio instead.
   Measured: 622px against a 1445px neighbour, which is the fault it was meant to
   fix. Leaving the height auto lets the grid's default `align-items: stretch`
   do it, and `__media` at `height: 100%` then has a definite box to fill. */
.promo-tile--fill {
  aspect-ratio: auto;
}

.promo-tile__media {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.promo-tile__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, var(--bg-overlay) 0%, var(--bg-overlay) 35%, transparent 80%);
}

.promo-tile__content {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding: var(--space-8);
}

.promo-tile__title {
  display: block;
  font-family: var(--ff-heading);
  font-size: var(--fs-h3);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.promo-tile__cue {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-start: var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  color: var(--text-on-brand);
}

.promo-tile__cue svg {
  width: 16px;
  height: 16px;
}

@media (max-width: 1100px) {
  .promo-tile,
  .promo-tile__media {
    min-height: 300px;
  }
}
/* ---------------------------------------------------------------------------
   --banner — the range photograph as a short banner at the head of a range's
   screen in the phone menu (MPG22): wide, not square, so the sub-ranges start
   above the fold. Resets the tablet minimum height above, which would
   otherwise make it 300px tall.
   --------------------------------------------------------------------------- */
.promo-tile--banner {
  aspect-ratio: 16/7;
}

.promo-tile--banner,
.promo-tile--banner .promo-tile__media {
  min-height: 0;
}

.promo-tile--banner .promo-tile__content {
  padding: var(--space-4);
}

.promo-tile--banner .promo-tile__title {
  font-size: var(--fs-h4);
}

.promo-tile--banner .promo-tile__cue {
  margin-block-start: var(--space-1);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
}

/* ---------------------------------------------------------------------------
   LAYOUT — proof-band  (NEW)
   Proof, not promises. The trust strip at the top says what the store will
   do; this band says who the store IS: trading since 2013, a real address in
   Malvern, the company behind it, the ways it takes payment, and what
   customers say. Each is a fact a visitor can check.

   Three panels in a row — the business (with the year set large: the one
   number on the page that is about the store and not a product), then the
   customer quotes as a pair of quote-cards — and a foot panel across the
   column carrying the payment marks and the way to reach a person.
   Below 1100 the panels stack; the quotes scroll sideways on a phone.
   --------------------------------------------------------------------------- */
.proof-band {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: var(--space-content-gap);
}

.proof-band__facts {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.proof-band__eyebrow {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-brand);
}

.proof-band__year {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-light);
  line-height: 1;
  color: var(--text-heading);
}

.proof-band__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

.proof-band__fact {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: var(--space-3);
}

.proof-band__fact dt {
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-heading);
}

.proof-band__fact dd {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.proof-band__detail {
  display: block;
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.proof-band__quotes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-content-gap);
  min-width: 0;
}

.proof-band__foot {
  grid-column: 1/-1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4) var(--space-8);
  padding: var(--space-6) var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.proof-band__pay {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}

.proof-band__label {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

/* payment-marks is built to sit centred under a checkout button with space
   above it; in this foot it leads a line instead. */
.proof-band__pay .payment-marks {
  justify-content: flex-start;
  margin: 0;
}

.proof-band__contact {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.proof-band__contact strong {
  font-weight: var(--fw-medium);
}

@media (max-width: 1100px) {
  .proof-band {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
  }
}
@media (max-width: 640px) {
  .proof-band__quotes {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 85%;
    gap: var(--space-4);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    margin-inline: calc(-1 * var(--gutter-small));
    padding-inline: var(--gutter-small);
    scroll-padding-inline: var(--gutter-small);
  }
  .proof-band__quotes > * {
    scroll-snap-align: start;
  }
  .proof-band__facts,
  .proof-band__foot {
    padding: var(--space-6);
  }
}
/* ---------------------------------------------------------------------------
   --solo — no customer quotes yet. They are added only when genuine (operator,
   2026-10-10), so until then the foot takes the quotes' two-thirds beside the
   facts panel, stacked, rather than leaving that space empty. Added in the
   MPG21 wiring pass.
   --------------------------------------------------------------------------- */
.proof-band--solo .proof-band__foot {
  grid-column: auto;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-6);
}

.prose {
  max-width: var(--container-reading);
}

.prose p {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.prose p + p {
  margin-block-start: var(--space-6);
}

.prose a {
  color: var(--text-link);
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.prose a:hover {
  color: var(--text-link-hover);
}

.prose ul,
.prose ol {
  margin: 0;
  padding-inline-start: var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.prose ul {
  list-style: none;
}

.prose ul > li {
  position: relative;
}

.prose ul > li::before {
  content: "";
  position: absolute;
  inset-inline-start: calc(-1 * var(--space-6));
  inset-block-start: 0.7em;
  width: 7px;
  height: 7px;
  border-radius: var(--radius-pill);
  background-color: var(--color-brand);
}

.prose li + li,
.prose ul + ul,
.prose ol + ol {
  margin-block-start: var(--space-3);
}

.prose p + ul,
.prose p + ol,
.prose ul + p,
.prose ol + p {
  margin-block-start: var(--space-6);
}

/* ---------------------------------------------------------------------------
   BLOCK — pull-quote  (NEW)
   Editorial only. The gradient fills the quote's own letterforms rather than a
   panel behind it, which is the same move the score ring makes and the only
   form the gradient takes in this brand. It never touches a store surface.
   --------------------------------------------------------------------------- */
.pull-quote {
  margin: var(--space-8) 0 0;
  padding-inline-start: var(--space-6);
  border-inline-start: 3px solid var(--color-brand);
}

.pull-quote__text {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h3);
  font-weight: var(--fw-light);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-brand);
  background-image: var(--gradient-editorial);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

@media (max-width: 640px) {
  .pull-quote {
    padding-inline-start: var(--space-4);
  }
  .pull-quote__text {
    font-size: var(--fs-h4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — quote-card  (NEW)
   One customer's words on a panel: a Paragon-blue quote mark, the quote in
   the heading font, light and italic (the brand's quoting voice, as
   pull-quote sets it — without the gradient, which is editorial only), and
   who said it, quietly. Built for GENUINE reviews; the mockup's are marked
   placeholders.
   --------------------------------------------------------------------------- */
.quote-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.quote-card__mark {
  display: block;
  width: 32px;
  height: 24px;
  color: var(--text-brand);
}

.quote-card__mark svg {
  display: block;
  width: 100%;
  height: 100%;
}

.quote-card__text {
  flex: 1 1 auto;
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-light);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.quote-card__by {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.range-card {
  display: flex;
  flex-direction: column;
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  text-decoration: none;
}

.range-card:hover {
  background-color: var(--bg-card-hover);
}

.range-card__media {
  display: block;
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
}

.range-card__body {
  display: block;
  padding: var(--space-6);
}

.range-card__title {
  display: block;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-heading);
  margin-block-end: var(--space-1);
}

.range-card__count {
  display: block;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
   BLOCK — range-hub  (NEW; replaces range-card + the Find It Fast directory)
   A range as a card that routes in one click at two depths: the photograph
   (the whole range, its name and count over a foot scrim — the brand's
   text-over-photography rule, so the name sets medium) and, beneath it on
   panel white, its top sub-ranges as a count-list closed by count-list's own
   "Shop all" link. range-card cannot carry this: it is one link end to end,
   and a link cannot hold links.

   --feature is the same card at the size the biggest ranges earn: a wider
   photograph and a larger name. The list column grows to fill the card so
   the "Shop all" line sits on its floor whatever the list length.

   Below 1100 the card turns on its side — photograph left, links right — so
   eight ranges stack as eight short rows instead of eight tall cards.
   --------------------------------------------------------------------------- */
.range-hub {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-panel);
}

.range-hub__visual {
  position: relative;
  display: block;
  background-color: var(--neutral-800);
  text-decoration: none;
}

.range-hub__media {
  display: block;
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
}

.range-hub--feature .range-hub__media {
  aspect-ratio: 3/2;
}

.range-hub__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, var(--bg-overlay) 0%, var(--bg-overlay) 20%, transparent 65%);
}

.range-hub__head {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4) var(--space-6);
}

.range-hub--feature .range-hub__head {
  padding: var(--space-6);
}

.range-hub__title {
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.range-hub--feature .range-hub__title {
  font-size: var(--fs-h3);
}

.range-hub__count {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.range-hub__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.range-hub__list {
  flex: 1 1 auto;
}

@media (max-width: 640px) {
  .range-hub {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  }
  .range-hub__media,
  .range-hub--feature .range-hub__media {
    height: 100%;
    min-height: 180px;
    aspect-ratio: auto;
  }
  .range-hub--feature .range-hub__title {
    font-size: var(--fs-h4);
  }
}
@media (max-width: 640px) {
  .range-hub__head,
  .range-hub--feature .range-hub__head {
    padding: var(--space-3);
  }
  .range-hub__title,
  .range-hub--feature .range-hub__title {
    font-size: var(--fs-body-lg);
  }
  /* The list rows take the narrower half of a phone; count-list's own
     desktop padding would leave them too little measure. */
  .range-hub .count-list__link,
  .range-hub .count-list__more {
    padding: var(--space-2) var(--space-4);
    font-size: var(--fs-small);
  }
}
/* ---------------------------------------------------------------------------
   The selected row takes the brand's current-item marking, the one count-list
   and the store rail use — blue-tint wash and a Paragon-blue leading rule —
   made louder for a menu: label, count and chevron in Paragon blue at medium
   weight, and on desktop the wash runs on to the column's dividing rule so the
   row reads as opening into the panel beside it. Not a filled blue bar: that
   was the old sheet, and it shouted every row equally.
   --------------------------------------------------------------------------- */
.range-tabs {
  display: block;
}

.range-tabs__home {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 2px solid var(--border-brand);
  border-radius: var(--radius-card);
  text-decoration: none;
}

.range-tabs__home:hover {
  background-color: var(--bg-card-hover);
}

.range-tabs__home-icon {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  color: var(--text-brand);
}

.range-tabs__home-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.range-tabs__home-text {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--space-1);
}

.range-tabs__home-label {
  font-family: var(--ff-heading);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
}

.range-tabs__home-note {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.range-tabs__home-arrow {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  color: var(--text-brand);
}

.range-tabs__label {
  display: block;
  margin-block: var(--space-6) var(--space-2);
  padding-inline: var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.range-tabs__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.range-tabs__link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-block: 0;
  border-inline-start: 4px solid transparent;
  border-inline-end: 0;
  background-color: transparent;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  text-align: start;
  color: var(--text-body);
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s ease-out, color 0.2s ease-out, border-color 0.2s ease-out;
}

.range-tabs__name {
  flex: 1 1 auto;
  min-width: 0;
}

.range-tabs__count {
  flex: 0 0 auto;
  font-size: var(--fs-small);
  color: var(--text-muted);
  transition: color 0.2s ease-out;
}

.range-tabs__chevron {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--neutral-500);
  transition: color 0.2s ease-out;
}

.range-tabs__chevron svg {
  display: block;
  width: 100%;
  height: 100%;
}

.range-tabs__link:hover {
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

.range-tabs__item--current .range-tabs__link {
  margin-inline-end: calc(var(--space-content-gap) * -1 - 1px);
  padding-inline-end: calc(var(--space-4) + var(--space-content-gap) + 1px);
  border-inline-start-color: var(--border-brand);
  background-color: var(--bg-card-hover);
  font-weight: var(--fw-medium);
  color: var(--text-link);
}

.range-tabs__item--current .range-tabs__count,
.range-tabs__item--current .range-tabs__chevron,
.range-tabs__link:hover .range-tabs__count,
.range-tabs__link:hover .range-tabs__chevron {
  color: var(--text-link);
}

/* ---------------------------------------------------------------------------
   --phone — the desktop column as full-width touch rows: 52px minimum, a
   hairline between rows, the set-apart box inset from the sheet edge. A
   chevron means the row opens the next screen; without one it goes straight
   to its listing.
   --------------------------------------------------------------------------- */
.range-tabs--phone .range-tabs__home {
  min-height: 64px;
  margin-inline: var(--space-4);
}

.range-tabs--phone .range-tabs__list {
  border-block: 1px solid var(--border-default);
}

.range-tabs--phone .range-tabs__item + .range-tabs__item {
  border-block-start: 1px solid var(--border-default);
}

.range-tabs--phone .range-tabs__link {
  width: 100%;
  min-height: 52px;
  padding-block: var(--space-2);
  padding-inline: var(--space-3) var(--space-4);
}

.range-tabs--phone .range-tabs__item--current .range-tabs__link {
  margin-inline-end: 0;
  padding-inline-end: var(--space-4);
}

.range-tabs--phone .range-tabs__chevron {
  width: 16px;
  height: 16px;
}

@media (prefers-reduced-motion: reduce) {
  .range-tabs__link,
  .range-tabs__count,
  .range-tabs__chevron {
    transition: none;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — reading-progress  (NEW)
   A thin Paragon-blue line fixed to the very top of the viewport, filling
   as the reader moves through the body — from the top of the reading card
   to the end of the last paragraph. Quiet: hidden until the reader has
   scrolled past the hero, 3px, no label. Off on phones, where nothing is
   fixed or sticky.
   --------------------------------------------------------------------------- */
.reading-progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 20;
  height: 3px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s linear;
}

.reading-progress--visible {
  opacity: 1;
}

.reading-progress__bar {
  display: block;
  height: 100%;
  background-color: var(--color-brand);
  transform: scaleX(var(--progress, 0));
  transform-origin: left center;
}

@media (prefers-reduced-motion: reduce) {
  .reading-progress {
    transition: none;
  }
}
@media (max-width: 640px) {
  .reading-progress {
    display: none;
  }
}
.recent-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--space-content-gap);
}

/* ---------------------------------------------------------------------------
   BLOCK — result-tabs  (NEW)
   Search mixes types, so the results page says which is which before it says
   anything else. All is the default and shows every band; each other tab
   narrows to one type (the search_engine switch at build).

   Tabs are navigation, so they are body-font labels rather than buttons; the
   current one takes the 3px Paragon-blue rule the store sidebar uses for its
   current item, laid along the bottom edge here because the tabs run across.
   Counts are quiet. A type with nothing in it is not drawn at all.
   --------------------------------------------------------------------------- */
.result-tabs {
  background-color: var(--bg-panel);
  border-block-start: 1px solid var(--border-default);
}

.result-tabs__list {
  display: flex;
  gap: var(--space-2);
  margin: 0;
  padding: 0 var(--space-card-padding);
  list-style: none;
  overflow-x: auto;
  scrollbar-width: none;
}

.result-tabs__list::-webkit-scrollbar {
  display: none;
}

.result-tabs__list > li {
  flex: 0 0 auto;
}

.result-tabs__tab {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  padding: var(--space-4) var(--space-4) calc(var(--space-4) - 3px);
  border-block-end: 3px solid transparent;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-decoration: none;
  white-space: nowrap;
}

.result-tabs__tab:hover {
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

.result-tabs__tab--current {
  border-block-end-color: var(--border-brand);
  font-weight: var(--fw-medium);
  color: var(--text-link);
}

.result-tabs__count {
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  color: var(--text-muted);
}

@media (max-width: 640px) {
  .result-tabs__list {
    gap: 0;
    padding-inline: var(--space-2);
  }
  .result-tabs__tab {
    padding-inline: var(--space-3);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — review-card  (REUSED, verbatim)
   --------------------------------------------------------------------------- */
.review-card {
  display: flex;
  flex-direction: row;
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

.review-card__media {
  display: block;
  flex: 0 0 360px;
  align-self: stretch;
}

.review-card__media img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
}

.review-card__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  padding: var(--space-card-padding);
}

.review-card__kicker {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-brand);
}

.review-card__title {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-regular);
  font-style: italic;
  line-height: var(--lh-heading);
}

.review-card__title a {
  color: var(--text-brand);
  text-decoration: none;
}

.review-card__title a:hover {
  color: var(--text-link-hover);
}

.review-card__score {
  display: flex;
  align-items: center;
  margin: var(--space-4) 0 0;
}

.review-card__unscored {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.review-card__unscored::before {
  content: "";
  flex: 0 0 auto;
  width: 24px;
  height: 3px;
  background-color: var(--color-brand);
}

.review-card__summary {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  margin: var(--space-4) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.review-card__date {
  margin: 0;
  margin-block-start: auto;
  padding-block-start: var(--space-4);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

@media (max-width: 640px) {
  .review-card {
    flex-direction: column;
  }
  .review-card__media {
    flex-basis: auto;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — review-intro  (NEW)
   The panel that introduces the magazine's reviews before the cards: one
   paragraph in the large light promotional setting, and the magazine's counts
   beside it. The counts are facts about the magazine, not review scores, so
   they take Paragon blue rather than the editorial gradient.

   DEPARTURE: composed in the editor, so each count is two paragraphs — the
   figure, then its label — in that order, and the stat stacks them as they come
   rather than reversing a dt/dd pair.
   --------------------------------------------------------------------------- */
/* SCOPED UNDER THE BLOCK. The parts are core paragraphs and headings carrying
   these classes, and the theme's core-block rules (`.wp-block-paragraph`,
   `h3.wp-block-heading`, core's flow margins) load later at the same weight —
   so each part is named inside its block to outrank them. */
.review-intro {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  align-items: center;
  gap: var(--space-12);
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.review-intro .review-intro__text {
  margin: 0;
  max-width: var(--container-reading);
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.review-intro .review-intro__stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
}

.review-intro .review-intro__stat {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-inline-start: var(--space-4);
  border-inline-start: 2px solid var(--border-brand);
}

.review-intro .review-intro__figure {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-brand);
}

.review-intro .review-intro__label {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

/* COMPOSED IN THE EDITOR. Core restores `.wp-block-group__inner-container` inside
   every group on a site with no theme.json, so the panel would lay out one
   wrapper instead of its parts. The wrapper is taken out of the layout — the
   global `.grid` repair, for this component's own flex/grid containers. */
.review-intro > .wp-block-group__inner-container,
.review-intro .review-intro__stats > .wp-block-group__inner-container,
.review-intro .review-intro__stat > .wp-block-group__inner-container {
  display: contents;
}

@media (max-width: 900px) {
  .review-intro {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
  }
}
@media (max-width: 640px) {
  .review-intro {
    padding: var(--space-6);
  }
  .review-intro .review-intro__text {
    font-size: var(--fs-body);
  }
  .review-intro .review-intro__stats {
    gap: var(--space-3);
  }
  .review-intro .review-intro__stat {
    padding-inline-start: var(--space-3);
  }
  .review-intro .review-intro__figure {
    font-size: var(--fs-h3);
  }
}
/* ---------------------------------------------------------------------------
   PAGE LAYOUT — the shell, the rail and the region grids.

   BUILT 2026-09-15 from six pieces of operator feedback, after three designs
   were rejected. Each of the six is answered in one place and the place is
   named, so a later session can see which choices are load-bearing:

   1. The short description goes BEFORE the buy box    → .buy-region__summary
   2. Loyalty points sit AFTER the buy box             → .buy-region__summary
   3. Stat pills live inside the product description   → .doc-figures
   4. The description takes the live site's column     → .store-layout
   5. Add to Basket never wraps to two lines           → .btn--commerce, .route-row
   6. The navigation rail comes back, desktop only     → .store-layout__sidebar

   THE COLUMN IS 1042px AND THAT IS THE POINT OF (4). It is what the live store
   gives its content: a 1400 page, a 328 rail, a 30 gap. Three drafts put the
   description at 680 or 740 because that is the styleguide's READING measure,
   and all three read as cramped — because the measure was set for editorial
   pages, where prose is alone on the page. A product description is not alone:
   it carries stat blocks, spec tables and feature rows, and it wants the room
   the store already gives it. The 680 measure still governs article pages.
   --------------------------------------------------------------------------- */
.page__inner {
  max-width: calc(var(--site-max-width) + var(--gutter-small) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter-small);
}

/* ---- the route bands ------------------------------------------------------

   (5) THE ROW MEASURES ITS COLUMNS, IT DOES NOT COUNT THEM. 'Add to Basket'
   needs about 244px with its wishlist button beside it, and a card's own
   padding takes 48 more — so 292px is the width below which the action cannot
   be served, and `auto-fill` fits as many of those as the row has room for.

   A fixed three-across was the first answer and it broke at 1150, where the
   rail is still present and the content column has dropped to 702: three cards
   of 214 each, and `white-space: nowrap` turned the squeeze into a horizontal
   scrollbar across the whole page. That nowrap is doing its job — it makes the
   failure visible instead of quietly wrapping the button again — but the fix is
   to stop hard-coding a column count that the content column cannot always
   afford.
   --------------------------------------------------------------------------- */
.route-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(292px, 1fr));
  gap: var(--space-content-gap);
}

/* ---------------------------------------------------------------------------
   BLOCK — score-badge  (NEW)
   The compact score beside a review's title: the catalogue's score ring and a
   quiet "Jump to verdict" link under it, wrapped to the ring's width. Hidden
   below 1100px, where the score strip under the byline takes its place.
   --------------------------------------------------------------------------- */
.score-badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding-block-start: var(--space-1);
  text-align: center;
}

.score-badge__link {
  max-width: 72px;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-link);
  text-decoration: none;
}

.score-badge__link:hover {
  color: var(--text-link-hover);
}

@media (max-width: 1100px) {
  .score-badge {
    display: none;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — score-glance  (NEW)
   The verdict at a glance, for the rail: the ring with its scale, then the
   five aspects as compact star rows. The full score panel stays at the end of
   the article where reviews conclude; this is the one-look version. Sits in a
   widget body.
   --------------------------------------------------------------------------- */
.score-glance__head {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding-block-end: var(--space-4);
  border-block-end: 1px solid var(--border-default);
}

.score-glance__overall {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.score-glance__label {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-heading);
}

.score-glance__scale {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.score-glance__aspects {
  margin: var(--space-2) 0 0;
  padding: 0;
  list-style: none;
}

.score-glance__aspect {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-2);
}

.score-glance__aspect + .score-glance__aspect {
  border-block-start: 1px solid var(--border-default);
}

.score-glance__aspect-label {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

/* ---------------------------------------------------------------------------
   BLOCK — score-list  (NEW)
   The compact 'best of' for a rail: the score, then the title, one line each,
   highest first. Built in count-list's construction — hairline separators,
   the blue-tint wash on hover, 24px inline padding — so the rail carries one
   list rhythm, not two. The difference is the thing on the left: a score is
   the point of the row, so it leads and it carries the editorial gradient the
   styleguide allows on review score figures, sitting on the ring's 3px
   Paragon-blue stroke laid flat. The title is the magazine's: heading font,
   regular, italic, Paragon blue.
   --------------------------------------------------------------------------- */
.score-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.score-list__item + .score-list__item {
  border-block-start: 1px solid var(--border-default);
}

.score-list__link {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-6);
  text-decoration: none;
}

.score-list__link:hover {
  background-color: var(--bg-card-hover);
}

.score-list__score {
  justify-self: start;
  padding-block-end: var(--space-1);
  border-block-end: 3px solid var(--border-brand);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: 1;
  color: var(--text-brand);
  background-image: var(--gradient-editorial);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.score-list__title {
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-brand);
}

.score-list__link:hover .score-list__title {
  color: var(--text-link-hover);
}

/* ---------------------------------------------------------------------------
   BLOCK — score-meter  (NEW)
   The large score: a white disc with the score drawn as an arc of Paragon
   blue around it — 58 fills 58% of the ring — and the figure in the
   editorial gradient inside. The same indicator as score-ring, grown, with
   the arc doing what a border cannot: showing how much of the ring is
   earned. Round, because it is an indicator.

   Two sizes: the default for the hero (the only big ring above the fold)
   and --lg for the verdict finale. The arc is complete in the markup, so the
   meter is right with no script at all. The finale's meter opts in to the
   reveal with data-reveal: the script sets --pending (arc empty) and lifts it
   when the meter scrolls into view, and the arc draws itself. Under reduced
   motion the script never sets --pending and the transition is off.
   --------------------------------------------------------------------------- */
.score-meter {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 112px;
  height: 112px;
  border-radius: var(--radius-pill);
  background-color: var(--bg-card);
}

.score-meter__ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.score-meter__track,
.score-meter__arc {
  fill: none;
  stroke-width: 7;
}

.score-meter__track {
  stroke: var(--arctic-200);
}

.score-meter__arc {
  stroke: var(--border-brand);
  stroke-dasharray: var(--score, 0) 100;
  transition: stroke-dasharray 1.6s cubic-bezier(0.22, 0.8, 0.25, 1);
}

.score-meter--pending .score-meter__arc {
  stroke-dasharray: 0 100;
}

.score-meter__value {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
}

.score-meter__figure {
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-medium);
  line-height: 1;
  color: var(--text-brand);
  background-image: var(--gradient-editorial);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  font-variant-numeric: tabular-nums;
}

.score-meter__scale {
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

.score-meter--lg {
  width: 168px;
  height: 168px;
}

.score-meter--lg .score-meter__figure {
  font-size: calc(var(--fs-h1) * 1.5);
}

@media (prefers-reduced-motion: reduce) {
  .score-meter__arc {
    transition: none;
  }
}
@media (max-width: 640px) {
  .score-meter--lg {
    width: 128px;
    height: 128px;
  }
  .score-meter--lg .score-meter__figure {
    font-size: var(--fs-h1);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — score-panel  (NEW)
   The verdict, read without reading the piece: one figure, five aspects, and
   what was good against what was not. It carries no border or ground because
   it sits inside the brand's bordered group — the one labelled-panel
   treatment — and the overall figure reuses the catalogue's score ring, which
   is where the editorial gradient is allowed to appear.

   The two verdict lists are genuinely uneven — two positives against four
   negatives on this review — so the columns start at the top and are never
   stretched level. A forced-level pair would read as a designed balance the
   review does not have.
   --------------------------------------------------------------------------- */
.score-panel {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--space-6) var(--space-12);
}

.score-panel__overall {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  text-align: center;
}

.score-panel__overall-label {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-heading);
}

.score-panel__overall-scale {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.score-panel__aspects {
  margin: 0;
  padding: 0;
  list-style: none;
}

.score-panel__aspect {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-2);
}

.score-panel__aspect + .score-panel__aspect {
  border-block-start: 1px solid var(--border-default);
}

.score-panel__aspect-label {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.score-panel__verdict {
  grid-column: 1/-1;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: var(--space-6) var(--space-12);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

.score-panel__column {
  min-width: 0;
}

.score-panel__column-title {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-heading);
}

.score-panel__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.score-panel__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding-block: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.score-panel__item svg {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin-block-start: 0.34em;
}

.score-panel__item--positive svg {
  color: var(--text-brand);
}

.score-panel__item--negative svg {
  color: var(--color-negative);
}

@media (max-width: 640px) {
  .score-panel,
  .score-panel__verdict {
    grid-template-columns: minmax(0, 1fr);
  }
  .score-panel__overall {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: var(--space-4);
    text-align: left;
  }
  .score-panel__aspect {
    flex-wrap: wrap;
    gap: var(--space-2);
  }
}
.score-ring {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border: 3px solid var(--border-brand);
  border-radius: var(--radius-pill);
  background-color: var(--bg-card);
}

.score-ring__figure {
  font-family: var(--ff-heading);
  font-size: var(--fs-h3);
  font-weight: var(--fw-medium);
  line-height: 1;
  color: var(--text-brand);
  background-image: var(--gradient-editorial);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ---------------------------------------------------------------------------
   BLOCK — score-strip  (NEW)
   The rail's verdict-at-a-glance, folded into the flow under the byline once
   the rail has gone (below 1100px): the score ring, the five sub-scores as a
   wrapping line of figures, and the jump link. On the panel's stripe-grey
   inset, the way series-bar sits, so it reads as furniture, not as a band.
   --------------------------------------------------------------------------- */
.score-strip {
  display: none;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  background-color: var(--bg-panel-alt);
  border-radius: var(--radius-card);
}

.score-strip__ring {
  flex: 0 0 auto;
  display: flex;
}

.score-strip__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.score-strip__aspects {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.score-strip__value {
  font-weight: var(--fw-medium);
  color: var(--text-body);
}

.score-strip__link {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
  text-decoration: none;
}

@media (max-width: 1100px) {
  .score-strip {
    display: flex;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — search-field  (NEW)
   The one thing search alone needs that the store did not already have: a
   field big enough to be the whole point of the surface it sits on.

   The box is the control (square, field-grey outline per the 1.3.0 border
   rule); the glyph and the clear cross sit inside it so the input keeps the
   full height as its hit area. Focus borrows the field atom's vocabulary
   exactly — brand border, blue-tint wash, a 2px brand ring clear of the box —
   so a focused search field and a focused checkout field read as one system.
   The Search button is the catalogue btn, joined flush to the box.
   --------------------------------------------------------------------------- */
.search-field {
  display: block;
  min-width: 0;
}

/* Present for screen readers; the placeholder and the glyph carry it visually. */
.search-field__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.search-field__row {
  display: flex;
  align-items: stretch;
}

.search-field__box {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  min-width: 0;
  min-height: 56px;
  border: 1px solid var(--border-input);
  border-inline-end: 0;
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
}

.search-field__box:focus-within,
.search-field__box--focus {
  border-color: var(--border-focus);
  background-color: var(--color-brand-soft);
}

.search-field__icon {
  flex: 0 0 auto;
  display: inline-flex;
  padding-inline: var(--space-4) var(--space-3);
  color: var(--text-brand);
}

.search-field__icon svg {
  width: 22px;
  height: 22px;
}

.search-field__input {
  flex: 1 1 auto;
  min-width: 0;
  align-self: stretch;
  padding: 0;
  border: 0;
  background: transparent;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}

.search-field__input:focus-visible {
  outline: none;
}

.search-field__input::placeholder {
  color: var(--neutral-500);
  opacity: 1;
}

.search-field__input::-webkit-search-cancel-button {
  display: none;
}

.search-field__clear {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  align-self: stretch;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.search-field__clear:hover {
  color: var(--text-link);
}

.search-field__clear svg {
  width: 16px;
  height: 16px;
}

.search-field__submit {
  flex: 0 0 auto;
  min-width: 112px;
}

@media (max-width: 640px) {
  .search-field__box {
    min-height: 48px;
  }
  .search-field__input {
    font-size: var(--fs-body);
  }
  .search-field__submit {
    min-width: 0;
    padding-inline: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — search-refine  (NEW)
   The results page's own furniture: the field repeated, pre-filled, so a
   shopper can sharpen the query in place; the type tabs along the panel's
   floor. One panel, because the field and the tabs answer the same question —
   what am I looking at, and how do I change it.
   --------------------------------------------------------------------------- */
.search-refine {
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-panel);
}

.search-refine__field {
  padding: var(--space-card-padding);
}

@media (max-width: 640px) {
  .search-refine__field {
    padding: var(--space-4);
  }
}
.section-head {
  margin-block-end: var(--space-6);
}

.section-head__title {
  font-family: var(--ff-heading);
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-heading);
  text-align: left;
}

/* The magazine's voice — a step smaller and muted, because the editorial side
   speaks more quietly than the shop. NOTHING ON THE STORE SIDE USES IT, and it
   is not for store furniture: a 26px muted title beside a 32px sibling reads as
   a mistake rather than a register, which is why the product page dropped it on
   2026-09-16. Kept for the article and magazine-archive templates, which is the
   context it was written for. Carried over from `band-title--quiet`. */
/* A BAND TITLE COMPOSED WITHOUT ITS WRAPPER.
   On a composed page a band head is a core/heading carrying this class, not a
   `<header class="section-head">` — there is no wrapper to hold the margin, and
   global's reset zeroes heading margins. The alternative was the editor
   serialising `style="margin-bottom:…"` into a pattern file, which is a
   hardcoded inline style in shipped template code and refused at commit.
   Same value as the wrapper's, from the same token. */
.section-head__title--standalone {
  margin-block-end: var(--space-6);
}

.section-head__title--quiet {
  font-size: var(--fs-h3);
  color: var(--neutral-600);
}

@media (max-width: 900px) {
  .section-head__title {
    font-size: var(--fs-h3);
  }
}
/* --inline + __count: a count set BESIDE the title rather than under it — the
   basket's "4 items · 3 packages" (MPG10). Ported from the mockup's
   archive-header--inline; a modifier on the existing head is a smaller change
   than porting a second opening block for one line. */
.section-head--inline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--space-4);
}

.section-head__count {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

/* --card: a card's own title inside a page — one step below the page title, so the
   page keeps one top-level heading (operator review of MPG11): Checkout at h2 size,
   each form card at h3. Ported from MPG11 for the checkout walk. */
.section-head--card .section-head__title {
  font-size: var(--fs-h3);
}

@media (max-width: 900px) {
  .section-head--card .section-head__title {
    font-size: var(--fs-h4);
  }
}
.section-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-start: var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
}

.section-link:hover {
  color: var(--text-link-hover);
}

.section-link__icon {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

/* The composed copy is a two-column document: prose at the reading measure on
   the left, the contents list as a rail on the right. The panel was always full
   width; the prose is not, and must not be — 1042px of body copy runs to about
   130 characters a line. The rail is what earns the space the measure leaves.
   Operator, 2026-09-14. */
.seo-doc {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 260px;
  gap: var(--space-12);
  align-items: start;
}

.seo-doc__rail {
  position: sticky;
  inset-block-start: var(--space-6);
  padding-inline-start: var(--space-6);
  border-inline-start: 1px solid var(--border-default);
}

/* In the rail the contents list stacks instead of running as a wrapped row. */
.seo-doc__rail .page-contents {
  margin: 0;
  padding: 0;
  border: 0;
}

.seo-doc__rail .page-contents__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.seo-doc__rail .page-contents__item::after {
  content: none;
}

@media (max-width: 900px) {
  .seo-doc {
    grid-template-columns: minmax(0, 1fr);
  }
  .seo-doc__rail {
    position: static;
    padding-inline-start: 0;
    border-inline-start: 0;
    border-block-start: 1px solid var(--border-default);
    padding-block-start: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — series-bar  (NEW)
   The compact series navigation directly under the article header. It has one
   job — let a reader who landed mid-series step back or forward — and one
   constraint: it must not push the first paragraph below the fold. So it is a
   single row on the panel's lightest inset (stripe grey, the styleguide's
   inset tone, not a band tint), with small type and no imagery.

   Three cells: previous on the left, the series and position in the middle,
   next on the right. Under the position sits a row of fifteen short ticks —
   one per entry, the current one in Paragon blue. It shows WHERE, not what
   has been read: there are no accounts, so nothing is tracked.

   At phone width the bar collapses to the one line the build brief asks for:
   "5 of 15 · Next →". Previous and both part titles drop out.
   --------------------------------------------------------------------------- */
.series-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-4) var(--space-6);
  background-color: var(--bg-panel-alt);
  border-radius: var(--radius-card);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
}

.series-bar__step {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
  text-decoration: none;
}

.series-bar__step--next {
  align-items: flex-end;
  text-align: right;
}

.series-bar__direction {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.series-bar__direction svg {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
}

.series-bar__title {
  overflow: hidden;
  max-width: 100%;
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.series-bar__step:hover .series-bar__title {
  color: var(--text-link-hover);
}

.series-bar__here {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

.series-bar__position {
  font-weight: var(--fw-medium);
  color: var(--text-body);
  white-space: nowrap;
}

.series-bar__ticks {
  display: flex;
  gap: 3px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.series-bar__tick {
  width: 8px;
  height: 3px;
  background-color: var(--border-strong);
}

.series-bar__tick--current {
  width: 16px;
  background-color: var(--color-brand);
}

.series-bar__compact {
  display: none;
}

@media (max-width: 640px) {
  .series-bar {
    display: flex;
    padding: var(--space-3) var(--space-4);
  }
  .series-bar__step,
  .series-bar__here {
    display: none;
  }
  .series-bar__compact {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    width: 100%;
  }
  .series-bar__compact-position {
    font-weight: var(--fw-medium);
    color: var(--text-body);
  }
  .series-bar__compact-next {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-weight: var(--fw-medium);
    color: var(--text-link);
    text-decoration: none;
  }
  .series-bar__compact-next svg {
    width: 14px;
    height: 14px;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — series-index  (NEW)
   The full run of a series, every entry, the current one marked. It is not a
   new list treatment: it is the brand's widget (a Paragon-blue title bar over
   a panel-white body) holding the brand's count-list, with the publication
   date standing in the count slot and --current marking this part. This block
   owns only what a series adds on top of those two — the phone-width
   collapse and the disclosure that undoes it.

   At phone width the list folds to the current entry and its two neighbours;
   every other entry carries series-index__far and is hidden until the reader
   presses "Show all 15". Order is publication order, so the neighbours are
   the previous and next parts, whatever they are called.
   --------------------------------------------------------------------------- */
.series-index {
  display: block;
}

.series-index__toggle {
  display: none;
}

@media (max-width: 640px) {
  .series-index:not(.series-index--open) .series-index__far {
    display: none;
  }
  .series-index__toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-3) var(--space-6);
    border: 0;
    border-block-start: 1px solid var(--border-default);
    border-radius: var(--radius-btn);
    background-color: transparent;
    font-family: var(--ff-body);
    font-size: var(--fs-small);
    font-weight: var(--fw-medium);
    line-height: var(--lh-heading);
    color: var(--text-link);
    cursor: pointer;
  }
  .series-index__toggle:hover {
    background-color: var(--bg-card-hover);
  }
  .series-index__toggle svg {
    width: 14px;
    height: 14px;
  }
  .series-index--open .series-index__toggle svg {
    transform: rotate(180deg);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — series-marker  (NEW)
   The line above an article's kicker that says which series the piece belongs
   to and where it sits in it. The series name is a link to the series page;
   the position is a count badge, and a count badge is one of the brand's round
   indicators, so it takes the pill radius. Outline rather than fill, because
   the marker is identity, not a control — the one filled blue element near the
   title should be nothing.
   --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   BLOCK — series-marker  (UPDATED — --on-image)
   --------------------------------------------------------------------------- */
.series-marker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
}

.series-marker__name {
  color: var(--text-link);
  text-decoration: none;
}

.series-marker__name:hover {
  color: var(--text-link-hover);
}

.series-marker__position {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--border-brand);
  border-radius: var(--radius-pill);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.04em;
  color: var(--text-brand);
  white-space: nowrap;
}

.series-marker--on-image .series-marker__name {
  color: var(--text-on-brand);
}

.series-marker--on-image .series-marker__name:hover {
  color: var(--paragon-300);
}

.series-marker--on-image .series-marker__position {
  border-color: var(--paragon-300);
  color: var(--paragon-300);
}

/* ---------------------------------------------------------------------------
   BLOCK — series-next  (NEW)
   The card a reader who has just finished a part is offered first: the next
   part of the same series, large. A sibling of article-card — same lead
   image at 16:9, same Paragon-blue kicker, same light italic title in blue —
   but it carries three things article-card has no slot for: the part's
   position in the series, its standfirst, and a button, because this is the
   one card on the page whose whole purpose is to be pressed.

   The magazine's card-title rule applies: regular weight, one lighter than
   the store would set the same size. It is set at the h3 size rather than
   article-card's h4 because it is the single card of its row.
   --------------------------------------------------------------------------- */
.series-next {
  display: flex;
  flex-direction: column;
  background-color: var(--bg-card);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

.series-next__media {
  display: block;
  width: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
  background-color: var(--neutral-800);
}

.series-next__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-card-padding);
}

.series-next__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.series-next__kicker {
  color: var(--text-brand);
}

.series-next__position {
  color: var(--text-muted);
}

.series-next__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h3);
  font-weight: var(--fw-regular);
  font-style: italic;
  line-height: var(--lh-heading);
}

.series-next__title a {
  color: var(--text-brand);
  text-decoration: none;
}

.series-next__title a:hover {
  color: var(--text-link-hover);
}

.series-next__standfirst {
  max-width: var(--container-article);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.series-next__date {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.series-next__action {
  margin-block-start: auto;
  padding-block-start: var(--space-2);
}

@media (max-width: 640px) {
  .series-next__body {
    padding: var(--space-6);
  }
  .series-next__title {
    font-size: var(--fs-h4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — series-steps  (NEW)
   Previous and next part, side by side, for the rail's series panel —
   series-bar's two outer cells without its middle, because in a 328px rail
   the position already sits in the series-marker above it.
   --------------------------------------------------------------------------- */
.series-steps {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  margin-block-start: var(--space-4);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--border-default);
}

.series-steps__step {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
  text-decoration: none;
}

.series-steps__step--next {
  align-items: flex-end;
  text-align: right;
}

.series-steps__direction {
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.series-steps__title {
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
}

.series-steps__step:hover .series-steps__title {
  color: var(--text-link-hover);
}

/* ---------------------------------------------------------------------------
   BLOCK — setup-band  (NEW, layout)
   Complete Your Setup: the one recommendation band the confirmation carries,
   below the order details and the help row so it never sits above what
   happens next. The canvas carries the section head and, pulled up against
   it, one muted line that belongs to the title; then four of the store's
   standard product cards at the panel gap; then the one way on, Continue
   Shopping, as the band's trailing action. No ground of its own — this brand
   has one ground, and the cards are the surfaces.
   DEPARTURE: no __grid. The four cards sit in the brand's own .grid.grid--4, which
   already steps 4 → 2 at 1100 and → 1 at 640 exactly as this band does
   (layouts/_grid.scss).
   --------------------------------------------------------------------------- */
.setup-band {
  display: block;
}

.setup-band__lead {
  margin: calc(-1 * var(--space-4)) 0 var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.setup-band__foot {
  display: flex;
  margin-block-start: var(--space-8);
}

@media (max-width: 640px) {
  .setup-band__lead {
    margin-block-start: calc(-1 * var(--space-3));
  }
  .setup-band__foot .btn {
    width: 100%;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — share-links  (NEW)
   Small text share links at the end of the article — not a floating bar and
   not the brand's social-row, which is for following the store. Closes a
   panel body under a hairline.
   --------------------------------------------------------------------------- */
.share-links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin: var(--space-4) 0 0;
  padding: var(--space-4) 0 0;
  border-block-start: 1px solid var(--border-default);
  list-style: none;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
}

.share-links__label {
  font-family: var(--ff-heading);
  font-weight: var(--fw-medium);
  color: var(--text-heading);
}

.share-links__link {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
}

.share-links__link:hover {
  color: var(--text-link-hover);
}

/* ---------------------------------------------------------------------------
   BLOCK — shipment-list  (NEW)
   What happens next, a row per package: the basket's own package-head, so the
   shopper recognises the three groups they saw before paying, with the
   package's items as small manufacturer shots at the far end. A row can carry
   one note under its status line — the pre-order's "Paid today" — indented to
   the status text so it reads as part of the same package. Rows are divided
   by the hairline, as rows inside a panel are, and the list closes on one
   line that applies to every package: how tracking arrives.

   Contents only — the surface is the panel it sits in. The thumbnails are the
   same hairline tile at the surface radius order-lines uses, a size up,
   because here they are the only product information in the row.
   --------------------------------------------------------------------------- */
.shipment-list__rows {
  margin: 0;
  padding: 0;
  list-style: none;
}

.shipment-list__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-4) var(--space-content-gap);
  padding-block: var(--space-6);
}

.shipment-list__item:first-child {
  padding-block-start: 0;
}

.shipment-list__item + .shipment-list__item {
  border-block-start: 1px solid var(--border-default);
}

.shipment-list__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.shipment-list__note {
  margin: 0;
  padding-inline-start: calc(24px + var(--space-3));
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.shipment-list__thumbs {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.shipment-list__thumb {
  width: 72px;
  padding: var(--space-1);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background-color: var(--bg-card);
}

.shipment-list__thumb img {
  display: block;
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: contain;
}

/* EXTENDED on the second review (operator, 2026-09-24): the foot is a row that
   can carry an action beside the tracking line (a Track button was tried there
   and removed — nothing is trackable until a package ships), and the list can
   close on one quieter line beneath (__after), indented to the foot's text. The
   line's type moved from __foot to __foot-text. */
.shipment-list__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4) var(--space-8);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

.shipment-list__foot-text {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.shipment-list__after {
  margin: var(--space-3) 0 0;
  padding-inline-start: calc(24px + var(--space-3));
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.shipment-list__foot-icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  color: var(--text-brand);
}

.shipment-list__foot-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* Phone: the thumbnails drop under the status line, indented to its text. */
@media (max-width: 640px) {
  .shipment-list__item {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
  }
  .shipment-list__thumbs {
    justify-content: flex-start;
    padding-inline-start: calc(24px + var(--space-3));
  }
  .shipment-list__thumb {
    width: 56px;
  }
  .shipment-list__note {
    font-size: var(--fs-small);
  }
  .shipment-list__foot {
    flex-direction: column;
    align-items: stretch;
  }
  .shipment-list__foot-text {
    align-items: flex-start;
    font-size: var(--fs-small);
    line-height: var(--lh-body);
  }
}
/* ---------------------------------------------------------------------------
   LAYOUT — shop-hero  (NEW; rebuilt on operator review 2)
   The paid-traffic landing moment, at the full 1400 column. A gaming set-up
   photographed in low light carries the promise, the search and the popular
   searches over a leading-edge scrim (the brand's text-over-photography rule,
   so the title sets medium). Beside it, two DEMAND shortcuts as built
   promo-tile--fill: Graphics Cards (the deepest range) and Controllers (the
   top search), so the two commonest intents are one click from landing.

   The popular searches sit on the photograph as square outline chips — the
   brand's control shape, drawn on-brand-white — rather than on a separate
   panel, so search and suggestions read as one move.
   --------------------------------------------------------------------------- */
.shop-hero {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--space-content-gap);
}

.shop-hero__main {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
  min-height: 480px;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--neutral-800);
}

.shop-hero__media {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.shop-hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--bg-overlay) 0%, var(--bg-overlay) 45%, transparent 92%);
}

.shop-hero__content {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  width: 100%;
  max-width: 640px;
  padding: var(--space-12);
}

.shop-hero__eyebrow {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-on-brand);
}

.shop-hero__title {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.shop-hero__standfirst {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-on-brand);
}

.shop-hero__popular {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.shop-hero__popular-label {
  margin-inline-end: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--text-on-brand);
}

.shop-hero__aside {
  display: grid;
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: var(--space-content-gap);
  min-width: 0;
}

@media (max-width: 900px) {
  .shop-hero {
    grid-template-columns: minmax(0, 1fr);
  }
  .shop-hero__aside {
    grid-template-rows: none;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .shop-hero {
    gap: var(--space-4);
  }
  .shop-hero__main {
    min-height: 0;
  }
  .shop-hero__scrim {
    background: var(--bg-overlay);
  }
  .shop-hero__content {
    max-width: none;
    padding: var(--space-8) var(--space-6);
  }
  .shop-hero__title {
    font-size: var(--fs-h2);
  }
  .shop-hero__standfirst {
    font-size: var(--fs-body);
  }
  .shop-hero__aside {
    gap: var(--space-4);
  }
  /* Two shortcuts side by side on a phone: the built tile's 300px floor and
     h3 title are sized for a column, not half a phone. */
  .shop-hero__aside .promo-tile,
  .shop-hero__aside .promo-tile__media {
    min-height: 180px;
  }
  .shop-hero__aside .promo-tile__content {
    padding: var(--space-4);
  }
  .shop-hero__aside .promo-tile__title {
    font-size: var(--fs-body-lg);
  }
  .shop-hero__aside .promo-tile__cue {
    margin-block-start: var(--space-1);
    font-size: var(--fs-small);
  }
}
/* --solo — no shortcut tiles: the photograph takes the column. Added in the
   MPG21 wiring pass, so a hero composed without tiles is not a two-thirds
   photograph beside an empty third. */
.shop-hero--solo {
  grid-template-columns: minmax(0, 1fr);
}

.spec-bullets {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-12);
}

.spec-bullets--single {
  grid-template-columns: minmax(0, 1fr);
}

.spec-bullets__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.spec-bullets__item {
  position: relative;
  padding-inline-start: var(--space-6);
  padding-block: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.spec-bullets__item::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.72em;
  width: 7px;
  height: 7px;
  border-radius: var(--radius-pill);
  background-color: var(--color-brand);
}

.spec-bullets__item + .spec-bullets__item {
  border-block-start: 1px solid var(--border-default);
}

@media (max-width: 640px) {
  .spec-bullets {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }
  .spec-bullets__list + .spec-bullets__list .spec-bullets__item:first-child {
    border-block-start: 1px solid var(--border-default);
  }
}
/* A modifier on the block, not a class of its own. It was `.spec-columns`, which
   read as a separate component and left `spec-grid` with no element carrying its
   own name — the block would have entered the catalogue with a root nothing
   matched. It resets `display` because the base rule is a grid and a grid
   container ignores `columns`. */
.spec-grid--columns {
  display: block;
  columns: 2;
  column-gap: var(--space-12);
}

.spec-grid--columns .spec-grid__group {
  break-inside: avoid;
  margin: 0 0 var(--space-8);
}

@media (max-width: 900px) {
  .spec-grid--columns {
    columns: 1;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — spec-grid  (NEW)
   A label-and-value list for the product's attributes, built to be read down
   rather than across. It replaces the striped two-column table the earlier
   drafts used, which had to be squeezed into a narrow column and lost the
   thing a table is for.

   FIFTY-FIVE PER CENT of the catalogue carries attributes; the other 45% has
   none. So the panel is a stack of GROUPS, each with its own small heading,
   and a group that has no data is simply not rendered. On a product with no
   attributes the panel still stands with its identity group, which every
   product has — it is never an empty shell with a header on it.
   --------------------------------------------------------------------------- */
.spec-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.spec-grid__group + .spec-grid__group {
  margin-block-start: var(--space-8);
}

.spec-grid__heading {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.spec-grid__row {
  display: grid;
  grid-template-columns: minmax(0, 42%) minmax(0, 1fr);
  gap: var(--space-4);
  padding-block: var(--space-3);
}

.spec-grid__row + .spec-grid__row {
  border-block-start: 1px solid var(--border-default);
}

.spec-grid__label {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-muted);
}

.spec-grid__value {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

@media (max-width: 1180px) {
  .spec-grid__rows {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-12);
  }
  .spec-grid__row {
    border-block-start: 1px solid var(--border-default);
  }
}
@media (max-width: 860px) {
  .spec-grid__rows {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* BLOCK — star-rating (NEW) */
.star-rating {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: 1;
}

.star-rating__stars {
  position: relative;
  display: inline-block;
  color: var(--neutral-300);
  letter-spacing: 1px;
  white-space: nowrap;
}

.star-rating__fill {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  width: var(--fill, 0%);
  overflow: hidden;
  color: var(--text-brand);
  white-space: nowrap;
}

.star-rating__count {
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.stock-alert {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  margin-block-start: var(--space-4);
}

.stock-alert .inline-form {
  align-self: stretch;
}

.stock-alert__title {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.stock-alert__note {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.stock-alert__joined {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.stock-alert__icon {
  flex: 0 0 auto;
  width: 1.25em;
  height: calc(1em * var(--lh-body));
  color: var(--color-positive);
}

.stock-alert__manage {
  margin-block-start: 0;
}

@media (max-width: 640px) {
  .stock-alert .inline-form__row {
    grid-template-columns: minmax(0, 1fr);
  }
}
.points-offer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-block-start: var(--space-4);
  padding: var(--space-4);
  border-radius: var(--radius-card);
  background-color: var(--color-brand-soft);
}

.points-offer__text {
  flex: 1 1 12rem;
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.points-offer__text strong {
  font-weight: var(--fw-medium);
}

.points-offer__action {
  flex: 0 0 auto;
}

/* ---------------------------------------------------------------------------
   BLOCK — step-list  (NEW)
   A numbered procedure inside a document — "How to return something". A
   numbered list in a help page is drawn as this (includes/help.php). nested-list
   is unordered by design, and the numbered blocks the brand does have
   (checkout-steps, score-list) are progress and scoring furniture, not running
   text.

   The marker is the step number in a Paragon-blue outline ring — a round
   indicator, so it takes the pill radius, as the styleguide allows for count
   badges — sized to one line of body text so it sits level with the first line
   of its step.
   --------------------------------------------------------------------------- */
.step-list {
  max-width: var(--container-reading);
  margin: var(--space-8) 0 0;
  padding: 0;
  list-style: none;
  counter-reset: step-list;
}

.step-list__item {
  position: relative;
  padding-inline-start: calc(28px + var(--space-3));
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
  counter-increment: step-list;
}

.step-list__item + .step-list__item {
  margin-block-start: var(--space-4);
}

.step-list__item::before {
  content: counter(step-list);
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 1.5px solid var(--color-brand);
  border-radius: var(--radius-pill);
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: 1;
  color: var(--text-brand);
}

.step-list__item strong {
  font-weight: var(--fw-medium);
  color: var(--text-heading);
}

.step-list__item a {
  font-weight: var(--fw-medium);
  color: var(--text-link);
  text-decoration: none;
}

.step-list__item a:hover {
  color: var(--text-link-hover);
}

/* ---------------------------------------------------------------------------
   PAGE LAYOUT — the shell, the rail and the region grids.

   BUILT 2026-09-15 from six pieces of operator feedback, after three designs
   were rejected. Each of the six is answered in one place and the place is
   named, so a later session can see which choices are load-bearing:

   1. The short description goes BEFORE the buy box    → .buy-region__summary
   2. Loyalty points sit AFTER the buy box             → .buy-region__summary
   3. Stat pills live inside the product description   → .doc-figures
   4. The description takes the live site's column     → .store-layout
   5. Add to Basket never wraps to two lines           → .btn--commerce, .route-row
   6. The navigation rail comes back, desktop only     → .store-layout__sidebar

   THE COLUMN IS 1042px AND THAT IS THE POINT OF (4). It is what the live store
   gives its content: a 1400 page, a 328 rail, a 30 gap. Three drafts put the
   description at 680 or 740 because that is the styleguide's READING measure,
   and all three read as cramped — because the measure was set for editorial
   pages, where prose is alone on the page. A product description is not alone:
   it carries stat blocks, spec tables and feature rows, and it wants the room
   the store already gives it. The 680 measure still governs article pages.
   --------------------------------------------------------------------------- */
/* `.page__inner` is NOT declared here. It was, identically, in this file and in
   `_page.scss` — the same rule and the same docblock, copied — until the MPG8
   walk found the pair. The page owns the page container; this file owns the
   store shell inside it. */
.store-layout {
  display: grid;
  grid-template-columns: var(--width-sidebar) minmax(0, 1fr);
  gap: var(--space-content-gap);
}

/* (6) The rail. It carries the store navigation and then the space the
   operator asked for — promotional tiles, which are the brand's own
   `promo-tile` block rather than anything new. On desktop it fills the page's
   left edge for its whole height; below 1100 it is removed outright rather
   than folded underneath, because a navigation column stacked under a product
   is furniture nobody scrolls to and the site header's menu already covers
   the same ground on a phone. */
.store-layout__sidebar {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  min-width: 0;
}

/* THE PROMO PAIR PINS AS ONE UNIT, the navigation scrolls away.
   The rail cannot be filled to match the column, and the arithmetic is not close:
   its content is ~1,800px against a product zone of ~8,800px on this product, and
   across 3,904 descriptions the median is 7,568 characters with only 18 under
   1,500. Filling by volume would need ten cards on a median product and twenty on
   a long one, and would still be wrong on the next one. So the rail stops trying
   to match a height nobody can know: the navigation scrolls past — it is used at
   the start of a visit, not during a read — and the promo pair stays beside the
   reader for the whole description.

   SQUARE TILES ARE WHAT MAKE THIS SIMPLE. At the rail's 328px a square is 328
   tall, so the pair is 686 with its gap, and that fits every window the rail
   renders in — it is removed below 1100px wide, and the shortest laptop it meets
   is about 800 tall. No height breakpoint, no shrinking, and one image ratio to
   design to.

   The pair was 883px when a tile took its height from the image's own aspect
   ratio, which did not fit an 800px window and wanted a max-height rule at a
   height breakpoint to cope. A fixed ratio removes the problem rather than
   handling it. */
.store-layout__promos {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  position: sticky;
  top: var(--space-8);
}

/* The tiles must not stretch. `promo-tile` carries its own square ratio, and the
   rail is a grid item as tall as the whole page — without this the two would share
   that height between them and render as one dark slab down the left of the page,
   which is what happened before the ratio existed. */
.store-layout__sidebar .promo-tile,
.store-layout__sidebar .promo-tile__media {
  flex: 0 0 auto;
}

@media (max-width: 1100px) {
  .store-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  /* (6) Removed outright on a phone, not stacked underneath. A navigation
     column beneath a product is furniture nobody scrolls to, and the site
     header's menu already covers the same ground there. */
  .store-layout__sidebar {
    display: none;
  }
  /* …EXCEPT WHERE THE RAIL IS THE POINT OF THE PAGE. That reasoning is about a
     PRODUCT — a shopper reading one item does not want a range list under it.
     A category funnel is the opposite case: the page's whole job is routing
     into the range, and the rail is the routing. So the removal stays the
     default and a funnel opts out, rather than the rule being softened for
     every template that shares this shell.

     It goes BELOW the content rather than above it. The range's own header and
     its type tiles are what the visitor came for; the full store list is where
     they go if this range was the wrong turn, and that is a decision made after
     reading, not before. MPG8 (design 17955) draws it this way. */
  .store-layout--nav-persists .store-layout__sidebar {
    display: flex;
    order: 2;
  }
  .store-layout--nav-persists .store-layout__content {
    order: 1;
  }
}
/* ---- the account variant (MPG13) -------------------------------------------

   The account area is the store's two-column shell at the store's own measures —
   the account menu in the 328px rail, the endpoint's content in the 1042px column.
   Two things differ, and both are this modifier.

   BOTH COLUMNS START ON ONE LINE: the content column stacks its panels with the
   content gap and every child's own block margins are zeroed, exactly as on the
   basket, the checkout and the confirmation.

   THE MENU NEVER DISAPPEARS. Below 1100 the rail is removed, as it is on a product,
   and the account menu comes back as one select-style control at the top of the
   content (`account-switch`), in `__switch`. The mockup switched at 900; it moves to
   1100 so the account and the store lose their rail at the same width, rather than
   leaving 900–1100 with no menu at all (operator, MPG13 checkpoint 2). Above that the
   switch renders no box, and a flex gap is only laid between boxes that render, so it
   costs the first panel nothing.
   --------------------------------------------------------------------------- */
.store-layout--account {
  align-items: start;
}

.store-layout--account .store-layout__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-content-gap);
  min-width: 0;
}

.store-layout--account .store-layout__content > * {
  margin-block: 0;
}

.store-layout__switch {
  display: none;
}

@media (max-width: 1100px) {
  .store-layout__switch {
    display: block;
  }
}
/* ---- the sidebar's one piece of canvas furniture ---------------------------

   The mockup calls this `store-sidebar__heading`, which would make it the only
   element of a block that has no rules of its own — and the class lint caught
   exactly that: a parent block nothing declares. It is the store layout's
   sidebar heading, so it is an element of `store-layout`, which is the block
   that already owns the column it sits in. Renamed rather than given an empty
   parent rule to satisfy the check.

   The negative bottom margin pulls the first filter panel back up to the
   sidebar's own gap: the heading labels the panels below it and should read as
   part of that group, not as a band of its own.
   --------------------------------------------------------------------------- */
/* The sidebar's one piece of canvas furniture. */
.store-layout__sidebar-heading {
  margin: var(--space-2) 0 calc(-1 * var(--space-2));
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

/* ---------------------------------------------------------------------------
   BLOCK — store-nav  (NEW)
   The store navigation sidebar, designed here for the first time and inherited
   by every store page after it — category, brand, search results, deals,
   product.

   A stack of Paragon-blue bars, one per top-level range, each a white
   body-font label with a down chevron, separated by thin rules. The rule is
   the panel showing through between two bars, which is what a stack of bars on
   a white panel actually looks like.

   THE DISCLOSURE is the one the reference specimen settled and not a second
   one: a real `details` and `summary`, the brand's own chevron turned to point
   down, turned up when the row is open. It works with no script, and a link
   pointing into a closed range opens it.

   THE OPEN BAR expands in place to a panel-white list of its subcategories,
   and that list is `count-list` — the same list the filter groups and the
   featured brands take, so the column carries one list treatment and not
   three. The current item is marked exactly as count-list already marks it:
   the blue-tint wash across the row and the three-pixel Paragon-blue leading
   rule, paid for out of the row's own padding so nothing shifts.

   The bar label follows the styleguide's navigation setting — body font,
   16px, light, uppercase — which is what distinguishes a navigation bar from
   the heading-font title bar a widget carries.
   --------------------------------------------------------------------------- */
.store-nav {
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-panel);
}

.store-nav__range + .store-nav__range {
  border-block-start: 1px solid var(--bg-panel);
}

.store-nav__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  /* Symmetrical again. The two-pixel nudge above this line existed to correct an
     ALL-CAPS label sitting high in its cap band; with the labels set as written,
     the descenders fill the lower half and the correction would push the text
     low. An optical fix is tied to the treatment that needed it. */
  padding: var(--space-3) var(--space-6);
  background-color: var(--color-brand);
  list-style: none;
  cursor: pointer;
}

.store-nav__bar::-webkit-details-marker {
  display: none;
}

.store-nav__bar::marker {
  content: "";
}

.store-nav__bar:focus-visible {
  outline: 2px solid var(--neutral-50);
  outline-offset: -3px;
}

.store-nav__label {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  /* The label is set AS WRITTEN — "PC Components", not "PC COMPONENTS". Operator,
     2026-09-16: the uppercase read wrong in the rail.
     Which takes the line-height back to the heading step and the tracking back to
     normal. Both were compensations for capitals: 1.2 reserves descender space
     that caps never use, and 0.04em opens up letterforms that uppercase needs and
     mixed case does not. */
  line-height: var(--lh-heading);
  letter-spacing: normal;
  /* Two pixels above the label, and ONLY the label — the bar's own padding stays
     symmetrical so the marker is not pushed with it. The two align on their
     optical centres rather than their boxes: the label's line box carries
     descender space below the letters that the eye does not count, so a box
     centred on the bar sits high against a chevron centred on the same axis. */
  padding-block-start: 2px;
  color: var(--text-on-brand);
}

/* The name as a link to the range's page: it takes the bar's width, so the
   chevron and the padding around it are what open the panel. */
.store-nav__label--link {
  flex: 1 1 auto;
  text-decoration: none;
}

.store-nav__label--link:hover {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.store-nav__label--link:focus-visible {
  outline: 2px solid var(--neutral-50);
  outline-offset: 2px;
}

/* 21px — half again on the 14 it was. At 14 the chevron read as a hint rather
   than a control next to a 16px label. */
.store-nav__marker {
  flex: 0 0 auto;
  display: inline-flex;
  width: 21px;
  height: 21px;
  color: var(--text-on-brand);
}

.store-nav__marker svg {
  width: 100%;
  height: 100%;
  transform: rotate(90deg);
}

.store-nav__range[open] .store-nav__marker svg {
  transform: rotate(-90deg);
}

/* THIRD LEVEL — indented, so the hierarchy reads down the rail.
   The indent goes on the LINK's inline padding, not on the list: a padded list
   would leave a strip of unhighlighted rail down the left of every child row,
   because the hover ground is the link's own background. Same reason the second
   level's padding lives there.
   `store-nav__children` had no rule at all until now — it is in the markup the
   mockup carries, and nothing had ever styled it, so a third-level item sat flush
   with its parent. */
.store-nav__children .count-list__link {
  padding-inline-start: calc(var(--space-6) + var(--space-4));
}

/* The fourth level — a third-level entry's own menu entries (NVIDIA Graphics
   Cards → its series; operator, 2026-11-10) — one step further in. */
.store-nav__children .store-nav__children .count-list__link {
  padding-inline-start: calc(var(--space-6) + var(--space-4) * 2);
}

/* A SECOND-LEVEL ROW WITH SUB-RANGES — the name is still the link to the range,
   and a chevron button beside it opens the drawer of sub-ranges in place
   (operator, 2026-10-10: Graphics Cards, Motherboards and Processors could only
   be opened by clicking through). Same chevron as the bars, in Paragon blue,
   pointing down when closed and up when open. The drawer is the
   `store-nav__children` list beneath, `hidden` until opened. */
.store-nav__parent {
  display: flex;
  align-items: stretch;
}

.store-nav__parent > .count-list__link {
  flex: 1 1 auto;
  min-width: 0;
}

.store-nav__toggle {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-12);
  padding: 0;
  border: 0;
  background-color: transparent;
  color: var(--text-brand);
  cursor: pointer;
}

.store-nav__toggle svg {
  width: 18px;
  height: 18px;
  transform: rotate(90deg);
}

.store-nav__toggle[aria-expanded=true] svg {
  transform: rotate(-90deg);
}

.store-nav__toggle:hover,
.count-list__item--current > .store-nav__toggle {
  background-color: var(--bg-card-hover);
}

.store-nav__toggle:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

/* THE DRAWER ANIMATES like the range bars above it — the `details` panels in
   _base.scss — at the same tempo: its height eases between 0 and its own
   content's (`interpolate-size` on body makes `auto` a target). It carries
   `hidden` while closed for its meaning, so the browser's own `display: none`
   is set aside here; `visibility` steps with the transition, which keeps the
   closed drawer out of the tab order and the accessibility tree once it has
   finished closing, and not before. */
.store-nav__children {
  display: block;
  block-size: auto;
  overflow: hidden;
  transition: block-size var(--motion-quick) var(--motion-ease), visibility var(--motion-quick) var(--motion-ease);
}

.store-nav__children[hidden] {
  display: block;
  block-size: 0;
  visibility: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .store-nav__children {
    transition: none;
  }
}
.store-nav__panel {
  background-color: var(--bg-panel);
  border-block-start: 1px solid var(--border-default);
}

@media (max-width: 640px) {
  .store-nav__bar {
    padding-inline: var(--space-4);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — suggestion-list  (NEW)
   empty-state carries a title, a line and one link; an empty search needs
   three ways out, so the three are their own block placed inside it — the
   card-line move again, empty-state reused unchanged. Numbered because they
   are in the order worth trying them. The numerals are round indicators in
   Paragon blue, the brand's structural colour.
   --------------------------------------------------------------------------- */
.suggestion-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
  max-width: 900px;
  margin: var(--space-8) auto 0;
  padding: 0;
  list-style: none;
  counter-reset: suggestion;
  text-align: left;
}

.suggestion-list__item {
  position: relative;
  padding-inline-start: 44px;
  counter-increment: suggestion;
}

.suggestion-list__item::before {
  content: counter(suggestion);
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 2px solid var(--border-brand);
  border-radius: var(--radius-pill);
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: 1;
  color: var(--text-brand);
}

.suggestion-list__head {
  display: block;
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.suggestion-list__text {
  display: block;
  margin-block-start: var(--space-1);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

@media (max-width: 900px) {
  .suggestion-list {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    max-width: 420px;
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — summary-toggle  (NEW)
   The order summary at phone width, folded into one bar at the top of the
   form: "Show order summary" in link blue with the chevron, the total at the
   far end in the commerce face. Open, it shows the same order-lines and
   order-totals the sidebar shows. A real disclosure, so it needs no script.

   On its own panel-white card, as everything on this canvas is. The page
   decides when it appears — at wider widths the sidebar does this job.
   --------------------------------------------------------------------------- */
.summary-toggle {
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.summary-toggle__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  list-style: none;
  cursor: pointer;
}

.summary-toggle__bar::-webkit-details-marker {
  display: none;
}

.summary-toggle__bar::marker {
  content: "";
}

.summary-toggle__bar:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

.summary-toggle__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-link);
}

.summary-toggle__label--open {
  display: none;
}

.summary-toggle[open] .summary-toggle__label--closed {
  display: none;
}

.summary-toggle[open] .summary-toggle__label--open {
  display: inline-flex;
}

.summary-toggle__icon {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--text-brand);
  transform: rotate(90deg);
}

.summary-toggle[open] .summary-toggle__icon {
  transform: rotate(-90deg);
}

.summary-toggle__total {
  font-family: var(--ff-chrome);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-body);
  white-space: nowrap;
}

.summary-toggle__body {
  padding: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

@media (max-width: 640px) {
  .summary-toggle__bar,
  .summary-toggle__body {
    padding-inline: var(--space-4);
  }
}
.tag-cloud {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-2);
}

.tag-cloud__tag {
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-card);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-link);
  text-decoration: none;
}

.tag-cloud__tag--sm {
  font-size: var(--fs-small);
}

.tag-cloud__tag--lg {
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-medium);
}

.tag-cloud__tag:hover {
  background-color: var(--bg-card-hover);
  color: var(--text-link-hover);
}

/* ---------------------------------------------------------------------------
   BLOCK — term-chips  (REUSED, verbatim)
   --------------------------------------------------------------------------- */
.term-chips {
  padding: var(--space-2) var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.term-chips__row {
  display: flex;
  align-items: baseline;
  gap: var(--space-6);
  padding-block: var(--space-4);
}

.term-chips__row + .term-chips__row {
  border-block-start: 1px solid var(--border-default);
}

.term-chips__label {
  flex: 0 0 96px;
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.term-chips__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.term-chips__chip {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  background-color: var(--bg-panel);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-decoration: none;
  white-space: nowrap;
}

.term-chips__chip:hover {
  border-color: var(--border-brand);
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

.term-chips__count {
  font-size: var(--fs-eyebrow);
  color: var(--text-muted);
}

.term-chips__chip:hover .term-chips__count {
  color: var(--text-link);
}

@media (max-width: 640px) {
  .term-chips {
    padding-inline: var(--space-4);
  }
  .term-chips__row {
    flex-direction: column;
    gap: var(--space-3);
  }
  .term-chips__label {
    flex-basis: auto;
  }
  .term-chips__list {
    flex-wrap: nowrap;
    align-self: stretch;
    overflow-x: auto;
    scrollbar-width: none;
    margin-inline-end: calc(var(--space-4) * -1);
    padding-inline-end: var(--space-4);
  }
  .term-chips__list::-webkit-scrollbar {
    display: none;
  }
  .term-chips__list > li {
    flex: 0 0 auto;
  }
}
/* ---------------------------------------------------------------------------
   --on-media — the chip list laid on a photograph, with no panel behind it:
   square outline chips drawn on-brand-white, counts in the same colour, the
   panel-white wash on hover. The store front's popular searches (shop-hero)
   and the spotlight's sub-ranges (cta-band--spotlight), MPG21. The list's own
   phone behaviour — one swipeable row — is kept.
   --------------------------------------------------------------------------- */
.term-chips__list--on-media .term-chips__chip {
  border-color: var(--color-text-on-brand);
  background-color: transparent;
  color: var(--text-on-brand);
}

.term-chips__list--on-media .term-chips__count {
  font-weight: var(--fw-light);
  color: var(--text-on-brand);
}

.term-chips__list--on-media .term-chips__chip:hover {
  border-color: var(--color-text-on-brand);
  background-color: var(--bg-card);
  color: var(--text-link);
}

.term-chips__list--on-media .term-chips__chip:hover .term-chips__count {
  color: var(--text-link);
}

/* ---------------------------------------------------------------------------
   --scroll — the block's phone treatment without its media query, for the
   phone menu (MPG22): label above, one row of chips scrolling sideways, chips
   at a 44px touch height, no panel of its own (it sits on the menu's sheet).
   --------------------------------------------------------------------------- */
.term-chips--scroll {
  padding: 0;
  border-radius: 0;
  box-shadow: none;
}

.term-chips--scroll .term-chips__row {
  flex-direction: column;
  gap: var(--space-3);
  padding-block: 0;
}

.term-chips--scroll .term-chips__label {
  flex-basis: auto;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.term-chips--scroll .term-chips__list {
  flex-wrap: nowrap;
  align-self: stretch;
  margin-inline-end: calc(var(--space-4) * -1);
  padding-inline-end: var(--space-4);
  overflow-x: auto;
  scrollbar-width: none;
}

.term-chips--scroll .term-chips__list::-webkit-scrollbar {
  display: none;
}

.term-chips--scroll .term-chips__list > li {
  flex: 0 0 auto;
}

.term-chips--scroll .term-chips__chip {
  align-items: center;
  min-height: 44px;
}

/* ---------------------------------------------------------------------------
   BLOCK — timeline  (NEW)
   A short dated sequence on its own panel — on the About page, the brand's two
   names. A Paragon-blue rule runs between round markers (round indicators take
   the pill radius); the year is the figure, set large and light in the heading
   font in Paragon blue, the name beneath it, one line of what changed. Not a
   progress indicator (checkout-steps) and not a procedure (step-list): it
   records what happened, in order.

   DEPARTURE: composed in the editor from core groups and paragraphs carrying
   these classes, so the year, name and line are paragraphs rather than spans in
   a list — each states its own margin.
   --------------------------------------------------------------------------- */
/* SCOPED UNDER THE BLOCK. The parts are core paragraphs and headings carrying
   these classes, and the theme's core-block rules (`.wp-block-paragraph`,
   `h3.wp-block-heading`, core's flow margins) load later at the same weight —
   so each part is named inside its block to outrank them. */
.timeline {
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.timeline .timeline__title {
  margin: 0 0 var(--space-6);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.timeline .timeline__item {
  position: relative;
  margin-block: 0;
  padding-inline-start: var(--space-8);
}

.timeline .timeline__item + .timeline__item {
  margin-block-start: var(--space-8);
}

/* The marker, level with the middle of the year figure. */
.timeline .timeline__item::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 17px;
  width: 14px;
  height: 14px;
  border: 3px solid var(--border-brand);
  border-radius: var(--radius-pill);
  background-color: var(--bg-panel);
}

/* The rule, from this marker down to the next one. */
.timeline .timeline__item:not(:last-child)::after {
  content: "";
  position: absolute;
  inset-inline-start: 6px;
  inset-block-start: 31px;
  inset-block-end: calc(-1 * var(--space-8) - 17px);
  width: 2px;
  background-color: var(--border-brand);
}

.timeline .timeline__year {
  margin: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h1);
  font-weight: var(--fw-light);
  line-height: var(--lh-heading);
  color: var(--text-brand);
}

.timeline .timeline__name {
  margin: var(--space-1) 0 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.timeline .timeline__text {
  margin: var(--space-2) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-body);
}

/* ---------------------------------------------------------------------------
   BLOCK — trust-row  (UPDATED — every statement is now a link)

   A claim the shopper can check is worth more than a claim they cannot, so
   each of the four statements now routes to the page that backs it: the
   Trustpilot profile, Store & Shipping Information twice, and the Clearpay
   FAQ. That turns the row from four pieces of decoration into four routes
   into the information centre.

   The card is unchanged. What moved is the padding: it now sits on the link
   rather than the item, so the whole card is the hit target and the row looks
   exactly as it did. Hover takes the label to Paragon blue — the brand's link
   colour, no underline — and nothing else moves.

   The old block's phone rules also stripped the cards back to hairline-
   separated rows. That contradicted the design brief's own instruction that a
   row of four short trust statements is four cards and not four columns, so
   the cards now stay cards at every width and simply stack.
   --------------------------------------------------------------------------- */
/* THE ROW FITS ITS CONTAINER, NOT ITS FIRST PAGE (MPG1 walk, 2026-09-16).

   This was `repeat( 3, … )`, fixed on 2026-09-16 because four statements in the
   product page's 962px column gave 222px each — a footer column's width for a
   line meant to be read at a glance. Three sat at 301 and read correctly.

   That is a measurement of the COLUMN, and the class was carrying it as though
   it were a property of the component. The homepage's band is four statements
   at the full 1400px page width, where four fit at ~330px — wider than the 301
   the product page settled on — and a hard three-column rule put the fourth on
   a row of its own.

   `auto-fit` at a 260px floor states the actual rule: as many across as fit
   without going under the width the copy needs. The product page is unchanged
   by it — three items in 962px still measure 301px each. The two breakpoints
   below still override deliberately: two across on a tablet rather than the
   three auto-fit would otherwise allow, and one on a phone. */
.trust-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
  gap: var(--space-content-gap);
}

.trust-row__item {
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-panel);
}

.trust-row__link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: 100%;
  padding: var(--space-card-padding);
  text-decoration: none;
}

/* 40px, matching the delivery icon in the buy box — the brand's existing size
   for an icon that carries a fact rather than decorates a label. At 30 these
   read as bullets beside their copy; the row is four claims, and the icon is
   half of each claim. One rule, so the product page's three take it too. */
.trust-row__icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  color: var(--text-brand);
}

.trust-row__icon svg {
  width: 100%;
  height: 100%;
}

.trust-row__label {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.trust-row__link:hover .trust-row__label {
  color: var(--text-link);
}

.trust-row__link:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

@media (max-width: 1100px) {
  .trust-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .trust-row {
    grid-template-columns: minmax(0, 1fr);
  }
  .trust-row__link {
    padding: var(--space-6);
  }
}
/* ---------------------------------------------------------------------------
   --outlined — each statement its own card with the brand's 2px Paragon-blue
   border, the outline the product page's Spread the Cost and loyalty points
   cards carry (`bordered-group`), without their title bar. The store front's
   trust points, between the hero and the ranges (operator, 2026-10-10). The
   card's shadow gives way to the border: one edge treatment, not two.
   --------------------------------------------------------------------------- */
.trust-row--outlined .trust-row__item {
  border: 2px solid var(--border-brand);
  box-shadow: none;
}

/* ---------------------------------------------------------------------------
   --line — the same promises as one quiet line rather than four cards, for a
   surface that is already a panel: the foot of the main menu (MPG22). A row of
   cards there would be a panel inside a panel, louder than the menu it closes.
   The icon drops to a 20px mark, the card ground and padding fall away, and the
   statements run left to right — one to a line on a phone, where they wrap.
   --------------------------------------------------------------------------- */
.trust-row--line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-12);
}

.trust-row--line .trust-row__item {
  background-color: transparent;
  border-radius: 0;
  box-shadow: none;
}

.trust-row--line .trust-row__link {
  gap: var(--space-2);
  padding: var(--space-1) 0;
}

.trust-row--line .trust-row__icon {
  width: 20px;
  height: 20px;
}

.trust-row--line .trust-row__label {
  font-size: var(--fs-small);
}

/* ---------------------------------------------------------------------------
   BLOCK — typeahead  (NEW)
   The search modal's panel. It hangs in the header log-in modal's shell —
   same scrim, same close control above the panel's right edge, same entrance —
   and takes the same flat panel-white surface at the card radius.

   Three parts, and only the middle one moves:
     __head  the field, fixed. Typing never scrolls it away.
     __body  the results, grouped by TYPE so a shopper sees at a glance which
             answer is a category, which a product and which an article. It
             scrolls inside the panel; the panel is capped against the
             viewport so it never spills off the screen.
     __all   the way to the full results page, pinned to the foot as a
             Paragon-blue row — structural blue, the brand's job for it.

   Category rows are text links with a count, because a count is what makes a
   category the better answer to a vague query. Product rows are the catalogue
   product-line (reused unchanged) with a stock-line in its body. Magazine rows
   carry a type label in the kicker style and the title in the magazine's own
   quieter italic voice.
   --------------------------------------------------------------------------- */
.typeahead {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 160px);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-panel);
}

.typeahead__head {
  flex: 0 0 auto;
  padding: var(--space-card-padding);
  padding-block-end: var(--space-6);
  border-block-end: 1px solid var(--border-default);
}

/* The phone sheet's title row; the shell's close control sits at its end. */
.typeahead__title {
  display: none;
  margin: 0 0 var(--space-4);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.typeahead__hint {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-muted);
  text-align: right;
}

.typeahead__key {
  display: inline-block;
  padding: 0 var(--space-1);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-btn);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  color: var(--text-body);
}

.typeahead__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.typeahead__group + .typeahead__group {
  border-block-start: 1px solid var(--border-default);
}

.typeahead__group-title {
  margin: 0;
  padding: var(--space-4) var(--space-6) var(--space-2);
  font-family: var(--ff-heading);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.typeahead__list {
  margin: 0;
  padding: 0 0 var(--space-2);
  list-style: none;
}

.typeahead__term {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
  text-decoration: none;
}

.typeahead__term:hover,
.typeahead__term--active {
  background-color: var(--bg-card-hover);
  color: var(--text-link);
}

.typeahead__term-name {
  font-weight: var(--fw-medium);
}

.typeahead__term-count {
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.typeahead__story {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  text-decoration: none;
}

.typeahead__story:hover {
  background-color: var(--bg-card-hover);
}

.typeahead__type {
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-brand);
}

.typeahead__story-title {
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-brand);
}

.typeahead__story:hover .typeahead__story-title {
  color: var(--text-link-hover);
}

.typeahead__empty {
  margin: 0;
  padding: var(--space-6) var(--space-card-padding) var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.typeahead__empty strong {
  font-weight: var(--fw-medium);
}

.typeahead__all {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-6);
  background-color: var(--btn-primary-bg);
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--btn-primary-text);
  text-decoration: none;
}

.typeahead__all:hover {
  background-color: var(--btn-primary-bg-hover);
  color: var(--btn-primary-text);
}

.typeahead__all svg {
  width: 16px;
  height: 16px;
}

/* Phone: the panel IS the screen. Field fixed at the top under a title row,
   results scrolling beneath, the See-all row on the floor. A sheet that meets
   the viewport edge on every side takes no corner. */
@media (max-width: 640px) {
  .typeahead {
    height: 100vh;
    height: 100dvh;
    max-height: none;
    border-radius: 0;
  }
  .typeahead__head {
    padding: var(--space-4) var(--space-4) var(--space-4);
  }
  .typeahead__title {
    display: block;
  }
  .typeahead__hint {
    display: none;
  }
  .typeahead__group-title,
  .typeahead__term,
  .typeahead__story {
    padding-inline: var(--space-4);
  }
  .typeahead__story {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
  }
}
.modal.search .modal__wrapper {
  padding: 0;
  background: none;
}

.modal.search .modal__close a {
  display: inline-flex;
  color: var(--text-on-chrome);
}

.modal.search .modal__close svg {
  width: 24px;
  height: 24px;
}

@media (max-width: 640px) {
  .modal.search {
    position: fixed;
    inset: 0;
    height: 100dvh;
  }
  .modal.search .modal__wrapper {
    top: 0;
    margin: 0;
    padding: 0;
    max-width: none;
  }
  .modal.search .modal__close {
    top: var(--space-4);
    right: var(--gutter-small);
  }
  .modal.search .modal__close a {
    color: var(--text-heading);
  }
}
.typeahead .searchwp-live-search-results {
  position: static;
  width: auto;
  min-width: 0;
  min-height: 0;
  max-height: none;
  background: none;
  box-shadow: none;
}

.typeahead__body:has(.searchwp-live-search-results-showing) .term-chips {
  display: none;
}

/* ---------------------------------------------------------------------------
   BLOCK — verdict-band  (NEW, layout)
   The review's finale: a full-bleed band after the body with the key art
   behind it, darker than the hero — the same scrim, turned up — so the
   finale is recognisably the article's own ending and not an advert. On it,
   over the reading column: the eyebrow, "The Verdict", and the one-line
   verdict in the magazine's italic, reversed. Beneath them, on a panel
   because content belongs on panels, the catalogue's score-panel with the
   large score meter as its overall figure — the meter fills to the score
   as the band scrolls into view. The rail column stays open so the art
   shows through on the right.

   A news article has no finale. Replaces MPG16's in-card verdict panel.
   --------------------------------------------------------------------------- */
.verdict-band {
  position: relative;
  margin-block-start: var(--space-12);
  overflow: hidden;
  background-color: var(--bg-chrome);
  scroll-margin-block-start: var(--space-6);
}

.verdict-band__media {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
}

.verdict-band__scrim {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(90deg, color-mix(in srgb, var(--bg-chrome) 94%, transparent) 0%, color-mix(in srgb, var(--bg-chrome) 86%, transparent) 55%, color-mix(in srgb, var(--bg-chrome) 55%, transparent) 100%);
}

.verdict-band__inner {
  position: relative;
  width: 100%;
  max-width: calc(var(--site-max-width) + var(--gutter-small) * 2);
  margin-inline: auto;
  padding: var(--space-16) var(--gutter-small);
}

.verdict-band__frame {
  display: grid;
  grid-template-columns: minmax(0, calc(var(--container-article) + var(--space-card-padding) * 2)) var(--width-sidebar);
  justify-content: center;
  gap: var(--space-8) var(--space-16);
}

.verdict-band__head,
.verdict-band__panel {
  grid-column: 1;
  min-width: 0;
}

.verdict-band__head {
  padding-inline: var(--space-card-padding);
}

.verdict-band__eyebrow {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--paragon-300);
}

.verdict-band__title {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h2);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.verdict-band__line {
  margin: var(--space-6) 0 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-h3);
  font-weight: var(--fw-regular);
  font-style: italic;
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.verdict-band__byline {
  margin: var(--space-4) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
  color: var(--text-on-chrome);
}

.verdict-band__panel {
  padding: var(--space-card-padding);
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
}

@media (max-width: 1100px) {
  .verdict-band__frame {
    grid-template-columns: minmax(0, calc(var(--container-article) + var(--space-card-padding) * 2));
  }
}
@media (max-width: 640px) {
  .verdict-band__inner {
    padding-block: var(--space-12);
  }
  .verdict-band__head {
    padding-inline: 0;
  }
  .verdict-band__title {
    font-size: var(--fs-h3);
  }
  .verdict-band__line {
    font-size: var(--fs-h4);
  }
  .verdict-band__panel {
    padding: var(--space-6);
  }
}
/* ---------------------------------------------------------------------------
   BLOCK — video-embed  (NEW)
   The play control is a control, so it is square like every other control in
   the brand — a round one would read as an indicator. The caption takes the
   same setting media-figure gives a caption, so an article's two kinds of
   media are captioned identically.
   --------------------------------------------------------------------------- */
.video-embed {
  margin: var(--space-8) 0 0;
}

.video-embed__facade {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: var(--radius-card);
  overflow: hidden;
  background-color: var(--neutral-800);
  cursor: pointer;
}

.video-embed__poster {
  display: block;
  width: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
}

.video-embed__play {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: var(--radius-btn);
  background-color: var(--btn-primary-bg);
  color: var(--btn-primary-text);
}

.video-embed__facade:hover .video-embed__play {
  background-color: var(--btn-primary-bg-hover);
}

.video-embed__play svg {
  width: 24px;
  height: 24px;
  fill: currentColor;
}

.video-embed__caption {
  margin-block-start: var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

@media (max-width: 640px) {
  .video-embed__play {
    width: 52px;
    height: 52px;
  }
}
.woocommerce-message,
.woocommerce-info,
.woocommerce-error {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-6);
  margin: 0;
  padding: var(--space-4) var(--space-6);
  border-inline-start: 4px solid var(--border-brand);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
  list-style: none;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-body);
}

.woocommerce-error {
  flex-direction: column;
  align-items: flex-start;
  border-inline-start-color: var(--color-negative);
}

.woocommerce-error li {
  margin: 0;
}

.woocommerce-notices-wrapper:not(:empty) + .breadcrumbs {
  margin-block-start: var(--space-4);
}

.woocommerce-notices-wrapper {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.woocommerce-message a.button,
.woocommerce-info a.button,
.woocommerce-message .restore-item {
  font-weight: var(--fw-medium);
  color: var(--text-brand);
  text-decoration: none;
}

.woocommerce-message a.button,
.woocommerce-info a.button {
  order: 1;
}

/* ---- widget (reused from the brand catalogue, verbatim) ---- */
.widget {
  background-color: var(--bg-panel);
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-panel);
}

.widget__title {
  margin: 0;
  padding: var(--space-3) var(--space-6);
  background-color: var(--color-brand);
  font-family: var(--ff-heading);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-on-brand);
}

.widget__body {
  padding: var(--space-6);
}

.widget__body--flush {
  padding: 0;
}

/*------------------------------------*\
	CORE BLOCKS
	The description region is a Gutenberg block area (operator, 2026-09-16), so
	these are not optional decoration — they are what 3,904 product descriptions
	are made of. Ten partials, scoped by what the catalogue actually uses.

	This group compiles AFTER components, deliberately: several block rules tie
	on specificity with component rules and are meant to win on source order.
\*------------------------------------*/
.wp-block-columns {
  --wp--style--block-gap: var(--space-8);
  margin-block: var(--space-8);
}

.wp-block-column {
  min-width: 0;
}

.content > .wp-block-cover {
  width: calc(100% + var(--space-card-padding) * 2);
  margin-block: var(--space-8);
  margin-inline: calc(var(--space-card-padding) * -1);
  padding: var(--space-12) var(--space-8);
  border-radius: 0;
}

.wp-block-cover {
  margin-block: var(--space-8);
  padding: var(--space-12) var(--space-8);
  border-radius: var(--radius-card);
}

.wp-block-cover .wp-block-heading {
  margin-block: var(--space-8) var(--space-3);
  font-weight: var(--fw-light);
  color: inherit;
}

.wp-block-cover .wp-block-heading + * {
  margin-block-start: 0;
}

.wp-block-cover .wp-block-heading:first-child {
  margin-block-start: 0;
}

.wp-block-cover .wp-block-heading:last-child {
  margin-block-end: 0;
}

.wp-block-cover img[alt^="Image needed"] {
  display: none;
}

/* One ruled list, not separate boxes: the rows sit on their dividers. Core's
   flow layout otherwise puts the block gap (32px here) above every row
   (operator, 2026-10-13). */
.wp-block-details + .wp-block-details {
  margin-block-start: 0;
  border-block-start: 1px solid var(--border-default);
}

.wp-block-details[open] {
  background-color: var(--bg-card-hover);
  border-inline-start: 3px solid var(--color-brand);
}

/* Core's own wrapper carries no measure, so the band would otherwise run the
   full width of the column while the component it matches is held to the
   reading measure. */
.doc-section .wp-block-details:first-of-type {
  margin-block-start: var(--space-8);
  border-block-start: 1px solid var(--border-default);
}

.doc-section .wp-block-details:last-of-type {
  border-block-end: 1px solid var(--border-default);
}

.wp-block-details > summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-4);
  list-style: none;
  cursor: pointer;
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

/* The browser's own disclosure triangle, removed in both dialects — the brand
   supplies its own marker below. */
.wp-block-details > summary::-webkit-details-marker {
  display: none;
}

.wp-block-details > summary::marker {
  content: "";
}

.wp-block-details > summary:hover {
  background-color: var(--bg-card-hover);
}

.wp-block-details > summary:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

.wp-block-details[open] > summary {
  padding-inline-start: calc(var(--space-4) - 3px);
  color: var(--text-link);
}

/* The chevron, at the far end of the row — the same position and the same
   direction the store sidebar and the main navigation already use to say a
   thing opens. */
.wp-block-details > summary::after {
  content: "";
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  margin-block-start: 0.45em;
  border-inline-end: 2px solid var(--color-brand);
  border-block-end: 2px solid var(--color-brand);
  transform: rotate(45deg);
}

.wp-block-details[open] > summary::after {
  transform: rotate(-135deg);
  margin-block-start: 0.7em;
}

/* The answer is whatever inner blocks the operator put there, so the padding
   goes on the children rather than on a wrapper that does not exist. */
.wp-block-details > :not(summary) {
  padding: 0 var(--space-4) var(--space-6);
  margin-block: 0;
  scroll-margin-block-start: var(--space-16);
}

.wp-block-details[open] > :not(summary) {
  padding-inline-start: calc(var(--space-4) - 3px);
}

@media (max-width: 640px) {
  .wp-block-details > summary {
    font-size: var(--fs-body);
  }
  .wp-block-details > :not(summary) {
    padding-inline: var(--space-3);
  }
  .wp-block-details[open] > :not(summary) {
    padding-inline-start: calc(var(--space-3) - 3px);
  }
}
.wp-block-embed {
  margin-block: var(--space-8);
}

.wp-block-embed iframe {
  display: block;
  border-radius: var(--radius-card);
}

.wp-block-group {
  border-radius: var(--radius-card);
}

.wp-block-group.has-background {
  padding: var(--space-6);
}

/* The restored-wrapper repair (`display: contents` on a `.grid` group's inner
   container, plus zeroing core's flow margin on its children) MOVED TO GLOBAL on
   2026-09-17 — `framework-v2/global/scss/blocks/_wp-block-group.scss`.

   It is a consequence of the no-`theme.json` policy meeting the global `.grid`
   primitive, not brand vocabulary, and ARTSABERS had independently written the
   identical pair. Do not re-add it here; if a grid group stacks, the global rule
   is the place to look. */
.wp-block-heading {
  font-family: var(--ff-heading);
  line-height: var(--lh-heading);
  margin-block: var(--space-8) var(--space-3);
}

h1.wp-block-heading {
  font-size: var(--fs-h1);
  font-weight: var(--fw-light);
}

h2.wp-block-heading {
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
}

h3.wp-block-heading {
  font-size: var(--fs-h3);
  font-weight: var(--fw-light);
}

h4.wp-block-heading {
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
}

h5.wp-block-heading,
h6.wp-block-heading {
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-medium);
}

:is(figure.wp-block-image, div.wp-block-image > figure) {
  margin-block: var(--space-6);
}

:is(figure.wp-block-image, div.wp-block-image > figure) img {
  border-radius: var(--radius-card);
  height: auto !important;
}

.wp-block-image figcaption {
  margin-block-start: var(--space-3);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.wp-block-image:has(img[alt^="Image needed"]) {
  display: none;
}

.wp-block-list {
  margin-block: var(--space-4);
  padding-inline-start: var(--space-6);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.wp-block-list li {
  margin-block-end: var(--space-2);
}

.wp-block-list li {
  position: relative;
}

.wp-block-list li::before {
  content: "";
  position: absolute;
  inset-inline-start: calc(var(--space-4) * -1);
  inset-block-start: 0.6em;
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background-color: var(--color-brand);
}

.wp-block-media-text {
  margin-block: var(--space-8);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.wp-block-media-text > .wp-block-media-text__content {
  padding: var(--space-8);
}

.wp-block-media-text__media img {
  border-radius: 0;
}

.wp-block-media-text:has(> .wp-block-media-text__media:empty),
.wp-block-media-text:has(> .wp-block-media-text__media img[alt^="Image needed"]) {
  grid-template-columns: 1fr;
  margin-inline: 0;
}

.wp-block-media-text:has(> .wp-block-media-text__media:empty) > .wp-block-media-text__media,
.wp-block-media-text:has(> .wp-block-media-text__media img[alt^="Image needed"]) > .wp-block-media-text__media {
  display: none;
}

.wp-block-media-text:has(> .wp-block-media-text__media:empty) > .wp-block-media-text__content,
.wp-block-media-text:has(> .wp-block-media-text__media img[alt^="Image needed"]) > .wp-block-media-text__content {
  grid-column: 1;
  padding: 0;
}

.wp-block-paragraph {
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.wp-block-paragraph.has-large-font-size {
  font-size: var(--fs-body-lg);
}

.spec-pills {
  margin-block: var(--space-12);
}

.spec-pills .wp-block-column {
  padding: var(--space-4) var(--space-3);
  border: 2px solid var(--border-brand);
  border-radius: var(--radius-card);
  text-align: center;
}

.spec-pills .wp-block-column:has(.wp-block-group p:first-child:empty) {
  display: none;
}

.spec-pills .wp-block-group.has-background {
  padding: 0;
  background-color: transparent;
}

.spec-pills .has-ugp-white-color,
.spec-pills .wp-block-group.has-ugp-white-color {
  color: var(--text-body);
}

.spec-pills .wp-block-group .has-large-font-size {
  font-family: var(--ff-body);
  font-size: var(--fs-h3);
  font-weight: var(--fw-regular);
  color: var(--text-body);
}

.spec-pills .wp-block-group p + p {
  margin-block-start: 0;
}

.spec-pills .wp-block-group .has-medium-font-size {
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.has-ugp-blue-color {
  color: var(--paragon-600);
}

.has-ugp--light-blue-color {
  color: var(--paragon-300);
}

.has-ugp-grey-color {
  color: var(--neutral-700);
}

.has-ugp-black-color {
  color: var(--neutral-900);
}

.has-ugp-white-color {
  color: var(--neutral-50);
}

.has-ugp-blue-background-color {
  background-color: var(--paragon-600);
}

.has-ugp--light-blue-background-color {
  background-color: var(--paragon-300);
}

.has-ugp-grey-background-color {
  background-color: var(--neutral-700);
}

.has-ugp-black-background-color {
  background-color: var(--neutral-900);
}

.has-ugp-white-background-color {
  background-color: var(--neutral-50);
}

.gform_validation_container,
.gform_wrapper .gfield_visibility_hidden {
  display: none !important;
}

.gform_wrapper {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.gform_wrapper form {
  margin: 0;
}

.gform_wrapper .gfield_required,
.gform_wrapper .gform_required_legend {
  display: none;
}

.gform_heading .gform_description {
  display: block;
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.gform_wrapper .gfield_label {
  display: block;
  margin-block-end: var(--space-2);
  padding: 0;
  font-family: var(--ff-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.gform_wrapper .gfield_description {
  margin: 0 0 var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

.gform_wrapper .ginput_container input,
.gform_wrapper .ginput_container select,
.gform_wrapper .ginput_container textarea {
  display: block;
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background-color: var(--bg-input);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-heading);
  color: var(--text-body);
}

.gform_wrapper .ginput_container input::placeholder,
.gform_wrapper .ginput_container textarea::placeholder {
  color: var(--neutral-500);
  opacity: 1;
}

.gform_wrapper .ginput_container input:focus,
.gform_wrapper .ginput_container select:focus,
.gform_wrapper .ginput_container textarea:focus {
  border-color: var(--border-focus);
  background-color: var(--color-brand-soft);
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.gform_wrapper .ginput_container select {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: var(--space-12);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 12'%3E%3Cpath d='M1.5 2 L10 9.5 L18.5 2' fill='none' stroke='%231D7DBB' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
  background-size: 14px auto;
  cursor: pointer;
}

.gform_wrapper .ginput_container select:has(.gf_placeholder:checked) {
  color: var(--neutral-500);
}

.gform_wrapper .ginput_container select option {
  color: var(--text-body);
}

.gfield_error .ginput_container input,
.gfield_error .ginput_container select,
.gfield_error .ginput_container textarea {
  border: 2px solid var(--color-negative);
  padding: calc(var(--space-3) - 1px);
}

.gform_wrapper .validation_message {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: var(--space-2) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--color-negative);
}

.gform_fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 24rem));
  gap: var(--space-6) var(--space-content-gap);
  align-items: start;
  justify-content: start;
}

.gform_fields .gfield {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.gform_fields .gsection,
.gform_fields .gfield--width-full {
  grid-column: 1/-1;
}

.gform_fields .gsection_title {
  margin: 0;
  padding-block-end: var(--space-3);
  border-block-end: 1px solid var(--border-default);
  font-family: var(--ff-heading);
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  line-height: var(--lh-heading);
  color: var(--text-heading);
}

.gform_fields .gfield + .gsection {
  margin-block-start: var(--space-4);
}

.gform_fields .gfield--optional .gfield_label::after {
  content: "Optional";
  margin-inline-start: var(--space-2);
  font-family: var(--ff-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-regular);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.gform_wrapper .ginput_container textarea {
  min-height: 9rem;
  line-height: var(--lh-body);
  resize: vertical;
}

.gform_wrapper .gform_footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-6);
  margin-block-start: var(--space-8);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-default);
}

.gform_wrapper .gform_validation_errors {
  padding: var(--space-3) var(--space-6);
  border: 2px solid var(--color-negative);
  border-radius: var(--radius-card);
  background-color: var(--bg-panel);
}

.gform_wrapper .gform_submission_error {
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  color: var(--color-negative);
}

.gform_wrapper .gform_validation_errors:focus {
  outline: none;
}

@media (max-width: 900px) {
  .gform_fields {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .gform_fields {
    grid-template-columns: minmax(0, 1fr);
  }
  .gform_wrapper .gform_footer .btn {
    width: 100%;
  }
}
:root {
  /*------------------------------------*\
  	LAYER 1 — palette
  	Measured values. Nothing derived, nothing generated.
  \*------------------------------------*/
  --paragon-600: #1D7DBB;
  --paragon-400: #25A6F9;
  --paragon-300: #60B9F6;
  --paragon-50: #E8F2F8;
  --arctic-100: #F6F6F6;
  --arctic-200: #E7EAED;
  --arctic-300: #DCDEDF;
  --neutral-50: #FFFFFF;
  --neutral-300: #DCDCDC;
  --neutral-400: #C4C4C4;
  --neutral-500: #9F9F9F;
  --neutral-550: #8A8A8A;
  --neutral-600: #606060;
  --neutral-700: #303030;
  --neutral-800: #262626;
  --neutral-900: #000000;
  --status-positive: #35943A;
  --status-negative: #DD0000;
  --status-warning: var(--paragon-50);
  /*------------------------------------*\
  	LAYER 2 — roles
  \*------------------------------------*/
  --color-brand: var(--paragon-600);
  --color-brand-strong: var(--neutral-700);
  --color-brand-soft: var(--paragon-50);
  --color-background: var(--arctic-300);
  --color-surface: var(--neutral-50);
  --color-surface-alt: var(--arctic-100);
  --color-surface-elevated: var(--neutral-50);
  --color-text: var(--neutral-900);
  --color-text-muted: var(--neutral-600);
  --color-text-on-brand: var(--neutral-50);
  --color-border: var(--neutral-400);
  --color-border-strong: var(--neutral-500);
  --color-positive: var(--status-positive);
  --color-warning: var(--status-warning);
  --color-negative: var(--status-negative);
  /*------------------------------------*\
  	LAYER 3 — usage
  \*------------------------------------*/
  --bg-page: var(--color-background);
  --bg-panel: var(--color-surface);
  --bg-panel-alt: var(--color-surface-alt);
  --bg-card: var(--color-surface);
  --bg-card-hover: var(--color-brand-soft);
  --bg-input: var(--color-surface);
  --bg-overlay: rgba( 0, 0, 0, 0.62 );
  --bg-chrome: var(--neutral-700);
  --bg-chrome-deep: var(--neutral-800);
  --bg-notice: var(--paragon-600);
  --text-on-chrome: var(--neutral-400);
  --gradient-editorial: linear-gradient( 135deg, var(--paragon-600) 0%, var(--paragon-400) 100% );
  --text-body: var(--color-text);
  --text-heading: var(--color-text);
  --text-muted: var(--color-text-muted);
  --text-brand: var(--color-brand);
  --text-link: var(--color-brand);
  --text-link-hover: var(--color-brand-strong);
  --text-on-brand: var(--color-text-on-brand);
  --border-default: var(--color-border);
  --border-strong: var(--color-border-strong);
  --border-brand: var(--color-brand);
  --border-focus: var(--color-brand);
  --border-input: var(--neutral-550);
  --btn-primary-bg: var(--color-brand);
  --btn-primary-bg-hover: var(--color-brand-strong);
  --btn-primary-text: var(--color-text-on-brand);
  /*------------------------------------*\
  	TYPE
  	Three faces. Ubuntu and Poppins are served from the theme (_fonts.scss);
  	Purista comes from the Adobe kit (qsv4pqt — the same kit the old store
  	loads, and domain-locked). Purista is the SELLING voice: product
  	titles, prices, add-to-basket, sale badges, always bold and slanted.
  \*------------------------------------*/
  --ff-heading: "Ubuntu Local", system-ui, -apple-system, "Segoe UI", sans-serif;
  --ff-body: "Poppins Local", system-ui, -apple-system, "Segoe UI", sans-serif;
  --ff-chrome: "purista-web", "Ubuntu Local", system-ui, sans-serif;
  --fs-h1: 40px;
  --fs-h2: 32px;
  --fs-h3: 26px;
  --fs-h4: 20px;
  --fs-body-lg: 18px;
  --fs-body: 16px;
  --fs-small: 14px;
  --fs-eyebrow: 12px;
  --fw-light: 300;
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-bold: 700;
  --lh-body: 1.7;
  --lh-heading: 1.2;
  /*------------------------------------*\
  	SPACE
  \*------------------------------------*/
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;
  --space-content-gap: 30px;
  --space-card-padding: 30px;
  /*------------------------------------*\
  	SHAPE
  	One radius. Every surface takes 10px; every control is square; only
  	indicators are round. There is no second surface radius — the token
  	for one was retired.
  \*------------------------------------*/
  --radius-card: 10px;
  --radius-btn: 0;
  --radius-input: 0;
  --radius-pill: 999px;
  --shadow-card: none;
  --shadow-panel: none;
  --shadow-1: 0 0 12px -3px var(--neutral-300);
  /*------------------------------------*\
  	LAYOUT
  	--site-max-width / --gutter-small are the names global/scss/layouts/
  	_wrapper.scss and _section.scss actually read (with generic
  	1440px/20px fallbacks) — they must carry the styleguide's measured
  	values here, or `.wrapper` / `.section__inner` silently render at the
  	generic fallback instead of the brand's own column.
  \*------------------------------------*/
  --site-max-width: 1400px;
  --gutter-small: 20px;
  --container-reading: 680px;
  --container-article: 800px;
  --width-sidebar: 328px;
  /*------------------------------------*\
  	MOTION
  	The two speeds framework-v2 already ships as transition mixins: 180ms
  	for anything a pointer touches directly, 300ms for a surface that
  	arrives underneath it. Nothing in this theme invents a third.
  \*------------------------------------*/
  --motion-quick: 180ms;
  --motion-standard: 300ms;
  --motion-ease: ease;
}
/*# sourceMappingURL=paragon.css.map */
