/* ==========================================================================
   DINKOMART — 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: var(--t-2xs);
  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; } }

/* THE MEDIA'S SQUARE CORNERS WERE EATING THE CARD'S TOP BORDER.

   `.pcard` is `border-radius: var(--r-card)` + `overflow: hidden` + a 0.8px
   border. This block is its FIRST child, it is opaque, and it is flush against
   the padding box on three sides — measured 0.8px in from left, top and right,
   which is exactly the border width. Its own corners were square, so the
   parent's rounded clip had to cut them, and that clip is antialiased onto the
   very same sub-pixel the border is drawn on, at a width where the border is
   not even one whole device pixel. The child paints after the border, so the
   child wins and the border loses its two TOP corners.

   Reported twice as "the top border is cut off". It only shows on hover
   because that is when refine.css §3 turns the border brand-green: a faint
   grey hairline losing its corners is invisible, a green one is not. The
   BOTTOM of the card has no child flush against it — the card's own surface is
   what meets the border there — which is exactly why only the top went.

   REMOVING THE OLD `::after` HAIRLINE DID NOT FIX THIS, and the note in
   refine.css §3 should be read with that in mind. There were two green lines
   at that edge; that pass removed the second one and this is the first.

   Matching the media's radius to the parent's INNER radius makes the clip a
   no-op, so there is no antialiased edge over the border at all. `- 1px`
   against a 0.8px border lands 0.2px inside the clip, which is the safe
   direction to err: a sliver of the card's own surface, never a cut border. */
.pcard-media {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--surface-2);
  overflow: hidden;
  border-radius: calc(var(--r-card) - 1px) calc(var(--r-card) - 1px) 0 0;
}
.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: var(--t-2xs);
  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: var(--t-2xs); 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: var(--t-2xs);
  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: var(--t-2xs);
  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.

   AND IT IS THE ONE PLACE IN THE BUILD THAT ANIMATES LAYOUT, against
   motion.css rule 1. A replacement was written on 2026-09-06 that reserved
   the full pill width and revealed it with `clip-path` - correct by the rule,
   and WORSE: with the box a fixed 92px and the pill collapsed to its right
   40px, `justify-content: flex-end` leaves the icon OUTSIDE the circle,
   because the invisible label still sits to its right. Getting the glyph back
   inside means either flipping the order to "Add +" or hard-coding an offset
   from the label's own width - which differs for Add, Enquire and Sold out.

   So this stays, and the reasoning for why it is tolerable is worth keeping:
   `.pcard-foot` is `justify-content: space-between`, so the price is anchored
   left and does not move when the button grows. Nothing outside the button
   reflows. Measured: the price sits at the same x hovered and not. */
.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: var(--t-2xs);
  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: var(--t-2xs);
  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: var(--t-2xs); }

/* 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: var(--t-2xs); 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.

   NOTE: this restates `box-shadow` 150 lines below the button's own block. It
   is harmless while the button carries its own background, and it is a trap
   the moment anything moves that background onto a pseudo-element - a 92px
   transparent box then casts a 92px shadow with only its right 40px painted,
   which reads as a pale empty pill beside the green circle. Ask why this line
   exists before working around it. */
.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. */
/* same geometry as `.pcard-media`, same fix — see the note there */
.spec-card-media {
  position: relative;
  aspect-ratio: 1 / 1;
  background: #fff;
  overflow: hidden;
  border-radius: calc(var(--r-card) - 1px) calc(var(--r-card) - 1px) 0 0;
}
.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: var(--t-2xs);
  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: var(--t-2xs);
  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(min(190px, 100%), 1fr)); margin-top: var(--s-6); }

