/* ==========================================================================
   Fonts — self-hosted.

   These were served from Google's CDN until launch prep. Every page load
   sent the visitor's IP address to a third party before they had any chance
   to object, which a German court (LG Munchen I, 3 O 17493/20) held to be
   an unlawful transfer. Serving the files ourselves removes the transfer
   entirely, removes two hosts from the Content-Security-Policy, and removes
   a round trip to a second origin from the critical path.

   Both families are SIL Open Font License 1.1, which permits this.
   Latin and latin-ext subsets only — the site has no other scripts.
   ========================================================================== */

@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/instrument-serif-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/instrument-serif-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: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/instrument-serif-400-normal-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/instrument-serif-400-normal-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: "Inter Tight";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/inter-tight-400-normal-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/inter-tight-400-normal-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: "Inter Tight";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/inter-tight-500-normal-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/inter-tight-500-normal-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;
}

/* ==========================================================================
   UNIQUE ROUTINES
   --------------------------------------------------------------------------
   Palette is fixed by the brief. One adjustment was required, documented here:

   --clay was specified as #8A7F73. Measured against --paper (#F7F5F2) that is
   3.60:1 — passes WCAG 2.2 AA for large text and UI, fails for body copy
   (4.5:1 required). The brief says adjust if it doesn't pass, so:

     --clay        #776E63   4.61:1 on paper. All secondary body text.
     --clay-soft   #8A7F73   original value. Rules, hairlines, and text at 24px+
                             where the AA threshold is 3:1.
     --mist        #B5AEA5   8.70:1 on ink. Secondary text on the dark sections,
                             because clay on ink measures only 3.81:1.
   ========================================================================== */

:root {
  --ink: #12100e;
  --paper: #f7f5f2;
  --stone: #e4dfd8;
  --clay: #776e63;
  --clay-soft: #8a7f73;
  --mist: #b5aea5;
  --accent: #3f4a3c;
  --accent-ink: #f7f5f2;

  --ink-rule: #2a2724;

  --serif: "Instrument Serif", "Newsreader", Georgia, "Times New Roman", serif;
  --ui: "Inter Tight", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Helvetica, Arial, sans-serif;

  --max: 1440px;
  --gutter: 1.5rem;
  --section: 7rem;
  /* Height the sticky header occupies. Sticky asides and jump-link targets
     both offset by this, so the two can never disagree. */
  --sticky-top: 5.75rem;

  --rise: cubic-bezier(0.16, 1, 0.3, 1);
}

