/* ==========================================================================
   AGRIYANA — Craft layer

   Loads last. Everything here either refines a component that already exists
   in components.css or adds one that did not. Kept separate so the original
   component layer stays readable and this file can be diffed on its own.

   Section index
     1  Texture and rules ......... grain, contours, hairlines
     2  Section heads ............. numbered, with a rule that draws
     3  Announcement ticker ....... marquee replacement for .strip
     4  Header ..................... mega menu, search, tools
     5  Product card v2 ........... variants, discount, stock, quick add
     6  Category tiles ............ grouped home / farm
     7  Machinery spec cards ...... the four real products
     8  Seasonal strip ............ what is fresh now
     9  Seller band ............... become a seller
     10 Credential wall ........... the documents that exist
     11 Footer refinements
     12 Responsive corrections .... must stay last
   ========================================================================== */

/* ==================================================================== 1. texture */

/* A single tileable noise texture, inlined so it costs no request. It sits at
   very low opacity over flat colour fields to stop large areas of bone or
   forest reading as dead flat digital colour. */
.grain-layer { position: relative; isolation: isolate; }
.grain-layer::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: var(--grain-opacity);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  mix-blend-mode: multiply;
}
[data-theme='dark'] .grain-layer::before { mix-blend-mode: screen; opacity: calc(var(--grain-opacity) * .6); }

/* Topographic contour lines. Used behind quiet sections so the page has depth
   without another photograph. Purely decorative, never carries meaning. */
.contour-bg { position: relative; isolation: isolate; overflow: hidden; }
.contour-bg > .contour-svg {
  position: absolute;
  inset: -10% -5%;
  width: 110%;
  height: 120%;
  z-index: -1;
  pointer-events: none;
  color: var(--contour-ink);
}
.contour-svg path { fill: none; stroke: currentColor; stroke-width: 1.25; vector-effect: non-scaling-stroke; }

/* ==================================================================== 2. section heads */

.sec-num {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  font-weight: 500;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: var(--s-4);
}
.sec-num::before {
  content: attr(data-n);
  display: grid;
  place-items: center;
  min-width: 26px;
  height: 20px;
  padding: 0 6px;
  border: 1px solid var(--border);
  border-radius: var(--r-chip);
  color: var(--accent-ink);
  background: var(--accent-soft);
  font-weight: 600;
  letter-spacing: .04em;
}
.on-band .sec-num { color: var(--band-fg-faint); }
.on-band .sec-num::before { background: rgba(238, 155, 60, .13); border-color: var(--band-border); color: var(--band-accent); }

/* the rule that runs the width of the section and draws itself on arrival */
.sec-rule { height: 1px; background: var(--hairline); transform-origin: left center; margin-bottom: var(--s-6); }
html.m-ready .sec-rule { transform: scaleX(0); transition: transform var(--dur-4) var(--ease-out); }
html.m-ready .sec-rule.is-in { transform: scaleX(1); }
.on-band .sec-rule { background: var(--band-hairline); }

/* headline sizing: the existing .sec-head is kept, this only tightens type */
.sec-head h2 {
  font-size: var(--t-2xl);
  letter-spacing: var(--tr-tight);
  line-height: var(--lh-snug);
  text-wrap: balance;
}
.sec-head-copy > p:not(.eyebrow) { max-width: 54ch; text-wrap: pretty; }

/* ==================================================================== 3. ticker */

.ticker {
  background: var(--forest-900);
  color: #C7D8CB;
  border-bottom: 1px solid rgba(255, 255, 255, .06);
}
.ticker .marquee-track {
  gap: 0;
  min-height: 36px;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .09em;
  text-transform: uppercase;
}
.tick-item {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  padding-inline: var(--s-6);
  white-space: nowrap;
}
.tick-item b { color: var(--harvest-400); font-weight: 600; }
.tick-item .ico { width: 14px; height: 14px; color: var(--sprout-500); flex: none; }
.tick-sep { width: 3px; height: 3px; border-radius: 50%; background: rgba(255, 255, 255, .28); flex: none; }

/* ==================================================================== 4. header */

/* --- nav proportions --------------------------------------------------
   Reported as "cluttered, too small, too much padding left and right", and
   the measurements agreed. The header sat inside the 1320px reading container
   with a 52px gutter, so at 1440 the five links, the search field and five
   icon buttons were squeezed into the middle ~1216px with dead space either
   side — everything small and touching, framed by emptiness. A header is
   chrome, not reading matter: it takes the wide container and a smaller
   gutter, which is what gives the items room to separate.

   The bar also grows 72 → 80px and the links 13 → 15px. 13px in a 72px bar
   was the "too small" part. */
.site-nav .nav-in {
  max-width: var(--container-wide);
  padding-inline: clamp(16px, 2.4vw, 34px);
}
:root { --nav-h: 80px; }
@media (max-width: 700px) { :root { --nav-h: 64px; } }

.nav-links { gap: var(--s-1); }
.nav-link { font-size: var(--t-base); height: 44px; padding-inline: var(--s-5); }
.nav-search { max-width: 440px; margin-inline: var(--s-5); }
.nav-tools { gap: var(--s-2); }

.site-nav { border-bottom: 1px solid transparent; }
.site-nav::after {
  /* the hairline is a pseudo-element so it can fade rather than pop on scroll */
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--border);
  opacity: 0;
  transition: opacity var(--dur-2) var(--ease-out);
}
.site-nav.is-stuck::after { opacity: 1; }
.nav-in { min-height: var(--nav-h); }

/* nav links get an underline that grows from the centre, not a background pill */
.nav-link { background: transparent !important; }
.nav-link::after {
  content: '';
  position: absolute;
  left: var(--s-4); right: var(--s-4);
  bottom: 6px;
  height: 2px;
  border-radius: 2px;
  background: var(--brand);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--dur-2) var(--ease-spring);
}
.nav-link:hover { color: var(--fg); }
.nav-link:hover::after,
.nav-link[aria-expanded='true']::after { transform: scaleX(1); }
.nav-link[aria-current='page'] { color: var(--brand-ink); }
.nav-link[aria-current='page']::after { transform: scaleX(1); }

/* --- mega menu -------------------------------------------------------
   The panel is anchored to the HEADER, not to its trigger. Centring a 900px
   panel on the "Shop" button pushed its left edge to -69px at 1440, because
   the trigger sits well left of centre. Anchoring to the sticky header and
   centring in the viewport means the panel is correct at every width the mega
   is visible at, with no per-breakpoint nudging.

   `.has-mega` is therefore deliberately NOT positioned — it must not become
   the containing block. */
.has-mega { position: static; }
.nav-link-mega { display: inline-flex; align-items: center; gap: 6px; border: 0; cursor: pointer; font-family: inherit; }
.nav-link-mega .ico { width: 15px; height: 15px; transition: transform var(--dur-2) var(--ease-out); }
.nav-link-mega[aria-expanded='true'] .ico { transform: rotate(180deg); }

.mega {
  position: absolute;
  z-index: var(--z-mega);
  top: calc(100% + 8px);
  left: 50%;
  width: min(1000px, calc(100vw - var(--gutter) * 2));
  padding: var(--s-7);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-xl);
  display: grid;
  grid-template-columns: 1fr 1fr .9fr;
  grid-template-areas:
    'home farm feature'
    'all  all  feature';
  gap: var(--s-6) var(--s-7);
  /* closed state: nudged up and scaled a hair, so opening reads as unfolding */
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -8px) scale(.985);
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-2) var(--ease-soil),
    visibility 0s linear var(--dur-2);
}
.mega.is-open {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
  transition-delay: 0s;
}
.mega-col h3 {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  font-weight: 500;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: var(--s-4);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--hairline);
}
.mega-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.mega-link {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3);
  margin-inline: calc(var(--s-3) * -1);
  border-radius: var(--r-ctl);
  text-decoration: none;
  color: var(--fg);
  font-size: var(--t-base);
  font-weight: 600;
  transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.mega-link:hover { background: var(--surface-2); color: var(--brand-ink); }