/* THE BAND'S ANSWER TO THE USP CARD in components.css — the same two-beat
   hover, read against the band palette instead of the page one.

   It was a 3.5% white fill (4% once atmosphere.css restated it) with a
   --band-border hairline and no elevation at all, so on a near-black band the
   four of them were rectangles you had to go looking for. A dark surface
   cannot be lifted with a shadow the way a light one can — a shadow on black
   is invisible. So the separation here comes from the fill stepping up and the
   border warming to the accent, which is the band's own light source.

   `.seller-perk` was taken out of the `.on-band` restatement in atmosphere.css
   for this: that rule is (0,2,0) and atmosphere loads after craft, so it beat
   `.seller-perk:hover` and the hover fill never landed. */
.seller-perk {
  position: relative;
  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-color: rgba(255, 255, 255, .045);
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .06) 0%, transparent 40%);
  overflow: hidden;                    /* clips the sweep to the radius */
  transition: transform var(--dur-2) var(--ease-spring),
              border-color var(--dur-1) var(--ease-out),
              background-color var(--dur-1) var(--ease-out);
}

/* beat two — the sweep, accent into sprout. The usp card runs brand into
   accent because that side is produce going out; this one runs the other way,
   which is the money and the inputs coming back. */
.seller-perk::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 2px;
  background: linear-gradient(90deg, var(--band-accent), var(--band-sprout));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-3) var(--ease-soil);
}
.seller-perk:hover {
  transform: translateY(-3px);
  border-color: var(--band-accent);
  background-color: rgba(255, 255, 255, .075);
}
.seller-perk:hover::after { transform: scaleX(1); }

/* beat one — the glyph gets a tile and floods on hover. The tile is painted on
   the <svg> itself: there is no wrapper element in the markup, and a
   background on a stroked icon behaves exactly like one on a span. */
.seller-perk .ico {
  width: 34px;
  height: 34px;
  padding: 7px;
  box-sizing: border-box;
  border-radius: 10px;
  color: var(--band-accent);
  background: color-mix(in srgb, var(--band-accent) 13%, transparent);
  transition: background-color var(--dur-1) var(--ease-out),
              border-radius var(--dur-2) var(--ease-spring),
              color var(--dur-1) var(--ease-out),
              transform var(--dur-2) var(--ease-spring);
}
/* the same ink micro.css uses on a filled band chip — a band is dark in both
   themes, so this one does not need to flip */
.seller-perk:hover .ico {
  background: var(--band-accent);
  color: #1A0D02;
  border-radius: 13px;
  transform: scale(1.06);
}
.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 */

/* A WALL, NOT FOUR CARDS — and it stays a wall on purpose.

   The usp strip and the seller perks are detached cards that lift on hover.
   This one is a register of documents, so the cells are butt-joined inside one
   rounded panel: `gap: 1px` over a --border ground, clipped by `overflow`, so
   the seams are the panel's own hairlines. A cell in a wall cannot lift out of
   it without tearing the seam, which is why the hover here is drawn rather
   than raised. Same language as the other two, different grammar.

   The wall now carries --shadow-sm. Everything else on this page sits on the
   elevation scale; a 1px outline on its own left it flat against the ground. */
