/* ==========================================================================
   Tokens
   ========================================================================== */

:root {
  --color-primary: #1D4840;
  --color-primary-ink: #1A3B34; /* deep shade for scrims/backdrops */
  
  --color-accent: #C09561;
  --color-accent-ink: #8B6535; /* text + button-fill use — 4.7:1 on bg, 6.1:1 under white */
  --color-accent-ink-hover: #725025; /* hover/active step down from accent-ink */

  --color-structural: #90A39D;
  
  --color-bg: #F1DECD;

  --color-trim: #B8AD9F;

  /* Not part of the five confirmed brand hexes above — introduced to give
     the monofloral/multifloral marks (label text + corner icon) a second
     color so Multifloral reads distinctly from Monofloral's teal
     (--color-structural), which single-handedly covered both states
     before. #ab7050 at 3.1:1 on --color-bg is below the 4.5:1 small-text
     threshold, same as --color-structural itself (2.0:1) — an accepted
     gap already present in this label, not a regression introduced here. */
  --color-multifloral: #ab7050;
  --color-surface: #E5D0B7; /* one step down from bg, same hue */
  --color-ink: #333333;
  --color-muted: #706E75; /* lighter step of ink — 4.6:1 on surface, 5.2:1 on bg */
  --color-on-dark: var(--color-bg);
  --color-on-accent: #FDFAF6;
  --color-border: #D4BFA8;
  /* Form validation errors (message text and invalid-field borders).
     5.7:1 on --color-bg, 5.0:1 on --color-surface – AA for text. */
  --color-error: #9B2F25;
  --color-focus-ring: var(--color-primary);

  /* MTB typography system — confirmed from the client's CI manual, now
     applied across body text and the .heading/.subheading system. */
  --font-family-base: "avenir-lt-pro", sans-serif;
  --font-weight-heavy: 700;
  --font-weight-roman: 400;
  --font-tracking-heading: 0.2em; /* tracking 200 in print = ~0.2em in CSS */
  --font-tracking-body: 0.08em; /* CI manual's tracking 50 converts to ~0.05em (same ratio as --font-tracking-heading's 200 -> 0.2em); bumped to 0.08em per direct request, a deliberate deviation from that conversion, not a re-derivation of it. */
  --font-scale-vertical: 95%; /* vertical scale from CI */

  /* Honeycomb lattice — geometry extracted programmatically from the
     client's vector source file (MTB Honey Collection cover, July '26):
     regular flat-top hexagons, edge length 22.64pt, tiled on a triangular
     lattice with a 43pt center-to-center spacing (~95% of the hexagons'
     natural touching distance, so adjacent outlines cross rather than
     just meet — the diamonds and six-pointed hexagram at each cluster's
     center are emergent from that overlap, not separately drawn shapes).
     The tile below carries only the alpha shape (used as a mask); actual
     color/opacity is applied via --pattern-tint, confirmed from the
     source as the site's own --color-structural at roughly 28% over the
     dark green base. Reused via mask rather than baking the color into
     the artwork, so the same tile can be retinted per surface. */
  --pattern-lattice: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A//www.w3.org/2000/svg%27%20width%3D%27101.88%27%20height%3D%2758.82%27%20viewBox%3D%270%200%20101.88%2058.82%27%3E%3Cpolygon%20points%3D%22-79.24%2C-58.82%20-90.56%2C-39.21%20-113.2%2C-39.21%20-124.52%2C-58.82%20-113.2%2C-78.43%20-90.56%2C-78.43%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22-45.28%2C-58.82%20-56.6%2C-39.21%20-79.24%2C-39.21%20-90.56%2C-58.82%20-79.24%2C-78.43%20-56.6%2C-78.43%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22-28.3%2C-29.41%20-39.62%2C-9.8%20-62.26%2C-9.8%20-73.58%2C-29.41%20-62.26%2C-49.02%20-39.62%2C-49.02%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%225.66%2C-29.41%20-5.66%2C-9.8%20-28.3%2C-9.8%20-39.62%2C-29.41%20-28.3%2C-49.02%20-5.66%2C-49.02%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22-79.24%2C0.0%20-90.56%2C19.61%20-113.2%2C19.61%20-124.52%2C0.0%20-113.2%2C-19.61%20-90.56%2C-19.61%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22-45.28%2C0.0%20-56.6%2C19.61%20-79.24%2C19.61%20-90.56%2C0.0%20-79.24%2C-19.61%20-56.6%2C-19.61%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22-28.3%2C29.41%20-39.62%2C49.02%20-62.26%2C49.02%20-73.58%2C29.41%20-62.26%2C9.8%20-39.62%2C9.8%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%225.66%2C29.41%20-5.66%2C49.02%20-28.3%2C49.02%20-39.62%2C29.41%20-28.3%2C9.8%20-5.66%2C9.8%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22-79.24%2C58.82%20-90.56%2C78.43%20-113.2%2C78.43%20-124.52%2C58.82%20-113.2%2C39.21%20-90.56%2C39.21%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22-45.28%2C58.82%20-56.6%2C78.43%20-79.24%2C78.43%20-90.56%2C58.82%20-79.24%2C39.21%20-56.6%2C39.21%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22-28.3%2C88.23%20-39.62%2C107.83%20-62.26%2C107.83%20-73.58%2C88.23%20-62.26%2C68.62%20-39.62%2C68.62%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%225.66%2C88.23%20-5.66%2C107.83%20-28.3%2C107.83%20-39.62%2C88.23%20-28.3%2C68.62%20-5.66%2C68.62%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2222.64%2C-58.82%2011.32%2C-39.21%20-11.32%2C-39.21%20-22.64%2C-58.82%20-11.32%2C-78.43%2011.32%2C-78.43%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2256.6%2C-58.82%2045.28%2C-39.21%2022.64%2C-39.21%2011.32%2C-58.82%2022.64%2C-78.43%2045.28%2C-78.43%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2273.58%2C-29.41%2062.26%2C-9.8%2039.62%2C-9.8%2028.3%2C-29.41%2039.62%2C-49.02%2062.26%2C-49.02%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22107.54%2C-29.41%2096.22%2C-9.8%2073.58%2C-9.8%2062.26%2C-29.41%2073.58%2C-49.02%2096.22%2C-49.02%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2222.64%2C0.0%2011.32%2C19.61%20-11.32%2C19.61%20-22.64%2C0.0%20-11.32%2C-19.61%2011.32%2C-19.61%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2256.6%2C0.0%2045.28%2C19.61%2022.64%2C19.61%2011.32%2C0.0%2022.64%2C-19.61%2045.28%2C-19.61%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2273.58%2C29.41%2062.26%2C49.02%2039.62%2C49.02%2028.3%2C29.41%2039.62%2C9.8%2062.26%2C9.8%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22107.54%2C29.41%2096.22%2C49.02%2073.58%2C49.02%2062.26%2C29.41%2073.58%2C9.8%2096.22%2C9.8%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2222.64%2C58.82%2011.32%2C78.43%20-11.32%2C78.43%20-22.64%2C58.82%20-11.32%2C39.21%2011.32%2C39.21%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2256.6%2C58.82%2045.28%2C78.43%2022.64%2C78.43%2011.32%2C58.82%2022.64%2C39.21%2045.28%2C39.21%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%2273.58%2C88.23%2062.26%2C107.83%2039.62%2C107.83%2028.3%2C88.23%2039.62%2C68.62%2062.26%2C68.62%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22107.54%2C88.23%2096.22%2C107.83%2073.58%2C107.83%2062.26%2C88.23%2073.58%2C68.62%2096.22%2C68.62%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22124.52%2C-58.82%20113.2%2C-39.21%2090.56%2C-39.21%2079.24%2C-58.82%2090.56%2C-78.43%20113.2%2C-78.43%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22158.48%2C-58.82%20147.16%2C-39.21%20124.52%2C-39.21%20113.2%2C-58.82%20124.52%2C-78.43%20147.16%2C-78.43%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22175.46%2C-29.41%20164.14%2C-9.8%20141.5%2C-9.8%20130.18%2C-29.41%20141.5%2C-49.02%20164.14%2C-49.02%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22209.42%2C-29.41%20198.1%2C-9.8%20175.46%2C-9.8%20164.14%2C-29.41%20175.46%2C-49.02%20198.1%2C-49.02%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22124.52%2C0.0%20113.2%2C19.61%2090.56%2C19.61%2079.24%2C0.0%2090.56%2C-19.61%20113.2%2C-19.61%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22158.48%2C0.0%20147.16%2C19.61%20124.52%2C19.61%20113.2%2C0.0%20124.52%2C-19.61%20147.16%2C-19.61%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22175.46%2C29.41%20164.14%2C49.02%20141.5%2C49.02%20130.18%2C29.41%20141.5%2C9.8%20164.14%2C9.8%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22209.42%2C29.41%20198.1%2C49.02%20175.46%2C49.02%20164.14%2C29.41%20175.46%2C9.8%20198.1%2C9.8%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22124.52%2C58.82%20113.2%2C78.43%2090.56%2C78.43%2079.24%2C58.82%2090.56%2C39.21%20113.2%2C39.21%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22158.48%2C58.82%20147.16%2C78.43%20124.52%2C78.43%20113.2%2C58.82%20124.52%2C39.21%20147.16%2C39.21%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22175.46%2C88.23%20164.14%2C107.83%20141.5%2C107.83%20130.18%2C88.23%20141.5%2C68.62%20164.14%2C68.62%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3Cpolygon%20points%3D%22209.42%2C88.23%20198.1%2C107.83%20175.46%2C107.83%20164.14%2C88.23%20175.46%2C68.62%20198.1%2C68.62%22%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%220.9%22/%3E%3C/svg%3E");
  --pattern-tint: oklch(from var(--color-structural) l c h / 0.28);

  /* Type */
  /* Avenir LT Pro (--font-family-base) is now the confirmed typeface
     everywhere, including the logo lockup — the Jost/Playfair Display
     placeholders these two tokens carried are gone. */
  --font-wordmark: var(--font-family-base);
  --font-honey: var(--font-family-base);

  /* Heading scale — confirmed brand hierarchy, measured directly from the
     client's brand documents (not a provisional ratio). --font-size-body
     is the 1rem reference point every other body-copy size in this file
     already assumes; the two heading tiers derive from it via calc() so
     they stay locked to the body size if it ever changes. */
  --font-size-body: 1rem;
  --font-size-heading: calc(var(--font-size-body) * 1.773); /* section/page titles */
  --font-size-subheading: calc(var(--font-size-body) * 1.545); /* sub-headings, list items, product names */

  /* Logo lockup — icon-to-wordmark ratios measured from the client's
     brand PDF. Every measurement derives from --logo-icon-height via
     calc() so the proportions stay locked at any size or breakpoint;
     never set logo-lockup dimensions as independent fixed values. */
  --logo-icon-height: 52px;
  --logo-mtb-size: calc(var(--logo-icon-height) * 0.2351);
  --logo-honey-size: calc(var(--logo-icon-height) * 0.3405);
  --logo-icon-gap: calc(var(--logo-icon-height) * 0.1554);
  --logo-line-gap: calc(var(--logo-icon-height) * 0.2531);

  /* Spacing — 4pt scale */
  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-sm: 1rem;
  --space-md: 1.5rem;
  --space-lg: 2rem;
  --space-xl: 3rem;
  --space-2xl: 4rem;
  --space-3xl: 6rem;

  /* Layout */
  --content-max-width: 78rem;
  /* Sticky header's rendered height — .site-header__inner's padding-top
     (--space-sm) + padding-bottom (--space-sm + 12px, to clear the
     header::before hairline with the same breathing room as the top) +
     .site-header's 2px accent border-bottom + the vertical logo lockup
     at the header's own 36px icon-height override (see .site-header
     .logo-lockup--vertical), ≈71.43px. Constant across every breakpoint
     since none of those inputs change responsively. Used by the home
     hero to size itself to exactly fill the viewport below the header. */
  --nav-height: 118px;

  /* z-index scale */
  --z-dropdown: 10;
  --z-sticky: 20;
  --z-modal-backdrop: 30;
  --z-modal: 40;
  --z-toast: 50;
  --z-tooltip: 60;

  /* Motion */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-fast: 150ms;
  --duration-base: 250ms;
  --duration-slow: 400ms;
}