.mega-link .ico { width: 18px; height: 18px; color: var(--fg-faint); transition: color var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out); flex: none; }
.mega-link:hover .ico { color: var(--brand); transform: translateX(2px); }
.mega-link .n {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  color: var(--fg-faint);
  font-weight: 500;
}
/* the panel's own way to the full catalogue, since the Shop button is a
   disclosure control and never navigates */
.mega-all {
  grid-area: all;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-ctl);
  text-decoration: none;
  color: var(--fg);
  transition: background-color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out);
}
.mega-all:hover { background: var(--brand-soft); border-color: var(--brand); border-style: solid; }
.mega-all b { display: block; font-family: var(--font-display); font-size: var(--t-base); font-weight: 700; }
.mega-all span span { font-size: var(--t-xs); color: var(--fg-subtle); }
.mega-all .ico { color: var(--brand); transition: transform var(--dur-1) var(--ease-out); }
.mega-all:hover .ico { transform: translateX(4px); }

.mega-col:nth-of-type(1) { grid-area: home; }
.mega-col:nth-of-type(2) { grid-area: farm; }

.mega-feature {
  grid-area: feature;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 230px;
  padding: var(--s-5);
  border-radius: var(--r-card);
  overflow: hidden;
  isolation: isolate;
  text-decoration: none;
  color: #fff;
  background: var(--forest-900);
}
.mega-feature img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; transition: transform var(--dur-4) var(--ease-out); }
.mega-feature::after { content: ''; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, rgba(6,21,13,.94), rgba(6,21,13,.35) 60%, rgba(6,21,13,.1)); }
.mega-feature:hover img { transform: scale(1.06); }
.mega-feature .eyebrow { color: var(--harvest-400); }
.mega-feature b { font-family: var(--font-display); font-size: var(--t-lg); letter-spacing: var(--tr-snug); display: block; margin-bottom: 4px; }
.mega-feature span { font-size: var(--t-sm); color: rgba(255,255,255,.78); }

@media (max-width: 1079px) { .mega { display: none !important; } }

/* --- search ---------------------------------------------------------- */
.nav-search .input {
  border-radius: var(--r-pill);
  background: var(--surface-2);
  border-color: transparent;
  transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
.nav-search .input:focus { background: var(--surface); border-color: var(--brand); box-shadow: var(--glow-brand); }
.nav-search kbd {
  position: absolute;
  right: 10px; top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--fg-faint);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 3px 6px;
  pointer-events: none;
  transition: opacity var(--dur-1) var(--ease-out);
}
.nav-search .input:focus ~ kbd { opacity: 0; }

/* --- header measure and rhythm ---------------------------------------
   The bar was reading cramped: everything was squeezed into the 1320px body
   container while a wide screen left 300px of dead margin either side, the
   links sat at 13px with a 2px gap, the tools at a 4px gap, and a 380px search
   field took the space the links needed. Six items fighting in the middle of an
   empty bar is what made it look cluttered.

   The header gets its own, wider measure — it is chrome, not body copy, and it
   is the one element that should use the full screen. Everything inside then
   gets room rather than being made smaller. */
.site-nav .nav-in {
  max-width: var(--container-wide);
  gap: var(--s-5);
}
@media (min-width: 1080px) {
  .nav-links { gap: var(--s-1); margin-left: var(--s-4); }
  .nav-link { font-size: var(--t-base); padding-inline: var(--s-5); height: 42px; }
  /* the search was taking the width the links wanted */
  .nav-search { max-width: 300px; margin-inline: var(--s-5); }
  .nav-tools { gap: 6px; }
}
@media (min-width: 1440px) {
  .nav-search { max-width: 360px; }
  .nav-links { gap: var(--s-2); }
}

/* --- tools ----------------------------------------------------------- */
.icon-btn { transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out); }
.icon-btn:active { transform: scale(.92); }
.cart-btn.is-bump { animation: cart-bump 460ms var(--ease-spring); }
@keyframes cart-bump {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.18); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) { .cart-btn.is-bump { animation: none; } }

/* ==================================================================== 4a. hero
   Moved to its own file: req/css/hero.css
   It is the largest single component on the site and was making this file hard
   to navigate. hero.css loads immediately before craft.css.
   ========================================================================== */

/* ==================================================================== 4b. legacy hero carousel

   The carousel already toggles `.is-on` per slide, so the copy animation hangs
   off that class rather than off the reveal observer. Every slide therefore
   animates each time it becomes active, not once on first paint, and
   carousel.js needed no changes at all. */

.hero-slide .hero-copy > * {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-soil);
}
.hero-slide.is-on .hero-copy > * { opacity: 1; transform: none; }
.hero-slide.is-on .hero-copy > *:nth-child(1) { transition-delay: 90ms; }
.hero-slide.is-on .hero-copy > *:nth-child(2) { transition-delay: 170ms; }
.hero-slide.is-on .hero-copy > *:nth-child(3) { transition-delay: 250ms; }
.hero-slide.is-on .hero-copy > *:nth-child(4) { transition-delay: 330ms; }

/* the photograph drifts against the copy. Oversized by 6% so the parallax
   offset can never expose an edge of the frame. */
.hero-slide img { transform: scale(1.06) translate3d(0, var(--pfy, 0px), 0); }
@media (prefers-reduced-motion: reduce) {
  .hero-slide .hero-copy > * { opacity: 1; transform: none; transition: none; }
  .hero-slide img { transform: none; }
}

/* the accent word in a hero headline gets an underline that draws after the
   line has settled */
.hero-copy h2 em { font-style: normal; position: relative; color: var(--harvest-400); white-space: nowrap; }
.hero-copy h2 em::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -.06em;
  height: 3px;
  border-radius: 3px;
  background: currentColor;
  opacity: .5;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-4) var(--ease-out) 620ms;
}
.hero-slide.is-on .hero-copy h2 em::after { transform: scaleX(1); }

/* ==================================================================== 5. product card v3

   Four lines of information and nothing else: picture, name, size, price.

   v2 stacked a merchandising tag, a subsidy seal, a category line, a proof
   sentence, two variant chips, a stock row and a price row. At 164px wide that
   measured 509px tall — a column of small text with a stamp-sized photo on
   top. Everything that was cut still exists; it lives on the product page,
   which is where somebody who wants the guarantee terms is going anyway.

   The whole card is one hover surface: the image scales, the card lifts, the
   save button fades in and the add button widens from a circle into a labelled
   pill. All four are transform or opacity, on one shared 300ms curve, so they
   read as one gesture rather than four things twitching.
   ========================================================================== */

.pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
  box-shadow: none;
  transition:
    transform var(--dur-2) var(--ease-soil),
    box-shadow var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out);
}
.pcard:hover {
  transform: translateY(-3px);
  border-color: transparent;
  box-shadow: var(--shadow-lg);
}
.pcard:focus-within { border-color: var(--brand); }
@media (prefers-reduced-motion: reduce) { .pcard:hover { transform: none; } }

.pcard-media {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--surface-2);
  overflow: hidden;
}
.pcard-media img { width: 100%; height: 100%; object-fit: cover; transition: transform 700ms var(--ease-soil); }
.pcard:hover .pcard-media img { transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) { .pcard:hover .pcard-media img { transform: none; } }