@media (min-width: 768px) {
  :root {
    --gutter: 3rem;
    --section: 10rem;
  }
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 16px;
  line-height: 1.65;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

@media (min-width: 768px) {
  body {
    font-size: 17px;
  }
}

img,
svg {
  display: block;
  max-width: 100%;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

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

a {
  color: inherit;
  text-decoration: none;
}

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

h1,
h2,
h3 {
  font-family: var(--serif);
  font-weight: 400;
  line-height: 0.95;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

::selection {
  background: var(--accent);
  color: var(--accent-ink);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}

.on-ink :focus-visible {
  outline-color: var(--paper);
}

/* --------------------------------------------------------------------------
   Layout primitives
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: var(--section);
}

.section--tight {
  padding-block: calc(var(--section) * 0.6);
}

.grid12 {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 1.5rem;
}

@media (min-width: 768px) {
  .grid12 {
    gap: 2rem;
  }
}

.rule {
  border: 0;
  border-top: 1px solid var(--stone);
}

.on-ink .rule {
  border-top-color: var(--ink-rule);
}

.ink {
  background: var(--ink);
  color: var(--paper);
}

/*
  Secondary text is 4.61:1 on --paper but only 3.78:1 on --stone, which fails
  AA for body copy. Rescoping the token inside stone-backed regions takes it
  to 4.81:1 without touching anything set on paper.
*/
.stone,
.honesty {
  background: var(--stone);
  --clay: #665f55;
}

.skip {
  position: absolute;
  left: 1rem;
  top: -100%;
  z-index: 100;
  background: var(--accent);
  color: var(--accent-ink);
  padding: 0.75rem 1.25rem;
  border-radius: 4px;
}

.skip:focus {
  top: 1rem;
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   Type
   -------------------------------------------------------------------------- */

.display {
  font-family: var(--serif);
  font-size: clamp(3rem, 8vw, 7rem);
  line-height: 0.95;
  letter-spacing: -0.02em;
}

.h2 {
  font-family: var(--serif);
  font-size: clamp(2.125rem, 4.4vw, 2.5rem);
  line-height: 1;
  letter-spacing: -0.02em;
}

.h3 {
  font-family: var(--serif);
  font-size: 1.5rem;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.eyebrow {
  font-family: var(--ui);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--clay);
  line-height: 1.4;
}

.on-ink .eyebrow {
  color: var(--mist);
}

.prose {
  max-width: 68ch;
}

.muted {
  color: var(--clay);
}

.on-ink .muted {
  color: var(--mist);
}

.mono {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

.link {
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--clay-soft);
  transition: text-decoration-color 200ms var(--rise);
}

.link:hover {
  text-decoration-color: currentColor;
}

.link-accent {
  color: var(--accent);
}

.on-ink .link-accent {
  color: var(--paper);
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  min-height: 3rem;
  padding: 0.875rem 1.75rem;
  border-radius: 4px;
  font-size: 0.9375rem;
  letter-spacing: 0.01em;
  line-height: 1;
  transition:
    background-color 200ms var(--rise),
    color 200ms var(--rise),
    border-color 200ms var(--rise);
}

.btn--primary {
  background: var(--accent);
  color: var(--accent-ink);
}

.btn--primary:hover {
  background: #354030;
}

.btn--secondary {
  border: 1px solid var(--ink);
  color: var(--ink);
}

.btn--secondary:hover {
  background: var(--ink);
  color: var(--paper);
}

.on-ink .btn--secondary {
  border-color: var(--mist);
  color: var(--paper);
}

.on-ink .btn--secondary:hover {
  background: var(--paper);
  color: var(--ink);
}

.btn--light {
  background: var(--paper);
  color: var(--ink);
}

.btn--light:hover {
  background: var(--stone);
}

.btn--block {
  width: 100%;
}

.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn-quiet {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  letter-spacing: 0.02em;
  border-bottom: 1px solid var(--clay-soft);
  padding-bottom: 2px;
  transition: border-color 200ms var(--rise);
}

.btn-quiet:hover {
  border-color: currentColor;
}

.arrow {
  display: inline-block;
  transition: transform 200ms var(--rise);
}

a:hover .arrow,
button:hover .arrow {
  transform: translateX(3px);
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--paper);
  border-bottom: 1px solid var(--stone);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  height: 4.25rem;
}

.wordmark {
  font-family: var(--ui);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
}

@media (min-width: 420px) {
  .wordmark {
    font-size: 0.8125rem;
    letter-spacing: 0.22em;
  }
}

.nav {
  display: none;
  gap: 2rem;
}

@media (min-width: 900px) {
  .nav {
    display: flex;
  }
}

.nav a {
  font-size: 0.875rem;
  letter-spacing: 0.01em;
  color: var(--clay);
  padding-block: 0.25rem;
  border-bottom: 1px solid transparent;
  transition:
    color 200ms var(--rise),
    border-color 200ms var(--rise);
}

.nav a:hover {
  color: var(--ink);
}

.nav a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

/* Specific enough to beat .cart-button's own display rule below. */
.header-actions [data-desktop-only] {
  display: none;
}

@media (min-width: 900px) {
  .header-actions [data-desktop-only] {
    display: inline-flex;
  }
}

.cart-button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  letter-spacing: 0.01em;
}

.cart-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.375rem;
  height: 1.375rem;
  padding-inline: 0.375rem;
  border-radius: 4px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.cart-count[data-empty="true"] {
  background: transparent;
  color: var(--clay);
  border: 1px solid var(--stone);
}

.menu-toggle {
  display: inline-flex;
  font-size: 0.875rem;
  letter-spacing: 0.02em;
}

@media (min-width: 900px) {
  .menu-toggle {
    display: none;
  }
}

.mobile-nav {
  display: none;
  border-top: 1px solid var(--stone);
  padding-block: 1.5rem 2rem;
}

.mobile-nav[data-open="true"] {
  display: block;
}

@media (min-width: 900px) {
  .mobile-nav[data-open="true"] {
    display: none;
  }
}

.mobile-nav a {
  display: block;
  padding-block: 0.625rem;
  font-size: 1.125rem;
  border-bottom: 1px solid var(--stone);
}

.mobile-nav a:last-child {
  border-bottom: 0;
}

/* --------------------------------------------------------------------------
   Announcement
   -------------------------------------------------------------------------- */

.announce {
  background: var(--ink);
  color: var(--mist);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  padding-block: 0.625rem;
}

/* --------------------------------------------------------------------------
   Motion — the entire vocabulary
   -------------------------------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity 400ms var(--rise),
    transform 400ms var(--rise);
}

.reveal[data-shown="true"] {
  opacity: 1;
  transform: none;
}

/*
  Photographs settle rather than rise. A frame carries more weight than a line
  of type, so it moves slower — 900ms against the copy's 400ms — and it moves
  in one dimension only: a 4% over-scale easing back to rest inside the frame,
  which .shot already clips. It supplies no fade of its own; the .reveal it
  sits in does that.

  Scale runs through a custom property so the settle and the hover state can
  each set it without two rules fighting over `transform`.
*/
.shot__img {
  transform: scale(var(--shot-scale, 1));
  transition: transform 900ms var(--rise);
}

.reveal .shot__img {
  --shot-scale: 1.04;
}

.reveal[data-shown="true"] .shot__img {
  --shot-scale: 1;
}

/* The hero is not inside a .reveal — it is the first thing on the page, so it
   settles on load instead of on scroll, and takes longer over it. */
@keyframes shot-settle {
  from {
    transform: scale(1.05);
  }
  to {
    transform: scale(1);
  }
}

.hero__art .shot__img {
  animation: shot-settle 1400ms var(--rise) both;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  /* Every selector that sets --shot-scale is named here, because a bare
     .shot__img is less specific than .reveal .shot__img and would not win. */
  .shot__img,
  .reveal .shot__img,
  .hero__art .shot__img,
  .card:hover .card__media .shot__img,
  .card:focus-visible .card__media .shot__img {
    --shot-scale: 1;
    animation: none;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* --------------------------------------------------------------------------
   Split — narrow label column, wide content column. The house layout.
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 2.5rem 1.5rem;
}

.split__label,
.split__body {
  grid-column: 1 / -1;
}

@media (min-width: 900px) {
  .split {
    gap: 2rem;
  }

  .split__label {
    grid-column: 1 / 4;
  }

  .split__body {
    grid-column: 5 / 13;
  }
}

/* --------------------------------------------------------------------------
   Hero — the one deliberate grid break on the site. Above 900px the product
   shot starts at column 5 and runs past the right gutter, off the page.
   -------------------------------------------------------------------------- */

.hero-band {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 2rem 1.5rem;
}

.hero-band__shot {
  grid-column: 1 / -1;
  order: 1;
}

.hero-band__caption {
  grid-column: 1 / -1;
  order: 2;
  align-self: end;
}

@media (min-width: 900px) {
  .hero-band {
    gap: 2rem;
  }

  .hero-band__caption {
    grid-column: 1 / 4;
    order: 1;
  }

  .hero-band__shot {
    grid-column: 5 / 13;
    order: 2;
    margin-right: calc(var(--gutter) * -1);
  }

  .hero-band__shot .shot {
    border-radius: 4px 0 0 4px;
  }
}

/* --------------------------------------------------------------------------
   Product imagery
   -------------------------------------------------------------------------- */

.shot {
  position: relative;
  background: var(--stone);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 3 / 4;
}

/*
  The photographs are cropped by the box rather than sized by it. --stone
  behind them means a frame that has not loaded yet reads as a tonal panel
  rather than as a hole, and `aspect-ratio` on .shot reserves the space, so
  nothing shifts when it arrives.
*/
.shot__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
}

.shot--wide {
  aspect-ratio: 4 / 3;
}

.shot--square {
  aspect-ratio: 1 / 1;
}

/* --------------------------------------------------------------------------
   Product grid + card
   -------------------------------------------------------------------------- */

.product-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem 1.5rem;
}

@media (min-width: 640px) {
  .product-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .product-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 3.5rem 2rem;
  }
}