/* ==========================================================================
   Reset
   ========================================================================== */

*, *::before, *::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  color-scheme: light;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
  font-family: var(--font-family-base);
  font-weight: var(--font-weight-roman);
  letter-spacing: var(--font-tracking-body);
  font-optical-sizing: auto;
  background: var(--color-bg);
  color: var(--color-ink);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

main {
  flex: 1 1 auto;
  position: relative;
  border-bottom: 2px solid var(--color-accent);
}

main::after {
  content: "";
  position: absolute;
  bottom: 0; /* rests directly on top of the border, not translated */
  left: 0;
  right: 0;
  height: 6.889px;
  background-image: repeating-linear-gradient(
    to right,
    var(--color-accent) 0px 6.562px,
    transparent 6.562px 15.431px);
  pointer-events: none;
}

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

/* button excluded: it already carries its own explicit letter-spacing
   (see .btn), which this must not touch. */
input, textarea, select {
  letter-spacing: inherit;
}

label {
  text-transform: uppercase;
}

a {
  color: inherit;
  text-decoration: none;
}

ul[class] {
  list-style: none;
  padding: 0;
}

button {
  background: none;
  border: none;
  cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   Utilities
   ========================================================================== */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

:focus {
  outline: none;
}

:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 3px;
  border-radius: 0;
}

.skip-link {
  position: fixed;
  top: -100%;
  left: var(--space-sm);
  z-index: var(--z-tooltip);
  padding: var(--space-2xs) var(--space-sm);
  background: var(--color-ink);
  color: var(--color-bg);
  border-radius: 0;
  font-weight: 600;
  transition: top var(--duration-base) var(--ease-out-expo);
}

.skip-link:focus-visible {
  top: var(--space-sm);
  outline-offset: 0;
}

/* Shared content-width constraint. Section content divs opt in by adding
   this class; full-bleed sections (imagery, drenched color blocks) opt
   out by simply omitting it. */
.container {
  max-width: var(--content-max-width);
  margin-inline: auto;
  padding-inline: var(--space-md);
}

/* Text link with a trailing arrow that nudges forward on hover/focus.
   Inherits color so it reads correctly on both dark and light surfaces. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-weight: 600;
}

.link-arrow span {
  display: inline-block;
  transition: transform var(--duration-fast) var(--ease-out-expo);
}

.link-arrow:hover span,
.link-arrow:focus-visible span {
  transform: translateX(3px);
}

/* ==========================================================================
   Headings
   ========================================================================== */

/* Every heading element site-wide sets tight (1) line-height — headings
   only, never body copy. Applies ahead of any more specific heading
   selector below; .impact__program-heading redeclares line-height for
   its own reasons and is kept at 1 too (see its own rule) rather than
   left to fall back to this one. */
h1, h2, h3, h4, h5, h6 {
  line-height: 1;
}

/* Confirmed brand hierarchy, measured directly from the client's brand
   documents — not a provisional treatment. Two size tiers only:
   .heading for page/section titles, .subheading for sub-headings, list
   items, and product names (see --font-size-heading / --font-size-subheading
   in Tokens). Literal --color-accent is the brand-specified heading color
   per those documents; it clears only 2.1:1 against --color-bg (below AA
   even at the large-text 3:1 threshold) — used here per explicit brand
   direction rather than swapped for the accessible --color-accent-ink. */
.heading,
.subheading {
  font-family: var(--font-family-base);
  text-transform: uppercase;
  letter-spacing: var(--font-tracking-heading);
  color: var(--color-accent);
  font-weight: var(--font-weight-roman);
}

.heading {
  font-size: var(--font-size-heading);
}

.subheading {
  font-size: var(--font-size-subheading);
}

/* Bold emphasis is selective, not mechanical: reserve <strong>/<b> for a
   genuine brand mention ("MTB", "Meant To Bee") or the clear topical lead
   word within a heading. Same size/color/tracking as the rest of the
   heading — weight is the only thing that changes. Most headings have no
   natural word to bold and should stay fully regular-weight. Superseded
   for the systematic MTB heading-weight split below — that mechanical,
   every-heading treatment uses .heading-heavy, not this rule. */
.heading strong,
.heading b,
.subheading strong,
.subheading b {
  font-weight: 700;
}

/* MTB heading weight treatment — confirmed CI pattern: each heading is
   split so ~50% of its words render Avenir Heavy, the rest inherit the
   heading's own Roman weight. A visual-balance judgment made per
   heading (not a fixed word-count ratio), always applied to the leading
   portion. Wrap the heavy words in this class; leave the rest bare. */
.heading-heavy {
  font-weight: var(--font-weight-heavy);
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: 0.7em 1.3em;
  border-radius: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.25em;
  white-space: nowrap;
  transition:
    background-color var(--duration-fast) var(--ease-out-expo),
    transform var(--duration-fast) var(--ease-out-expo),
    box-shadow var(--duration-fast) var(--ease-out-expo);
}

.btn--cta {
  /* accent-ink, not the literal accent hex: white text on the raw
     #c19562 gold only hits 2.7:1. accent-ink is the same hue/chroma,
     darkened until white clears 4.5:1 (see token comment above). */
  background: var(--color-accent-ink);
  color: var(--color-on-accent);
}

.btn--cta:hover {
  background: var(--color-accent-ink-hover);
  transform: translateY(-1px);
  box-shadow: 0 10px 20px -10px oklch(0 0 0 / 0.5);
}

.btn--cta:active {
  transform: translateY(0);
  box-shadow: none;
}

.btn--block {
  width: 100%;
}

/* ==========================================================================
   Site Header
   ========================================================================== */

header::before {
  content: "";
  position: absolute;
  bottom: 10px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--color-accent);
}

header::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  transform: translateY(100%);
  height: 6.889px;
  background-image: repeating-linear-gradient(
    to right,
    var(--color-accent) 0px 6.562px,
    transparent 6.562px 15.431px);
}

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--color-primary);
  color: var(--color-on-dark);
  --color-focus-ring: var(--color-on-dark);
  box-shadow: 0 1px 0 oklch(0 0 0 / 0);
  transition: box-shadow var(--duration-base) var(--ease-out-expo);
  border-bottom: 2px solid var(--color-accent);
}

.site-header.is-scrolled {
  box-shadow: 0 12px 24px -16px oklch(0.10 0.03 179.23 / 0.55);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding-top: var(--space-sm);
  /* Bottom padding isn't symmetric with the top: it also has to clear the
     hairline (header::before, 10px offset + 2px height = 12px, measured
     from this element's own padding edge) before the same --space-sm gap
     to the hairline is reached, so the logo lockup reads as centred in
     the space above the hairline rather than in the header's full height
     (which also includes the border-bottom below the hairline). */
  padding-bottom: calc(var(--space-sm) + 12px);
}

/* Logo lockup — bee icon above (or, via this base rule alone, beside)
   the two-line "meant to bee / HONEY" wordmark. Shared by the header,
   mobile nav, and footer (see logo-lockup.njk); sizing is entirely
   token-driven (see --logo-* in Tokens) so every instance stays
   proportionally identical to the others, just at its own scale. Every
   current instance applies the .logo-lockup--vertical modifier below
   — the brand's native icon-over-wordmark stack (cover page, product
   labels) — so this base rule's own row layout is what --vertical
   overrides, not a shape used on its own anywhere today. */
.logo-lockup {
  display: inline-flex;
  align-items: center;
  gap: var(--logo-icon-gap);
  transition: opacity var(--duration-fast) var(--ease-out-expo);
}

.logo-lockup:hover,
.logo-lockup:focus-visible {
  opacity: 0.85;
}

.logo-lockup__icon {
  flex-shrink: 0;
  height: var(--logo-icon-height);
  width: auto;
  color: var(--color-accent);
}

/* Site-header-only: the sticky header's lockup is the single-file
   mtb-logo-light.svg (icon + wordmark baked into one asset) rather than
   the icon+text markup below. 71.4375px matches that markup's previous
   rendered height in this exact header context (36px --logo-icon-height,
   .site-header__inner's padding), so the header's own sizing — its
   --nav-height, the hairline clearance above it — didn't need to change
   alongside this swap. */
.logo-lockup__img {
  flex-shrink: 0;
  height: 71.4375px;
  width: auto;
}

.logo-lockup__text {
  display: flex;
  flex-direction: column;
  gap: var(--logo-line-gap);
}

.logo-lockup__mtb {
  font-family: var(--font-wordmark);
  font-size: var(--logo-mtb-size);
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--color-accent);
  white-space: nowrap;
}

.logo-lockup__honey {
  font-family: var(--font-honey);
  font-size: var(--logo-honey-size);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.05em;
  color: var(--color-on-dark);
  white-space: nowrap;
}