/* machinery photography is supplier flyer artwork, not a studio shot */
.pcard-media.is-contain { background: #fff; }
.pcard-media.is-contain img { object-fit: contain; padding: 0; }

/* one badge, top left, small */
.pcard-badge {
  position: absolute;
  top: 10px; left: 10px;
  z-index: 2;
  padding: 5px 9px;
  border-radius: var(--r-chip);
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  background: var(--surface);
  color: var(--fg);
  box-shadow: var(--shadow-sm);
}
.pcard-badge.is-best { background: var(--accent); color: var(--accent-fg); }
.pcard-badge.is-new  { background: var(--brand); color: var(--brand-fg); }
.pcard-badge.is-low  { background: var(--danger-soft); color: var(--danger); }
.pcard-badge.is-seal { background: var(--accent-soft); color: var(--accent-ink); }

/* the saving reads as a stamp in the corner rather than another line of text */
.pcard-off {
  position: absolute;
  right: 10px; bottom: 10px;
  z-index: 2;
  display: grid;
  place-items: center;
  min-width: 42px; height: 42px;
  border-radius: 50%;
  background: var(--brand);
  color: var(--brand-fg);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -.02em;
  box-shadow: var(--shadow-md);
}
.pcard-off small { display: block; font-size: 7.5px; letter-spacing: .1em; opacity: .85; margin-top: 1px; }

.pcard-save {
  position: absolute;
  top: 8px; right: 8px;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border: 0;
  border-radius: 50%;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  backdrop-filter: blur(8px);
  color: var(--fg-muted);
  cursor: pointer;
  opacity: 0;
  transform: scale(.7);
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-spring), color var(--dur-1) var(--ease-out);
}
.pcard:hover .pcard-save,
.pcard:focus-within .pcard-save,
.pcard-save.is-on { opacity: 1; transform: none; }
.pcard-save:hover { color: var(--danger); }
.pcard-save.is-on { color: var(--danger); }
.pcard-save.is-on .ico { fill: currentColor; }

.pcard-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: var(--s-4) var(--s-4) var(--s-4);
  flex: 1;
}
.pcard-name {
  font-family: var(--font-display);
  font-size: var(--t-base);
  font-weight: 700;
  letter-spacing: var(--tr-snug);
  line-height: 1.25;
  margin: 0;
  /* two lines maximum, so a long machinery name cannot set the row height */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.pcard-name a { text-decoration: none; color: inherit; }
.pcard-name a::after { content: ''; position: absolute; inset: 0; z-index: 1; }

.pcard-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .05em;
  color: var(--fg-faint);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pcard-meta b { color: var(--brand-ink); font-weight: 500; }

.pcard-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  margin-top: auto;
  padding-top: var(--s-4);
}
.price { display: block; min-width: 0; }
.price-line { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.price-line small {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.price-now {
  font-family: var(--font-display);
  font-size: var(--t-lg);
  font-weight: 800;
  letter-spacing: var(--tr-tight);
  font-variant-numeric: tabular-nums;
  color: var(--fg);
}
.price-was {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  color: var(--fg-faint);
  text-decoration: line-through;
}

/* circle that widens into a pill. `width` is animated only here, on a single
   small element with no siblings to reflow, which keeps it cheap. */
.pcard-act { position: relative; z-index: 2; flex: none; }
.add-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--brand);
  color: var(--brand-fg);
  font-family: var(--font-body);
  font-size: var(--t-sm);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  cursor: pointer;
  text-decoration: none;
  box-shadow: var(--shadow-xs);
  transition: width var(--dur-2) var(--ease-soil), gap var(--dur-2) var(--ease-soil),
              background-color var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out);
}
.add-btn .ico { flex: none; }
.add-btn-text {
  max-width: 0;
  opacity: 0;
  transition: max-width var(--dur-2) var(--ease-soil), opacity var(--dur-1) var(--ease-out);
}
.pcard:hover .add-btn { width: 92px; gap: 6px; }
.pcard:hover .add-btn .add-btn-text { max-width: 60px; opacity: 1; }
.add-btn:hover { background: var(--brand-hover); }
.add-btn:active { transform: scale(.94); }
.add-btn.is-wa { background: var(--surface-2); color: var(--fg); border: 1px solid var(--border-strong); }
.add-btn.is-wa:hover { background: var(--brand); color: var(--brand-fg); border-color: var(--brand); }
.pcard:hover .add-btn.is-wa { width: 108px; }
.add-btn.is-out { background: var(--surface-2); color: var(--fg-faint); box-shadow: none; }
.add-btn[disabled] { pointer-events: none; }

/* a fine pointer gets the reveal; a finger gets the label permanently, because
   there is no hover to trigger it with */
@media (hover: none), (pointer: coarse) {
  .add-btn { width: auto; min-width: 44px; height: 44px; padding: 0 var(--s-4); gap: 6px; }
  .add-btn .add-btn-text { max-width: 70px; opacity: 1; }
  .pcard-save { opacity: 1; transform: none; width: 40px; height: 40px; }
}

/* ==================================================================== 5b. legacy card bits
   Kept so the old class names still resolve where they are used outside the
   grid (cart lines, the product page). Not used by the card itself any more. */

.pcard { border-radius: var(--r-card); box-shadow: var(--shadow-xs); }
.pcard:hover { box-shadow: var(--shadow-lg); border-color: var(--border-strong); }
.pcard-media { aspect-ratio: 4 / 3; }
.pcard-body { padding: var(--s-4) var(--s-5) var(--s-5); gap: 6px; }

/* the fact line: one short proof under the name, never a marketing sentence */
.pcard-proof {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .045em;
  color: var(--fg-subtle);
  margin: 0;
}
.pcard-proof .ico { width: 13px; height: 13px; color: var(--sprout); flex: none; }

/* variant chips on the card face, so with/without motor never costs a page load */
.pcard-variants { display: flex; flex-wrap: wrap; gap: 5px; position: relative; z-index: 2; margin-top: 2px; }
.vchip {
  appearance: none;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--fg-muted);
  border-radius: var(--r-pill);
  padding: 5px 11px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .04em;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out);
}
.vchip:hover { border-color: var(--brand); color: var(--brand-ink); }
.vchip[aria-pressed='true'] { background: var(--brand); border-color: var(--brand); color: var(--brand-fg); }
.vchip:active { transform: scale(.95); }

/* price block: selling price leads, MRP struck through, saving as a chip.
   The brief is explicit that MRP and selling price must not be conflated. */
.price-line { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s-2); }
.price-now { font-size: var(--t-xl); letter-spacing: var(--tr-tight); }
.price-was { font-size: var(--t-xs); }
.price-off {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .05em;
  color: var(--success);
  background: var(--success-soft);
  border-radius: var(--r-chip);
  padding: 3px 6px;
}
.price-unit { font-size: 10px; }

/* stock signal. Three states only, and "out" disables the control. */
.pcard-stock { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-mono); font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--fg-faint); }
.pcard-stock i { width: 6px; height: 6px; border-radius: 50%; background: var(--success); flex: none; }
.pcard-stock.is-low i { background: var(--accent); }
.pcard-stock.is-low  { color: var(--accent-ink); }
.pcard-stock.is-out i { background: var(--fg-faint); }

/* quick add: the button becomes the stepper in place rather than swapping for
   a different control, so the row never reflows under the cursor */
.add-btn { min-height: 40px; font-size: var(--t-sm); box-shadow: var(--shadow-xs); }
.add-btn .ico { transition: transform var(--dur-2) var(--ease-spring); }
.add-btn:hover .ico { transform: rotate(90deg); }
.add-btn.is-wa .ico { transition: transform var(--dur-2) var(--ease-out); }
.add-btn.is-wa:hover .ico { transform: none; }
.add-btn[disabled] { opacity: .45; pointer-events: none; }

/* wishlist, top-right of the media, only materialises on hover or focus */
.pcard-save {
  position: absolute;
  top: var(--s-3); right: var(--s-3);
  z-index: 3;
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border: 0;
  border-radius: 50%;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(8px);
  color: var(--fg-muted);
  cursor: pointer;
  opacity: 0;
  transform: scale(.8) translateY(-4px);
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-spring), color var(--dur-1) var(--ease-out);
}
.pcard:hover .pcard-save,
.pcard:focus-within .pcard-save,
.pcard-save.is-on { opacity: 1; transform: none; }
.pcard-save:hover { color: var(--danger); }
.pcard-save.is-on { color: var(--danger); }
.pcard-save.is-on .ico { fill: currentColor; }
@media (pointer: coarse) { .pcard-save { opacity: 1; transform: none; } }

/* badge stack, top-left */
.pcard-flags .badge { box-shadow: var(--shadow-xs); backdrop-filter: blur(6px); }
.badge-new  { background: var(--brand); border-color: transparent; color: var(--brand-fg); }
.badge-best { background: var(--accent); border-color: transparent; color: var(--accent-fg); }
.badge-iron { background: var(--iron-soft); border-color: transparent; color: var(--iron-ink); }