.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/*
  Hovering a card used to drop the image to 88% opacity. Over a drawing that
  read as a dim; over a photograph it reads as a wash, and it puts the frame
  out of step with the palette. A slow scale says the same thing — this is the
  thing you are pointing at — without touching the tone.
*/
.card:hover .card__media .shot__img,
.card:focus-visible .card__media .shot__img {
  --shot-scale: 1.03;
  transition-duration: 700ms;
}

.card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.card__name {
  font-family: var(--serif);
  font-size: 1.375rem;
  letter-spacing: -0.02em;
  line-height: 1;
}

.card__price {
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.card__meta {
  display: flex;
  gap: 0.75rem;
  font-size: 0.8125rem;
  color: var(--clay);
}

.card__promise {
  color: var(--clay);
  font-size: 0.9375rem;
}

.tag {
  display: inline-block;
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--clay);
  border: 1px solid var(--stone);
  border-radius: 2px;
  padding: 0.25rem 0.5rem;
  line-height: 1.2;
}

/* --------------------------------------------------------------------------
   Filters
   -------------------------------------------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 2.5rem;
  align-items: flex-start;
}

.filter-group {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.chip {
  border: 1px solid var(--stone);
  border-radius: 4px;
  padding: 0.5rem 0.875rem;
  font-size: 0.8125rem;
  color: var(--clay);
  background: transparent;
  transition:
    border-color 200ms var(--rise),
    color 200ms var(--rise),
    background-color 200ms var(--rise);
}

.chip:hover {
  border-color: var(--clay-soft);
  color: var(--ink);
}

.chip[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

/* --------------------------------------------------------------------------
   Accordion
   -------------------------------------------------------------------------- */

.accordion {
  border-top: 1px solid var(--stone);
}

.accordion__item {
  border-bottom: 1px solid var(--stone);
}

.accordion__trigger {
  display: flex;
  width: 100%;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
  padding-block: 1.5rem;
  text-align: left;
  font-size: 1.0625rem;
}

.accordion__icon {
  flex: none;
  width: 0.75rem;
  height: 0.75rem;
  position: relative;
  align-self: center;
  color: var(--clay);
}

.accordion__icon::before,
.accordion__icon::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: currentColor;
}

.accordion__icon::before {
  width: 100%;
  height: 1px;
}

.accordion__icon::after {
  width: 1px;
  height: 100%;
  transition: transform 300ms var(--rise);
}

.accordion__trigger[aria-expanded="true"] .accordion__icon::after {
  transform: scaleY(0);
}