/* Vertical lockup — the brand's icon-over-wordmark stack, used at three
   scales (footer, sticky header, mobile nav). --logo-icon-height drives
   every other --logo-* value via calc(), so overriding just that one
   custom property per context (below) re-derives the whole stack's
   proportions automatically — the footer's 84px default here is the
   largest instance, not a footer-only rule. */
.logo-lockup--vertical {
  --logo-icon-height: 84px;
  --logo-mtb-size: calc(var(--logo-icon-height) * 0.2351);
  --logo-honey-size: calc(var(--logo-icon-height) * 0.3405);
  --logo-icon-to-text-gap: calc(var(--logo-icon-height) * 0.1554);
  --logo-line-gap: calc(var(--logo-icon-height) * 0.2531);
  flex-direction: column;
  gap: var(--logo-icon-to-text-gap);
}

.logo-lockup--vertical .logo-lockup__text {
  align-items: center;
}

/* Sticky header and mobile nav need the same vertical stack at a size
   that actually fits a nav bar — overriding --logo-icon-height alone
   (higher specificity than the bare rule above) keeps every proportion
   identical to the footer's, just scaled down. */
.site-header .logo-lockup--vertical,
.mobile-nav__header .logo-lockup--vertical {
  --logo-icon-height: 36px;
}

.site-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* Desktop nav */

.site-nav {
  display: none;
}

.site-nav__list {
  display: flex;
  gap: var(--space-md);
}

.site-nav__link {
  position: relative;
  display: inline-block;
  padding-block: var(--space-2xs);
  font-size: 0.9375rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.25em;
  color: oklch(from var(--color-on-dark) l c h / 0.85);
}

.site-nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: var(--color-on-dark);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-base) var(--ease-out-expo);
}

.site-nav__link:hover,
.site-nav__link:focus-visible {
  color: var(--color-on-dark);
}

.site-nav__link:hover::after,
.site-nav__link:focus-visible::after,
.site-nav__link[aria-current="page"]::after {
  transform: scaleX(1);
}

.site-nav__link[aria-current="page"] {
  color: var(--color-on-dark);
  font-weight: 600;
}

/* The header's CTA is replaced by the hamburger menu below 1024px; this
   is header-specific chrome, not a rule about .btn--cta in general. */
.site-header__actions .btn--cta {
  display: none;
}

/* Mobile nav toggle */

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  position: relative;
}

.nav-toggle__box {
  width: 22px;
  height: 16px;
  position: relative;
}

.nav-toggle__box::before,
.nav-toggle__box::after,
.nav-toggle__bar {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  border-radius: 0;
  background: var(--color-on-dark);
  transition:
    transform var(--duration-base) var(--ease-out-expo),
    opacity var(--duration-base) var(--ease-out-expo);
}

.nav-toggle__box::before {
  top: 0;
}

.nav-toggle__bar {
  top: 7px;
}

.nav-toggle__box::after {
  bottom: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__box::before {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__box::after {
  transform: translateY(-7px) rotate(-45deg);
}

/* 1024px (desktop), not 768px (tablet): at 768px the 5 nav labels + CTA
   don't have room and wrap mid-word. Verified in-browser. */
@media (min-width: 64rem) {
  .site-nav {
    display: block;
  }

  .site-header__actions .btn--cta {
    display: inline-flex;
  }

  .nav-toggle {
    display: none;
  }
}

/* ==========================================================================
   Mobile Nav Dialog
   ========================================================================== */

.mobile-nav {
  margin: 0;
  padding: var(--space-lg) var(--space-md);
  border: 0;
  position: fixed;
  inset: 0 0 0 auto;
  width: min(22rem, 88vw);
  height: 100dvh;
  max-height: 100dvh;
  max-width: none;
  background: var(--color-primary);
  color: var(--color-on-dark);
  --color-focus-ring: var(--color-on-dark);
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  box-shadow: -32px 0 48px -24px oklch(0 0 0 / 0.45);
  transform: translateX(100%);
  opacity: 0;
  transition:
    transform var(--duration-slow) var(--ease-out-expo),
    opacity var(--duration-slow) var(--ease-out-expo),
    overlay var(--duration-slow) allow-discrete,
    display var(--duration-slow) allow-discrete;
}

.mobile-nav[open] {
  transform: translateX(0);
  opacity: 1;
}

@starting-style {
  .mobile-nav[open] {
    transform: translateX(100%);
    opacity: 0;
  }
}

.mobile-nav::backdrop {
  background: oklch(0.15 0.02 179.23 / 0.55);
  opacity: 0;
  transition:
    opacity var(--duration-slow) var(--ease-out-expo),
    overlay var(--duration-slow) allow-discrete,
    display var(--duration-slow) allow-discrete;
}

.mobile-nav[open]::backdrop {
  opacity: 1;
}

@starting-style {
  .mobile-nav[open]::backdrop {
    opacity: 0;
  }
}

.mobile-nav__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.mobile-nav__close {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-on-dark);
}

.mobile-nav__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.mobile-nav__list a {
  display: inline-block;
  font-size: 1.375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  opacity: 0.85;
}

.mobile-nav__list a:hover,
.mobile-nav__list a:focus-visible,
.mobile-nav__list a[aria-current="page"] {
  opacity: 1;
}

.mobile-nav__list a[aria-current="page"] {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.mobile-nav .btn--cta {
  display: inline-flex;
  margin-top: auto;
}

/* Matches the .site-nav breakpoint above — desktop nav takes over here. */
@media (min-width: 64rem) {
  .mobile-nav {
    display: none;
  }
}

/* ==========================================================================
   Newsletter Popup
   ========================================================================== */

/* Native <dialog>, opened non-modally via .show() (never .showModal()) —
   deliberately not the mobile-nav dialog's pattern. .show() creates no
   ::backdrop, sets no aria-modal, and leaves the rest of the document
   exactly as interactive and scrollable as before; the card is just a
   normally-stacked fixed-position element (hence the explicit z-index
   below, since it isn't promoted to the top layer). main.js moves focus
   onto the card on open and closes it on Escape only while focus is
   still inside it — there is no focus trap, so Tab/Shift+Tab keeps
   moving through the whole page as usual.

   The closed state is visibility/opacity/transform, not display: the
   UA stylesheet hides a <dialog> without [open] via `display: none`,
   which has no in-between state to transition through — closing would
   just vanish instantly. Forcing `display: block` unconditionally here
   keeps the element continuously rendered; `visibility` (which the
   browser flips at the START of a transition when becoming visible, and
   only at the END when becoming hidden) plus `pointer-events: none`
   keeps it inert and unhittable while closed, without ever touching
   display. */
.newsletter-popup {
  display: block;
  margin: 0;
  padding: var(--space-lg);
  border: 0;
  border-radius: 0;
  position: fixed;
  z-index: var(--z-toast);
  inset: auto var(--space-sm) var(--space-sm) var(--space-sm);
  width: auto;
  max-width: none;
  max-height: calc(100dvh - var(--space-lg));
  overflow-y: auto;
  background: var(--color-surface);
  color: var(--color-ink);
  box-shadow: 0 24px 48px -24px oklch(0 0 0 / 0.35);
  visibility: hidden;
  pointer-events: none;
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity var(--duration-base) var(--ease-out-expo),
    transform var(--duration-base) var(--ease-out-expo),
    visibility var(--duration-base) linear;
}

.newsletter-popup[open] {
  visibility: visible;
  pointer-events: auto;
  opacity: 1;
  transform: translateY(0);
}

.newsletter-popup__close {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-muted);
  border-radius: 0;
  transition:
    color var(--duration-fast) var(--ease-out-expo),
    background-color var(--duration-fast) var(--ease-out-expo);
}

.newsletter-popup__close:hover,
.newsletter-popup__close:focus-visible {
  color: var(--color-ink);
  background: oklch(from var(--color-ink) l c h / 0.08);
}

/* Full vertical lockup (bee icon over wordmark over HONEY), reused as-is
   from the footer/header (see logo-lockup.njk) — same markup, same
   native colors, just scaled down via the same --logo-icon-height
   override pattern the sticky header and mobile nav already use (see
   .site-header .logo-lockup--vertical) so it reads as a compact
   identity mark rather than the footer's hero-sized version. */
.newsletter-popup__logo {
  margin-bottom: var(--space-xs);
}

.newsletter-popup__logo .logo-lockup--vertical {
  --logo-icon-height: 40px;
}

/* Popup-specific override: matches this context's previous 40px
   --logo-icon-height above (still set, though .logo-lockup__img doesn't
   read it) at the same measured height-to-icon-height ratio used for the
   header and footer overrides (1.984375), so the popup's logo doesn't
   change size alongside this swap. */
.newsletter-popup .logo-lockup__img {
  height: 79.375px;
}

.newsletter-popup__heading {
  padding-right: var(--space-xl);
}

.newsletter-popup__body {
  margin-top: var(--space-sm);
  max-width: 32ch;
  font-size: 0.9375rem;
  line-height: 1.6;
}

.newsletter-popup__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}

.newsletter-popup__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
}

.newsletter-popup__label {
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--color-ink);
}

/* Same rationale as the contact form: --color-muted, not --color-border,
   carries the default field border so it clears the 3:1 non-text
   contrast SC 1.4.11 needs against the card's --color-surface fill. */
.newsletter-popup__input {
  width: 100%;
  padding: var(--space-2xs) var(--space-sm);
  background: var(--color-bg);
  border: 1.5px solid var(--color-muted);
  border-radius: 0;
  font-size: 0.9375rem;
  color: var(--color-ink);
  transition: border-color var(--duration-fast) var(--ease-out-expo);
}

.newsletter-popup__input:hover,
.newsletter-popup__input:focus-visible {
  border-color: var(--color-primary);
}

.newsletter-popup .btn--cta {
  margin-top: var(--space-2xs);
}

/* Form feedback inside the popup (shared .form-error / .form-status /
   .form-honeypot rules live under "Form feedback"). The popup's fields
   and form use their own gaps (3xs / sm), so the "take no space while
   empty" offsets are restated with those values – at rest the card is
   exactly as tall as it was before validation was wired up. */
.newsletter-popup__field > .form-error:empty {
  margin-top: calc(-1 * var(--space-3xs));
}

.newsletter-popup__form > .form-status:empty {
  margin-top: calc(-1 * var(--space-sm));
}

.newsletter-popup__input[aria-invalid="true"] {
  border-color: var(--color-error);
}