/* ==================================================================== 6. category tiles */

.cat-group-head {
  display: flex;
  align-items: baseline;
  gap: var(--s-4);
  margin-bottom: var(--s-5);
}
.cat-group-head h3 {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-muted);
  margin: 0;
  white-space: nowrap;
}
.cat-group-head .dir {
  display: inline-grid;
  place-items: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--brand-soft);
  color: var(--brand-ink);
}
.cat-group-head .dir .ico { width: 13px; height: 13px; }
.cat-group-head::after { content: ''; flex: 1; height: 1px; background: var(--hairline); }

.cat-card { min-height: 246px; }
.cat-card::after { transition: opacity var(--dur-3) var(--ease-out); }
.cat-card:hover::after { opacity: .88; }
.cat-card h3 { font-size: var(--t-lg); }
.cat-card p { font-size: var(--t-sm); }
/* the feature card carries more room, so it gets the larger type */
.cat-grid > .cat-card:nth-child(1) h3 { font-size: var(--t-2xl); }
.cat-grid > .cat-card:nth-child(1) p  { font-size: var(--t-md); max-width: 40ch; }

/* --- drawn tiles ---------------------------------------------------------
   Categories with no honest photograph. A tinted gradient field, a very large
   watermark of the category's own glyph bled off the corner, and the grain
   texture — so it reads as an authored surface rather than a photo that failed
   to load. See the note in catalog.js `categoryCards()`. */
.cat-card.is-drawn {
  --ct: var(--forest-500);
  background:
    radial-gradient(120% 92% at 8% 8%, color-mix(in srgb, var(--ct) 52%, transparent), transparent 62%),
    linear-gradient(152deg, var(--forest-800), var(--forest-900) 62%);
  isolation: isolate;
}
.cat-card.is-drawn[data-tint='clay']    { --ct: var(--iron-500); }
.cat-card.is-drawn[data-tint='forest']  { --ct: var(--forest-400); }
.cat-card.is-drawn[data-tint='harvest'] { --ct: var(--harvest-500); }
.cat-card.is-drawn[data-tint='sprout']  { --ct: var(--sprout-500); }

/* the scrim exists to make photo cards readable; a drawn card is already dark,
   so it only needs a whisper at the foot */
.cat-card.is-drawn::after {
  background: linear-gradient(to top, rgba(6, 20, 12, .72) 4%, transparent 62%);
}

.cat-mark {
  position: absolute;
  right: -12%;
  bottom: -14%;
  width: 62%;
  height: auto;
  aspect-ratio: 1;
  z-index: -1;
  stroke: currentColor;
  stroke-width: .85;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: color-mix(in srgb, var(--ct) 74%, transparent);
  opacity: .3;
  transition: transform var(--dur-4) var(--ease-soil), opacity var(--dur-3) var(--ease-out);
}
.cat-card.is-drawn:hover .cat-mark { transform: scale(1.06) rotate(-4deg); opacity: .42; }
@media (prefers-reduced-motion: reduce) { .cat-card.is-drawn:hover .cat-mark { transform: none; } }

/* the feature slot gets a bigger mark, since it has twice the area */
.cat-grid > .cat-card.is-drawn:nth-child(1) .cat-mark { width: 46%; right: -6%; bottom: -8%; }
/* the copy lifts slightly to make room for the CTA on hover, all transform */
.cat-card > h3, .cat-card > p, .cat-go { transition: transform var(--dur-3) var(--ease-soil); }
.cat-card:hover > h3, .cat-card:hover > p { transform: translateY(-4px); }

/* ==================================================================== 7. machinery spec card

   Machinery is not sold like a tomato, so it keeps its own component — but the
   first attempt at that turned into a 629px tower. This version follows the
   same rhythm as the product card (picture, name, one fact line, price) and
   differs only where the difference earns its place: the model number rides on
   the image, the subsidy seal is a mark rather than a text badge, and the
   action is Enquire rather than Add.
   ========================================================================== */

.spec-grid { display: grid; gap: var(--s-4); grid-template-columns: 1fr; }
@media (min-width: 560px)  { .spec-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .spec-grid { grid-template-columns: repeat(4, 1fr); } }

.spec-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
  transition: transform var(--dur-2) var(--ease-soil),
              box-shadow var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out);
}
.spec-card:hover { transform: translateY(-3px); border-color: transparent; box-shadow: var(--shadow-lg); }
@media (prefers-reduced-motion: reduce) { .spec-card:hover { transform: none; } }

/* The supplied artwork is PORTRAIT (1279x1600) and SQUARE (1599x1599). It was
   being dropped into a 4:3 landscape frame with 16px of padding, so every
   flyer shrank to fit the height and sat as a small stamp inside a wide grey
   box — which is exactly what it looked like.

   A 1:1 frame matches the square pair exactly and leaves the portrait pair a
   thin margin either side. The background is white because the flyers are
   themselves white to the edge, so the frame and the artwork become one
   surface and the product fills the card. Padding is zero for the same reason. */
.spec-card-media {
  position: relative;
  aspect-ratio: 1 / 1;
  background: #fff;
  overflow: hidden;
}
.spec-card-media img {
  width: 100%; height: 100%;
  object-fit: contain;
  padding: 0;
  transition: transform 700ms var(--ease-soil);
}
.spec-card:hover .spec-card-media img { transform: scale(1.05); }
@media (prefers-reduced-motion: reduce) { .spec-card:hover .spec-card-media img { transform: none; } }

.spec-model {
  position: absolute;
  top: 10px; left: 10px;
  padding: 5px 9px;
  border-radius: var(--r-chip);
  background: var(--iron-500);
  color: #fff;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  box-shadow: var(--shadow-sm);
}
.spec-seal {
  position: absolute;
  top: 8px; right: 8px;
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-fg);
  box-shadow: var(--shadow-sm);
}

.spec-card-body { display: flex; flex-direction: column; gap: 3px; padding: var(--s-4); flex: 1; }
.spec-card-body h3 {
  font-family: var(--font-display);
  font-size: var(--t-base);
  font-weight: 700;
  letter-spacing: var(--tr-snug);
  line-height: 1.25;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.spec-card-body h3 a { color: inherit; text-decoration: none; }
.spec-card-body h3 a::after { content: ''; position: absolute; inset: 0; z-index: 1; }

.spec-facts {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .05em;
  color: var(--fg-faint);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.spec-facts b { color: var(--iron-ink); font-weight: 500; }

.spec-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  margin-top: auto;
  padding-top: var(--s-4);
  position: relative;
  z-index: 2;
}
.spec-card:hover .add-btn { width: 108px; gap: 6px; }
.spec-card:hover .add-btn .add-btn-text { max-width: 70px; opacity: 1; }

/* --- the machinery band ------------------------------------------------
   This was forced dark in BOTH themes: `.band.on-band` plus a stack of
   hard-coded hex overrides (`#101A12`, `#6B7A6E`, `#F2EFE7`) that pinned every
   card to light-on-dark regardless of the theme. In the light theme it dropped
   a black slab into the middle of an otherwise bone page.

   It is now a normal section that follows the theme — a half-step surface in
   light, genuinely dark in dark — and the cards use the ordinary `.spec-card`
   styling, which already puts the flyer artwork on its own white tile
   (`.spec-card-media`). The separation between the home side and the farm side
   is carried by the surface step and the rules, not by inverting the palette. */
.mach-band {
  background: var(--bg-2);
  border-block: 1px solid var(--border);
}
.mach-band .spec-card { box-shadow: var(--shadow-sm); }
.mach-band .spec-card:hover { box-shadow: var(--shadow-lg); }
/* the flyer artwork is white to the edge, so its tile stays white in both
   themes — that part of the original reasoning still holds */
.mach-band .spec-card-media { background: var(--white); }

.mach-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-6);
  margin-top: var(--s-8);
  padding-top: var(--s-6);
  border-top: 1px solid var(--band-hairline);
}
.mach-note {
  display: flex;
  gap: var(--s-3);
  margin: 0;
  max-width: 62ch;
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--band-fg-muted);
}
.mach-note .ico { color: var(--band-accent); flex: none; margin-top: 2px; }