.accordion__panel {
  display: none;
  padding-bottom: 1.75rem;
  max-width: 62ch;
  color: var(--clay);
}

.accordion__panel[data-open="true"] {
  display: block;
}

/* --------------------------------------------------------------------------
   Disclosure
   -------------------------------------------------------------------------- */

.disclosure {
  border-top: 1px solid var(--stone);
  border-bottom: 1px solid var(--stone);
}

.disclosure + .disclosure {
  border-top: 0;
}

.disclosure summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding-block: 1.25rem;
  cursor: pointer;
  list-style: none;
  font-size: 0.9375rem;
}

.disclosure summary::-webkit-details-marker {
  display: none;
}

.disclosure summary::after {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-right: 1px solid var(--clay);
  border-bottom: 1px solid var(--clay);
  transform: translateY(-2px) rotate(45deg);
  transition: transform 300ms var(--rise);
}

.disclosure[open] summary::after {
  transform: translateY(2px) rotate(-135deg);
}

.disclosure__body {
  padding-bottom: 1.5rem;
  color: var(--clay);
  font-size: 0.9375rem;
  max-width: 62ch;
}

.honesty {
  background: var(--stone);
  border-radius: 4px;
  padding: 1.75rem;
}

.honesty ul {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.honesty li {
  display: grid;
  grid-template-columns: 1.25rem 1fr;
  font-size: 0.9375rem;
}

.honesty li::before {
  content: "—";
  color: var(--clay);
}

/* --------------------------------------------------------------------------
   Cart drawer
   -------------------------------------------------------------------------- */

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(18, 16, 14, 0.4);
  z-index: 50;
  opacity: 0;
  pointer-events: none;
  transition: opacity 300ms var(--rise);
}

.overlay[data-open="true"] {
  opacity: 1;
  pointer-events: auto;
}

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  width: min(27rem, 100vw);
  background: var(--paper);
  border-left: 1px solid var(--stone);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 400ms var(--rise);
  visibility: hidden;
}

.drawer[data-open="true"] {
  transform: none;
  visibility: visible;
}

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

.drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.5rem;
  border-bottom: 1px solid var(--stone);
}

.drawer__body {
  flex: 1;
  overflow-y: auto;
  padding: 1.5rem;
}

.drawer__foot {
  border-top: 1px solid var(--stone);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.line-item {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  gap: 1rem;
  padding-block: 1.25rem;
  border-bottom: 1px solid var(--stone);
}

.line-item:first-child {
  padding-top: 0;
}

.line-item:last-child {
  border-bottom: 0;
}

.qty {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--stone);
  border-radius: 4px;
}

.qty button {
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--clay);
  transition: color 200ms var(--rise);
}

.qty button:hover {
  color: var(--ink);
}

.qty output {
  min-width: 2rem;
  text-align: center;
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
}

.totals {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-size: 0.9375rem;
}

.totals__row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}

.totals__row--sum {
  padding-top: 0.75rem;
  border-top: 1px solid var(--stone);
  font-size: 1.0625rem;
}

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

.field {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.field label {
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--clay);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  background: transparent;
  border: 1px solid var(--stone);
  border-radius: 4px;
  padding: 0.8125rem 0.875rem;
  font-size: 0.9375rem;
  transition: border-color 200ms var(--rise);
}

.field input:hover,
.field select:hover,
.field textarea:hover {
  border-color: var(--clay-soft);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--accent);
}

.field select {
  appearance: none;
  padding-right: 2.5rem;
}

.select-wrap {
  position: relative;
}

.select-wrap::after {
  content: "";
  position: absolute;
  right: 1rem;
  top: 50%;
  width: 7px;
  height: 7px;
  border-right: 1px solid var(--clay);
  border-bottom: 1px solid var(--clay);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}

.field[data-invalid="true"] input,
.field[data-invalid="true"] select {
  border-color: #8c3b2f;
}

.field__error {
  font-size: 0.8125rem;
  color: #8c3b2f;
}

.field-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}