.cred-wall {
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
@media (min-width: 700px)  { .cred-wall { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .cred-wall { grid-template-columns: repeat(4, 1fr); } }

/* FLEX, NOT GRID, AND THAT IS THE BUG THIS FIXES.

   `.cred-doc` has always asked for `margin-top: auto` to sit on the floor of
   its cell. It never got there: the cell was `display: grid` with
   `align-content: start`, which packs every row to the top and leaves the free
   space below the last one, so auto margins have nothing to push against. The
   document line just trailed whatever the paragraph happened to end at — the
   four dashed rules landed at four different heights and the wall read as
   badly set. A flex column gives the auto margin something to consume, and the
   grid already stretches the cells to a common height, so all four rules now
   sit on one baseline. */
.cred {
  position: relative;
  background: var(--surface);
  padding: var(--s-6);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  transition: background-color var(--dur-2) var(--ease-out);
}

/* beat one — the spine. The record is pulled from the file: a rule draws down
   the leading edge of the cell, brand into accent, top to bottom. It is the
   usp card's bottom sweep turned through ninety degrees. */
.cred::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: linear-gradient(180deg, var(--brand), var(--accent));
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform var(--dur-3) var(--ease-soil);
}
.cred:hover { background: var(--surface-2); }
.cred:hover::before { transform: scaleY(1); }

.cred-key {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  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 {
  position: relative;
  margin-top: auto;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .06em;
  color: var(--accent-ink);
  padding-top: var(--s-3);
  border-top: 1px dashed var(--border);
}

/* beat two — the dashed rule inks in. A tear-line becoming a signed one, which
   is the argument this whole section is making: the document exists.

   Drawn as an overlay rather than by switching `border-top-style` to solid,
   because border-style is a discrete property and would snap instead of
   running. `top: -1px` puts it on the border, not under it — absolute children
   are placed against the padding box, which starts below the border. */
.cred-doc::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: -1px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-3) var(--ease-soil);
}
.cred:hover .cred-doc::before { transform: scaleX(1); }

/* ==================================================================== 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: var(--t-2xs); 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: var(--t-2xs);
    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: var(--t-2xs);
  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(min(96px, 100%), 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: var(--t-2xs);
  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(min(190px, 100%), 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(min(190px, 100%), 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: var(--t-2xs);
  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: var(--t-2xs);
  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: var(--t-2xs); 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: var(--t-2xs);
  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: DINKOMART 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: var(--t-2xs);
  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: var(--t-2xs);
  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.php, reached as `contact.php#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: var(--t-2xs);
  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%; }
}

/* THE CARD IS NARROWEST ABOVE 400px, NOT BELOW IT, AND THE RULE ABOVE MISSED
   THE WHOLE BAND WHERE THAT IS TRUE.

   `.prod-grid` is two-up all the way to 560 (line 1411), and `1fr` of a 414px
   viewport is a SMALLER card than the single column a 340px viewport gives.
   So 401..560 was the one band with a narrow card and a side-by-side foot.

   What it cost: the touch rule below gives `.add-btn` `width: auto` and its
   full label permanently, and `.pcard-act` is `flex: none`, so the button
   never gives — the price absorbs the entire shortfall. Measured at 414 on
   /machinery: 125px of content box, 104px of it taken by "Enquire", leaving
   `.price` 13px wide to hold 68px of "from Rs 26,500". `.price` is
   `overflow: visible`, so it painted straight under the button and `.pcard`
   (`overflow: hidden`) chopped the rest — every price on the page cut in half
   on an iPhone XR, 12/13/14 Pro Max, or any 412-430px Android.

   Scoped to `.prod-grid` on purpose. The rails are the other place a `.pcard`
   lives and they are NOT affected: `.rail-track` cards are 78% of the viewport
   in this band (~305-410px), which has room for both. Measured across
   320..560 — /index reported no price overflow at any width, only the five
   catalogue pages did. Widening the rule to every foot would stack a control
   under a price in a 410px card that never needed it.

   AND THE BOUND IS 575, NOT 560, BECAUSE THE GRID DOES NOT GET WIDER AT 561 —
   IT GETS NARROWER. Leaving the two-up band drops `.prod-grid` back to
   `auto-fill minmax(min(100%, 230px), 1fr)`, whose 230px floor is BELOW the
   ~253px a side-by-side foot needs, so 561 still lands on two columns and the
   card actually shrinks from 250 to 249. Measured per width: 4px cut at 561,
   clean from 570. 575 clears it with margin and, as a bonus, removes the flip
   that used to happen at exactly 561. The grid's 230px floor is left alone on
   purpose — the note at line 1405 explains what it is for. */
@media (max-width: 575px) {
  .prod-grid .pcard-foot { flex-direction: column; align-items: stretch; gap: var(--s-3); }
  .prod-grid .pcard-act, .prod-grid .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; }
}