/* ==================================================================== 8. seasonal strip */

.season-tabs { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-bottom: var(--s-6); }
.season-tab {
  appearance: none;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--fg-muted);
  border-radius: var(--r-pill);
  min-height: 40px;
  padding: 0 var(--s-5);
  font-family: var(--font-body);
  font-size: var(--t-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
}
.season-tab:hover { border-color: var(--brand); color: var(--brand-ink); }
.season-tab[aria-selected='true'] { background: var(--fg); border-color: var(--fg); color: var(--bg); }

.season-list { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.season-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--border);
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--fg);
  text-decoration: none;
  transition: transform var(--dur-1) var(--ease-spring), border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
.season-pill:hover { transform: translateY(-2px); border-color: var(--brand); box-shadow: var(--shadow-sm); }
.season-pill .ico { width: 15px; height: 15px; color: var(--sprout); }

/* ==================================================================== 9. seller band */

.seller-grid { display: grid; gap: var(--s-8); align-items: center; }
@media (min-width: 900px) { .seller-grid { grid-template-columns: 1.05fr .95fr; gap: var(--s-11); } }

.seller-perks { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); margin-top: var(--s-6); }
.seller-perk {
  display: grid;
  grid-template-columns: 34px 1fr;
  gap: var(--s-3);
  align-items: start;
  padding: var(--s-4);
  border: 1px solid var(--band-border);
  border-radius: var(--r-ctl);
  background: rgba(255, 255, 255, .035);
}
.seller-perk .ico { color: var(--band-accent); }
.seller-perk b { display: block; font-size: var(--t-sm); font-weight: 700; margin-bottom: 2px; }
.seller-perk span { font-size: var(--t-xs); color: var(--band-fg-muted); line-height: 1.5; }

/* ==================================================================== 10. credential wall */

.cred-wall { display: grid; gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r-panel); overflow: hidden; }
@media (min-width: 700px)  { .cred-wall { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .cred-wall { grid-template-columns: repeat(4, 1fr); } }

.cred {
  background: var(--surface);
  padding: var(--s-6);
  display: grid;
  gap: var(--s-3);
  align-content: start;
  transition: background-color var(--dur-2) var(--ease-out);
}
.cred:hover { background: var(--surface-2); }
.cred-key {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
}
.cred b { font-family: var(--font-display); font-size: var(--t-md); letter-spacing: var(--tr-snug); line-height: 1.25; }
.cred p { font-size: var(--t-sm); color: var(--fg-muted); margin: 0; line-height: 1.55; }
.cred-doc {
  margin-top: auto;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .06em;
  color: var(--accent-ink);
  padding-top: var(--s-3);
  border-top: 1px dashed var(--border);
}

/* ==================================================================== 10b. shop filters */

/* Active filter chips. These sit above the grid so what is applied is visible
   without opening the rail, and each one removes itself. */
.active-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  padding-bottom: var(--s-5);
  margin-bottom: var(--s-5);
  border-bottom: 1px solid var(--hairline);
}
.fchip-label {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-right: var(--s-1);
}
.fchip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 34px;
  padding: 0 var(--s-3) 0 var(--s-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--t-sm);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out);
}
.fchip .ico { width: 13px; height: 13px; opacity: .6; transition: opacity var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out); }
.fchip:hover { border-color: var(--danger); color: var(--danger); }
.fchip:hover .ico { opacity: 1; transform: rotate(90deg); }
.fchip:active { transform: scale(.95); }
.fchip.is-clear { background: transparent; border-style: dashed; color: var(--fg-subtle); padding-inline: var(--s-4); }
.fchip.is-clear:hover { border-style: solid; border-color: var(--fg); color: var(--fg); }

/* facet groups in the rail */
.facet-group { display: grid; gap: var(--s-2); }
.facet-group + .facet-group { margin-top: var(--s-6); padding-top: var(--s-6); border-top: 1px solid var(--hairline); }
.facet-group[hidden] { display: none; }
.facet-head {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  font-weight: 500;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: 0 0 var(--s-1);
}
.facet-head .ico { width: 14px; height: 14px; }

/* An option reads as a checkbox because that is what it behaves like. The box
   is drawn rather than using a real input, so the whole row is one 44px target
   and the label never desynchronises from the control. */
.facet-opt {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  min-height: 40px;
  padding: 0 var(--s-3);
  margin-inline: calc(var(--s-3) * -1);
  border: 0;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--fg-muted);
  font-family: var(--font-body);
  font-size: var(--t-sm);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out), opacity var(--dur-1) var(--ease-out);
}
.facet-opt::before {
  content: '';
  flex: none;
  width: 17px; height: 17px;
  border: 1.5px solid var(--border-strong);
  border-radius: 5px;
  background: var(--surface);
  transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
}
.facet-opt:hover { background: var(--surface-2); color: var(--fg); }
.facet-opt:hover::before { border-color: var(--brand); }
.facet-opt[aria-pressed='true'] { color: var(--fg); }
.facet-opt[aria-pressed='true']::before {
  background: var(--brand);
  border-color: var(--brand);
  /* the tick is a background image so it needs no extra element */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E");
  background-size: 13px;
  background-position: center;
  background-repeat: no-repeat;
}
.facet-opt .n {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}
/* an option that would return nothing is dimmed but never removed — options
   appearing and disappearing under the cursor is worse than a dead end */
.facet-opt.is-empty { opacity: .4; }

/* the rail itself */
.filters { padding-right: var(--s-2); }
@media (min-width: 1080px) {
  .filters {
    position: sticky;
    top: calc(var(--nav-h) + var(--s-5));
    max-height: calc(100vh - var(--nav-h) - var(--s-8));
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }
}

.shop-bar { border-bottom: 0; padding-bottom: 0; margin-bottom: var(--s-5); }
.shop-count { color: var(--fg-muted); font-weight: 500; }

/* Results grid: a comfortable minimum so three cards never squeeze to four.

   Stays two-up down to 340px rather than collapsing to one. A 375px phone gives
   each card about 160px, which the card is built for — below 400px its foot
   already stacks the price above a full-width button. One-up on a phone means
   two products per screen, which is the wrong trade for a produce catalogue. */
/* Measured: with the 250px rail the grid area is ~911px at 1440, so this sits
   at three columns of ~293px there — a comfortable size for a card carrying an
   image, a proof line, a price and a control. The 230px floor only changes
   anything above roughly 1600px, where it allows a fourth column instead of
   stretching three cards past 320px. */
.prod-grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr)); gap: var(--s-5) var(--s-4); }
@media (max-width: 560px) { .prod-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); } }
@media (max-width: 339px) { .prod-grid { grid-template-columns: 1fr; } }

/* At two-up on a phone the card has to shed height, not just padding.
   Measured at 375px a machinery card came out 164 x 509 — a 1:3 tower. The
   three things doing it were the category line wrapping to two lines, the
   proof line running to three, and the two variant chips stacking because
   they cannot sit side by side in 164px. Clamping the first two and turning
   the chips into a single scrollable row takes roughly 75px off without
   dropping any information or breaking the 40px touch target on the chips. */