/* Consent row: a <label> for the larger hit area, so undo the global
   label uppercase – it's a sentence. Sized like the popup's body copy. */
.newsletter-popup__consent {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2xs);
  font-size: 0.8125rem;
  line-height: 1.5;
  text-transform: none;
  color: var(--color-ink);
  cursor: pointer;
}

.newsletter-popup__consent input[type="checkbox"] {
  flex-shrink: 0;
  width: 1.125rem;
  height: 1.125rem;
  margin: 0.1em 0 0;
  accent-color: var(--color-primary);
}

.newsletter-popup__consent a {
  color: var(--color-accent-ink);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.newsletter-popup__consent a:hover,
.newsletter-popup__consent a:focus-visible {
  color: var(--color-accent-ink-hover);
}

/* No-JS sign-up result (#newsletter-sent / #newsletter-error): shown in
   the popup's own corner, on the popup's surface, since the page it
   returns to can be any page. "Dismiss" changes the fragment, so :target
   no longer matches and it hides – no JS needed. */
.newsletter-notice:target {
  position: fixed;
  z-index: var(--z-toast);
  inset: auto var(--space-sm) var(--space-sm) var(--space-sm);
  max-width: none;
  margin: 0;
  padding: var(--space-md) var(--space-lg);
  background: var(--color-surface);
  box-shadow: 0 24px 48px -24px oklch(0 0 0 / 0.35);
}

.newsletter-notice__dismiss {
  display: inline-block;
  margin-top: var(--space-2xs);
  font-size: 0.875rem;
}

@media (min-width: 48rem) {
  .newsletter-notice:target {
    inset: auto var(--space-lg) var(--space-lg) auto;
    width: min(24rem, 90vw);
  }
}

@media (min-width: 48rem) {
  .newsletter-popup {
    inset: auto var(--space-lg) var(--space-lg) auto;
    width: min(24rem, 90vw);
  }
}

/* Chat-widget-style reopen button. Sits in the same corner once the card
   has been dismissed and stays available for the rest of the 24-hour
   suppression window (see main.js). Same visibility/opacity/transform
   approach as .newsletter-popup above, for the same reason: display
   toggling has no in-between state to transition through. */
.newsletter-popup-launcher {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  z-index: var(--z-toast);
  right: var(--space-sm);
  bottom: var(--space-sm);
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--color-primary);
  color: var(--color-on-dark);
  --color-focus-ring: var(--color-on-dark);
  box-shadow: 0 12px 24px -12px oklch(0 0 0 / 0.45);
  visibility: hidden;
  pointer-events: none;
  opacity: 0;
  transform: scale(0.85);
  transition:
    opacity var(--duration-base) var(--ease-out-expo),
    transform var(--duration-base) var(--ease-out-expo),
    visibility var(--duration-base) linear;
}

.newsletter-popup-launcher.is-visible {
  visibility: visible;
  pointer-events: auto;
  opacity: 1;
  transform: scale(1);
}

.newsletter-popup-launcher:hover {
  background: var(--color-primary-ink);
}

.newsletter-popup-launcher__icon {
  width: 26px;
  height: auto;
}

@media (min-width: 48rem) {
  .newsletter-popup-launcher {
    right: var(--space-lg);
    bottom: var(--space-lg);
  }
}

/* ==========================================================================
   Site Footer
   ========================================================================== */

.site-footer {
  position: relative;
  isolation: isolate;
  background: var(--color-primary);
  color: var(--color-on-dark);
  --color-focus-ring: var(--color-on-dark);
}

.site-footer__inner {
  display: grid;
  gap: var(--space-2xl) var(--space-lg);
  padding-block: var(--space-xl);
  grid-template-areas:
    "brand"
    "nav"
    "wholesale";
}

.site-footer__brand {
  grid-area: brand;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

/* Footer-specific override: the footer's lockup was the largest instance
   of the icon+text markup (84px --logo-icon-height, the base
   .logo-lockup--vertical default with no smaller override applied), so
   .logo-lockup__img's header-sized 71.4375px default is too small here.
   166.6875px matches that markup's old rendered height at 84px (the same
   height-to-icon-height ratio measured in the header, 1.984375, scaled
   up), so the footer's logo doesn't change size alongside this swap. */
.site-footer .logo-lockup__img {
  height: 166.6875px;
}

.site-footer__nav {
  grid-area: nav;
}

.site-footer__wholesale {
  grid-area: wholesale;
}

/* Tablet: brand keeps its own row, nav and wholesale share the second. */
@media (min-width: 48rem) {
  .site-footer__inner {
    grid-template-columns: repeat(2, 1fr);
    grid-template-areas:
      "brand brand"
      "nav wholesale";
  }
}

/* Desktop: all three columns share one row and an equal third — the
   brand column no longer carries a tagline to reserve extra width for,
   just the centered vertical logo lockup (see .logo-lockup--vertical). */
@media (min-width: 64rem) {
  .site-footer__inner {
    grid-template-columns: repeat(3, 1fr);
    grid-template-areas: "brand nav wholesale";
    gap: var(--space-lg);
  }
}

.site-footer__nav-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-top: var(--space-md);
}

.site-footer__nav-list a {
  color: oklch(from var(--color-on-dark) l c h / 0.85);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  transition: color var(--duration-fast) var(--ease-out-expo);
}

.site-footer__nav-list a:hover,
.site-footer__nav-list a:focus-visible {
  color: var(--color-on-dark);
}

.site-footer__wholesale p {
  margin-top: var(--space-md);
  max-width: 32ch;
  color: oklch(from var(--color-on-dark) l c h / 0.8);
  line-height: 1.6;
}

.site-footer__wholesale .link-arrow {
  margin-top: var(--space-md);
  text-transform: uppercase;
}

.site-footer__bottom {
  padding-block: var(--space-lg);
  border-top: 1px solid oklch(from var(--color-on-dark) l c h / 0.15);
  font-size: 0.8125rem;
  color: oklch(from var(--color-on-dark) l c h / 0.65);
  text-align: center;
}

/* ==========================================================================
   Home — Hero
   ========================================================================== */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(100svh - var(--nav-height));
  background: var(--color-primary);
}

/* Hero-specific override: like the footer, the hero's lockup was the
   base (unscaled) --logo-icon-height: 84px instance of the icon+text
   markup, with no smaller per-context override, so it needs the same
   166.6875px height as .site-footer .logo-lockup__img rather than the
   header's default. */
.hero .logo-lockup__img {
  height: 166.6875px;
}

.hero__scroll-indicator {
  position: absolute;
  left: 50%;
  bottom: var(--space-lg);
  transform: translateX(-50%);
  display: flex;
  padding: 0;
  line-height: 0;
  color: var(--color-accent);
  opacity: 1;
  transition: opacity var(--duration-base) var(--ease-out-expo);
}