@media (min-width: 560px) {
  .field-row--2 {
    grid-template-columns: 1fr 1fr;
  }

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

.form-stack {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.newsletter {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  max-width: 28rem;
}

.newsletter input {
  flex: 1 1 12rem;
}

/* --------------------------------------------------------------------------
   Spec table
   -------------------------------------------------------------------------- */

.spec {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.spec th,
.spec td {
  text-align: left;
  padding: 0.875rem 0;
  border-bottom: 1px solid var(--stone);
  vertical-align: top;
}

.spec th {
  font-weight: 400;
  color: var(--clay);
  width: 40%;
  padding-right: 1.5rem;
}

.on-ink .spec th,
.on-ink .spec td {
  border-bottom-color: var(--ink-rule);
}

.on-ink .spec th {
  color: var(--mist);
}

/* --------------------------------------------------------------------------
   Data table
   -------------------------------------------------------------------------- */

.table-scroll {
  overflow-x: auto;
}

.table {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.table th,
.table td {
  text-align: left;
  padding: 0.875rem 1.5rem 0.875rem 0;
  border-bottom: 1px solid var(--stone);
  vertical-align: top;
}

.table thead th {
  font-weight: 400;
  color: var(--clay);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  line-height: 1.4;
}

.table__rowhead {
  font-weight: 400;
  color: var(--ink);
  font-size: 0.9375rem;
  letter-spacing: normal;
  text-transform: none;
}

/* --------------------------------------------------------------------------
   Consent banner

   Only rendered when UR.flags.consent is on — see js/consent.js for why it
   is currently off. Anchored to the bottom rather than covering the page:
   this is a question, not a wall, and the site is fully usable while it is
   open. The two buttons are deliberately the same size and weight. Making
   "Allow" louder than "Decline" is the most-fined dark pattern in the EU
   and it is a styling decision, which is why the note lives here.
   -------------------------------------------------------------------------- */

.consent {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 60;
  background: var(--ink);
  color: var(--paper);
  border-top: 1px solid var(--ink-rule);
}

.consent__inner {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding: 1.5rem var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem 2.5rem;
  justify-content: space-between;
}

.consent__copy {
  flex: 1 1 28rem;
}

.consent__title {
  font-family: var(--serif);
  font-size: 1.25rem;
  letter-spacing: -0.02em;
  margin-bottom: 0.375rem;
}

.consent__body {
  color: var(--mist);
  font-size: 0.875rem;
  line-height: 1.6;
  max-width: 62ch;
}

.consent__body a {
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.consent__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  flex: 0 0 auto;
}

/* Equal width, so neither reads as the default. */
.consent__actions .btn {
  min-width: 8.5rem;
  justify-content: center;
}

.consent :focus-visible {
  outline-color: var(--paper);
}

@media (max-width: 40rem) {
  .consent__actions {
    width: 100%;
  }
  .consent__actions .btn {
    flex: 1 1 0;
    min-width: 0;
  }
}

/* --------------------------------------------------------------------------
   Notice

   Stands where a buy button would, and on the pages that describe buying,
   while the shop is closed. Deliberately not styled as a warning: nothing
   has gone wrong, the reader simply cannot do the thing the page is shaped
   around, and they should be told once, calmly, in the place they looked.
   -------------------------------------------------------------------------- */

.notice {
  background: var(--stone);
  border-radius: 4px;
  padding: 1.125rem 1.25rem;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink);
  max-width: 60ch;
}

.notice strong {
  font-weight: 500;
}

.notice--wide {
  max-width: none;
  margin-bottom: 3rem;
}

/* On the two --ink sections, where --stone would be a hole in the page. */
.notice--light {
  background: transparent;
  border: 1px solid var(--clay);
  color: var(--mist);
}

.notice--light strong {
  color: var(--paper);
}

/* --------------------------------------------------------------------------
   Legal documents

   Privacy, terms, cookies and accessibility. These are the only pages on the
   site read for reference rather than read through, so they get list and
   definition styles the marketing pages have no use for. Measure is held
   tighter than --prose: a retention table is scanned, and a long line is
   harder to scan than to read.
   -------------------------------------------------------------------------- */

.legal {
  max-width: 64ch;
}

.legal p {
  color: var(--clay);
}

.legal .h4 {
  font-family: var(--ui);
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--ink);
  margin-top: 0.75rem;
}

.legal__list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  color: var(--clay);
}

.legal__list li {
  position: relative;
  padding-left: 1.5rem;
}

/* An en dash rather than a bullet — the same mark the honesty lists use, so
   the two read as one voice. */
.legal__list li::before {
  content: "–";
  position: absolute;
  left: 0;
  color: var(--clay-soft);
}

.legal__list ol,
ol.legal__list {
  counter-reset: legal-item;
}

ol.legal__list li::before {
  counter-increment: legal-item;
  content: counter(legal-item, decimal-leading-zero);
  font-family: var(--ui);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  top: 0.2em;
}

.legal__dl {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  font-size: 0.9375rem;
}

.legal__dl > div {
  display: grid;
  grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
  gap: 0.25rem 1.5rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--stone);
}

.legal__dl dt {
  font-family: var(--ui);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--clay);
  line-height: 1.4;
  padding-top: 0.2em;
}

.legal__dl dd {
  color: var(--ink);
}

@media (max-width: 40rem) {
  .legal__dl > div {
    grid-template-columns: 1fr;
  }
}

/* A qualification on the section above it, not an aside to be skipped. The
   rule is the accent because this is the one place on a legal page where a
   reader losing the thread has a consequence. */
.legal__note {
  border-left: 2px solid var(--accent);
  padding: 0.125rem 0 0.125rem 1.25rem;
  font-size: 0.9375rem;
}

.legal__pre {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--ink);
  background: var(--stone);
  border-radius: 4px;
  padding: 1.5rem;
  overflow-x: auto;
  white-space: pre;
  tab-size: 2;
}