@media (max-width: 560px) {
  .pcard-body { padding: var(--s-3) var(--s-4) var(--s-4); }
  .pcard-name { font-size: var(--t-base); }
  .price-now { font-size: var(--t-lg); }
  .pcard-cat { font-size: 9.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* -webkit-box is what makes line-clamp work, but it also drops the flex
     centring, so the icon would sit on its own line and eat the clamp budget.
     The icon goes; at 10px it was decoration, and the words are the proof. */
  .pcard-proof {
    font-size: 10px;
    line-height: 1.35;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .pcard-proof .ico { display: none; }
  .pcard-variants {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    /* let the chips reach the card edge as they scroll out */
    margin-inline: calc(var(--s-4) * -1);
    padding-inline: var(--s-4);
  }
  .pcard-variants::-webkit-scrollbar { display: none; }
  .vchip { flex: none; }
}

/* paging, not infinite scroll: the visitor keeps control of how much loads,
   and the count above the button says where they are in the set */
.load-more {
  display: grid;
  justify-items: center;
  gap: var(--s-4);
  padding: var(--s-9) 0 var(--s-4);
}
.load-more-count {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: 0;
}
.load-more .btn { min-width: 200px; }
.load-more .btn .ico { transition: transform var(--dur-2) var(--ease-spring); }
.load-more .btn:hover .ico { transform: translateY(3px); }

/* the mobile filter sheet gets a real height and its own scroll */
#filterDrawer { max-height: 86vh; }
#filterDrawer .offcanvas-body { overflow-y: auto; }
.filter-count-pill {
  display: inline-grid;
  place-items: center;
  min-width: 19px; height: 19px;
  padding: 0 5px;
  margin-left: 6px;
  border-radius: var(--r-pill);
  background: var(--brand);
  color: var(--brand-fg);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
}

/* ==================================================================== 10c. product page

   Three problems, from the screenshot:

   1. The frame was locked to 1:1 with `object-fit: contain`. Supplier flyer
      artwork is landscape, so a square frame left a third of the panel empty
      and the product floated in a white void. Contained artwork now gets a 4:3
      frame; real photography keeps the square.
   2. The variant picker was two 62px full-width slabs, which read as the most
      important thing on the page. They are now pills on one row.
   3. The right column was one long undifferentiated scroll. A key-facts strip
      under the title gives the eye somewhere to land before the spec table.
   ========================================================================== */

.pdp-frame { aspect-ratio: 1 / 1; box-shadow: var(--shadow-sm); }
.pdp-frame.is-contain { aspect-ratio: 1 / 1; background: #fff; }
.pdp-frame.is-contain img { padding: 0; }

.pdp-title { font-size: var(--t-3xl); letter-spacing: var(--tr-flat); line-height: 1.02; text-wrap: balance; }
.pdp-model {
  padding: 5px 10px;
  border-radius: var(--r-chip);
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--fg-muted);
  font-size: var(--t-2xs);
}
.pdp-info .lede { font-size: var(--t-md); max-width: 54ch; }

.pdp-price { gap: var(--s-3); margin: var(--s-5) 0 var(--s-2); align-items: baseline; }
.pdp-price .now { font-size: var(--t-3xl); }

/* --- key facts strip --------------------------------------------------- */
.pdp-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 1px;
  margin: var(--s-6) 0;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  overflow: hidden;
}
.pdp-fact { background: var(--surface); padding: var(--s-4); display: grid; gap: 3px; }
.pdp-fact dt {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
}
.pdp-fact dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--fg);
  line-height: 1.25;
}

/* --- variants as pills ------------------------------------------------- */
.variant-set {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-bottom: var(--s-6);
}
.variant-opt {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 46px;
  width: auto;
  padding: 0 var(--s-4);
  border: 1.5px solid var(--border-strong);
  border-radius: var(--r-pill);
  background: var(--surface);
  transition: border-color var(--dur-1) var(--ease-out),
              background-color var(--dur-1) var(--ease-out),
              transform var(--dur-1) var(--ease-out);
}
.variant-opt span { font-size: var(--t-sm); font-weight: 600; }
.variant-opt b { font-size: var(--t-sm); font-weight: 800; color: var(--fg-muted); }
.variant-opt:hover { border-color: var(--brand); }
.variant-opt:active { transform: scale(.97); }
.variant-opt[aria-pressed='true'] { border-color: var(--brand); background: var(--brand-soft); }
.variant-opt[aria-pressed='true'] b { color: var(--brand-ink); }

.pdp-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s-3); }
.pdp-price .price-off { font-size: var(--t-xs); padding: 4px 9px; align-self: center; }

.pdp-mrp-note {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .04em;
  color: var(--fg-subtle);
  margin: var(--s-2) 0 0;
  max-width: 46ch;
  line-height: 1.5;
}
.pdp-info .pcard-stock { margin-top: var(--s-3); }
.pdp-secondary { display: flex; gap: var(--s-3); margin-top: var(--s-4); }

.pdp-block { padding-top: var(--s-6); margin-top: var(--s-6); }
.pdp-block h2 { font-size: var(--t-md); letter-spacing: var(--tr-snug); }

.guarantee-grid { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.guarantee-item {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: var(--s-3);
  align-items: start;
  padding: var(--s-4);
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface-2);
}
.guarantee-item .ico { color: var(--brand); margin-top: 1px; }
.guarantee-item b { display: block; font-size: var(--t-sm); font-weight: 700; line-height: 1.3; }
.guarantee-item span span { font-family: var(--font-mono); font-size: var(--t-2xs); color: var(--accent-ink); letter-spacing: .04em; }

/* ==================================================================== 10c-old. product page */

.pdp-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s-3); }
.pdp-price .price-off {
  font-size: var(--t-xs);
  padding: 4px 9px;
  align-self: center;
}
/* The MRP note is the sentence that keeps the two numbers honest. Brief §40
   warns against treating the printed MRP as the selling price, so the page
   always says which one is on screen. */
.pdp-mrp-note {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .04em;
  color: var(--fg-subtle);
  margin: var(--s-2) 0 0;
  max-width: 46ch;
  line-height: 1.5;
}
.pdp-info .pcard-stock { margin-top: var(--s-3); }
.pdp-secondary { display: flex; gap: var(--s-3); margin-top: var(--s-4); }

.guarantee-grid { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.guarantee-item {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: var(--s-3);
  align-items: start;
  padding: var(--s-4);
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface-2);
}
.guarantee-item .ico { color: var(--brand); margin-top: 1px; }
.guarantee-item b { display: block; font-size: var(--t-sm); font-weight: 700; line-height: 1.3; }
.guarantee-item span span { font-family: var(--font-mono); font-size: var(--t-2xs); color: var(--accent-ink); letter-spacing: .04em; }

/* ==================================================================== 10d. support topics */

.topic-list { list-style: none; margin: var(--s-4) 0 0; padding: 0; display: grid; gap: 1px; }
.topic-list li {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--hairline);
  font-size: var(--t-sm);
  color: var(--fg-muted);
  line-height: 1.45;
}
.topic-list li:last-child { border-bottom: 0; }
.topic-list .ico { color: var(--brand); flex: none; margin-top: 2px; }

/* ==================================================================== 10e. farm box

   The page promised a crate and then never showed one: three price cards and a
   seasonal calendar, with the actual product described only in prose. These are
   the components that make it concrete.
   ========================================================================== */

/* --- the week ----------------------------------------------------------
   What happens between the order closing and the box arriving. The site's art
   direction is "numbers are the ornament", and this is the one place on the
   Farm Box page with real times in it, so the times do the ornamenting. */
.week { position: relative; display: grid; gap: var(--s-6); }
@media (min-width: 1000px) { .week { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--s-5); } }

/* the spine. Vertical on a phone, horizontal from 1000px, drawn once behind
   the whole row rather than as a border on each step. */
.week::before {
  content: '';
  position: absolute;
  left: 6px; top: 8px; bottom: 8px;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--brand), var(--chill) 52%, var(--accent));
  opacity: .32;
}
@media (min-width: 1000px) {
  .week::before {
    left: 0; right: 0; top: 6px; bottom: auto;
    width: auto; height: 2px;
    background: linear-gradient(90deg, var(--brand), var(--chill) 52%, var(--accent));
  }
}

.week-step { position: relative; padding-left: var(--s-8); }
@media (min-width: 1000px) { .week-step { padding-left: 0; padding-top: var(--s-7); } }

.week-step::before {
  content: '';
  position: absolute;
  left: 0; top: 3px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--brand);
}
@media (min-width: 1000px) { .week-step::before { top: 0; } }
.week-step[data-cold]::before { border-color: var(--chill); }
.week-step[data-warm]::before { border-color: var(--accent); }