.hero__scroll-indicator.is-hidden {
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .hero .logo-lockup {
    animation: hero-logo-in 3s var(--ease-out-expo) 200ms both;
  }

  @keyframes hero-logo-in {
    from {
      opacity: 0;
      transform: translateY(12px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
}

/* ==========================================================================
   Home — Mission (identity statement between the hero and the teasers;
   no border, since the hero photo above already reads as a clean break
   — matches .beekeeper-cta's restrained, centered register, minus the
   border-top that section uses to separate itself from flat content)
   ========================================================================== */

.mission {
  padding-block: var(--space-3xl);
  text-align: center;
}

.mission__body {
  max-width: 60ch;
  margin-top: var(--space-sm);
  margin-inline: auto;
  line-height: 1.7;
  text-wrap: pretty;
}

.mission__body + .mission__body {
  margin-top: var(--space-sm);
}

.mission__link {
  margin-top: var(--space-lg);
}

/* ==========================================================================
   Home — Teasers (Our Story / Honey Collection)
   ========================================================================== */

.teaser {
  display: grid;
  grid-template-columns: 1fr;
}

.teaser__media {
  max-height: 100vh;
}

.teaser__media img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.teaser__content {
  display: flex;
  align-items: center;
  padding-block: var(--space-2xl);
}

.teaser__body {
  margin-top: var(--space-sm);
  max-width: 48ch;
  line-height: 1.6;
}

.teaser .link-arrow,
.teaser .btn--cta {
  margin-top: var(--space-lg);
}

@media (min-width: 64rem) {
  .teaser {
    grid-template-columns: 1fr 1fr;
    /* Fixed row height so both teasers match regardless of each source
       photo's native aspect ratio — letting the image dictate row height
       here made Our Story and Honey Collection wildly different heights.
       grid-auto-rows (not min-height on the container) so the row track
       itself is definite — a percentage height on .teaser__media img
       can't resolve against a container whose height is only implied. */
    grid-auto-rows: minmax(30rem, auto);
  }

  .teaser__media img {
    aspect-ratio: auto;
    height: 100%;
  }

  .teaser--reverse .teaser__media {
    order: 2;
  }
}

/* ==========================================================================
   Page Opener
   ========================================================================== */

.page-opener__image img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* Beekeeping-specific override: the shared rule above defaults to
   object-position: center (50% 50%), which crops into the beekeeper's
   head at this photo's tall aspect ratio against the hero's wide crop. */
.page-opener--beekeeping .page-opener__image img {
  object-position: center top;
}

/* Honey-Collection-specific override: the shared rule above defaults to
   object-position: center (50% 50%), which crops out the jars and front
   product spread at the bottom of this photo. Shifting past 50% on the
   Y axis crops more off the top and less off the bottom instead. */
.page-opener--honey-collection .page-opener__image img {
  object-position: center 65%;
}

.page-opener__content {
  padding-block: var(--space-xl) var(--space-2xl);
}

.page-opener__heading {
  /* Overrides .heading's literal gold: peach reads more clearly than
     gold on the primary-green band (see .impact, .page-opener__content
     below), same override as .impact__heading. */
  color: var(--color-on-dark);
  text-wrap: balance;
}

.page-opener__lede {
  margin-top: var(--space-md);
  max-width: 60ch;
  font-size: 1.125rem;
  line-height: 1.6;
  text-wrap: pretty;
}

@media (min-width: 64rem) {
  .page-opener__image img {
    aspect-ratio: 16 / 9;
  }
}

/* ==========================================================================
   Split Sections
   ========================================================================== */

.split-section {
  display: grid;
  grid-template-columns: 1fr;
}

.split-section__media img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.split-section__content {
  display: flex;
  align-items: center;
  padding-block: var(--space-2xl);
}

.split-section__body {
  max-width: 60ch;
  line-height: 1.7;
  text-wrap: pretty;
}

.split-section__heading + .split-section__body {
  margin-top: var(--space-md);
}

.split-section__body + .split-section__body {
  margin-top: var(--space-sm);
}

@media (min-width: 64rem) {
  .split-section {
    grid-template-columns: 1fr 1fr;
  }

  /* The image must fill whatever height the text column naturally sets,
     not contribute its own intrinsic proportions to the row's height —
     the "How it started" photo is tall at this crop and otherwise
     ballooned the whole row far past what its two paragraphs need.
     Taking the img out of flow (absolute, filling a stretched relative
     wrapper) removes it from the grid's auto-row-sizing calculation
     entirely, so the row is sized by text content alone. */
  .split-section__media {
    position: relative;
  }

  .split-section__media img {
    position: absolute;
    inset: 0;
    aspect-ratio: auto;
    height: 100%;
  }

  .split-section--reverse .split-section__media {
    order: 2;
  }
}

/* ==========================================================================
   Pull Quote
   ========================================================================== */

.pull-quote {
  padding-block: var(--space-3xl);
  background: var(--color-surface);
  text-align: center;
}

.pull-quote__text {
  max-width: 44ch;
  margin-inline: auto;
}

.pull-quote__text p {
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.25rem);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.pull-quote__attribution {
  margin-top: var(--space-md);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-muted);
}

/* ==========================================================================
   Values
   ========================================================================== */

.values {
  padding-block: var(--space-3xl);
}

.values__heading {
  max-width: 20ch;
  text-wrap: balance;
}

.values__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  margin-top: var(--space-xl);
}

.values__item p {
  margin-top: var(--space-2xs);
  max-width: 60ch;
  line-height: 1.6;
  text-wrap: pretty;
}

@media (min-width: 64rem) {
  .values__inner {
    display: grid;
    grid-template-columns: 1fr 1.6fr;
    align-items: start;
    gap: var(--space-2xl);
  }

  .values__list {
    margin-top: 0;
  }
}

/* ==========================================================================
   Impact (the human/programme story behind the honey — Beekeeping page)
   ========================================================================== */

/* Primary-green band, shared with .page-opener__content — the
   full-bleed band behind the heading + standfirst on the four
   interior-page headers (Honey Collection, Beekeeping, Our Story,
   Contact) — so both surfaces stay consistent. Plain field, no lattice
   overlay (the honeycomb stays with .site-header/.site-footer). Each
   band keeps its own padding declared separately. The contained content
   lives in the nested .impact__inner / .page-opener__inner container.

   Text: --color-on-dark (peach) on --color-primary measures ~7.8:1,
   clearing AA for body and large text. */
.impact,
.page-opener__content {
  background: var(--color-primary);
  color: var(--color-on-dark);
  --color-focus-ring: var(--color-on-dark);
}

.impact {
  padding-block: var(--space-3xl);
}

.impact__heading {
  max-width: 20ch;
  color: var(--color-on-dark);
  text-wrap: balance;
}

.impact__grid {
  display: grid;
  gap: var(--space-xl);
  margin-top: var(--space-xl);
}

/* Elevated body copy, not a heading: regular weight keeps it from
   competing with .impact__heading above it. Sized a step above
   .impact__body but well under heading scale. */
.impact__lead {
  max-width: 32ch;
  font-size: clamp(1.125rem, 1.05rem + 0.4vw, 1.3125rem);
  font-weight: 400;
  line-height: 1.5;
  text-wrap: balance;
}

.impact__body {
  max-width: 52ch;
  line-height: 1.7;
  text-wrap: pretty;
}

.impact__lead + .impact__body {
  margin-top: var(--space-md);
}

/* Subordinate to .impact__heading: sized and tracked down from the
   shared .subheading scale so it reads as one level below the
   section title, not a second instance of it. */
.impact__program-heading {
  color: var(--color-on-dark);
  font-size: 1.0625rem;
  letter-spacing: 0.12em;
  line-height: 1;
}

.impact__program-heading + .impact__body {
  margin-top: var(--space-sm);
}

.impact__list {
  margin-top: var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.impact__list li {
  padding-block: var(--space-2xs);
  border-top: 1px solid oklch(from var(--color-on-dark) l c h / 0.5);
}

/* Presented as a data row, not a stat-card grid: a genuine tabular
   reading of the four production numbers. Dividers, not cards, keep
   them from reading like a SaaS metric-tile template. Divider color is
   --color-on-dark (the section's own text color) at 0.5 opacity —
   measured at 3.2:1 against the primary-green field, clearing the
   SC 1.4.11 3:1 non-text threshold for a boundary that carries
   structural meaning. */
.impact__stats {
  display: grid;
  gap: var(--space-md);
  margin-top: var(--space-2xl);
  padding-top: var(--space-xl);
  border-top: 1px solid oklch(from var(--color-on-dark) l c h / 0.5);
}

.impact__stat-value {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
  font-size: clamp(1.75rem, 1.4rem + 1.2vw, 2.25rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.01em;
}

/* Decorative only — the stat's meaning is carried by the number/label
   text, not the glyph, so it's aria-hidden inside the dt. currentcolor
   picks up --color-on-dark from .impact, but set explicitly too so the
   icon stays on-brand even if pulled out of this flex context. */
.impact__stat-icon {
  flex-shrink: 0;
  color: var(--color-on-dark);
}

.impact__stat-label {
  margin-top: var(--space-3xs);
  font-size: 0.9375rem;
}

.impact__footnote {
  margin-top: var(--space-2xl);
  max-width: 60ch;
  font-size: 0.9375rem;
  line-height: 1.6;
  text-wrap: pretty;
}

@media (min-width: 48rem) {
  .impact__stats {
    grid-template-columns: repeat(4, 1fr);
  }

  .impact__stat + .impact__stat {
    padding-left: var(--space-md);
    border-left: 1px solid oklch(from var(--color-on-dark) l c h / 0.5);
  }
}

@media (min-width: 64rem) {
  .impact__grid {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2xl);
  }
}

/* ==========================================================================
   Why It Matters (brief context pause between the programme detail above
   and the shop handoff below — deliberately the lightest section on the
   page: a heading and three short paragraphs, no list, no stats)
   ========================================================================== */

.why-it-matters {
  padding-block: var(--space-3xl);
}

.why-it-matters__heading {
  max-width: 20ch;
  text-wrap: balance;
}

.why-it-matters__columns {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
  margin-top: var(--space-xl);
}

.why-it-matters__body {
  max-width: 60ch;
  line-height: 1.7;
  text-wrap: pretty;
}

/* The section's key statement — set apart from .why-it-matters__body via
   size and color, not restructured into a heading or pull quote. Size
   mirrors .impact__lead's lead-sentence scale for consistency with the
   page's existing "considered statement" register. Extra margin/padding
   (beyond the border-top separator every note-style paragraph would get)
   is the "breathing room" that marks this one out from the body copy
   above and below it.

   Literal --color-accent gold text on --color-bg measures 2.08:1 — below
   AA even at the large-text 3:1 threshold. This is the same pairing as
   the confirmed Heading-Gold Exception (DESIGN.md §3, ~2.1:1) and is
   applied here on the same basis: explicit brand-gold-as-text direction
   for this specific statement, not a silent accessibility trade-off.
   Don't extend literal gold to further body text without the same kind
   of explicit confirmation. */
.why-it-matters__note {
  margin-top: var(--space-2xl);
  padding-top: var(--space-xl);
  padding-bottom: var(--space-sm);
  border-top: 1px solid var(--color-border);
  font-size: clamp(1.125rem, 1.05rem + 0.4vw, 1.3125rem);
  line-height: 1.6;
  color: var(--color-accent);
  text-align: center;
  text-wrap: pretty;
}

@media (min-width: 64rem) {
  .why-it-matters__columns {
    flex-direction: row;
    gap: var(--space-2xl);
  }

  .why-it-matters__body {
    flex: 1;
  }
}

/* ==========================================================================
   Beekeeper CTA (mid-page invitation to the beekeeper audience — same
   centered, bordered CTA pattern as Page CTA below, just a wider text
   measure since this copy runs longer than a one-line handoff)
   ========================================================================== */

.beekeeper-cta {
  padding-top: var(--space-3xl);
  padding-bottom: var(--space-lg);
  border-top: 1px solid var(--color-border);
  text-align: center;
}

/* .beekeeper-cta__inner spans the full .container width (matching the
   two-column sections above), so the body paragraph gets its own
   readability cap here — same pattern as .impact__body / .why-it-matters__body. */
.beekeeper-cta__body {
  max-width: 60ch;
  margin-top: var(--space-sm);
  margin-inline: auto;
  line-height: 1.7;
  text-wrap: pretty;
}

.beekeeper-cta .btn--cta {
  margin-top: var(--space-lg);
}

/* Beekeeper application form (beekeeping.njk, #apply). Fields reuse the
   contact form's classes (.contact-form, __field, __label, __input,
   __textarea) so labels, inputs, spacing and focus/hover borders match it
   exactly; the rules below only cover what the contact form doesn't have.
   The section is centred, so the form is centred as a block and its own
   content left-aligned. main.js hides #apply on load and animates it open
   from the toggle button above. */
/* padding, not margin: the open/close animation runs on this element's
   height, so the gap above the form is part of what expands. */
/* "Apply to become a beekeeper" at the .btn tracking is ~384px – wider
   than a phone's content column – so this one may wrap (centred) instead
   of .btn's default nowrap overflowing the viewport. Unchanged wherever
   it fits on one line. */
.beekeeper-cta [data-apply-toggle] {
  max-width: 100%;
  white-space: normal;
  text-align: center;
}

.beekeeper-form-wrap {
  padding-top: var(--space-lg);
  text-align: left;
  /* Clears the sticky header (117px + its 7px tooth strip, the same at
     every breakpoint) when #apply is scrolled into view – deep link or
     focus – so the form's first field isn't tucked underneath it. */
  scroll-margin-top: 8rem;
}

.beekeeper-form {
  margin-inline: auto;
}

/* .beekeeper-cta .btn--cta above would also give the submit button its
   toggle's top margin; keep the contact form's own submit spacing. */
.beekeeper-form .btn--cta {
  margin-top: var(--space-2xs);
}

.beekeeper-form__optional {
  font-weight: 400;
  text-transform: none;
  color: var(--color-muted);
}

.beekeeper-form__hint {
  font-size: 0.875rem;
  color: var(--color-muted);
}

.beekeeper-form__fieldset {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* A <legend>, not a <label>, so it doesn't pick up the global label
   uppercase on its own; restated so it reads like every other field
   label in the form. */
.beekeeper-form__legend {
  padding: 0;
  margin-bottom: var(--space-2xs);
  text-transform: uppercase;
}

.beekeeper-form__options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-md);
}

/* Radio and consent rows are <label>s for a larger hit area; undo the
   global label uppercase – these are sentences, not field names. */
.beekeeper-form__option,
.beekeeper-form__consent {
  display: flex;
  gap: var(--space-2xs);
  text-transform: none;
  color: var(--color-ink);
  cursor: pointer;
}

.beekeeper-form__option {
  align-items: center;
}

.beekeeper-form__consent {
  align-items: flex-start;
  font-size: 0.9375rem;
  line-height: 1.5;
}

.beekeeper-form input[type="radio"],
.beekeeper-form input[type="checkbox"] {
  flex-shrink: 0;
  width: 1.125rem;
  height: 1.125rem;
  margin: 0;
  accent-color: var(--color-primary);
}

/* Optically centre the box on the first line of the consent sentence. */
.beekeeper-form__consent input[type="checkbox"] {
  margin-top: 0.2em;
}

.beekeeper-form__consent a {
  color: var(--color-accent-ink);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.beekeeper-form__consent a:hover,
.beekeeper-form__consent a:focus-visible {
  color: var(--color-accent-ink-hover);
}

/* Honeypot: off-screen rather than display:none (some bots skip hidden
   inputs); tabindex="-1" and aria-hidden in the markup keep it out of the
   tab order and the accessibility tree. */
.beekeeper-form__hp {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Status region: the shared .form-status styles (Form feedback, below)
   apply. The shared rule that cancels an empty status's flex gap is undone
   here so the space under "Submit application" stays exactly as it was
   before the form was wired up. */
.contact-form.beekeeper-form > .form-status:empty {
  margin-top: 0;
}

/* No-JS result notices (#apply-sent / #apply-error): centred as a block
   like the form in this centred section, text left-aligned like the form. */
.beekeeper-cta .form-notice {
  margin-inline: auto;
  text-align: left;
}

/* ==========================================================================
   Downloads (quiet supplementary resources, not a CTA — no border
   chrome, so it still reads as a trailing note rather than another
   section competing for attention, but generously padded and centered
   so it feels considered rather than appended)
   ========================================================================== */

.downloads {
  padding-top: var(--space-lg);
  padding-bottom: var(--space-3xl);
  text-align: center;
}

.downloads__label {
  font-size: 0.9375rem;
  font-weight: 600;
}

/* Items align to each other (icons share one vertical axis), while the
   list as a whole shrinks to its content width and centers via auto
   margins — flex align-items:center would center each link individually
   instead. */
.downloads__list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
  margin-top: var(--space-sm);
  margin-inline: auto;
  width: fit-content;
}

.downloads__icon {
  flex-shrink: 0;
}

.downloads__icon path,
.downloads__icon polyline {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ==========================================================================
   Page CTA (closing handoff to a conversion page)
   ========================================================================== */

.page-cta {
  padding-block: var(--space-3xl);
  border-top: 1px solid var(--color-border);
  text-align: center;
}

.page-cta__inner {
  max-width: 40ch;
  margin-inline: auto;
}

.page-cta__body {
  margin-top: var(--space-sm);
  line-height: 1.6;
}

.page-cta .btn--cta {
  margin-top: var(--space-lg);
}

/* ==========================================================================
   Process (Option B: a gold progression line threading four numbered
   circles through two paired steps, each pair sharing one image. The
   second pair mirrors the first — line/circles and image swap sides —
   per the approved mockup. Earns its numbering because the steps are a
   genuine ordered flow, not a decorative section eyebrow.

   Rail and content both use flex justify-content:space-between so
   circle 01 / step 1 share the same top edge and circle 02 / step 2
   share the same bottom edge, whatever the column's stretched height
   ends up being (driven by whichever of rail/content/media is tallest). */

.process {
  padding-block: var(--space-3xl);
}

.process__heading {
  max-width: 20ch;
  text-wrap: balance;
}

.process__pairs {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xl);
  margin-top: var(--space-xl);
}

.process__pair {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "rail content"
    "media media";
  column-gap: var(--space-lg);
  row-gap: var(--space-lg);
}

.process__rail {
  grid-area: rail;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

/* Confirmed gold exception, the same shape as the navbar cap and footer
   seam in DESIGN.md — a structural progression marker from the approved
   mockup, not decorative fill. The circle's peach fill (matching the
   page background, not the teal sections) punches through the line so
   it visibly threads behind, not through, each digit. */
.process__number {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 1.5px solid var(--color-accent);
  background: var(--color-bg);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--color-accent-ink);
  font-variant-numeric: tabular-nums;
}

.process__line {
  flex: 1 1 auto;
  width: 2px;
  min-height: 2rem;
  background: var(--color-accent);
}

/* Short trailing tail below the final circle (04) signals the sequence
   has ended, per the mockup — an extension past the rail's own box
   rather than part of the space-between distribution above. */
.process__rail--end::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -2rem;
  transform: translateX(-50%);
  width: 2px;
  height: 2rem;
  background: var(--color-accent);
}

.process__pair-content {
  grid-area: content;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-lg);
}