/* --------------------------------------------------------------------------
   Unresolved placeholder

   Legal copy marks facts only the business can supply in double brackets.
   They render like this — in the accent, in the middle of a sentence —
   because a privacy notice with a hole in it must not be publishable by
   accident. When the site is ready to launch, none of these exist.
   -------------------------------------------------------------------------- */

.token {
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--ui);
  font-size: 0.6875em;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.2em 0.5em;
  border-radius: 4px;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Standards list (in / out)
   -------------------------------------------------------------------------- */

.standards {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3rem;
}

@media (min-width: 768px) {
  .standards {
    grid-template-columns: 1fr 1fr;
    gap: 4rem;
  }
}

.standards ul {
  border-top: 1px solid var(--stone);
}

.standards li {
  display: grid;
  grid-template-columns: 1.5rem 1fr;
  gap: 0.75rem;
  padding-block: 0.875rem;
  border-bottom: 1px solid var(--stone);
  font-size: 0.9375rem;
}

.standards li span:first-child {
  color: var(--clay);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   Editorial
   -------------------------------------------------------------------------- */

.article p {
  margin-bottom: 1.5rem;
}

.article h2 {
  font-size: 1.875rem;
  margin-top: 3.5rem;
  margin-bottom: 1.25rem;
}

.article ul {
  margin-bottom: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.article ul li {
  display: grid;
  grid-template-columns: 1.25rem 1fr;
}

.article ul li::before {
  content: "—";
  color: var(--clay);
}

.article blockquote {
  margin: 3rem 0;
  padding-left: 1.5rem;
  border-left: 1px solid var(--accent);
  font-family: var(--serif);
  font-size: 1.5rem;
  line-height: 1.25;
  letter-spacing: -0.02em;
}

/* --------------------------------------------------------------------------
   Reviews
   -------------------------------------------------------------------------- */

.review {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--stone);
}

.review__body {
  font-size: 1.0625rem;
}

.review__meta {
  font-size: 0.8125rem;
  color: var(--clay);
}

/* --------------------------------------------------------------------------
   Product detail
   -------------------------------------------------------------------------- */

.pdp {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3rem;
}

@media (min-width: 900px) {
  .pdp {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 4rem;
  }
}

@media (min-width: 1200px) {
  .pdp {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 5rem;
  }
}

.pdp__media {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

@media (min-width: 900px) {
  .pdp__media {
    position: sticky;
    top: 5.75rem;
    align-self: start;
  }
}

.pdp__thumbs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}

.pdp__content {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
}

.pdp__buy {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.steps {
  counter-reset: step;
  display: flex;
  flex-direction: column;
}

.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: 0.5rem;
  padding-block: 1rem;
  border-bottom: 1px solid var(--stone);
  align-items: baseline;
}

.steps li:first-child {
  border-top: 1px solid var(--stone);
}

.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-variant-numeric: tabular-nums;
  color: var(--clay);
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
}

.on-ink .steps li,
.on-ink .steps li:first-child {
  border-color: var(--ink-rule);
}

.on-ink .steps li::before {
  color: var(--mist);
}

/* --------------------------------------------------------------------------
   Routine (dark section)
   -------------------------------------------------------------------------- */

.toggle {
  display: inline-flex;
  border: 1px solid var(--ink-rule);
  border-radius: 4px;
  padding: 3px;
  gap: 3px;
}

.toggle button {
  padding: 0.5rem 1.25rem;
  border-radius: 2px;
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mist);
  transition:
    background-color 200ms var(--rise),
    color 200ms var(--rise);
}

.toggle button[aria-pressed="true"] {
  background: var(--paper);
  color: var(--ink);
}

.toggle--light {
  border-color: var(--stone);
}

.toggle--light button {
  color: var(--clay);
}

.toggle--light button[aria-pressed="true"] {
  background: var(--accent);
  color: var(--accent-ink);
}

.routine-steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}

@media (min-width: 768px) {
  .routine-steps {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 2rem;
  }
}

.routine-step {
  padding-block: 2rem;
  border-top: 1px solid var(--stone);
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}

.on-ink .routine-step {
  border-top-color: var(--ink-rule);
}

.routine-step__no {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--clay);
  font-variant-numeric: tabular-nums;
}

.on-ink .routine-step__no {
  color: var(--mist);
}

.routine-step__name {
  font-family: var(--serif);
  font-size: 1.75rem;
  letter-spacing: -0.02em;
  line-height: 1;
}

/* --------------------------------------------------------------------------
   Quiz
   -------------------------------------------------------------------------- */

.quiz-option {
  display: block;
  width: 100%;
  text-align: left;
  border: 1px solid var(--stone);
  border-radius: 4px;
  padding: 1.25rem 1.5rem;
  transition:
    border-color 200ms var(--rise),
    background-color 200ms var(--rise);
}

.quiz-option:hover {
  border-color: var(--accent);
}

.quiz-option[aria-pressed="true"] {
  border-color: var(--accent);
  background: rgba(63, 74, 60, 0.06);
}

.quiz-option strong {
  display: block;
  font-weight: 400;
  font-size: 1.0625rem;
}