.week-when {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  font-weight: 600;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--accent-ink);
  margin-bottom: var(--s-2);
}
.week-step[data-cold] .week-when { color: var(--chill); }
.week-step b {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-md);
  font-weight: 700;
  letter-spacing: var(--tr-snug);
  line-height: 1.25;
  margin-bottom: var(--s-2);
}
.week-step p { margin: 0; font-size: var(--t-sm); color: var(--fg-muted); line-height: 1.5; }
.on-band .week-step p { color: var(--band-fg-muted); }
.on-band .week-step::before { background: var(--band-bg); }
.on-band .week-when { color: var(--band-accent); }
.on-band .week-step[data-cold] .week-when { color: var(--band-chill); }
.on-band .week-step[data-cold]::before { border-color: var(--band-chill); }
.on-band .week-step[data-warm]::before { border-color: var(--band-accent); }

/* --- this week's crate --------------------------------------------------
   `.crate` was styled in pages.css and never used by any page. It is the one
   component that answers the question the page opens with, so it is now the
   thing directly under the headline. */
.crate-items {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(50%, 136px), 1fr));
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  overflow: hidden;
}
.crate-item { background: var(--glass-2); padding: var(--s-4); display: grid; gap: 3px; align-content: start; }
.crate-item b { font-family: var(--font-display); font-size: var(--t-sm); font-weight: 700; letter-spacing: var(--tr-snug); }
.crate-item span {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .05em;
  color: var(--fg-faint);
}

.crate-weigh {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px dashed var(--border);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: .05em;
  color: var(--fg-subtle);
}
.crate-weigh b { color: var(--fg); font-weight: 600; font-variant-numeric: tabular-nums; }

/* --- plans -------------------------------------------------------------- */
.plan-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s-3); }
.plan-for {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: 0;
}
/* the size chip: how many items, as a number, because that is the one thing
   that actually differs between the three plans */
.plan-size {
  display: grid;
  place-items: center;
  min-width: 46px; height: 46px;
  flex: none;
  border-radius: 50%;
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.plan-size small { display: block; font-size: 7.5px; letter-spacing: .1em; opacity: .8; margin-top: 2px; }
.plan.is-pick .plan-size { background: var(--brand); color: var(--brand-fg); }

/* `.mach-foot` and `.mach-note` were written for the dark machinery band on the
   home page, so they reach for `--band-*` colours. The farmers page reuses them
   on a LIGHT section, where `--band-fg-muted` is a pale sage that reads at about
   1.8:1 on bone. Off-band they take the page's own palette. */
.section:not(.band) .mach-foot { border-top-color: var(--border); }
.section:not(.band) .mach-note { color: var(--fg-muted); }
.section:not(.band) .mach-note .ico { color: var(--accent-ink); }

/* ==================================================================== 10f. farmers

   The page's actual argument is a division of labour: you grow, we do
   everything between the gate and the kitchen. That was being carried by four
   identical `.fact` tiles — the same generic component the About page also
   used twice — which stated the parts without stating the split. Two columns
   facing each other say it in the shape, before anything is read.
   ========================================================================== */

.duty {
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  overflow: hidden;
}
@media (min-width: 860px) { .duty { grid-template-columns: 1fr 1fr; } }

.duty-col { background: var(--glass-2); padding: var(--s-7) var(--s-6); }
.on-band .duty { background: var(--band-border); border-color: var(--band-border); }
.on-band .duty-col { background: rgba(255, 255, 255, .04); }

.duty-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-5);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--hairline);
}
.on-band .duty-head { border-bottom-color: var(--band-hairline); }
.duty-ico {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  flex: none;
  border-radius: var(--r-ctl);
  background: var(--brand-soft);
  color: var(--brand);
}
.duty-col.is-ours .duty-ico { background: var(--accent-soft); color: var(--accent-ink); }
.on-band .duty-ico { background: rgba(255, 255, 255, .08); color: var(--band-sprout); }
.on-band .duty-col.is-ours .duty-ico { background: rgba(238, 155, 60, .14); color: var(--band-accent); }

.duty-head b {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-lg);
  font-weight: 700;
  letter-spacing: var(--tr-snug);
  line-height: 1.2;
}
.duty-head span {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-top: 3px;
}
/* --band-fg-faint is calibrated against the band's own background. `.duty-col`
   lifts that background by 4% white, which is enough to drop this label to
   2.9:1 — measured. The muted step clears 5:1 on the lifted surface. Any small
   label on a lightened band surface needs --band-fg-muted, not -faint. */
.on-band .duty-head span { color: var(--band-fg-muted); }

.duty ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-4); }
.duty li { display: flex; gap: var(--s-3); align-items: flex-start; font-size: var(--t-sm); color: var(--fg-muted); line-height: 1.55; }
.on-band .duty li { color: var(--band-fg-muted); }
.duty li .ico { color: var(--sprout); flex: none; margin-top: 2px; }
.duty-col.is-ours li .ico { color: var(--accent-ink); }
.on-band .duty-col.is-ours li .ico { color: var(--band-accent); }
.duty li b { color: var(--fg); font-weight: 700; }
.on-band .duty li b { color: var(--band-fg); }

/* ==================================================================== 10g. about

   Two components. The timeline gains a drawn spine so the ten stages read as
   one continuous line rather than seven bordered rows — the page is called
   "we are the line", and the layout should agree with the sentence.

   `.entity` exists because of a rule in PROJECT_CONTEXT §1 that the site has
   to keep: AGRIYANA ONE LLP and DINKO AGRITECH are two separate legal
   entities and must not be mixed in customer copy. They were previously two
   tiles in a four-tile grid of generic facts, sitting beside "subsidy status"
   and "guarantee terms" as though all four were the same kind of thing. Given
   them their own paired component, the distinction is structural instead of
   something a reader has to infer.
   ========================================================================== */

.timeline { position: relative; }
@media (min-width: 800px) {
  /* the spine runs down the gutter between the stage key and the prose */
  .timeline::before {
    content: '';
    position: absolute;
    left: 194px; top: var(--s-6); bottom: var(--s-6);
    width: 2px;
    border-radius: 2px;
    background: linear-gradient(180deg, var(--brand), var(--chill) 46%, var(--accent) 78%, var(--iron));
    opacity: .3;
  }
  .tl-row { position: relative; }
  .tl-row::before {
    content: '';
    position: absolute;
    left: 189px; top: calc(var(--s-6) + 5px);
    width: 12px; height: 12px;
    border-radius: 50%;
    background: var(--bg);
    border: 2px solid var(--brand);
    z-index: 1;
  }
  .tl-row[data-tint='chill']::before  { border-color: var(--chill); }
  .tl-row[data-tint='gold']::before   { border-color: var(--accent); }
  .tl-row[data-tint='iron']::before   { border-color: var(--iron); }
}
.tl-row[data-tint='chill'] .tl-key { color: var(--chill); }
.tl-row[data-tint='iron']  .tl-key { color: var(--iron-ink); }

/* --- the two legal entities -------------------------------------------- */
.entities { display: grid; gap: var(--s-4); }
@media (min-width: 840px) { .entities { grid-template-columns: 1fr 1fr; } }

.entity {
  position: relative;
  padding: var(--s-7) var(--s-6) var(--s-6);
  border: 1px solid var(--band-border);
  border-radius: var(--r-card);
  background: rgba(255, 255, 255, .04);
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .06) 0%, transparent 38%);
}
/* a colour edge so the two are told apart before they are read */
.entity::before {
  content: '';
  position: absolute;
  left: var(--s-6); right: var(--s-6); top: 0;
  height: 3px;
  border-radius: 0 0 3px 3px;
  background: var(--band-sprout);
}
.entity.is-machinery::before { background: var(--band-iron); }

.entity-role {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  /* muted, not faint — `.entity` lifts the band by 4% white and -faint measured
     4.2:1 against it. See the note on `.duty-head span`. */
  color: var(--band-fg-muted);
  margin: 0 0 var(--s-2);
}
.entity-name {
  font-family: var(--font-display);
  font-size: var(--t-xl);
  font-weight: 800;
  letter-spacing: var(--tr-tight);
  line-height: 1.1;
  margin: 0 0 var(--s-3);
  color: var(--band-fg);
}
.entity-what { font-size: var(--t-sm); color: var(--band-fg-muted); line-height: 1.55; margin: 0 0 var(--s-5); }