.process__step p {
  margin-top: var(--space-xs);
  max-width: 60ch;
  line-height: 1.6;
  text-wrap: pretty;
}

.process__pair-media {
  grid-area: media;
}

.process__pair-media img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

@media (min-width: 64rem) {
  .process__pair {
    grid-template-columns: auto 1fr 1fr;
    grid-template-areas: "rail content media";
    column-gap: var(--space-xl);
    align-items: stretch;
  }

  /* Mirrors the pair: image swaps to the outer-left edge, the gold
     rail/circles move to the outer-right edge, text stays adjacent to
     its rail on the new side. */
  .process__pair--reverse {
    grid-template-columns: 1fr 1fr auto;
    grid-template-areas: "media content rail";
  }

  .process__pair-media {
    position: relative;
  }

  .process__pair-media img {
    position: absolute;
    inset: 0;
    aspect-ratio: auto;
    height: 100%;
  }
}

/* ==========================================================================
   Contact
   ========================================================================== */

.contact {
  padding-block: var(--space-3xl);
}

.contact__inner {
  display: grid;
  gap: var(--space-2xl);
}

.contact__lede {
  margin-top: var(--space-md);
  max-width: 50ch;
  line-height: 1.6;
}

.contact__method {
  margin-top: var(--space-xl);
}

.contact__method-label {
  display: block;
  font-size: 0.9375rem;
  font-weight: 600;
}

.contact__method-link {
  position: relative;
  display: inline-block;
  margin-top: var(--space-2xs);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--color-primary);
}

.contact__method-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: currentcolor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-base) var(--ease-out-expo);
}

.contact__method-link:hover::after,
.contact__method-link:focus-visible::after {
  transform: scaleX(1);
}

.contact__address {
  margin-top: var(--space-md);
  font-style: normal;
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.6;
}

.contact__note {
  margin-top: var(--space-md);
  max-width: 50ch;
  font-size: 0.9375rem;
  color: var(--color-muted);
  line-height: 1.6;
}

.contact-form-wrap {
  margin-top: var(--space-xl);
}

.contact-form__intro {
  font-size: 0.9375rem;
  font-weight: 600;
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  max-width: 28rem;
  margin-top: var(--space-sm);
}

.contact-form__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.contact-form__label {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-ink);
}

/* --color-border is too close in lightness to --color-bg/--color-surface
   for a UI-boundary role (SC 1.4.11 needs 3:1); --color-muted clears it
   comfortably against both, so it carries the default field border here
   instead of the hairline-divider border token. */
.contact-form__input,
.contact-form__textarea {
  width: 100%;
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-surface);
  border: 1.5px solid var(--color-muted);
  border-radius: 0;
  font-size: 1rem;
  color: var(--color-ink);
  transition: border-color var(--duration-fast) var(--ease-out-expo);
}

.contact-form__textarea {
  min-height: 8rem;
  resize: vertical;
}

.contact-form__input:hover,
.contact-form__textarea:hover,
.contact-form__input:focus-visible,
.contact-form__textarea:focus-visible {
  border-color: var(--color-primary);
}

.contact-form .btn--cta {
  align-self: flex-start;
  margin-top: var(--space-2xs);
}

/* ==========================================================================
   Form feedback (shared by every validated form – form-validator.js)
   Field errors, invalid borders, the submit status region, the busy
   button, the no-JS result notices and the honeypot. None of it shows
   until there's something to say, so a form at rest looks exactly as
   it did before validation was wired up.
   ========================================================================== */

.form-error {
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--color-error);
}

/* Empty error slots stay in the DOM (each field's aria-describedby points
   at one) but take no room: cancel the field's 8px flex gap above them. */
.form-error:empty {
  margin-top: calc(-1 * var(--space-2xs));
}

.contact-form__input[aria-invalid="true"],
.contact-form__textarea[aria-invalid="true"] {
  border-color: var(--color-error);
}