.quiz-option span {
  display: block;
  color: var(--clay);
  font-size: 0.875rem;
  margin-top: 0.25rem;
}

.progress {
  display: flex;
  gap: 4px;
}

.progress span {
  flex: 1;
  height: 2px;
  background: var(--stone);
}

.progress span[data-done="true"] {
  background: var(--accent);
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--stone);
  padding-block: 4.5rem 2.5rem;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3rem;
}

@media (min-width: 640px) {
  .footer-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .footer-grid {
    grid-template-columns: 2fr 1fr 1fr 1fr;
    gap: 4rem;
  }
}

.footer-col h2 {
  font-family: var(--ui);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--clay);
  margin-bottom: 1.25rem;
  line-height: 1.4;
}

.footer-col li {
  margin-bottom: 0.625rem;
}

.footer-col a {
  font-size: 0.9375rem;
  color: var(--clay);
  transition: color 200ms var(--rise);
}

.footer-col a:hover {
  color: var(--ink);
}

.footer-base {
  margin-top: 4rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--stone);
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  justify-content: space-between;
  font-size: 0.8125rem;
  color: var(--clay);
}

/* Statutory trading disclosure. Small, because it is reference material —
   but present on every page, because that is the requirement. */
.footer-legal {
  margin-top: 1.5rem;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--clay);
  max-width: 78ch;
}

/* --------------------------------------------------------------------------
   Utilities
   -------------------------------------------------------------------------- */

.stack {
  display: flex;
  flex-direction: column;
}

.stack-2 {
  gap: 0.5rem;
}
.stack-3 {
  gap: 0.75rem;
}
.stack-4 {
  gap: 1rem;
}
.stack-6 {
  gap: 1.5rem;
}
.stack-8 {
  gap: 2rem;
}
.stack-12 {
  gap: 3rem;
}
.stack-16 {
  gap: 4rem;
}

.row {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: center;
}

.divide-y > * + * {
  border-top: 1px solid var(--stone);
  padding-top: 1.5rem;
  margin-top: 1.5rem;
}

.two-col {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
}

@media (min-width: 768px) {
  .two-col {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4rem;
  }
}

.three-col {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
}

@media (min-width: 768px) {
  .three-col {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 3rem;
  }
}

.page-head {
  padding-block: 5rem 3rem;
}

@media (min-width: 768px) {
  .page-head {
    padding-block: 7rem 4rem;
  }
}

.toast {
  position: fixed;
  left: 50%;
  bottom: 2rem;
  transform: translate(-50%, 12px);
  z-index: 70;
  background: var(--ink);
  color: var(--paper);
  padding: 0.875rem 1.25rem;
  border-radius: 4px;
  font-size: 0.875rem;
  opacity: 0;
  pointer-events: none;
  transition:
    opacity 300ms var(--rise),
    transform 300ms var(--rise);
}

.toast[data-open="true"] {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* --------------------------------------------------------------------------
   Canvas — content column plus an evidence column.

   The site was built left-weighted: every page set its content in a narrow
   column and left the right half of wide viewports empty, which reads as a
   failed load rather than as restraint. This is the primitive that fixes it.

   The rule the fill obeys: the evidence column carries a product image or
   information the reader would otherwise scroll to find. Never decoration.
   Where a page has neither to offer it takes .canvas--centred instead.

   `.split` further up is the older label/body layout and is left untouched.
   -------------------------------------------------------------------------- */

.canvas {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 3rem 1.5rem;
}

.canvas__body,
.canvas__aside {
  grid-column: 1 / -1;
}

/*
  No CSS reordering anywhere. Visual order follows DOM order at every width,
  so keyboard focus order and screen-reader order can never disagree with what
  is on screen — including on the cart and checkout, where lifting the summary
  above the line items on small screens would have broken exactly that.
*/

@media (min-width: 1024px) {
  .canvas {
    gap: 2rem;
  }

  .canvas__body {
    grid-column: 1 / 8;
  }

  .canvas__aside {
    grid-column: 9 / -1;
  }

  /* A wider body for pages whose content is a grid rather than prose. The
     aside stays on column 9 so it lines up with the page heading above it —
     the body takes the air column instead of the aside moving. */
  .canvas--wide .canvas__body {
    grid-column: 1 / 9;
  }

  /* No aside earned: centre rather than leave the right side dead. */
  .canvas--centred .canvas__body {
    grid-column: 3 / 11;
  }

  .canvas--centred-tight .canvas__body {
    grid-column: 4 / 10;
  }

  .canvas__aside--sticky > .aside {
    position: sticky;
    top: var(--sticky-top);
    /* Never trap the reader inside an aside taller than the viewport. */
    max-height: calc(100vh - var(--sticky-top) - 2rem);
    overflow-y: auto;
    scrollbar-width: none;
  }

  .canvas__aside--sticky > .aside::-webkit-scrollbar {
    display: none;
  }
}

/* Jump links must clear the sticky header. */
[data-spy-target] {
  scroll-margin-top: calc(var(--sticky-top) + 1.5rem);
}

/* A card grid inside the narrower body column drops to two across. */
@media (min-width: 1024px) {
  .canvas__body .product-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* The shop filters, stacked as a rail rather than laid out as a bar. */
.filters--rail {
  flex-direction: column;
  gap: 2rem;
}

/* --------------------------------------------------------------------------
   The evidence column itself. Quiet by construction: it must never out-shout
   the content column beside it.
   -------------------------------------------------------------------------- */

.aside {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
}

.aside__block {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.aside__label {
  font-family: var(--ui);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--clay);
}

.aside__note {
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--clay);
}

.aside__index {
  display: flex;
  flex-direction: column;
  list-style: none;
}

.aside__index li {
  border-top: 1px solid var(--stone);
}

.aside__index a,
.aside__index button {
  display: grid;
  grid-template-columns: 1.75rem 1fr;
  gap: 0.5rem;
  align-items: baseline;
  width: 100%;
  padding-block: 0.6875rem;
  border: 0;
  background: none;
  font: inherit;
  font-size: 0.875rem;
  line-height: 1.35;
  text-align: left;
  color: var(--clay);
  cursor: pointer;
  transition: color 250ms var(--rise);
}

.aside__index a:hover,
.aside__index button:hover {
  color: var(--ink);
}

.aside__index [aria-current="true"] {
  color: var(--ink);
}

.aside__no {
  font-family: var(--ui);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  color: var(--mist);
  transition: color 250ms var(--rise);
}

.aside__index [aria-current="true"] .aside__no {
  color: var(--accent);
}

.aside__index button[data-answered="false"] {
  color: var(--mist);
  cursor: default;
}

.aside__progress {
  position: relative;
  height: 1px;
  background: var(--stone);
}

.aside__progress span {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--accent);
  transition: width 120ms linear;
}