.entity-facts { display: grid; gap: 0; margin: 0; }
.entity-facts > div {
  display: grid;
  grid-template-columns: 128px minmax(0, 1fr);
  gap: var(--s-4);
  padding: var(--s-3) 0;
  border-top: 1px solid var(--band-hairline);
}
.entity-facts dt {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--band-fg-muted);
}
.entity-facts dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--band-fg);
  font-variant-numeric: tabular-nums;
}
.entity-facts dd.is-pending { color: var(--band-accent); }

@media (max-width: 460px) {
  .entity-facts > div { grid-template-columns: 1fr; gap: 2px; }
}

/* ==================================================================== 10h. contact

   The checkout form is tall enough that the running total leaves the screen
   about halfway down it, which is the one number somebody filling in a
   delivery address wants to keep an eye on. Sticky on desktop only — on a
   phone the column is stacked, so pinning it would just cover the form. */
@media (min-width: 940px) {
  .checkout-side { position: sticky; top: calc(var(--nav-h) + var(--s-5)); }
}

/* ==================================================================== 10i. checkout

   Checkout is its own page now. It used to be a section bolted onto the bottom
   of contact.html, reached as `contact.html#checkout` — which meant the last
   step of buying something lived on the page about how to phone the company,
   and the browser title, the breadcrumb and the back button all disagreed with
   what the visitor was actually doing.
   ========================================================================== */

/* --- where you are ------------------------------------------------------
   A checkout that does not say how many steps are left is the main reason
   people abandon one. Three steps, and this page is the third. */
.ck-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-3);
  counter-reset: ck;
}
@media (min-width: 760px) { .ck-steps { grid-template-columns: repeat(3, 1fr); gap: var(--s-5); } }

.ck-step {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--glass);
  background-image: linear-gradient(180deg, var(--glass-line) 0%, transparent 40%);
}
.ck-step-n {
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  flex: none;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--fg-subtle);
}
.ck-step-t { display: grid; gap: 1px; min-width: 0; }
.ck-step-t b { font-size: var(--t-sm); font-weight: 700; }
.ck-step-t span {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .05em;
  color: var(--fg-faint);
}

.ck-step.is-done .ck-step-n { background: var(--brand); border-color: var(--brand); color: var(--brand-fg); }
.ck-step.is-done { border-color: var(--border); }
.ck-step.is-now  { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.ck-step.is-now .ck-step-n { background: var(--fg); border-color: var(--fg); color: var(--bg); }

/* --- how you will pay ---------------------------------------------------
   The options that are not connected yet are SHOWN and disabled rather than
   hidden, because a checkout offering only cash with no explanation reads as
   a limitation rather than a stage. `.is-soon` says which it is. */
.pay-list { display: grid; gap: var(--s-2); margin-top: var(--s-4); }

.pay-opt {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border: 1.5px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out);
}
.pay-opt input { position: absolute; opacity: 0; pointer-events: none; }

/* drawn control rather than a native radio, so the whole row is one target
   and the mark cannot desynchronise from the label */
.pay-mark {
  position: relative;
  flex: none;
  width: 20px; height: 20px;
  border: 1.5px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface);
  transition: border-color var(--dur-1) var(--ease-out);
}
.pay-mark::after {
  content: '';
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: var(--brand);
  transform: scale(0);
  transition: transform var(--dur-1) var(--ease-spring);
}
.pay-opt:hover { border-color: var(--border-strong); }
.pay-opt:has(input:checked) { border-color: var(--brand); background: var(--brand-soft); }
.pay-opt:has(input:checked) .pay-mark { border-color: var(--brand); }
.pay-opt:has(input:checked) .pay-mark::after { transform: scale(1); }
.pay-opt:focus-within { outline: 3px solid var(--border-focus); outline-offset: 2px; }

.pay-txt { display: grid; gap: 2px; min-width: 0; flex: 1; }
.pay-txt b { font-size: var(--t-sm); font-weight: 700; }
.pay-txt span { font-size: var(--t-xs); color: var(--fg-subtle); line-height: 1.45; }
.pay-opt > .ico { color: var(--brand); flex: none; }

.pay-opt.is-soon { cursor: not-allowed; opacity: .62; background: var(--surface-2); }
.pay-opt.is-soon:hover { border-color: var(--border); }

@media (pointer: coarse) { .pay-opt { padding-block: var(--s-5); } }

/* ==================================================================== 11. footer */

.site-footer { padding-block: var(--s-12) var(--s-7); }
.site-footer .foot-col a { position: relative; }
.site-footer .foot-col a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-2) var(--ease-out);
}
.site-footer .foot-col a:hover::after { transform: scaleX(1); }

/* a strata edge along the top of the footer, drawn not imaged */
.foot-strata { display: block; width: 100%; height: 46px; color: var(--bg); margin-bottom: calc(var(--s-12) * -1); position: relative; z-index: 1; }

/* ==================================================================== 12. responsive corrections
   These must beat everything above, so they stay at the end of the file.
   ========================================================================== */

/* Below 1080 the mega menu is gone and the drawer takes over; the drawer needs
   real category structure rather than five flat links. */
.drawer-group { border-bottom: 1px solid var(--border); }
.drawer-group summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  min-height: 56px;
  font-family: var(--font-display);
  font-size: var(--t-lg);
  font-weight: 700;
  color: var(--fg);
  cursor: pointer;
  list-style: none;
}
.drawer-group summary::-webkit-details-marker { display: none; }
.drawer-group summary .ico { transition: transform var(--dur-2) var(--ease-out); color: var(--fg-subtle); }
.drawer-group[open] summary .ico { transform: rotate(180deg); }
.drawer-sub { list-style: none; margin: 0; padding: 0 0 var(--s-4); display: grid; gap: 2px; }
.drawer-sub a {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-2);
  border-radius: var(--r-ctl);
  color: var(--fg-muted);
  text-decoration: none;
  font-size: var(--t-base);
  font-weight: 600;
}
.drawer-sub a:hover { background: var(--surface-2); color: var(--brand-ink); }
.drawer-sub .ico { width: 17px; height: 17px; color: var(--fg-faint); }

/* Rails: one full card plus a peek of the next, so it is obvious the row
   scrolls without needing a scrollbar or an arrow on a phone. */
@media (max-width: 639px) {
  .rail-track { grid-auto-columns: 78%; gap: var(--s-3); }
  .spec-figs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* At the narrowest width the card foot stacks: price above, action full width.
   Side by side, the price truncates and the button drops below 44px. */
@media (max-width: 400px) {
  .pcard-foot { flex-direction: column; align-items: stretch; gap: var(--s-3); }
  .pcard-act, .add-btn { width: 100%; }
}

/* Touch: everything interactive clears 44px.

   Measured at 375px, three controls were under it and had to be fixed rather
   than waived:

   .hero-dot     rendered 42x4, because it doubles as a progress bar. The bar
                 stays 4px; an invisible ::before pad carries the hit area, so
                 the target grows without the design changing.
   .foot-col a   rendered 21px tall in a 12px-gap list, 33px of effective
                 target. Min-height 40 with a 4px gap gives a clean 44.
   .brand        rendered 36px. It is a big, isolated target but it is also the
                 way home, so it gets the full 44 as well.

   Product card titles measure 19px and are deliberately left alone: the title
   anchor carries `::after { inset: 0 }`, so the real target is the whole card. */
@media (pointer: coarse) {
  .vchip { min-height: 40px; padding-inline: var(--s-4); }
  .season-tab, .season-pill { min-height: 44px; }
  .pcard-save { width: 44px; height: 44px; }
  .mega-link { padding-block: var(--s-4); }

  .hero-dot { position: relative; }
  .hero-dot::before { content: ''; position: absolute; inset: -20px -3px; }

  .foot-col ul { gap: var(--s-1); }
  .foot-col a { min-height: 40px; }

  .brand { min-height: 44px; }
}