/* Submit result from the handler (role="status", aria-live="polite"). */
.form-status {
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* Kept rendered while empty so screen readers announce what's added
   later; the negative margin cancels the form's gap so it adds no space. */
.contact-form > .form-status:empty {
  margin-top: calc(-1 * var(--space-md));
}

.form-status.success {
  font-weight: 600;
  color: var(--color-primary);
}

.form-status.error {
  font-weight: 600;
  color: var(--color-error);
}

.form-status.error-list ul {
  margin-top: var(--space-2xs);
  padding-left: 1.25em;
  font-weight: 400;
  list-style: disc;
}

.contact-form .btn--cta.is-loading {
  cursor: progress;
  opacity: 0.75;
}

/* No-JS result: the handler redirects to #<form>-sent / #<form>-error and
   the matching notice appears; otherwise they're never shown. */
.form-notice {
  display: none;
  max-width: 28rem;
  margin-top: var(--space-sm);
  padding: var(--space-sm);
  border: 1.5px solid currentColor;
  font-weight: 600;
  line-height: 1.5;
}

.form-notice:target {
  display: block;
}

/* Jumping to the #fragment focuses the notice (tabindex="-1", so screen
   readers start there); it isn't interactive, and its own border already
   frames it – no second focus ring around it. */
.form-notice:focus {
  outline: none;
}

.form-notice--success {
  color: var(--color-primary);
}

.form-notice--error {
  color: var(--color-error);
}

.form-notice a {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Honeypot: off-screen rather than display:none (some bots skip hidden
   inputs); tabindex="-1" and aria-hidden in the markup keep it out of the
   tab order and the accessibility tree. */
.form-honeypot {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.contact__social {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-top: var(--space-xl);
}

.contact__social-label {
  flex-shrink: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-muted);
}

/* Eight icons don't fit beside the label on narrow phones: wrap them
   onto further rows (the same gap applies between rows) instead of
   letting the row's min-content width push the whole contact column
   past the viewport. min-width: 0 lets this flex item shrink below
   that min-content width so the wrap can happen; flex-shrink: 0 on the
   label above keeps "Find us on" on one line while it does. */
.contact__social-links {
  display: flex;
  flex-wrap: wrap;
  min-width: 0;
  gap: var(--space-2xs);
}

/* When the eight icons can't all sit beside the label (label ~85px +
   --space-sm gap + 8 x 2.5rem icons + 7 gaps ≈ 477px of row width),
   cap the icon area at four icons so the wrap is an even 4 + 4 rather
   than 7 + 1 or 5 + 3. Keyed to the row's own width (container query),
   not the viewport, since the row sits in a half-width column on
   desktop. Below ~285px of row width even four don't fit and the
   icons fall back to wrapping naturally. */
.contact__social {
  container-type: inline-size;
}

@container (max-width: 30rem) {
  .contact__social-links {
    max-width: calc(4 * 2.5rem + 3 * var(--space-2xs));
  }
}

/* Literal --color-accent (not --color-accent-ink) is intentional here,
   matching the logo-lockup treatment: a decorative brand-gold icon fill
   rather than text carrying a contrast requirement. It clears 3:1 against
   --color-surface but not against --color-bg; each link still has an
   aria-label so the control is identifiable independent of icon contrast. */
.contact__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1.5px solid var(--color-border);
  border-radius: 0;
  color: var(--color-accent);
  background: var(--color-surface);
  transition:
    color var(--duration-fast) var(--ease-out-expo),
    border-color var(--duration-fast) var(--ease-out-expo);
}

.contact__social-link:hover,
.contact__social-link:focus-visible {
  color: var(--color-accent-ink-hover);
  border-color: var(--color-accent-ink-hover);
}

@media (min-width: 64rem) {
  .contact__inner {
    grid-template-columns: 1fr 1fr;
  }
}

/* ==========================================================================
   Product Grid
   ========================================================================== */

.product-grid-section {
  padding-block: var(--space-3xl);
}

/* Category switcher for the collection (Honey / Gifts & Accessories). Deliberately
   not the .btn/pill or .site-nav underline-on-hover treatments: this is
   its own persistent-baseline pattern — a full-width hairline the active
   tab's indicator sits on — closer to an editorial section-navigation
   device than a generic UI tab component. Gold is reserved for
   product-linked moments only (see the Provenance Rule in DESIGN.md), so
   the active state is carried by --color-primary, the site's other
   identity color, not a third structural use of --color-accent. */
.collection-tabs {
  display: flex;
  gap: var(--space-lg);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Firefox/modern-Chromium equivalent of hiding the scrollbar without
     losing the scroll behavior itself — a graceful fallback once more
     categories push this bar past the viewport width. */
  scrollbar-width: none;
  border-bottom: 1px solid var(--color-border);
}

.collection-tabs::-webkit-scrollbar {
  display: none;
}

.collection-tabs__tab {
  position: relative;
  flex-shrink: 0;
  padding-block: var(--space-sm);
  font-size: 0.9375rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
  color: var(--color-muted);
  transition: color var(--duration-fast) var(--ease-out-expo);
}

.collection-tabs__tab::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--color-primary);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-base) var(--ease-out-expo);
}

.collection-tabs__tab:hover,
.collection-tabs__tab:focus-visible {
  color: var(--color-ink);
}

.collection-tabs__tab[aria-selected="true"] {
  color: var(--color-primary);
  font-weight: 600;
}

.collection-tabs__tab[aria-selected="true"]::after {
  transform: scaleX(1);
}

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-2xl) var(--space-lg);
  margin-top: var(--space-xl);
  list-style: none;
  padding: 0;
}

/* auto-fit (above) collapses tracks with no content and redistributes
   their space to whatever tracks ARE occupied — exactly what the Honey
   grid wants once it's full of cards, but the Gifts & Accessories and
   Hospitality grids hold only a few cards, so at wide widths auto-fit would stretch them
   to fill the row. auto-fill keeps every track the fit-width algorithm
   would otherwise create, occupied or not, so each card sits at one
   card's width from the left with the remaining tracks left empty
   rather than stretched or centered — same sizing math, same
   breakpoints, as the Honey grid it's still a .product-grid. */
.collection-tabs__panel[aria-labelledby="collection-tab-gifts"] .product-grid,
.collection-tabs__panel[aria-labelledby="collection-tab-hospitality"] .product-grid {
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

.product-card {
  display: flex;
  flex-direction: column;
}

.product-card__visual {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--color-surface);
}

.product-card__photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--duration-base) var(--ease-out-expo);
}

.product-card:hover .product-card__photo {
  transform: scale(1.04);
}

/* Pre-photography placeholder jar (see jar-placeholder.njk) — a plain
   illustrated glass/lid drawn from the same border/surface/accent tokens
   as the rest of the system, standing in for a product with no real
   photography yet. Sizing is scoped per context (card vs. detail)
   below; the glass/neck/lid/svg rules are shared. */
.jar-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.jar-placeholder__svg {
  width: auto;
  height: 100%;
  transition: transform var(--duration-base) var(--ease-out-expo);
}

.jar-placeholder__glass {
  fill: none;
  stroke: var(--color-border);
  stroke-width: 1.5;
}

.jar-placeholder__neck {
  fill: var(--color-surface);
  stroke: var(--color-border);
  stroke-width: 1.5;
}

/* Gold to match the real jars' lids. --color-accent is only ~1.8:1
   against --color-surface, so the accent-ink stroke keeps the lid's
   edge defined; opaque so the neck's outline doesn't show through. */
.jar-placeholder__lid {
  fill: var(--color-accent);
  stroke: var(--color-accent-ink);
  stroke-width: 1.5;
}

/* Neutral no-photography stand-in for gifts/accessories (see
   product-placeholder.njk): the brand bee mark in the same --color-border
   tone the jar placeholder draws its glass with, centered on the
   surface panel. Same hover scale as the photos/jar so every card in a
   row responds alike. */
.product-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.product-placeholder__mark {
  width: 42%;
  max-width: 180px;
  height: auto;
  fill: var(--color-border);
  transition: transform var(--duration-base) var(--ease-out-expo);
}

.product-card:hover .product-placeholder__mark {
  transform: scale(1.04);
}

/* Desktop focus view: .product-detail__media takes its height from the
   row there (align-items: stretch, aspect-ratio: auto), so it's the
   media's own content that keeps it from collapsing to the text
   column's height. A photo or the jar placeholder's 320px SVG does that;
   the much shorter bee mark doesn't, so this gives the placeholder the
   same 320px floor the jar placeholder has. Mobile keeps the base 1/1
   box untouched. */
@media (min-width: 64rem) {
  .product-detail__media .product-placeholder {
    min-height: 320px;
  }
}

.product-card__visual .jar-placeholder {
  padding: var(--space-lg);
}

.product-card__visual .jar-placeholder__svg {
  max-height: 220px;
}

.product-card:hover .jar-placeholder__svg {
  transform: scale(1.04);
}

/* Monofloral/multifloral corner mark. A translucent, blurred backing disc
   carries legibility across all nine photos — including the busier ones
   (gift box, bulk tubs, mini-jar clusters) — without the mark reading as a
   decorative sticker; backdrop-filter is a progressive enhancement, the
   82%-opaque fill alone still separates the icon from the photo beneath. */
.product-card__floral-badge {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(2.25rem, 6vw, 2.75rem);
  aspect-ratio: 1;
  border-radius: 0;
  background: oklch(from var(--color-bg) l c h / 0.82);
  box-shadow: 0 1px 4px oklch(0 0 0 / 0.2);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.product-card__floral-icon {
  width: 62%;
  height: 62%;
  fill: var(--color-structural);
}

/* Multifloral's three-hexagon variant (see floral-badge.njk) — same
   modifier pattern as .product-card__floral-type.is-multifloral below,
   applied here since the icon is currently toggled off via
   data-floral-icons="off" rather than a class on the badge itself. */
.product-card__floral-icon--multifloral {
  fill: var(--color-multifloral);
}

/* Toggle point: intentionally disabled, not dead code. The corner icon
   is hidden per client request while the "Monofloral"/"Multifloral"
   text label stays as-is; the markup/CSS above is untouched so this is
   trivially reversible — remove data-floral-icons="off" from
   .product-grid (or flip it to "on") in honey-collection.njk to
   restore the icon. */
.product-grid[data-floral-icons="off"] .product-card__floral-badge {
  display: none;
}

.product-card__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding-top: var(--space-md);
}

/* Short qualifier under a product name (e.g. the taster stand's "Fits
   21 × 28g glass jars"). Muted ink, not gold: it's information about
   the product, not part of the heading. --color-muted is 5.2:1 on bg. */
.product-card__subtitle,
.product-detail__subtitle {
  margin-top: var(--space-2xs);
  font-size: 0.9375rem;
  color: var(--color-muted);
}

.product-card__desc {
  margin-top: var(--space-2xs);
  line-height: 1.5;
  text-wrap: pretty;
}

/* margin-top: auto pins the label to the bottom of the stretched body,
   directly above the meta row, so it lines up across a row however many
   lines a neighbor's description wraps to. The minimum gap from the
   description moves to padding-top so the tallest card in a row (zero
   free space) still keeps it. */
.product-card__floral-type {
  margin-top: auto;
  padding-top: var(--space-sm);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-align: right;
  color: var(--color-primary);
}

/* Multifloral gets its own color (see --color-multifloral); every other
   value (Monofloral, TBD, "Monofloral (unconfirmed)") stays the
   .product-card__floral-type default above. */
.product-card__floral-type.is-multifloral {
  color: var(--color-multifloral);
}

.product-card__meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  /* auto, not a fixed value: pushes the price/CTA row to the bottom of
     the stretched card so it lines up across a row even when a neighbor's
     description wraps to an extra line. Verified via bounding-box check —
     a fixed margin left rows misaligned by the wrap difference. */
  margin-top: auto;
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-border);
}