.aside__card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.5rem;
  border: 1px solid var(--stone);
  border-radius: 4px;
}

.aside__figure {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.aside__caption {
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--clay);
}

/* Fact pairs — used under every page heading. */
.meta-list {
  display: flex;
  flex-direction: column;
  margin: 0;
}

.meta-list > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.5rem;
  padding-block: 0.75rem;
  border-top: 1px solid var(--stone);
  font-size: 0.875rem;
}

.meta-list dt {
  color: var(--clay);
}

.meta-list dd {
  margin: 0;
  text-align: right;
}

/* --------------------------------------------------------------------------
   Home hero — full-bleed split. Sits outside .shell so the shot can run to
   the right edge of the viewport; the copy column re-aligns itself to the
   shell's left gutter at every width.
   -------------------------------------------------------------------------- */

.hero {
  display: grid;
  grid-template-columns: 1fr;
}

.hero__copy {
  display: flex;
  align-items: center;
  padding: 3.5rem var(--gutter) 3rem;
}

.hero__copy > * {
  width: 100%;
}

/*
  The art panel sits on --paper, which is within a shade of the plaster wall
  in the frame itself, so the two halves of the hero meet without a visible
  join while the photograph loads and after it has.
*/
.hero__art {
  position: relative;
  overflow: hidden;
  background: var(--paper);
}

.hero__art .shot {
  border-radius: 0;
  aspect-ratio: 4 / 3;
  background: var(--paper);
}

@media (min-width: 1024px) {
  .hero {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    /*
      The hero frame is 4:3 and the panel is roughly half the viewport wide,
      so a short hero would crop the row of vessels top and bottom to a band.
      The generous height keeps the surface they stand on, and the wall above
      them, inside the frame.
    */
    min-height: min(88vh, 880px);
  }

  .hero__copy {
    justify-content: flex-end;
    padding-block: 4rem;
    /*
      No padding on the inner edge. With it, the right-aligned copy stopped a
      gutter short of the centre line and its left edge fell a gutter left of
      the shell — visibly out of line with the wordmark in the header.
    */
    padding-inline: var(--gutter) 0;
  }

  .hero__copy > * {
    max-width: calc(var(--max) / 2 - var(--gutter));
  }

  .hero__art {
    height: 100%;
  }

  /*
    Pinned rather than sized. Left in flow the SVG contributes its intrinsic
    3:4 ratio to the grid row, so at 1920 the hero grew to ~1280px tall and
    pushed the call to action below the fold. Taking it out of flow lets
    min-height and the copy decide the height, and the shot simply fills it.
  */
  .hero__art .shot {
    position: absolute;
    inset: 0;
    width: auto;
    height: auto;
    aspect-ratio: auto;
    border-radius: 0;
  }
}

/*
  The caption sits on the photograph, and what is behind it changes: shadowed
  limestone in the portrait frame, lit limestone in the landscape one. --clay
  measured 1.71:1 against the first and no single text colour clears AA
  against both, so the caption carries its own ground. Flat fill, 4px radius,
  no shadow — the same rules as everything else.
*/
.hero__caption {
  position: absolute;
  left: 1.5rem;
  bottom: 1.5rem;
  padding: 0.4rem 0.6rem;
  border-radius: 4px;
  background: var(--ink);
  color: var(--accent-ink);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