/* When a floral label sits above the meta row, the label's auto margin
   already takes the free space; a second auto margin here would split it
   and leave the label floating. Cards without a label (gift packs) keep
   the meta row's own auto margin above. */
.product-card__floral-type + .product-card__meta {
  margin-top: 0;
}

.product-card__price {
  font-weight: 700;
  /* accent-ink, not the literal accent hex — the raw gold only hits
     2.1:1 against the page background (see token comment above). */
  color: var(--color-accent-ink);
}

.product-card__cta {
  padding: 0;
  font-size: 0.9375rem;
  color: var(--color-accent-ink);
}

.product-card__cta:hover,
.product-card__cta:focus-visible {
  color: var(--color-accent-ink-hover);
}

/* ==========================================================================
   Product Detail (Honey Collection focus view)
   ========================================================================== */

/* .container, not a bespoke width: this page is utility content (a size
   selector, a price, an action someone needs to actually use) rather
   than the editorial teaser__/split-section__ pattern, so it's meant to
   read as contained and legible the way the Honey Collection grid does
   — not bled to the viewport edge the way those sections deliberately
   are. Combining the grid layout and .container on one element mirrors
   .value-prop__inner, the site's other image+text grid that's meant to
   sit fully inset rather than edge-to-edge.

   padding-top lives here, once, instead of being repeated as a top
   inset on both .product-detail__media and .product-detail__content:
   with no padding of its own this element sat flush against the sticky
   nav, so the media column's surface-color fill — which paints through
   its own padding box, not just its content box — touched the nav
   directly even though padding technically existed inside it.
   --space-3xl, not the 64px that was duplicated on the two children:
   it's the top spacing every other section on the site actually uses
   (.product-grid-section, .contact, .values, .process, .pull-quote). */
.product-detail {
  display: grid;
  grid-template-columns: 1fr;
  padding-block: var(--space-3xl);
}

/* Inline and bottom only — no padding-top here any more, that's the
   parent's job now (see .product-detail above). This is purely the mat
   around the photo on the sides that still need one. */
.product-detail__media {
  position: relative;
  aspect-ratio: 1 / 1;
  padding-inline: var(--space-lg);
  padding-bottom: var(--space-lg);
  background: var(--color-surface);
}

/* 1/1 is the product photos' real native ratio (every source PNG is
   1080x1080, the product shot centered on a square canvas) — not a
   guess. object-fit: contain, not cover: with the box already matching
   the photo's own ratio the two render identically today, but contain
   is what actually guarantees the whole photo stays visible if a future
   photo ships at a different ratio, instead of quietly cropping it. */
.product-detail__photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.product-detail__media .jar-placeholder__svg {
  max-height: 320px;
}

.product-detail__content {
  padding-block: var(--space-xl) var(--space-2xl);
}

.product-detail__back {
  color: var(--color-accent-ink);
}

.product-detail__back:hover,
.product-detail__back:focus-visible {
  color: var(--color-accent-ink-hover);
}

.product-detail__floral-type {
  margin-top: var(--space-lg);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--color-structural);
}

/* Same modifier as .product-card__floral-type.is-multifloral — kept in
   sync with the selected varietal on the gift-pack page by main.js. */
.product-detail__floral-type.is-multifloral {
  color: var(--color-multifloral);
}

.product-detail__name {
  margin-top: var(--space-2xs);
}

/* .product-detail__description: the gift-pack focus view's equivalent of
   .product-detail__tasting — same prose treatment, distinct name because
   "tasting note" doesn't apply outside the honey varietal pages. */
.product-detail__tasting,
.product-detail__description {
  margin-top: var(--space-lg);
  max-width: 60ch;
  font-size: 1.0625rem;
  line-height: 1.7;
  text-wrap: pretty;
  white-space: pre-line;
}

.product-detail__pairing {
  margin-top: var(--space-md);
  max-width: 60ch;
  line-height: 1.7;
  text-wrap: pretty;
}

.product-detail__pairing strong {
  color: var(--color-ink);
  font-weight: 600;
}

.product-detail__form {
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  max-width: 24rem;
  border-top: 1px solid var(--color-border);
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.product-detail__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

/* Sits where .product-detail__field's varietal/size <select> would on a
   fixed-assortment entry (no selector to show) — same muted-prose
   treatment as .product-detail__pairing, no max-width clamp since this
   is a single short line rather than running copy. */
.product-detail__assortment-note {
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--color-muted);
}

/* Six-jar assortment stepper (gift-pack-6 only): one row per honey
   varietal, quantity controlled by a pair of round +/- buttons rather
   than a native <input type="number"> — full control over the disabled
   states main.js drives (plus-button cap at 6, minus-button floor at 0)
   without fighting native spinner UI. */
.varietal-stepper-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

.varietal-stepper-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
}

.varietal-stepper-row__name {
  font-size: 0.9375rem;
  color: var(--color-ink);
}

.varietal-stepper {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
}

/* Same border/hover language as .product-detail__select: --color-muted
   border at rest, --color-primary on hover/focus — the stepper reads as
   a sibling of the site's one other form control, not a bespoke widget. */
.varietal-stepper__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 1.5px solid var(--color-muted);
  border-radius: 0;
  background: var(--color-surface);
  color: var(--color-ink);
  font-size: 1rem;
  line-height: 1;
  transition: border-color var(--duration-fast) var(--ease-out-expo), color var(--duration-fast) var(--ease-out-expo);
}

.varietal-stepper__btn:hover:not(:disabled),
.varietal-stepper__btn:focus-visible:not(:disabled) {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* Muted, not hidden — a capped plus button or a zeroed minus button is
   still a meaningful part of the row (a screen reader still hears "0",
   "Increase X quantity, disabled"), not something to remove. */
.varietal-stepper__btn:disabled {
  color: var(--color-muted);
  opacity: 0.5;
  cursor: not-allowed;
}

.varietal-stepper__count {
  min-width: 1.5rem;
  text-align: center;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Same divider role as .product-detail__form's own top border — marks
   the boundary between the list (input) and this running summary
   (status) rather than decorating it. */
.varietal-stepper-total {
  margin-top: var(--space-sm);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-border);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-ink);
}

/* Mirrors .product-detail__price.is-confirmed: the same accent-ink
   "this is real/ready now" cue, triggered at the moment the six-jar
   total is met rather than the moment a varietal is picked. */
.varietal-stepper-total.is-complete {
  color: var(--color-accent-ink);
}

.product-detail__label {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-ink);
}

/* Same rationale as .contact-form__input: --color-muted, not --color-border,
   carries the default field border so it clears the 3:1 non-text contrast
   SC 1.4.11 needs against the surrounding page background. Plain native
   <select>, no custom listbox/appearance override. */
.product-detail__select {
  width: 100%;
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-surface);
  border: 1.5px solid var(--color-muted);
  border-radius: 0;
  font-size: 1rem;
  color: var(--color-ink);
  transition: border-color var(--duration-fast) var(--ease-out-expo);
}

.product-detail__select:hover,
.product-detail__select:focus-visible {
  border-color: var(--color-primary);
}

/* Price left, order link right on one line wherever both fit. Neither
   wraps internally (nowrap on each); when the two don't fit side by side
   (long prices like "R1,350.00 per 2.8 kg", or narrow phones), the row
   wraps and the link drops to its own line, kept right-aligned by its
   margin-left: auto. */
.product-detail__purchase {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs) var(--space-md);
}

/* Default state is the "Pricing on request" placeholder — italic/muted
   so it reads as honest placeholder copy, not an invented price. The
   .is-confirmed modifier (toggled by main.js to match the selected
   size — see the pricesBySize lookup on the <option> elements) swaps in
   the same weight/color treatment as a real price gets on the grid
   card (.product-card__price), so a confirmed price reads as a real
   price the moment one is selected. */
.product-detail__price {
  font-size: 0.9375rem;
  font-style: italic;
  white-space: nowrap;
}

.product-detail__price.is-confirmed {
  font-weight: 700;
  font-style: normal;
  color: var(--color-accent-ink);
}

/* "Order on WhatsApp" link (order-cta.njk). It was a <button>, so the
   padding and letter-spacing below restate what the browser's button
   defaults gave it – the link keeps exactly the same size, tracking and
   position in the purchase row. */
.product-detail__cta {
  margin-left: auto;
  padding: 1px 6px;
  letter-spacing: normal;
  white-space: nowrap;
  color: var(--color-accent-ink);
}

.product-detail__cta:hover,
.product-detail__cta:focus-visible {
  color: var(--color-accent-ink-hover);
}

/* Not orderable yet – the six-jar stepper below six jars: main.js drops
   the href and sets aria-disabled="true", so it can't be clicked or
   focused. Muted, not hidden. Out-specifies the hover rule above and the
   .link-arrow arrow nudge so it never looks interactive. */
.product-detail__cta[aria-disabled="true"] {
  color: var(--color-muted);
  cursor: not-allowed;
}

.product-detail__cta[aria-disabled="true"]:hover span {
  transform: none;
}

@media (min-width: 64rem) {
  .product-detail {
    grid-template-columns: 1fr 1fr;
    /* column-gap, not padding on either child: the space belongs to the
       gap between the columns, not to the media or content column
       individually. --space-2xl matches .value-prop__inner's desktop
       gap, the site's other container-wrapped image+text grid. */
    column-gap: var(--space-2xl);
    /* stretch, not start: both columns now span the full row height
       evenly, so media and content end at the same y (not just start at
       it) — no more empty space below a shorter media box. The photo
       itself doesn't stretch or distort to match: object-fit: contain
       on .product-detail__photo (unchanged) keeps it at its own true
       proportions and centers it in whatever extra vertical space the
       surrounding box gains; only the box grows, never the image. */
    align-items: stretch;
  }

  .product-detail__media {
    padding-inline: var(--space-2xl);
    padding-bottom: var(--space-2xl);
    /* aspect-ratio: 1/1 (base rule) only sizes this box when its height
       is otherwise free to be "auto" — align-items: stretch now supplies
       a definite height from the row instead, so the ratio has nothing
       left to resolve here. Explicit override so that's a stated fact
       about this breakpoint, not an implicit side effect of stretch. */
    aspect-ratio: auto;
  }

  .product-detail__content {
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* No top component: duplicated .product-detail__media's old top
       padding at the same value, both existing only to fake a gap from
       the nav that .product-detail's own padding-top now provides once,
       for real. Bottom is unrelated (end-of-content spacing) and stays. */
    padding-block: 0 var(--space-2xl);
  }
}
